public void buildUnit(int slotIndex, IUnitInfo unit)
    {
        if (unit == null) return;

        TargetedAction upgradeAction = null;

        //Begin by destroying the old unit
        if( units[slotIndex] != null ) {
            upgradeAction = units[slotIndex].originCard.upgrader;
            if( upgradeAction != null ) ui.triggerFlash( new int[]{slotIndex} );
            destroyUnit( slotIndex );
            //If destroyed unit has an UPGRADE, it will trigger the UI flash as it's being destroyed
        }

        //Create the actual unit
        enqueueAction (delegate(IGameplay g) {
            GameUnit u = new GameUnit ();
            u.energy = unit.getEnergy ();
            u.originCard = unit.getOriginCard ();
            u.name = unit.getName ();

            //Add attributes attached to this card
            foreach (string attr in unit.getAttributes())
                u.addAttribute (attr, (int)unit.getAttrValue (attr));

            //Register triggers attached to this card
            foreach( Trigger t in unit.getOriginCard().getTriggers() )
                registerTrigger( t, slotIndex );

            units [slotIndex] = u;
            ui.onCreateUnit (slotIndex, u);
        });

        //Do the UPGRADE trigger
        if( upgradeAction != null )
            enqueueAction ( delegate(IGameplay g) {
                upgradeAction(g, slotIndex);
            });

        //Supply
        if (getAttributeTotal (BoardManager.supplyAttr) > 0)
        enqueueAction( delegate(IGameplay g) {
            List<int> supplySlots = new List<int>(BoardManager.MAX_UNITS);
            int supplyTotal = 0;
            for( int i = 0; i < BoardManager.MAX_UNITS; ++i ) {
                if( i == slotIndex || units[i] == null ) continue;
                int? supplyValue = units[i].getAttrValue(supplyAttr);
                if( supplyValue != null && supplyValue != 0 ) {
                    supplySlots.Add(i);
                    supplyTotal += (int)supplyValue;
                }
            }

            if( supplySlots.Count > 0 ) g.modifyEnergy(slotIndex, supplyTotal );
            ui.triggerFlash( supplySlots.ToArray() );
        });

        //buildup
        if( getAttributeTotal(BoardManager.buildupAttr) > 0 )
        enqueueAction( delegate(IGameplay g) {
            for( int i = 0; i < BoardManager.MAX_UNITS; ++i ) {
                if( i == slotIndex || units[i] == null ) continue;
                int? buildupValue = units[i].getAttrValue(buildupAttr);
                if( buildupValue != null && buildupValue != 0 )
                    g.modifyEnergy( i, (int)buildupValue );
            }
        });

        //CreateUnit triggers (other than supply/buildup)
        foreach (Trigger t in allTriggers) if (t is CreateUnitTrigger) {
            CreateUnitTrigger captured = t as CreateUnitTrigger;
            if( captured.test != null && !captured.test(this, t.attachedSlot, slotIndex) ) continue;
            enqueueAction ( delegate(IGameplay g) {
                byte flags = captured.run( g, captured.attachedSlot, slotIndex);
                if( (flags & Trigger.FLASH) != 0 ) ui.triggerFlash( captured.attachedSlot );
                if( (flags & Trigger.REMOVE) != 0 ) allTriggers.Remove( captured );
            });
        }
    }