• 🏆 Texturing Contest #33 is OPEN! Contestants must re-texture a SD unit model found in-game (Warcraft 3 Classic), recreating the unit into a peaceful NPC version. 🔗Click here to enter!
  • It's time for the first HD Modeling Contest of 2024. Join the theme discussion for Hive's HD Modeling Contest #6! Click here to post your idea!

[JASS] JASS Troubles

Status
Not open for further replies.
Level 4
Joined
Sep 18, 2007
Messages
104
Well I opened up an old clan project and decided to recode it all in JASS for practice, and I ran into some problems. The following to triggers aren't working...

This trigger is supposed to display the message "*Hero Name*'s forces have been obliterated") to all players. Nothing happens, not even the debug.

JASS:
function DeathMessageActions takes nothing returns nothing
    call DisplayTextToForce( GetPlayersAll(), ( "|cff32cd32" + ( GetHeroProperName(GetTriggerUnit()) + " Forces have been Obliterated|r" ) ) )
    debug call BJDebugMsg("Debug1")
endfunction

//===========================================================================
function InitTrig_DeathMessage takes nothing returns nothing
    local trigger DeathMessage = CreateTrigger()
    call TriggerRegisterUnitEvent( DeathMessage, gg_unit_H00A_0025, EVENT_UNIT_DEATH )
    call TriggerRegisterUnitEvent( DeathMessage, gg_unit_H003_0022, EVENT_UNIT_DEATH )
    call TriggerRegisterUnitEvent( DeathMessage, gg_unit_H006_0023, EVENT_UNIT_DEATH )
    call TriggerRegisterUnitEvent( DeathMessage, gg_unit_H002_0016, EVENT_UNIT_DEATH )
    call TriggerRegisterUnitEvent( DeathMessage, gg_unit_H009_0019, EVENT_UNIT_DEATH )
    call TriggerRegisterUnitEvent( DeathMessage, gg_unit_O001_0020, EVENT_UNIT_DEATH )
    call TriggerRegisterUnitEvent( DeathMessage, gg_unit_H001_0018, EVENT_UNIT_DEATH )
    call TriggerRegisterUnitEvent( DeathMessage, gg_unit_E000_0017, EVENT_UNIT_DEATH )
    call TriggerRegisterUnitEvent( DeathMessage, gg_unit_H008_0024, EVENT_UNIT_DEATH )
    call TriggerRegisterUnitEvent( DeathMessage, gg_unit_H004_0423, EVENT_UNIT_DEATH )
    call TriggerAddAction( DeathMessage, function DeathMessageActions )
	set DeathMessage = null
endfunction

This trigger is supposed to spawn units at the location of the Gate Captain. The debug message comes up, but no units spawn. Also gate captains do not die, they switch owners before that. I have already wrote that script though.

JASS:
globals
   constant group captains = GetUnitsOfTypeIdAll('h00B')
endglobals

function Spawns takes nothing returns nothing
    local location loc = GetUnitLoc(GetEnumUnit()) 
    call CreateNUnitsAtLoc( 2, 'h005', GetOwningPlayer(GetEnumUnit()), loc, bj_UNIT_FACING )
    call CreateNUnitsAtLoc( 3, 'hfoo', GetOwningPlayer(GetEnumUnit()), loc, bj_UNIT_FACING )
    call CreateNUnitsAtLoc( 4, 'nhea', GetOwningPlayer(GetEnumUnit()), loc, bj_UNIT_FACING )
    set loc = null
endfunction

function Trig_Gate_Spawn_Actions takes nothing returns nothing
    call ForGroup( captains, function Spawns )
    debug call BJDebugMsg("Debug2")
endfunction

//===========================================================================
function InitTrig_Gate_Spawn takes nothing returns nothing
    local trigger GateSpawn = CreateTrigger()
    call TriggerRegisterTimerEventPeriodic( GateSpawn, 120.00 )
    call TriggerAddAction( GateSpawn, function Trig_Gate_Spawn_Actions )
    set GateSpawn = null
endfunction
 
Last edited:
Level 11
Joined
Apr 6, 2008
Messages
760
JASS:
globals
    group captains = CreateGroup() //must create a group
endglobals

function Spawns takes nothing returns nothing
    local location loc = GetUnitLoc(GetEnumUnit())
