• 🏆 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] Spawn Creeps

Status
Not open for further replies.
Level 4
Joined
Apr 25, 2011
Messages
73
Hi. I seem to have problems with the spawning trigger I made. Here it is:

JASS:
function Spw1 takes nothing returns boolean
    return ( GetUnitTypeId(GetFilterUnit()) == 'npig' )
endfunction

function Spw2 takes nothing returns boolean
    return ( GetUnitTypeId(GetFilterUnit()) == 'nder' )
endfunction

function Spw_A takes nothing returns nothing
    local integer a
    local integer b
    local player p
    local group g
    local rect r
    local location l
    local boolexpr e
    
    set r = Rect(-10500.00, -15700.00, -5400.00, -14300.00)
    set l =  Location(GetRandomReal(GetRectMinX(r), GetRectMaxX(r)), GetRandomReal(GetRectMinY(r), GetRectMaxY(r)))
    set p = Player(PLAYER_NEUTRAL_AGGRESSIVE)
    set e = (Condition (function Spw1))

    set g = CreateGroup()
    call GroupEnumUnitsInRect(g, r, e )
    set  a = CountUnitsInGroup(g)
    call DestroyBoolExpr(e)
    call DestroyGroup(g)
    set g = null

    set e = (Condition (function Spw2))
    set g = CreateGroup()
    call GroupEnumUnitsInRect(g, r, e)
    set b = CountUnitsInGroup(g)
    call DestroyBoolExpr(e)
    call DestroyGroup(g)
    
    if ( a < 5 ) then
        call CreateNUnitsAtLoc( 1, 'npig', p, l, bj_UNIT_FACING )
        call RemoveLocation(l)
    endif
    
    set l =  Location(GetRandomReal(GetRectMinX(r), GetRectMaxX(r)), GetRandomReal(GetRectMinY(r), GetRectMaxY(r)))
    if ( b < 5 ) then
        call CreateNUnitsAtLoc( 1, 'nder', p, l, bj_UNIT_FACING )
        call RemoveLocation(l)
    endif

    set e = null
    set p = null
    set l = null
    set r = null
    set g = null
endfunction

//===========================================================================
function InitTrig_Spw takes nothing returns nothing
    local trigger t
    local integer index
    set t = CreateTrigger( )
    set index = 0
    loop
        call TriggerRegisterTimerEvent(t, 30, true)
        set index = index + 1
        exitwhen index == bj_MAX_PLAYER_SLOTS
    endloop
    call TriggerAddAction( t, function Spw_A )
    set t = null
endfunction

Ok. So... I works perfectly, I don't think it leaks or something (but if it does, please let me know). The problem is the amount of units it creates. I want 1 unit to spawn and it spawns 5... The thing is that it doesn't spawn them in the same point. It spawns them in different locations. Just like a loop. But I didn't use one there...

In game, after I kill 2 or 3 units, it will spawn the 2 or 3 units (which is correct), but it does it simultaneously. I tried with CreateUnitAtLoc, but it seemed to have the same result. So I changed it with CreateNUnitsAtLoc which still has the same effect.

If you know how to solve my problem, please let me know. But, please, don't post here your spawning triggers, unless they are really "Only for dummies", 'cuz I'm not in the mood of thinking how to make another trigger for spawning creeps.
 
Level 28
Joined
Jan 26, 2007
Messages
4,789
JASS:
loop
    call TriggerRegisterTimerEvent(t, 30, true)
    set index = index + 1
    exitwhen index == bj_MAX_PLAYER_SLOTS
endloop
You create multiple of the same periodic events.
If you have this event 2 times, the trigger will run twice every 30-second mark (you've got 16 of these events, you only want 1).
It is run multiple times, but the random location will of course be different - thus creating your problem.

There is no need for the loop here, as it's not a player-event (besides, you don't do anything with the index).


Some additional notes:
1) Set variables the moment you create them.
Instead of:
JASS:
local rect r
set r = Rect(-10500.00, -15700.00, -5400.00, -14300.00)
Do:
JASS:
local rect r = Rect(-10500.00, -15700.00, -5400.00, -14300.00)
2) Don't use locations in JASS. Use coordinates.
Instead of:
JASS:
set l =  Location(GetRandomReal(GetRectMinX(r), GetRectMaxX(r)), GetRandomReal(GetRectMinY(r), GetRectMaxY(r)))
Do:
JASS:
local real x = GetRandomReal(GetRectMinX(r), GetRectMaxX(r))
local real y = GetRandomReal(GetRectMinY(r), GetRectMaxY(r))

