• Listen to a special audio message from Bill Roper to the Hive Workshop community (Bill is a former Vice President of Blizzard Entertainment, Producer, Designer, Musician, Voice Actor) 🔗Click here to hear his message!
  • Read Evilhog's interview with Gregory Alper, the original composer of the music for WarCraft: Orcs & Humans 🔗Click here to read the full interview.

Training Units with Triggers

Status
Not open for further replies.
So I have this trigger I'm working on where a unit that's initially made unavailable for training is temporarily made available again, ordered to be trained, and made unavaible again. When I use variables, however, it doesn't work. I need to use the unit id directly, and I'd rather avoid hardcoding it.

It starts out like this
JASS:
if GetUnitTypeId(TrainedUnit) == 'vsd1' then
    set GoldCost[m]     = 200
    set LumberCost[m]   = 0
    set UnitType[m]     = 'vsde'
endif

Then in another function I do this:
JASS:
call SetPlayerUnitAvailableBJ(UnitType[m], true, m.owner)
call IssueImmediateOrderById(m.dummy, UnitType[m])
call SetPlayerUnitAvailableBJ(UnitType[m], false, m.owner)

The above doesn't work. However, if I do this...
JASS:
call SetPlayerUnitAvailableBJ('vsde', true, m.owner)
call IssueImmediateOrderById(m.dummy, 'vsde')
call SetPlayerUnitAvailableBJ('vsde', false, m.owner)

...it works correctly. I've checked and made sure the value of m remains the same so the array isn't the problem. UnitType is an integer array, and all functions and variables are used inside the same scope.
 
What it does it that when I click to train a unit (which is a dummy), a projectile (which is a unit) shoots out of the building and when it lands, it's ordered to train a unit. I've tested this with the actual unit code ('vsde') and it works. It's only when I use UnitType[m] that it fails to do the same thing.

The projectile system I'm using is BPower's Missile.