call CreateNUnitsAtLoc( 2, 'h005', GetOwningPlayer(GetEnumUnit()), loc, bj_UNIT_FACING )
    call CreateNUnitsAtLoc( 3, 'hfoo', GetOwningPlayer(GetEnumUnit()), loc, bj_UNIT_FACING )
    call CreateNUnitsAtLoc( 4, 'nhea', GetOwningPlayer(GetEnumUnit()), loc, bj_UNIT_FACING )
    set loc = null
endfunction

function Trig_Gate_Spawn_Actions takes nothing returns nothing
    call ForGroup( captains, function Spawns )
    debug call BJDebugMsg("Debug2")
endfunction

//===========================================================================
function InitTrig_Gate_Spawn takes nothing returns nothing
    local trigger GateSpawn = CreateTrigger()
    call TriggerRegisterTimerEventPeriodic( GateSpawn, 120.00 )
    call TriggerAddAction( GateSpawn, function Trig_Gate_Spawn_Actions )

    call GetUnitsOfTypeIdAll('h00B') //get the units here
    
    set GateSpawn = null
endfunction

petty inefficent code, get rid of those locations
 
Level 4
Joined
Sep 18, 2007
Messages
104
Thank you. But I am new to JASS, and may I ask what you suggest to optimize the code?

And I may as well ask, what's the difference between nulling a location and removing it.

JASS:
local location loc
set loc = null
call RemoveLocation(loc)
 
Last edited:
Level 11
Joined
Apr 6, 2008
Messages
760
if u null a location Var the location is still there and will take up size, if u remove it the location gets removed and wont take any size. all i can tell you.

but dont use locations much better to use X/Y

and i dont think call ForGroup is that good either since u need to call a new function

ill rewrite the code to a efficent tomorrow so u can learn from it gotta sleep now
 
Level 14
Joined
Nov 23, 2008
Messages
187
You forgot something:

JASS:
globals
    group captains = null
    // it should be null, because GetUnitsOfTypeIdAll() creates resulting group.
endglobals

function InitTrig_Gate_Spawn takes nothing returns nothing
    local trigger GateSpawn = CreateTrigger()
    call TriggerRegisterTimerEventPeriodic( GateSpawn, 120.00 )
    call TriggerAddAction( GateSpawn, function Trig_Gate_Spawn_Actions )
    // --->>
    set captains = GetUnitsOfTypeIdAll('h00B') //get the units here
    // <<---
    set GateSpawn = null
endfunction

And I think, that picking should be periodical (for that case, if Gate Captain was killed). My variant:

JASS:
globals
  group captains = CreateGroup()
  boolexpr conditions = null
endglobals

function Spawns takes nothing returns boolean
  local unit u = GetFilterUnit()
  local real x = 0.
  local real y = 0.
  local real f = 0.
  local player p = null
  if GetUnitTypeId(u) == 'h00B' then
    set x = GetUnitX(u)
    set y = GetUnitY(u)
    set f = GetUnitFacing(u)
    set p = GetOwningPlayer(u)
    // -----
    // >> Creating units
    call CreateUnit(p, 'h005', x, y, f)
    // . . .
    // . . .
    call CreateUnit(p, 'nhea', x, y, f)
  endif
  set u = null
  return false
endfunction

function Trig_Gate_Spawn_Actions takes nothing returns nothing
  local integer i = 0
  loop
    call GroupEnumUnitsOfPlayer(captains, Player(i), conditions)
    exitwhen i > 15
  endloop
endfunction

function InitTrig_Gate_Spawn takes nothing returns nothing
  call TimerStart(CreateTimer(), 120.0, true, function Trig_Gate_Spawn_Actions)
  set conditions = Condition(function Spawns)
endfunction

About the first issue - ensure, that your unit variables are not equal to null.
 
Level 4
Joined
Sep 18, 2007
Messages
104
I should of probably stated that the gate captains do not get killed, I will update first post. Should I use TimerUtils then since you recommend a timer?
 
Level 8
Joined
Aug 4, 2006
Messages
357
i think the problem is that your triggers are local. when function InitTrig_DeathMessage is run at map intialization, it creates a local trigger DeathMessage that only exists within that function. it registers events and actions for DeathMessage. at the end of the function, the trigger DeathMessage no longer exists. so, the trigger actions don't get set off. try changing your InitTrig functions to the following:

JASS:
function InitTrig_DeathMessage takes nothing returns nothing
    set gg_trg_DeathMessage = CreateTrigger()
    call TriggerRegisterUnitEvent( gg_trg_DeathMessage, gg_unit_H00A_0025, EVENT_UNIT_DEATH )
    call TriggerRegisterUnitEvent( gg_trg_DeathMessage, gg_unit_H003_0022, EVENT_UNIT_DEATH )
    call TriggerRegisterUnitEvent( gg_trg_DeathMessage, gg_unit_H006_0023, EVENT_UNIT_DEATH )
    call TriggerRegisterUnitEvent( gg_trg_DeathMessage, gg_unit_H002_0016, EVENT_UNIT_DEATH )
    call TriggerRegisterUnitEvent( gg_trg_DeathMessage, gg_unit_H009_0019, EVENT_UNIT_DEATH )
    call TriggerRegisterUnitEvent( gg_trg_DeathMessage, gg_unit_O001_0020, EVENT_UNIT_DEATH )
    call TriggerRegisterUnitEvent( gg_trg_DeathMessage, gg_unit_H001_0018, EVENT_UNIT_DEATH )
    call TriggerRegisterUnitEvent( gg_trg_DeathMessage, gg_unit_E000_0017, EVENT_UNIT_DEATH )
    call TriggerRegisterUnitEvent( gg_trg_DeathMessage, gg_unit_H008_0024, EVENT_UNIT_DEATH )
    call TriggerRegisterUnitEvent( gg_trg_DeathMessage, gg_unit_H004_0423, EVENT_UNIT_DEATH )
    call TriggerAddAction( gg_trg_DeathMessage, function DeathMessageActions )
endfunction


JASS:
function InitTrig_Gate_Spawn takes nothing returns nothing
    set gg_trg_GateSpawn = CreateTrigger()
    call TriggerRegisterTimerEventPeriodic( gg_trg_GateSpawn, 120.00 )
    call TriggerAddAction( gg_trg_GateSpawn, function Trig_Gate_Spawn_Actions )
endfunction

after you make these changes, export your map script, view it in JassCraft, and make sure all your triggers are being initialized at the top (e.g. "trigger gg_trg_DeathMessage = null")


a location variable "points" to a certain location. removing the location that the variable points to frees up the memory that the location was occupying. This keeps the game from slowing down over time since every location that is created is also removed. Setting a variable = null makes the variable no longer reference anything, so you should RemoveLocation(loc) before you set loc = null.
 
Last edited:
Level 14
Joined
Nov 23, 2008
Messages
187
I should of probably stated that the gate captains do not get killed, I will update first post. Should I use TimerUtils then since you recommend a timer?
There's no such need, because timer would stay all the game.

Ok, the second variant with single unit pick:

JASS:
globals
  group captains = CreateGroup()
endglobals

function Conditions takes nothing returns boolean
  if GetUnitTypeId(GetFilterUnit()) == 'h00B' then
    call GroupAddUnit(captains, GetFilterUnit())
  endif
  return false
endfunction 

function Spawns takes nothing returns nothing
  local unit u = GetEnumUnit()
  local real x = GetUnitX(u)
  local real y = GetUnitY(u)
  local real f = GetUnitFacing(u)
  local player p = GetOwningPlayer(u)

  // >> Creating units
  call CreateUnit(p, 'h005', x, y, f)
  // . . .
  call CreateUnit(p, 'nhea', x, y, f)

  set u = null
endfunction

function OnTimer takes nothing returns nothing
  call ForGroup(captains, function Spawns)
endfunction

function InitTrig_Gate_Spawn takes nothing returns nothing
  local integer i = 0
  local group gr = CreateGroup()
  loop
    call GroupEnumUnitsOfPlayer(gr, Player(i), Condition(function Conditions))
    exitwhen i > 15
  endloop
  call DestroyGroup(gr)
  set gr = null

  call TimerStart(CreateTimer(), 120.0, true, function OnTimer)
endfunction

(Almost the same, that Ciebron wrote. Almost ;) )

By the way, ForGroup is better than a FirstOfGroup loop.