3) Replace BJ's with natives
Instead of:
JASS:
call CreateNUnitsAtLoc( 1, 'nder', p, l, bj_UNIT_FACING )
Do:
JASS:
call CreateUnit( p, 'nder', x, y, 270. )

5) If you want to count units in a group:
JASS:
local group g = CreateGroup()

call GroupEnumUnitsInRect(g, r, null)

loop
    set u = FirstOfGroup(g)
    exitwhen u == null
    
    if GetUnitTypeId(u) == 'npig' then
        set a = a+1
    elseif GetUnitTypeId(u) == 'nder' then
        set b = b+1
    endif
    call GroupRemoveUnit(g, u)
endloop
(remove the boolexpr).
 
Level 4
Joined
Apr 25, 2011
Messages
73
~ap0calypse~
I did what you said... But it seems now it spawns 3 units of both 'nder' and 'npig'. Any ideas why?

Here is it:

JASS:
function Spw_A takes nothing returns nothing
    local integer a
    local integer b
    local real x
    local real y
    local player p
    local group g
    local unit u

    set p = Player(PLAYER_NEUTRAL_AGGRESSIVE)
    set a = 0
    set b = 0


    set g = CreateGroup()
    call GroupEnumUnitsInRect(g, r, null)
    
    loop
         set u = FirstOfGroup(g)
        exitwhen u == null
   
        if GetUnitTypeId(u) == 'nder' then
            set a = a+1
        elseif GetUnitTypeId(u) == 'npig' then
            set b = b+1
        endif
        call GroupRemoveUnit(g, u)
    endloop

    set x = GetRandomReal(-10500.00, -5400.00)
    set y = GetRandomReal(-15700.00, -14300.00)
    if ( a < 5 ) then
        call CreateUnit( p, 'nder', x, y, bj_UNIT_FACING )
    endif
    
    set x = GetRandomReal(-10500.00, -5400.00)
    set y = GetRandomReal(-15700.00, -14300.00)
    if ( b < 5 ) then
        call CreateUnit( p, 'npig', x, y, bj_UNIT_FACING )
    endif

    set p = null
    set g = null
endfunction

//===========================================================================
function InitTrig_Spw takes nothing returns nothing
    local trigger t
    set t = CreateTrigger()
    call TriggerRegisterTimerEvent(t, 30, true)
    call TriggerAddAction( t, function Spw_A )
    set t = null
endfunction

It seems, lately, that it creates any number < 5 but not 1...

Edit: It seems it creates 2 of each units. And yes, it stops at 5 units each...
Do you know how to solve this? :-S
 
Level 18
Joined
Sep 14, 2012
Messages
3,413
Why don't you set your local at their declaration ?
JASS:
local integer a = 0
local integer b = 0
local player p = Player(12) //Instead of PLAYER_NEUTRAL_AGGRESIVE
local group g = CreateGroup( )
local trigger t = CreateTrigger() //In your Init function
In this code you don't create the rect r ^^
 
Level 4
Joined
Apr 25, 2011
Messages
73
JASS:
function Spw_A takes nothing returns nothing
    local integer a = 0
    local integer b = 0
    local real x
    local real y
    local player p = Player(12)
    local group g = CreateGroup()
    local rect r = Rect(-10500.00, -15700.00, -5400.00, -14300.00)
    local unit u
    
    call GroupEnumUnitsInRect(g, r, null)
    
    loop
        set u = FirstOfGroup(g)
        exitwhen u == null
   
        if GetUnitTypeId(u) == 'nder'  then
            set a = a+1
        elseif GetUnitTypeId(u) == 'npig'  then
            set b = b+1
        endif
        call GroupRemoveUnit(g, u)
    endloop

    set x = GetRandomReal(-10500.00, -5400.00)
    set y = GetRandomReal(-15700.00, -14300.00)
    if ( a < 5 ) then
        call CreateUnit( p, 'nder', x, y, bj_UNIT_FACING )
    endif
    
    set x = GetRandomReal(-10500.00, -5400.00)
    set y = GetRandomReal(-15700.00, -14300.00)
    if ( b < 5 ) then
        call CreateUnit( p, 'npig', x, y, bj_UNIT_FACING )
    endif

    set p = null
    set r = null
    set g = null
endfunction

