HomeUser Control Panel (unavailable in archive)ForumsTutorialsArt GalleryResourcesMaps

Seemingly Random Spawn Loop Bug

01-08-2008, 08:15 PM#1
Karawasa
I'm trying to figure out this game breaking bug, but haven't been able to yet. What happens, is that the spawn loop will end before it should. Every round is supposed to spawn 30 creeps, but sometimes it spawns less (and thus fucks up the entire game). I haven't been able to trace the source of the bug, and haven't been able to recreate it reliably either.

I'm posting the code here in the hopes that someone has an idea of what it could be. I'd really appreciate any input, as the bug is quite game breaking.

By the way, the previous incarnation of this trigger (GUI) used waits instead of a timer, and never suffered from this bug. Just wanted to throw that out there.

Collapse JASS:
scope StartLevel

globals
    private constant integer UID_RONALD = 'n00I'
    private timer Tspawn = CreateTimer()
    private constant real SPAWN_PERIOD = 0.45
endglobals


//===========================================================================
function CreepFilter takes nothing returns boolean
    return udg_CreepOwner[GetUnitUserData(GetFilterUnit())] == GetEnumPlayer() and IsUnitType(GetFilterUnit(), UNIT_TYPE_ANCIENT) == false and IsUnitAliveBJ(GetFilterUnit()) == true
endfunction


//===========================================================================
function CountCreeps takes nothing returns nothing
    local integer id = GetPlayerId(GetEnumPlayer())
    local group g = CreateGroup()
   
    set udg_Level_Name = GetObjectName(udg_Spawns[udg_Level - 1])
    call DisplayTimedTextToPlayer( GetEnumPlayer(),0.,0., 5.00, ( "Level " + ( I2S(udg_Level) + ( ": " + ( udg_Level_Name + ( " " + ( udg_Extra + ( " - " + ( I2S(30) + " Spawns" ) ) ) ) ) ) ) ) )

    call GroupEnumUnitsOfPlayer(g,ConvertedPlayer( ( id  / 2 ) + 9 ),Condition(function CreepFilter))
    set udg_Creeps_Left[id] = CountUnitsInGroup(g)
    set udg_Creeps_Left[id] = udg_Creeps_Left[id]+(30)
   
    call DestroyGroup(g)
    set g = null
endfunction


//===========================================================================
function AlivePlayerFilter takes nothing returns boolean
    return ( udg_Player_Lives[GetPlayerId(GetFilterPlayer())] > 0 )
endfunction

//===========================================================================
function SpawnRonald takes nothing returns nothing
    local integer id = GetPlayerId(GetEnumPlayer())
    local unit u
    local real hp
   
    if udg_Spawn_Loop > 0 then
        set udg_Temp_Point = GetRectCenter(udg_Region_Spawn[id])
        set u = CreateUnitAtLoc(ConvertedPlayer( ( id  / 2 ) + 9 ),UID_RONALD,udg_Temp_Point,270.)
        call RemoveLocation(udg_Temp_Point)
        //call SetUnitUserData( u, GetConvertedPlayerId(GetEnumPlayer()) )
        set udg_CreepOwner[GetUnitIndex(u)] = GetEnumPlayer()
        set hp = ((udg_Difficulty[id]-1)*.125)+.50
        call SetWidgetLife(u,GetUnitState(u,UNIT_STATE_MAX_LIFE)*hp)
       
        set u = null
    endif
endfunction

//===========================================================================
function Start_Level_Ronalds takes nothing returns nothing
    set udg_Spawn_Loop = udg_Spawn_Loop + 1
    if udg_Spawn_Loop>31 then
        call PauseTimer(Tspawn)
        return
    endif
   
    set udg_Player_Group = GetPlayersMatching(Condition(function AlivePlayerFilter))
    call ForForce( udg_Player_Group, function SpawnRonald )
    call DestroyForce(udg_Player_Group)
endfunction


