• 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.

[Solved] Simple unit creation script does nothing (from GUI)

Status
Not open for further replies.
Level 2
Joined
Jun 18, 2017
Messages
6
Hello, I'm currently in the process of rewriting my old project from GUI to JASS (and learning it) and as in the title, the simple script doesn't create the unit. I have no idea what could be wrong, even after stripping the code to this simple form. Any guidelines appreciated.

JASS:
function Trig_Initial_units_Func001001001 takes nothing returns boolean
    return GetPlayerSlotState(GetFilterPlayer()) == PLAYER_SLOT_STATE_PLAYING and GetPlayerController(GetFilterPlayer()) == MAP_CONTROL_USER 
endfunction
function Trig_Initial_units_Func001A takes nothing returns nothing
        call CreateNUnitsAtLoc( 1, 'hkni', GetEnumPlayer(), OffsetLocation(GetPlayerStartLocationLoc(GetEnumPlayer()), 0, 0.00), 270.00 )
endfunction
function Trig_Initial_units_Actions takes nothing returns boolean
    call ForForce( GetPlayersMatching(Condition(function Trig_Initial_units_Func001001001)), function Trig_Initial_units_Func001A )
    return true
endfunction
//===========================================================================
function InitTrig_Units takes nothing returns nothing
    local trigger t = CreateTrigger(  )
    call TriggerAddCondition( t, function Trig_Initial_units_Actions )
    set t = null
endfunction
 
Level 16
Joined
Mar 25, 2016
Messages
1,327
TriggerAddCondition takes a boolexpr, so you have to surround the function with Condition:
call TriggerAddCondition( t, Condition(function Trig_Initial_units_Actions ))
Does the map even start with this syntax error?

There is no event atached to the trigger.

Does it run at map init? This will not work, because this function only runs the automatically created trigger gg_trg_Units that is not used in your code.

You have local trigger with no event attached to it. It cannot run because nothing can access it.

I assume you want Trig_Initial_units_Actions to run at map init. You have several options:
directly call it in the init function (could previously lead to reaching the op limit, if too many things are done without starting a new thread. 1.29 raised the op limit, so it probably won't be a problem)
If you do this, you might as well inline it in the init function
evaluate the trigger in the init function (less efficient than the first one)
use an event like after 0 seconds (is slightly different than doing it instantly)

The trigger leaks, because a force is created and no destroyed.
Same for the location(s).

If you use JASS you generally don't use locations at all. Using reals is faster and you don't need to remove them.
 
One could also use "ExecuteFunc", it allows calling a function by its name in a new thread.
call ExecuteFunc("Trig_Initial_units_Actions") would requier the removage of that return value.

Most player loops in jass are done by iterating from 0 to bj_MAX_PLAYER_SLOTS, or the other wayaround, like shown in this function from blizzard.
JASS:
function TriggerRegisterAnyUnitEventBJ takes trigger trig, playerunitevent whichEvent returns nothing
    local integer index

    set index = 0
    loop
        call TriggerRegisterPlayerUnitEvent(trig, Player(index), whichEvent, null)

        set index = index + 1
        exitwhen index == bj_MAX_PLAYER_SLOTS
    endloop
endfunction
 
Since they explained most of the peculiarities already, I would only point out the lack of a trigger evaluation

JASS:
function InitTrig_Units takes nothing returns nothing
    local trigger t = CreateTrigger(  ) 
    call TriggerAddCondition( t, Condition(function Trig_Initial_units_Actions) )
    // call TriggerEvaluate(t)
    set t = null
endfunction

If the trigger needs to listen to an event, register it. Otherwise, if done on map initialization, just do TriggerEvaluate or Triggered item, depending on if you added a triggercondition or triggeraction.

Dealing with leaks is another matter that is already discussed, and is not within the scope of this answer.
 
Level 2
Joined
Jun 18, 2017
Messages
6
Does the map even start with this syntax error?
Yes, it was starting like that, but nothing happened afterwards.
Does it run at map init? This will not work, because this function only runs the automatically created trigger gg_trg_Units that is not used in your code.
Just to be sure, is that way fine knowing that this trigger will be run on the initialization? If i wanted to have this trigger outside of the initialization one, I'd need to call TriggerEvaluate of this one in the one that runs on initialization?
JASS:
function InitTrig_Initial_units takes nothing returns nothing
    set gg_trg_Initial_units = CreateTrigger(  )
    call TriggerAddCondition( gg_trg_Initial_units, Condition(function Trig_Initial_units_Actions) )
    call TriggerEvaluate(gg_trg_Initial_units)
    set gg_trg_Initial_units = null
endfunction
Most player loops in jass are done by iterating from 0 to bj_MAX_PLAYER_SLOTS
Wouldn't iterating like that be kind of inefficient? Let's say we have 24 player map and just 2 are playing, won't that go through 24 slots instead of just 2?

I am aware of leaks, will be fixing them after i get everything to run just fine.
Thanks a lot, I understand triggers more clearly now, and most importantly everything works just fine.
 
Last edited:
et's say we have 24 player map and just 2 are playing, won't that go through 24 slots instead of just 2?
You are right, it would iterate all 24 slots instead of only 2.
tested around a bit you could simply use bj_FORCE_ALL_PLAYERS it only contains active playing slots and there is no need to destroy it.
 
Status
Not open for further replies.
Top