function InitTrig_Spw takes nothing returns nothing
    local trigger t = CreateTrigger()
    call TriggerRegisterTimerEvent(t, 30, true)
    call TriggerAddAction( t, function Spw_A )
    set t = null
endfunction

~Malhorne~
I did what you said, although nothing changed... And I didn't want to give it a value when I declare it because this is only a little tiny part of my trigger. It actually creates units all over the map. So if I do "set x = ..." then I can copy-paste it easier.
And I did create the region. It's just I didn't copy it here.

Still the same problem... Anymore help?
 
Level 4
Joined
Apr 25, 2011
Messages
73
How the heck
This code will create a unit only if you have 5 or more units of this type in the region.
if it says "if a < 5 then actions" ???

Also I don't know if there is anyway to destroy a rect. Only nullify it. As for the group... It's my last concern... The whole trigger is not working how it should, why should I even bother with the group thingy? I need the trigger to work...
 
Level 4
Joined
Apr 25, 2011
Messages
73
This is the version of the trigger (now 2 little tiny pieces).
I just wanted to know if I should nullify any of the variables... I mean... Is it working how it should? Or, on prolonged use, it will lag the game?
Please advice me. xD

JASS:
function Spw_A takes nothing returns nothing
    local integer a 
    local integer b 
    local real x
    local real y
    local player p = Player(12)
    local group g
    local rect r
    local unit u
    
//===================================================================================
    set a = 0
    set b = 0
    set g = CreateGroup()
    set r = Rect(-10500.00, -15700.00, -5400.00, -14300.00)
    
    call GroupEnumUnitsInRect(g, r, null)
    
    loop
        set u = FirstOfGroup(g)
        exitwhen u == null
        if GetUnitTypeId(u) == 'nder'  then
            set a = a+1
        elseif GetUnitTypeId(u) == 'npig'  then
            set b = b+1
        endif
        call GroupRemoveUnit(g, u)
    endloop
    
    call DestroyGroup(g)

    set x = GetRandomReal(GetRectMinX(r),GetRectMaxX(r))
    set y = GetRandomReal(GetRectMinY(r), GetRectMaxY(r))
    if ( a < 5 ) then
        call CreateUnit( p, 'nder', x, y, bj_UNIT_FACING )
    endif
    
    set x = GetRandomReal(GetRectMinX(r),GetRectMaxX(r))
    set y = GetRandomReal(GetRectMinY(r), GetRectMaxY(r))
    if ( b < 5 ) then
        call CreateUnit( p, 'npig', x, y, bj_UNIT_FACING )
    endif
    
    call RemoveRect(r)

//===================================================================================
    
    set a = 0
    set b = 0
    set g = CreateGroup()
    set r = Rect(-5100.00, -15700.00, 1200.00, -14300.00)
    
    call GroupEnumUnitsInRect(g, r, null)
    
    loop
        set u = FirstOfGroup(g)
        exitwhen u == null
        if GetUnitTypeId(u) == 'nban' then
            set a = a+1
        elseif GetUnitTypeId(u) == 'nbld'  then
            set b = b+1
        endif
        call GroupRemoveUnit(g, u)
    endloop

    call DestroyGroup(g)

    set x = GetRandomReal(GetRectMinX(r), GetRectMaxX(r))
    set y = GetRandomReal(GetRectMinY(r), GetRectMaxY(r))
    if ( a < 8 ) then
        call CreateUnit( p, 'nban', x, y, bj_UNIT_FACING )
    endif
    
    set x = GetRandomReal(GetRectMinX(r), GetRectMaxX(r))
    set y = GetRandomReal(GetRectMinY(r), GetRectMaxY(r))
    if ( b < 2 ) then
        call CreateUnit( p, 'nbld' , x, y, bj_UNIT_FACING )
    endif
    
    call RemoveRect(r)

//=============================================================    

    set r = null
    set g = null
    set p = null
    set u = null

function InitTrig_Spw takes nothing returns nothing
    local trigger t = CreateTrigger()
    call TriggerRegisterTimerEvent(t, 30, true)
    call TriggerAddAction( t, function Spw_A )
    set t = null
endfunction

As I was saying, I don't give a value to a variable the moment I create it for copy-paste purpose... Plus that I think that declaring them all and then use of them is more ordered. I would like my codes to be easy to read...

So... Is it ok to go with? Or there are some changes to be done?
 
Status
Not open for further replies.
Top