//===========================================================================
function SpawnCreep takes nothing returns nothing
    local integer id = GetPlayerId(GetEnumPlayer())
    local unit u
    local real hp
   
    if udg_Spawn_Loop > 0 then
        set udg_Temp_Point = GetRectCenter(udg_Region_Spawn[id])
        set u = CreateUnitAtLoc(ConvertedPlayer( ( id  / 2 ) + 9 ),udg_Spawns[udg_Level - 1],udg_Temp_Point,270.)
        call RemoveLocation(udg_Temp_Point)
        //call SetUnitUserData( u, GetConvertedPlayerId(GetEnumPlayer()) )
        set udg_CreepOwner[GetUnitIndex(u)] = GetEnumPlayer()
        call UnitAddAbility(u,udg_Spawn_HP[udg_Level - 1])
        set hp = ((udg_Difficulty[id]-1)*.125)+.50
        call SetWidgetLife(u,GetUnitState(u,UNIT_STATE_MAX_LIFE)*hp)
       
        set u = null
    endif
endfunction

//===========================================================================
function Start_Level_Spawns takes nothing returns nothing
    set udg_Spawn_Loop = udg_Spawn_Loop + 1
    if udg_Spawn_Loop>31 then
        call PauseTimer(Tspawn)
        return
    endif
   
    set udg_Player_Group = GetPlayersMatching(Condition(function AlivePlayerFilter))
    call ForForce( udg_Player_Group, function SpawnCreep )
    call DestroyForce(udg_Player_Group)
endfunction

//===========================================================================
function Trig_Start_Level_Actions takes nothing returns nothing
    set udg_Between_Levels = false
    set udg_Level =  udg_Level + 1
    set udg_Extra = ( "(" + ( udg_Level_Desc[( udg_Level - 1 )] + ")" ) )
   
    if udg_Level < 61 then
        set udg_Player_Group = GetPlayersMatching(Condition(function AlivePlayerFilter))
        call ForForce( udg_Player_Group, function CountCreeps )
        call DestroyForce(udg_Player_Group)
    endif
   
    if udg_Level < 61 then
        set udg_Spawn_Loop = 1
        call TimerStart(Tspawn,SPAWN_PERIOD,true,function Start_Level_Spawns)
    else
        call DisplayTextToForce( bj_FORCE_ALL_PLAYERS, "The Ronald round starts now. Good luck!" )
        call TriggerExecute( gg_trg_Create_Leaderboard )
        set udg_Spawn_Loop = 1
        call TimerStart(Tspawn,SPAWN_PERIOD,true,function Start_Level_Ronalds)
    endif
endfunction

//===========================================================================
public function InitTrig takes nothing returns nothing
    local trigger trig = CreateTrigger()
    call TriggerRegisterTimerExpireEventBJ( trig, udg_Between_Levels_Timer )
    call TriggerAddAction( trig, function Trig_Start_Level_Actions )
endfunction

endscope

Here is the old GUI version in case it helps for reference.