>> ADDED <<
i think the problem is that your triggers are local. when function InitTrig_DeathMessage is run at map intialization, it creates a local trigger DeathMessage that only exists within that function. it registers events and actions for DeathMessage. at the end of the function, the trigger DeathMessage no longer exists.

No sir, you're wrong, there is absolutely no matter, global or local variable the trigger is. You can check it by yourself:

JASS:
function TestFunc takes nothing returns nothing
  call BJDebugMsg("zomg")
endfunction

function InitTrig_Test takes nothing returns nothing
  local trigger tr = CreateTrigger()
  call TriggerAddAction(tr, function TestFunc)
  call TriggerRegisterTimerEvent(tr, 1.0, false)
endfunction

is identical to:

JASS:
function TestFunc takes nothing returns nothing
  call BJDebugMsg("zomg")
endfunction

function InitTrig_Test takes nothing returns nothing
  set gg_trg_Test = CreateTrigger()
  call TriggerAddAction(gg_trg_Test, function TestFunc)
  call TriggerRegisterTimerEvent(gg_trg_Test, 1.0, false)
endfunction

Both variants would work.
 
Level 8
Joined
Aug 4, 2006
Messages
357
No sir, you're wrong, there is absolutely no matter, global or local variable the trigger is. You can check it by yourself:
...
Both variants would work.

hmm... both variants may work but i don't understand why. could you explain how the local trigger can exist outside the init function? does it have something to do with the hidden native code of CreateTrigger or TriggerRegisterEvent or TriggerAddAction? :confused: bleh... sorry if make this thread go off on a tangent.
 
Level 21
Joined
Aug 21, 2005
Messages
3,699
any handle, this includes units, locations, triggers, are nothing more than pointers.

If you create a local unit or location and the function ends, the pointer to this unit is removed, but the actual unit or location is still in-game. Especially in the case of locations this usually results in memory leaks. The location is still in-game and consumes memory but you've lost reference to it because your location pointer was local.

The same is true for triggers: the actual trigger behind the trigger pointer variable is still there and will still run. You simply lost reference to the trigger var but it's still there.
 
Level 4
Joined
Sep 18, 2007
Messages
104
I have another question, I just recoded my Spawn trigger and wanted some feedback. Just wondering if I should call the CreateUnit actions X amount of times or loop it like this:
JASS:
globals
    group Captains = CreateGroup()
    constant integer ID1 = 'h005'
    constant integer ID2 = 'hfoo'
    constant integer ID3 = 'nhea'
endglobals

function Reinforcements takes nothing returns nothing
    local integer i = 0
    local unit u = GetEnumUnit()
    local player p = GetOwningPlayer(u)
    local real x = GetUnitX(u)
    local real y = GetUnitY(u)
    local real f = GetUnitFacing(u)
    loop
        exitwhen i == 2 
        call CreateUnit(p, ID1, x, y, f) 
        set i = i + 1
    endloop
    loop
        exitwhen i == 5  
        call CreateUnit(p, ID2, x, y, f) 
        set i = i + 1
    endloop
    loop
        exitwhen i == 9 
        call CreateUnit(p, ID3, x, y, f) 
        set i = i + 1
    endloop  
    set u = null
    set p = null
    set i = 0
    set x = 0
    set y = 0
    set f = 0
endfunction

function SpawnActions takes nothing returns nothing
    call ForGroup( Captains, function Reinforcements )
endfunction

//===========================================================================
function InitTrig_Gate_Spawn takes nothing returns nothing
    local trigger trig = CreateTrigger()
    call TriggerRegisterTimerEventPeriodic( trig, 120.00 )
    call TriggerAddAction( trig, function SpawnActions )
    set Captains = GetUnitsOfTypeIdAll('h00B')
endfunction
 
Level 14
Joined
Nov 23, 2008
Messages
187
If the X is a constant and not too big number, it would be better to write CreateUnit() X times. If X is dependant to another variable, or changes with time, make a loop.

Also, you don't need to null reals, integers and strings:

JASS:
//    set i = 0
//    set x = 0
//    set y = 0
//    set f = 0
 
Level 4
Joined
Sep 18, 2007
Messages
104
Alright, thanks, they are constant throughout the entire game, and I didn't think I needed to null reals or integers, just wasn't sure and wanted to be safe. Wish I could rep you again, you've been a great help.
 
Status
Not open for further replies.
Top