HomeUser Control Panel (unavailable in archive)ForumsTutorialsArt GalleryResourcesMaps

What's the best way for...

04-09-2007, 10:58 AM#1
Toink
An AoS creep spawn and checkpoints? I never really took this seriously before, I leaked helluva lot. I don't know what's the best and most efficient way for the spawn and moving shit >_>

I need your suggestions
04-09-2007, 11:20 AM#2
Jacek
just open some aos map and check how they did it
04-09-2007, 12:16 PM#3
Rising_Dusk
Come now, it isn't that hard at all.
And no, using structs for a creep spawning system would be overkill, parallel arrays do the trick marvelously.

This is basically what I do --
Code:
- Put all of the creep spawners, creep spawn types, and creep spawn coordinates into parallel arrays.
- Loop from 0 to whatever the final index is for your last spawner.
- Check the spawner is alive.
- Spawn the basic units.
- Check if it's a special spawn wave. If so, spawn special units.
- Done.
Yes, that's it.
04-09-2007, 12:25 PM#4
blu_da_noob
You can safely ignore jacek. He is spamming struct in plenty of threads.
04-09-2007, 12:38 PM#5
Rising_Dusk
I forgot to mention, but you might want to check the owner of the spawners to make sure you're spawning creeps for the correct players.
04-10-2007, 01:18 PM#6
Toink
Thanks for the replies, but would you mind explaining what parallel arrays are? I don't know shit..
04-10-2007, 01:54 PM#7
Captain Griffen
Spawn groups 1-n correlate to array indexes 1-n

So spawn group 2 uses Location[2], Type[2] and Number[2] for the info.

These are examples of parallel arrays. Basically what structs use, but this doesn't require dynamic stuff (normally, unless spawn types change).
04-10-2007, 03:44 PM#8
Toink
Thanks for that Griff.. :D

EDIT:

This is what I've made, is it right?

Code:
function CreateCreep takes integer i, integer unitrawcode, player p returns nothing
    call CreateNUnitsAtLoc( 1, unitrawcode, p, udg_Location[i], 270 )
endfunction

function CreepWave takes nothing returns nothing
local timer t = GetExpiredTimer()
local integer i = 1
    loop
        exitwhen i == 8
        if IsUnitAliveBJ(udg_Spawner[i]) == true 
            call CreateCreep(i, rawcode[i], udg_Player[i])
        endif
        set i = i+1
    endloop
endfunction


function Trig_Creep_Waves_Actions takes nothing returns nothing
local timer t = NewTimer()
    call TimerStart(t, 30, true, function CreepWave)
endfunction
04-10-2007, 08:24 PM#9
oNdizZ
well, that won't work quite as you want it.

first function is quite useless and won't work.
You are refering to a local (integer i) variable which isnt declared in that function. And that function quite easily be written inside your CreepWave function.
so instead of:
Collapse JASS:
function CreepWave takes nothing returns nothing
        ...if IsUnitAliveBJ(udg_Spawner[i]) == true then
            call CreateCreep(i, rawcode[i], udg_Player[i])
        endif...

you would have:

Collapse JASS:
function CreepWave takes nothing returns nothing
        ...if IsUnitAliveBJ(udg_Spawner[i]) == true then
            call CreateUnit(udg_Player[i],rawcode[i],GetLocationX(udg_Location[i]),GetLocationY(udg_Location[i]),270.) 
        endif...

Collapse JASS:
function Trig_Creep_Waves_Actions takes nothing returns nothing
local timer t = NewTimer()
    call TimerStart(t, 30, true, function CreepWave)
endfunction

declaring a new local variable in this function is not only taking some extra hard work to write, but it also leaks since you aren't cleaning it.

Collapse JASS:
function Trig_Creep_Waves_Actions takes nothing returns nothing
local timer t = NewTimer()
    call TimerStart(t, 30, true, function CreepWave)
endfunction
set t = null

this is how it would be cleaned. You should actually store the timer in a global since you want to destroy it, but, since you are probably going to use it until the end of the game, this won't be a serious threat.
And because of this, you won't even have to use a local (since you aren't storing it in a global), and therefore something like this would be better:

Collapse JASS:
function Trig_Creep_Waves_Actions takes nothing returns nothing
    call TimerStart(NewTimer(), 30, true, function CreepWave)
endfunction

Oh right, just noticed you wrote NewTimer() instead of CreateTimer(). I just want to say that I have never used structs, CSCache or any other system, so I can't be sure how they deal with the cleaning.

Anyways...
Your udg_Player array, have you stored every player's force's Computer playerid in it? Like: Red: 11, Blue: 11... Yellow: 11, Orange: 12, Green: 12?

If you haven't, then you are currently creating one unit of different types for every player.
I'm not sure if you understood Captain Griffen completely (else, it's I who misunderstood you). Think of the spawn as a regular Tower Defense spawn, except in your case you don't wait until every creep is killed.

In your CreepWave function, you should add these highlighted things:

Collapse JASS:
function CreepWave takes nothing returns nothing
local timer t = GetExpiredTimer()
local integer i = 1
    loop
        exitwhen i == 8
        if IsUnitAliveBJ(udg_Spawner[i]) == true then
            call CreateUnit(udg_Player[i],rawcode[udg_level],GetLocationX(udg_Location[i]),GetLocationY(udg_Location[i]),270.) 
        endif
        set i = i+1
    endloop
    set udg_level = udg_level+1
endfunction

More comming... ...soon(?)
04-11-2007, 09:44 AM#10
Toink
OMG, if your gonna bash me with those things you should have understood my function first.

Code:
function CreateCreep takes integer i, integer unitrawcode, player p returns nothing
    call CreateNUnitsAtLoc( 1, unitrawcode, p, udg_Location[i], 270 )