Trigger:
Start Level
Collapse Events
Time - Between_Levels_Timer expires
Conditions
Collapse Actions
Set Between_Levels = False
Set Level = (Level + 1)
Set Extra = (( + (Level_Desc[(Level - 1)] + )))
Unit - Create 1 Spawns[(Level - 1)] for Player 12 (Brown) at (Player 12 (Brown) start location) facing 270.00 degrees
Unit - Remove (Last created unit) from the game
Collapse If (All Conditions are True) then do (Then Actions) else do (Else Actions)
Collapse If - Conditions
Level Less than 61
Collapse Then - Actions
Set Player_Group = (All players matching (Player_Lives[((Player number of (Matching player)) - 1)] Greater than 0))
Collapse Player Group - Pick every player in Player_Group and do (Actions)
Collapse Loop - Actions
Set Temp_Group = (Units of type Spawns[(Level - 1)])
Game - Display to (Player group((Picked player))) for 5.00 seconds the text: (Level + ((String(Level)) + (: + ((Name of (Random unit from Temp_Group)) + ( + (Extra + ( - + ((String((15 + ((Difficulty[((Player number of (Picked player)) - 1)] + 0) x 3)))) + spawns))))))))
Custom script: call DestroyGroup (udg_Temp_Group)
Set Creeps_Left[((Player number of (Picked player)) - 1)] = (Number of units in (Units owned by (Player(((((Player number of (Picked player)) - 1) / 2) + 9))) matching ((((Matching unit) is alive) Equal to True) and ((((Matching unit) is An Ancient) Equal to False) and ((Custom value of (Matching unit)) Equal to (Play
Set Creeps_Left[((Player number of (Picked player)) - 1)] = (Creeps_Left[((Player number of (Picked player)) - 1)] + (15 + (Difficulty[((Player number of (Picked player)) - 1)] x 3)))
Custom script: call DestroyForce(udg_Player_Group)
Else - Actions
Collapse If (All Conditions are True) then do (Then Actions) else do (Else Actions)
Collapse If - Conditions
Level Less than 61
Collapse Then - Actions
Collapse For each (Integer Spawn_Loop) from 1 to 30, do (Actions)
Collapse Loop - Actions
Wait 0.30 game-time seconds
Set Player_Group = (All players matching (Player_Lives[((Player number of (Matching player)) - 1)] Greater than 0))
Collapse Player Group - Pick every player in Player_Group and do (Actions)
Collapse Loop - Actions
Collapse If (All Conditions are True) then do (Then Actions) else do (Else Actions)
Collapse If - Conditions
Spawn_Loop Greater than (15 - (Difficulty[((Player number of (Picked player)) - 1)] x 3))
Collapse Then - Actions
Set Temp_Point = (Center of Region_Spawn[((Player number of (Picked player)) - 1)])
Unit - Create 1 Spawns[(Level - 1)] for (Player(((((Player number of (Picked player)) - 1) / 2) + 9))) at Temp_Point facing 270.00 degrees
Custom script: call RemoveLocation(udg_Temp_Point)
Unit - Set the custom value of (Last created unit) to (Player number of (Picked player))
Unit - Set life of (Last created unit) to (50.00 + ((Real((Difficulty[((Player number of (Picked player)) - 1)] - 1))) x 12.50))%
Set Temp_Point = (Center of Region_Leak[((Player number of (Picked player)) - 1)])
Unit - Order (Last created unit) to Move To Temp_Point
Custom script: call RemoveLocation(udg_Temp_Point)
Else - Actions
Custom script: call DestroyForce(udg_Player_Group)
Collapse Else - Actions
Leaderboard - Create a leaderboard for (All players) titled Ronald Spawn Count
Leaderboard - Show (Last created leaderboard)
Leaderboard - Add Player 12 (Brown) to (Last created leaderboard) with label Spawn and value Ronalds
Game - Display to (All players) the text: The Ronald round st...
Countdown Timer - Start Spawn_Ronald as a Repeating timer that will expire in 1.00 seconds
Trigger - Run Spawn Ronald <gen> (ignoring conditions)
01-08-2008, 08:41 PM#2
Troll-Brain
the timer Between_Levels_Timer can't expire more than each 9 s (0.3*30) ?
01-08-2008, 11:00 PM#3
Toadcop
hmmm do you have tested if threads still alive ? aka add some message on function end ? and yes begin... or you could make it internal.
for example.

timer executes function
Code:
if not mybool then 
 set mybool=true
else
 call echo("WTF !? Dead Thread walking TT") // it's a error message
endif
...
// bla bla your code
...
 set mybool=false
01-08-2008, 11:46 PM#4
Vexorian
Please explain this: ConvertedPlayer( ( id / 2 ) + 9 )
Notice that ConvertedPlayer requires ids that begin with 1.

There are a lot of things to fix in your code, but I need to understand that one before doing anything.

Do you really intend it to require 13 seconds to generate all the units?
01-09-2008, 12:23 AM#5
Karawasa
Quote:
Originally Posted by Vexorian
Please explain this: ConvertedPlayer( ( id / 2 ) + 9 )
Notice that ConvertedPlayer requires ids that begin with 1.

There are a lot of things to fix in your code, but I need to understand that one before doing anything.

Do you really intend it to require 13 seconds to generate all the units?

I appreciate the response Vexorian (and others), and would be grateful for any fixes.

There are 8 human players in the map. In order to reduce creep clumping during movement, the map was converted from 1 computer spawning player to 4. What this means, is that every two players gets a computer spawner. Thus, id/2 from 0-7 will generate a range from 0-3. Add 9 to that, and you get a range between 9-12. Players 9-12 are the computer spawners.
01-09-2008, 12:32 AM#6
Vexorian
id : 0-7

id/2 : 0-3

id/2 + 9 : 9-12

(id/2 +9) - 1 = 8-11

I think you are better adding by 8 and using Player() instead of ConvertedPlayer(), but it looks like the issue was not caused by this gonna take a further look.
01-09-2008, 12:45 AM#7
cohadar
That part is irrelevant Vex.
If I remember correctly it has something to do with assigning witch human player will get witch computer player to fight against.

This is the source of problem:
Collapse JASS:
//===========================================================================
function Start_Level_Spawns takes nothing returns nothing
    set udg_Spawn_Loop = udg_Spawn_Loop + 1
    if udg_Spawn_Loop>31 then
        call PauseTimer(Tspawn)
        return
    endif
   
    set udg_Player_Group = GetPlayersMatching(Condition(function AlivePlayerFilter))
    call ForForce( udg_Player_Group, function SpawnCreep )
    call DestroyForce(udg_Player_Group)
endfunction

This function is periodically called, and in every periodic call it creates a force of all active players and spawns a creep for them.

That whole force thing should be out of there,
perhaps doing it at the beginning of each level.

Maybe it is hitting the OP limit for some reason??

Ok so the above function is calling this for each player
Collapse JASS:
//===========================================================================
function SpawnCreep takes nothing returns nothing
    local integer id = GetPlayerId(GetEnumPlayer())
    local unit u
    local real hp
   
    if udg_Spawn_Loop > 0 then
        set udg_Temp_Point = GetRectCenter(udg_Region_Spawn[id])
        set u = CreateUnitAtLoc(ConvertedPlayer( ( id  / 2 ) + 9 ),udg_Spawns[udg_Level - 1],udg_Temp_Point,270.)
        call RemoveLocation(udg_Temp_Point)
        //call SetUnitUserData( u, GetConvertedPlayerId(GetEnumPlayer()) )
        set udg_CreepOwner[GetUnitIndex(u)] = GetEnumPlayer() // <------<<
        call UnitAddAbility(u,udg_Spawn_HP[udg_Level - 1])
        set hp = ((udg_Difficulty[id]-1)*.125)+.50
        call SetWidgetLife(u,GetUnitState(u,UNIT_STATE_MAX_LIFE)*hp)
       
        set u = null
    endif
endfunction
The line I marked with an arrow is the line that uses PUI function GetUnitIndex()
the commented line above is how it used to be before.
Now Karawasa once asked me if error might be happening because of PUI.
I said no. If it was an error in PUI it would be reported by system itself.
And as far as I know Karawasa did not report any PUI messages showing up.
Karawasa?
Anyways I just wanted to mention that in the unlikely case that I was wrong.

My best bet for fixing the problem right now is putting those forces outside the loop and making udg_Spawn_Loop a private variable inside spawn scope so it is sure no other triggers are messing with it.

EDIT:
Important question: does spawning stop for ALL players or only for some players.
If it is only some players the error is probably here:
Collapse JASS:
//===========================================================================
function AlivePlayerFilter takes nothing returns boolean
    return ( udg_Player_Lives[GetPlayerId(GetFilterPlayer())] > 0 )
endfunction
01-09-2008, 01:17 AM#8
Karawasa
@Cohadar: No error messages for PUI come up. In regards to the bug itself, it stops spawning for ALL players.
01-09-2008, 01:46 AM#9
rain9441
My guess is your problem is elsewhere, check all the points where you start udg_Between_Levels_Timer up because if you start it before it has spawned all 30 monsters you'd get the effect of only ... 20 of them spawning. Something similar... I looked over your code and there is no reason it wouldnt spawn all 30.
01-09-2008, 02:13 AM#10
Karawasa
@rain9441:

Trigger:
Unit Dies
Collapse Events
Unit - A unit Dies
Conditions
Collapse Actions
Set Temp_Player = CreepOwner[(Custom value of (Dying unit))]
Set Temp_Int = ((Player number of Temp_Player) - 1)
Collapse If (All Conditions are True) then do (Then Actions) else do (Else Actions)
Collapse If - Conditions
Level Less than 61
((Owner of (Dying unit)) is an enemy of Player 1 (Red)) Equal to True
Player_Lives[Temp_Int] Greater than 0
((Dying unit) is An Ancient) Equal to False
(Level of Resurrection for (Dying unit)) Equal to 0
Collapse Then - Actions
Set Bounty_Bonus = 1.00
Set Bounty_Bonus = (Bounty_Bonus + (0.50 x (Real((Level of Arbitrage for (Killing unit))))))
Player - Add (Max(0, (Integer(((Power(Bounty_Base, ((Real((Level of Spawn Level for (Dying unit)))) - 1.00))) x Bounty_Bonus))))) to Temp_Player Current gold
Floating Text - Create floating text that reads (+ + (String((Max(0, (Integer(((Power(Bounty_Base, (Real(((Level of Spawn Level for (Dying unit)) - 1))))) x Bounty_Bonus)))))))) above (Dying unit) with Z offset 20.00, using font size 10.00, color (100.00%, 100.00%, 20.00%), and 0.00% transparency
Floating Text - Change (Last created floating text): Disable permanence
Floating Text - Set the velocity of (Last created floating text) to 32.00 towards 90.00 degrees
Floating Text - Change the fading age of (Last created floating text) to 0.50 seconds
Floating Text - Change the lifespan of (Last created floating text) to 1.00 seconds
Set Creeps_Left[Temp_Int] = (Creeps_Left[Temp_Int] - 1)
Collapse For each (Integer Dying_Creep_Player) from 1 to 8, do (Actions)
Collapse Loop - Actions
Collapse If (All Conditions are True) then do (Then Actions) else do (Else Actions)
Collapse If - Conditions
Player_Lives[(Dying_Creep_Player - 1)] Greater than 0
Creeps_Left[(Dying_Creep_Player - 1)] Equal to 0
Between_Levels Equal to False
Collapse Then - Actions
Collapse If (All Conditions are True) then do (Then Actions) else do (Else Actions)
Collapse If - Conditions
Extreme_Mode_On Equal to True
Collapse Then - Actions
Set Start_Timer_Modifier = 0.00
Trigger - Run StartTimer <gen> (ignoring conditions)
Collapse Else - Actions
Set Start_Timer_Modifier = (24.00 - ((Real(Difficulty[(Dying_Creep_Player - 1)])) x 4.00))
Trigger - Run StartTimer <gen> (ignoring conditions)
Else - Actions
Custom script: call PolledWait2(5)
Unit - Remove (Dying unit) from the game
Else - Actions

Trigger:
StartTimer
Events
Conditions
Collapse Actions
Collapse If (All Conditions are True) then do (Then Actions) else do (Else Actions)
Collapse If - Conditions
Level Equal to 0
Collapse Then - Actions
Countdown Timer - Start Between_Levels_Timer as a One-shot timer that will expire in 25.00 seconds
Collapse Else - Actions
Collapse If (All Conditions are True) then do (Then Actions) else do (Else Actions)
Collapse If - Conditions
(Level mod 5) Equal to 0
Collapse Then - Actions
Trigger - Turn off Random <gen>
Trigger - Turn on Random After Lvl 5 <gen>
Collapse If (All Conditions are True) then do (Then Actions) else do (Else Actions)
Collapse If - Conditions
Short_Mode_On Equal to True
Level Equal to 15
Collapse Then - Actions
Countdown Timer - Start Between_Levels_Timer as a One-shot timer that will expire in 25.00 seconds
Collapse Else - Actions
Countdown Timer - Start Between_Levels_Timer as a One-shot timer that will expire in 20.00 seconds
Collapse If (All Conditions are True) then do (Then Actions) else do (Else Actions)
Collapse If - Conditions
Level Equal to 60
Collapse Then - Actions
Trigger - Run Count Living Players <gen> (checking conditions)
Trigger - Run Check Last Survivor <gen> (checking conditions)
Collapse Else - Actions
Player - Set the current research level of HP Bonus to ((Level - 1) / 5) for Player 9 (Gray)
Player - Set the current research level of HP Bonus to ((Level - 1) / 5) for Player 10 (Light Blue)
Player - Set the current research level of HP Bonus to ((Level - 1) / 5) for Player 11 (Dark Green)
Player - Set the current research level of HP Bonus to ((Level - 1) / 5) for Player 12 (Brown)
Set Player_Group = (All players matching (Player_Lives[((Player number of (Matching player)) - 1)] Greater than 0))
Collapse Player Group - Pick every player in Player_Group and do (Actions)
Collapse Loop - Actions
Collapse If (All Conditions are True) then do (Then Actions) else do (Else Actions)
Collapse If - Conditions
Random_Element[((Player number of (Picked player)) - 1)] Equal to True
Collapse Then - Actions
Game - Display to (Player group((Picked player))) the text: |c0000AA00+++++++++...
Collapse Else - Actions
Game - Display to (Player group((Picked player))) the text: |c0000AA00+++++++++...
Player - Add 1 to (Picked player) Current lumber
Custom script: call DestroyForce(udg_Player_Group)
Trigger - Run Random Bosses <gen> (ignoring conditions)
Collapse Else - Actions
Countdown Timer - Start Between_Levels_Timer as a One-shot timer that will expire in Start_Timer_Modifier seconds
Collapse If (All Conditions are True) then do (Then Actions) else do (Else Actions)
Collapse If - Conditions
Collapse Or - Any (Conditions) are true
Collapse Conditions
Level Equal to 51
Level Equal to 56
Collapse Then - Actions
Set Player_Group = (All players matching (Player_Lives[((Player number of (Matching player)) - 1)] Greater than 0))
Collapse Player Group - Pick every player in Player_Group and do (Actions)
Collapse Loop - Actions
Game - Display to (Player group((Picked player))) the text: |cffffaacc+++++++++...
Unit - Create 1 Elemental Essence for (Picked player) at (((Picked player) start location) offset by ((775.00 + ((Real(Elemental_Count[((Player number of (Picked player)) - 1)])) x 75.00)), 880.00)) facing 270.00 degrees
Unit - Make (Last created unit) Invulnerable
Unit - Pause (Last created unit)
Set Elemental_Count[((Player number of (Picked player)) - 1)] = (Elemental_Count[((Player number of (Picked player)) - 1)] + 1)
Custom script: call DestroyForce(udg_Player_Group)
Else - Actions
Set Between_Levels = True
01-09-2008, 02:45 AM#11
rain9441
I'm seeing some inconsistancies here. In Trigger Unit Dies you set Temp_Player = CreepOwner[(Custom value of (Dying unit))]. In the spawning function you set CreepOwner[GetUnitIndex(u)] = GetEnumPlayer().

Now heres the strange part. You never set the custom value of the unit when its spawned, is that set another time? Assuming it isn't, you'd essentially have 0 custom value for all units. GetUnitIndex() probably never returns 0, i don't know the specifics but my guess is 0 would mean error or null. So ALL checks in the Unit Dies trigger would have Temp_Player = CreepOwner[0] which is probably null.

(Player number of NULL) - 1 is probably -1.

Array access of -1 yields?

Maybe I'm reading this wrong...

EDIT: Found another issue:

CreepFilter -- udg_CreepOwner[GetUnitUserData(GetFilterUnit())], GetUnitUserData should be GetUnitIndex no? If that returns 0 then udg_creepOwner is probably null, and (null == GetEnumPlayer()) == FALSE always, so you are essentially counting no units in CountCreeps function. Add 30 to that, you got yourself a mis-valued counter. It'll say theres 30 units left in the wave but really theres 36 because 6 of those units are still alive. My guess is your TD allows for multiple waves to coexist at the same time? (OK its not a guess I've played your TD before :P). If it says theres 30 but theres 36, then you may have a problem down the road.
01-09-2008, 02:46 AM#12
Vexorian
Try using a normal loop instead of ForForce (which nobody outside of GUI should use)

When you do ForForce you rely unnecessarily on the handle stuff if you got a bug in your map that screws the handle ref counter then this problem could be a consequence.

You can also just apply code reuse and fix the whole Ronalds stuff, you have extra code for that stuff when just using the normal spawn code + very few if then elses inside of it would work.

Use debugging messages to verify that the timer itself runs 30 times
01-09-2008, 03:53 AM#13
Karawasa
@rain9441: I don't think either of those are an issue, as the above mentioned bug is the only problem I am having. If there was a problem with custom value, bounty and other functions would work incorrectly. If there was a problem with the count, then the next wave timer would sometimes not start. Neither of these happen. I really appreciate you looking through the code though.

@Vexorian: Would you be kind enough to rewrite the code to reflect your changes? Do you have any other ideas? What do you think of Cohadar's idea?
01-09-2008, 04:14 PM#14
cohadar
Quote:
Originally Posted by rain9441
I'm seeing some inconsistancies here. In Trigger Unit Dies you set Temp_Player = CreepOwner[(Custom value of (Dying unit))]. In the spawning function you set CreepOwner[GetUnitIndex(u)] = GetEnumPlayer()....

There are no inconsistencies regarding Custom Unit Data,
GetUnitIndex is a function from PUI that automatically sets index for every unit,
and since it is called for every unit after it is spawned there is no need to call it any more, you can use Custom Value Directly.
The problem is not there.

I tested the game (with debug messages) and it was all fine all 40 levels.
I guess it only happens in multiplayer for some reason.

The most probably reason is what Vex mentioned.
Handle Stack Corruption

Here is why I think so:
I installed this trigger in EleTD:
Expand JASS:
It basically displays the handle count on a map.

What I discovered is that EleTD is leaking like 30 handles per second
even when there is nothing happening on the map.

Combined with overly optimistic use of gamecache == pwned
(you can blame emjlr3 for that )

-------------------------------------------------------------------
Well Karawasa it basically comes to this:
Looks like you will finally have to get off you lazy ass and learn some jass.
Most importantly cleaning memory leaks and nulling locals.
Otherwise EleTD is as good as dead.
-------------------------------------------------------------------
01-09-2008, 07:53 PM#15
emjlr3
feel free to change my GC usage to PUI, since that is all I use it for, in anycase, GC is not the reason this bugs, and don't even begin to think it is, hundreds of peple have used GC for many things in vrey big maps, including me, with no problems

the bug is not reproducable, it haappens at random times in random games, and I nor Kara have been able to reproduce it in Single Player or Online

as I have told Kara before, the only reasons this would bug is if the timer randomly stopped, cold(however, other triggers should reactivate it, as you have seen), if an OP limit is hit somewhere(again, other triggers should activate it), or if the ForForce somehow stopped in the middle

I do not think the problem lies in this trigger, as I have said before, any thing botched in here, creeps would stop spawning in the middle of doing so, which does not happen (unless somehow the ForForce can bug and hit an OP limit or some shit, like I said)...

I think it funny that at first all people looked at were things that in no way reflected this bug, only less then perfectly optimized coding, as if that were the cure to all the worlds problems...