There's the full code:
JASS:
scope vsUnitTraining
    
    globals
        private integer array UnitType
        private integer array GoldCost
        private integer array LumberCost
    endglobals
    
    struct vsUnitTrainingMissile extends array
    
        //onRemove
        private static method onRemove takes Missile m returns boolean
            local integer newGold     = 0
            local integer newLumber   = 0
            local location RallyPoint = GetUnitRallyPoint(m.source)
            
            call UnitRemoveAbility(m.dummy, 'Arav')
            
            //Remove Locust
            call ShowUnit(m.dummy, false)
            call UnitRemoveAbility(m.dummy, 'Aloc')
            call ShowUnit(m.dummy, true)
            //call UnitAddAbility(m.dummy, 'Abrf')
            //call IssueImmediateOrder(m.dummy, 852138)
            //call UnitRemoveAbility(m.dummy, 'Abrf')
            call SetUnitInvulnerable(m.dummy, false)
            //call SetUnitPathing(m.dummy, true)
            //End Remove Locust
            
            call SetUnitPropWindow(m.dummy, 0.)
            
            set newGold = GetPlayerState(m.owner, PLAYER_STATE_RESOURCE_GOLD) + GoldCost[m]
            set newLumber = GetPlayerState(m.owner, PLAYER_STATE_RESOURCE_LUMBER) + LumberCost[m]
            call SetPlayerState(m.owner, PLAYER_STATE_RESOURCE_GOLD, newGold)
            call SetPlayerState(m.owner, PLAYER_STATE_RESOURCE_LUMBER, newLumber)
            
            //The following is where it stops working
            call SetPlayerUnitAvailableBJ(UnitType[m], true, m.owner)
            call IssueImmediateOrderById(m.dummy, UnitType[m])
            call SetPlayerUnitAvailableBJ(UnitType[m], false, m.owner)
            
            set GoldCost[m]     = 0
            set LumberCost[m]   = 0
            set UnitType[m]     = 0
            
            if GetUnitRallyUnit(m.source) != null then
                call IssueTargetOrderById(m.dummy, 851980, GetUnitRallyUnit(m.source)) //851980 == "setrally"
            elseif RallyPoint != null then
                call IssuePointOrderLoc(m.dummy, "setrally", RallyPoint)
            endif
    
            call RemoveLocation(RallyPoint)
            
            return false
        endmethod
        
        implement MissileStruct
        
    endstruct

    function vs_Unit_Training takes nothing returns boolean
        
        local unit Source           = GetTriggerUnit()
        local unit TrainedUnit      = null
        local unit FactoryDummy     = null
        
        local player SourcePlayer   = GetOwningPlayer(Source)
        local integer newGold       = 0
        local integer newLumber     = 0
        
        local real SOURCE_X         = 0.
        local real SOURCE_Y         = 0.
        local real IMPACT_X         = 0.
        local real IMPACT_Y         = 0.
        local real Angle            = 0.
        local real Vector           = 0.
        
        local Missile m             = 0
        
        if GetUnitTypeId(Source) == 'vssr' then //Summoning Rift
            
            set TrainedUnit = GetTrainedUnit()
            
            set Angle    = GetRandomReal(0, 6.28319)
            set Vector   = GetRandomReal(220,380)
            
            set SOURCE_X = GetUnitX(Source)
            set SOURCE_Y = GetUnitY(Source)
            set IMPACT_X = SOURCE_X + Cos(Angle) * Vector
            set IMPACT_Y = SOURCE_Y + Sin(Angle) * Vector
            
            set FactoryDummy = CreateUnit(SourcePlayer, 'vsri', SOURCE_X, SOURCE_Y, Rad2Deg(Angle))
            
            set m           = Missile.createEx(FactoryDummy, IMPACT_X, IMPACT_Y, 40.00)
            set m.speed     = 8
            set m.model     = "Abilities\\Spells\\Undead\\DevourMagic\\DevourMagicBirthMissile.mdl"//"Abilities\\Weapons\\SludgeMissile\\SludgeMissile.mdl"
            set m.arc       = GetRandomReal(1.4, 1.43)
            set m.source    = Source
            set m.owner     = SourcePlayer

            call vsUnitTrainingMissile.launch(m)
            
            if GetUnitTypeId(TrainedUnit) == 'vsd1' then //Devourer
                set GoldCost[m]     = 200
                set LumberCost[m]   = 0
                set UnitType[m]     = 'vsde'
            elseif GetUnitTypeId(TrainedUnit) == 'aaaa' then //??
                set GoldCost[m]     = 0
                set LumberCost[m]   = 0
                set UnitType[m]     = 0
            endif
            
            call IssueImmediateOrderById(Source, 851976)
            
            set newGold = GetPlayerState(SourcePlayer, PLAYER_STATE_RESOURCE_GOLD) - GoldCost[m]
            set newLumber = GetPlayerState(SourcePlayer, PLAYER_STATE_RESOURCE_LUMBER) - LumberCost[m]
            call SetPlayerState(SourcePlayer, PLAYER_STATE_RESOURCE_GOLD, newGold)
            call SetPlayerState(SourcePlayer, PLAYER_STATE_RESOURCE_LUMBER, newLumber)
            
            set FactoryDummy = null
            set TrainedUnit = null
        endif
        
        set Source = null
        
        return false
    endfunction

    //===========================================================================
    function InitTrig_vs_Unit_Training takes nothing returns nothing
        set gg_trg_vs_Unit_Training = CreateTrigger()
        call TriggerRegisterAnyUnitEventBJ( gg_trg_vs_Unit_Training, EVENT_PLAYER_UNIT_TRAIN_START )
        call TriggerAddCondition( gg_trg_vs_Unit_Training, function vs_Unit_Training )
    endfunction

endscope
 
Test it yourself. Integer arrays is definitly not the problem.

Check if important variables are set properly. For example this set TrainedUnit = GetTrainedUnit().
It should not be valid at all, because in the event you wrote there no actual unit exists. Only the unittypeid might be checked when a unit starts training.
 

Attachments

  • test.w3m
    16.2 KB · Views: 59
I managed to make it work with orders by catching the decimal version of the unit id. vsd1 in this instance is 1987273777. The only hiccup was forcing the building to cancel training of the dummy, because the order fires before the unit enters the training queue, so ordering the GetTriggerUnit() to do cancel (851976) would make it cancel nothing. I had to make a separate trigger for that - even then there was complications, however, since the building trains only dummy units that way, I simply order it to cancel every time it trains a unit.