endfunction

function CreepWave takes nothing returns nothing
local timer t = GetExpiredTimer()
local integer i = 1
    loop
        exitwhen i == 8
        if IsUnitAliveBJ(udg_Spawner[i]) == true 
            call CreateCreep(i, rawcode[i], udg_Player[i])
        endif
        set i = i+1
    endloop
endfunction


function Trig_Creep_Waves_Actions takes nothing returns nothing
local timer t = NewTimer()
    call TimerStart(t, 30, true, function CreepWave)
endfunction

First you say the first function is stupid and it doesn't have locals declared, that's why it takes arguments doh!

Second, I'm not nulling that timer.

Third, nullifying a variable after 'endfunction'? I don't think so.

Last, I don't want your suggestion. I have a constant and non-changing creep wave.

You don't understand my system, first I will explain it to you.

After 30 seconds of gametime, a timer starts.

Every 30 seconds, that timer expires and a function is called. This function has a loop, calling another function inside that loop with integer and player arguments. That function called creates X units at X loc for X player. Player[0] - Player[5] is set to player 6, Player[6] to player [11] is set to player 12. So that the first four calls inside the loop are created for player 6, and the last four for player 12.
04-11-2007, 11:21 AM#11
Rising_Dusk
What the hell do you need the timer declared for anyways?
And inline that stupid function call, it's slow and unnecessary.
Oh, and jass tags, please.

You also forgot a "then"
That thing wouldn't even parse.

Here... Try this..
Collapse JASS:
function CreepWave takes nothing returns nothing
    local integer i = 1
    
    loop
        exitwhen i == 8
        if GetWidgetLife(udg_Spawner[i]) > 0.405 then
            call CreateUnit(rawcode[i], udg_Player[i], GetLocationX(udg_Location[i]), GetLocationY(udg_Location[i]), 270)
            //********************************************
            //* I can't figure out why you would need the players to be global.
            //* Doesn't it consistently spawn creeps for the same player?
            //* 
            //* This also spawns only one unit per player per spot?
            //* If this is what you want, then sure, but this isn't a very elaborate spawn.
            //*
        endif
        set i = i + 1
    endloop
endfunction

function Trig_Creep_Waves_Actions takes nothing returns nothing
    call TimerStart(NewTimer(), 30., true, function CreepWave)
endfunction

Here, I wrote a little more elaborate of an idea too.
Collapse JASS:
function CreepWave takes nothing returns nothing
    local integer i = 0
    local integer j = 0
    local integer maxspawns = 5 // Some Number
    local unit s
    
    loop
        exitwhen i > 7  //Runs through eight spawners
        if GetWidgetLife(udg_Spawner[i]) > 0.405
            if GetOwningPlayer(udg_Spawner[i]) == Player(13) then //This is team A's creep player.
                loop
                    exitwhen j > maxspawns
                    set s = CreateUnit(RACE1_rawcode[j], Player(13), GetLocationX(udg_Location[i]), GetLocationY(udg_Location[i]), 270)
                    //********************************************
                    //* Setting them to vars lets you do stuff to them.
                    //* Like, you might need to add creep upgrades and stuff.
                    //* Whatever is necessary for your map.
                    //*
                    //* This loops through all rawcodes from 'j=0' to 'j=maxspawns'
                    //* and creates them all for player i at location i.
                    //*
                    //* You also don't need to fill 6 array values with the same player.
                    //* If it's constant, make it constant.
                    set j = j + 1
                endloop
            else                                                  //Now we're going through team B's spawns.
                loop
                    exitwhen j > maxspawns
                    set s = CreateUnit(RACE2_rawcode[j], Player(14), GetLocationX(udg_Location[i]), GetLocationY(udg_Location[i]), 270)
                    set j = j + 1
                endloop
            endif
        endif
        set i = i + 1 
    endloop
    //* Note, these aren't directly parallel arrays anymore.
    //* The "rawcode" array is simply loaded with all of the spawnable unit types for one race.
    //* Hence the "RACE1_rawcode" and "RACE2_rawcode"
    //*
    //* You could "still" load them all directly into the same array, but in my opinion I'd prefer
    //* being able to 100% follow my own code rather than make it as short as possible.
    //*
    //* I expect to be yelled at for that. xD
    
    set s = null
endfunction

function Trig_Creep_Waves_Actions takes nothing returns nothing
    call TimerStart(NewTimer(), 30., true, function CreepWave)
endfunction
Take it for what it's worth.
04-11-2007, 03:25 PM#12
Toink
Thanks, that's great stuff. Now I have to give you some kandy..err rep xD

Btw..

Quote:
Originally Posted by You
I can't figure out why you would need the players to be global.

It is automatic, so that I won't have to check if 'Integer A' or 'i' is less than 5 to create it for player 6 or if it's greater than that to create it for player 12.

EDIT: Oh, I have to spread the rep around <_<

DOUBLE EDIT: Oh I see why I was stupidly wrong with my system, I designed mine to create it for players without so many 'if's. Yours is perfect.

TRIPLE EDIT:
Quote:
//* This also spawns only one unit per player per spot?

No, check in my loop where it calls the function that creates the units. Spawns a maximum of four, but I can't seem to make them spawn 3 basic melees, 2 ranged and 1 elite melee. Can only spawn 1 of those types. Do you mind if I use and/or modify your system?
04-11-2007, 03:31 PM#13
Vexorian
huh? Not using structs is overkill, the suffix notation of arrays makes it harder to read...
04-11-2007, 03:34 PM#14
Toink
So are you saying structs are fine?
04-11-2007, 03:38 PM#15
Vexorian
Structs and pararel arrays are actually the same, so it doens't matter