JASS:
scope vsUnitTraining
    
    
    globals
        private integer array UnitType
        private integer array GoldCost
        private integer array LumberCost
    endglobals
    
    
    struct vsUnitTrainingMissile extends array
    
        //onRemove
        private static method onRemove takes Missile m returns boolean
            local integer newGold     = 0
            local integer newLumber   = 0
            local location RallyPoint = GetUnitRallyPoint(m.source)
            
            call UnitRemoveAbility(m.dummy, 'Arav')
            
            //Remove Locust
            call ShowUnit(m.dummy, false)
            call UnitRemoveAbility(m.dummy, 'Aloc')
            call ShowUnit(m.dummy, true)
            //call UnitAddAbility(m.dummy, 'Abrf')
            //call IssueImmediateOrder(m.dummy, 852138)
            //call UnitRemoveAbility(m.dummy, 'Abrf')
            call SetUnitInvulnerable(m.dummy, false)
            call SetUnitPathing(m.dummy, true)
            //End Remove Locust
            
            call SetUnitPropWindow(m.dummy, 0.)
            
            set newGold = GetPlayerState(m.owner, PLAYER_STATE_RESOURCE_GOLD) + GoldCost[m]
            set newLumber = GetPlayerState(m.owner, PLAYER_STATE_RESOURCE_LUMBER) + LumberCost[m]
            call SetPlayerState(m.owner, PLAYER_STATE_RESOURCE_GOLD, newGold)
            call SetPlayerState(m.owner, PLAYER_STATE_RESOURCE_LUMBER, newLumber)
            
            call SetPlayerUnitAvailableBJ(UnitType[m], true, m.owner)
            call IssueImmediateOrderById(m.dummy, UnitType[m])
            call SetPlayerUnitAvailableBJ(UnitType[m], false, m.owner)
            
            set GoldCost[m]     = 0
            set LumberCost[m]   = 0
            set UnitType[m]     = 0
            
            if GetUnitRallyUnit(m.source) != null then
                call IssueTargetOrderById(m.dummy, 851980, GetUnitRallyUnit(m.source)) //851980 == "setrally"
            elseif RallyPoint != null then
                call IssuePointOrderLoc(m.dummy, "setrally", RallyPoint)
            endif
    
            call RemoveLocation(RallyPoint)
            
            return false
        endmethod
        
        implement MissileStruct
        
    endstruct

    
    function vs_Unit_Training takes nothing returns boolean
        
        local unit Source           = GetTriggerUnit()
        local unit FactoryDummy     = null
        
        local player SourcePlayer   = GetOwningPlayer(Source)
        local integer newGold       = 0
        local integer newLumber     = 0
        
        local real SOURCE_X         = 0.
        local real SOURCE_Y         = 0.
        local real IMPACT_X         = 0.
        local real IMPACT_Y         = 0.
        local real Angle            = 0.
        local real Vector           = 0.
        
        local Missile m             = 0
        
        if /*
        [Devourer]      */(GetIssuedOrderId() == 1987273777 or /*
        [Hollowman]     */ GetIssuedOrderId() == 0000111100 ) then
            
            set Angle    = GetRandomReal(0, 6.28319)
            set Vector   = GetRandomReal(220,380)
            
            set SOURCE_X = GetUnitX(Source)
            set SOURCE_Y = GetUnitY(Source)
            set IMPACT_X = SOURCE_X + Cos(Angle) * Vector
            set IMPACT_Y = SOURCE_Y + Sin(Angle) * Vector
            
            set FactoryDummy = CreateUnit(SourcePlayer, 'vsri', SOURCE_X, SOURCE_Y, Rad2Deg(Angle))
            
            set m           = Missile.createEx(FactoryDummy, IMPACT_X, IMPACT_Y, 40.00)
            set m.speed     = 8
            set m.model     = "Abilities\\Spells\\Undead\\DevourMagic\\DevourMagicBirthMissile.mdl"//"Abilities\\Weapons\\SludgeMissile\\SludgeMissile.mdl"
            set m.arc       = GetRandomReal(1.4, 1.43)
            set m.source    = Source
            set m.owner     = SourcePlayer

            call vsUnitTrainingMissile.launch(m)
            
            if GetIssuedOrderId() == 1987273777 then //Devourer
                set GoldCost[m]     = 200
                set LumberCost[m]   = 0
                set UnitType[m]     = 'vsde'
            elseif GetIssuedOrderId() == 0000111100 then //??
                set GoldCost[m]     = 0
                set LumberCost[m]   = 0
                set UnitType[m]     = 0
            endif
            
            set newGold = GetPlayerState(SourcePlayer, PLAYER_STATE_RESOURCE_GOLD) - GoldCost[m]
            set newLumber = GetPlayerState(SourcePlayer, PLAYER_STATE_RESOURCE_LUMBER) - LumberCost[m]
            call SetPlayerState(SourcePlayer, PLAYER_STATE_RESOURCE_GOLD, newGold)
            call SetPlayerState(SourcePlayer, PLAYER_STATE_RESOURCE_LUMBER, newLumber)
            
            set FactoryDummy = null
        endif
        
        set Source = null
        
        return false
    endfunction

    
    //===========================================================================
    function InitTrig_vs_Unit_Training takes nothing returns nothing
        set gg_trg_vs_Unit_Training = CreateTrigger()
        call TriggerRegisterAnyUnitEventBJ( gg_trg_vs_Unit_Training, EVENT_PLAYER_UNIT_ISSUED_ORDER )//EVENT_PLAYER_UNIT_TRAIN_START )
        call TriggerAddCondition( gg_trg_vs_Unit_Training, function vs_Unit_Training )
    endfunction

    
endscope


Thanks for pointing out the issue in my code :)
+rep
 
Status
Not open for further replies.
Top