HomeUser Control Panel (unavailable in archive)ForumsTutorialsArt GalleryResourcesMaps

Player leave event..

01-01-2010, 07:50 PM#1
StRoNgFoE_2000
I need to verify this little issue I came across that's pretty irritating. If I create a trigger with the event a player leaves game, in the action script it seems I cannot use the triggering player in another function call, it ends up being null (I think).

Collapse JASS:
scope PlayerLeaves initializer Init
//=================================================================================================================
//=                                          PLAYER LEAVE DETECTION                                              =
//=================================================================================================================
// Purpose: To detect when a player leaves the game and run function to take necessary actions when this happens.
//=================================================================================================================
globals
    trigger PLAYERLEAVES // -- Store trigger in a global so it can be disabled when game end script runs.
endglobals
//=================================================================================================================
// -- The trigger function that fires when players leaves the game. PlayerRemove function found in InternalFunctions.
function PlayerLeavesGame takes nothing returns nothing
    local player  p = GetTriggerPlayer()
    call DisplayMessage(7.5, PLAYER_COLOR[GetPlayerId(p)] + GetPlayerName(p) + "|r" + " has left the game.")
    call PlayerRemove(p)
    set p = null
endfunction
//=================================================================================================================
private function Init takes nothing returns nothing
    local integer i = 0
    set PLAYERLEAVES = CreateTrigger()
    loop
        exitwhen i > 5
        call TriggerRegisterPlayerEvent(PLAYERLEAVES, Player(i), EVENT_PLAYER_LEAVE)
        set i = i + 1
    endloop
    call TriggerAddAction(PLAYERLEAVES, function PlayerLeavesGame)
endfunction

endscope

The function PlayerRemove (which just does a bunch of random stuff regarding the player leaving), never sees the player. I know the script is running because it shows the message that the player has left the game. What frustrates me is it works fine in single player, but for some reason not in multiplayer. I suppose I could recode using integers but I think I may have tried that a few days back, and referring to the player using Player(playerid) didn't work either (again not sure if I really did!). Will give another test.

Is all of this a known issue or is this a personal problem?
01-01-2010, 08:42 PM#2
Troll-Brain
I don't know if your function PlayerRemove really needs a player argument, or in other words if the function is used somewhere else where players events are not involved.

But basically you can simply use GetTriggerPlayer() in your function PlayerRemove, in this sample.
Yeah i know it's senseless ...

Anyway, it's most likely that you crash the thread in your function PlayerRemove, instead of an obscure bug.
Show us this function.
01-01-2010, 10:41 PM#3
StRoNgFoE_2000
I already went ahead and replaced my arguments with integers, so just imagine they all took a player instead of an int (still did not test in multiplayer too tired). Theres quite a few functions that get called here, the reason they are broken apart is so I can call them seperately for different situations.

Collapse JASS:
function UpdatePlayerStatus takes integer playerID returns nothing
    local integer x = 2
    local playerslotstate s = GetPlayerSlotState(Player(playerID))
    if (s == PLAYER_SLOT_STATE_PLAYING) then
    //--If player is playing add player to force.
        if (playerID < 3) then
            call ForceAddPlayer(F_TOPTEAM, Player(playerID))
        else
            call ForceAddPlayer(F_BOTTEAM, Player(playerID))
        endif
    else
    //--If affecting the bottom team, change the digit to display on multiboard.
        if (playerID > 2) then
            set x = 5
        endif
    //--If player is not playing and is in a force, remove player.
        call ForceRemovePlayer(F_TOPTEAM, Player(playerID))
        call ForceRemovePlayer(F_BOTTEAM, Player(playerID))
    //--Update the board's player name text and set buildings to computer controlled.
        call UpdateBoard(MULTIBOARD, 1, (playerID+x), PLAYER_COLOR[playerID] + "-Empty-|r")
        call SetUnitOwner(U_BANKBUILDING[playerID], Player(12), true)
        call SetUnitOwner(U_RACEBUILDING[playerID], Player(12), true)
        call SetUnitOwner(U_SHRINETRACKER[playerID], Player(12), true)
        call SetUnitOwner(U_BOSSTRACKER[playerID], Player(12), true)
    //--If want to remove builders and tower count, do now.
        if (U_BUILDER[playerID] != null) then
            call RemoveUnit(U_BUILDER[playerID])
            set U_BUILDER[playerID] = null
        endif
        set TOWERS[playerID] = 0
        call UpdateBoard(MULTIBOARD, 4, (playerID+x), "0") // Display 0 Towers 
    endif
    set s = null
endfunction

//*****************************************************************************************************************
// -- Function that takes a Player Number and distributes income to other players on the team.
function DistributeIncome takes integer playerID returns nothing
    local integer x    = 0
    local integer pn_a = 0
    local integer pn_b = 0
    local playerslotstate pss_a
    local playerslotstate pss_b
//--Sets up the data for the players affected.
    if (playerID == 0) then
        set pn_a = 1
        set pn_b = 2
    elseif (playerID == 1) then
        set pn_a = 0
        set pn_b = 2
    elseif (playerID == 2) then
        set pn_a = 0
        set pn_b = 1
    elseif (playerID == 3) then
        set pn_a = 4
        set pn_b = 5
    elseif (playerID == 4) then
        set pn_a = 3
        set pn_b = 5
    elseif (playerID == 5) then
        set pn_a = 3
        set pn_b = 4
    endif
    set pss_a = GetPlayerSlotState(Player(pn_a))
    set pss_b = GetPlayerSlotState(Player(pn_b))
//--Distributes the income of the player that isn't here to his/her teammates.
    if (pss_a == PLAYER_SLOT_STATE_PLAYING) and (pss_b == PLAYER_SLOT_STATE_PLAYING) then
        set INCOME[playerID] = (INCOME[playerID] / 2)
        set INCOME[pn_a] = (INCOME[pn_a] + INCOME[playerID])
        set INCOME[pn_b] = (INCOME[pn_b] + INCOME[playerID])
    elseif (pss_a == PLAYER_SLOT_STATE_PLAYING) and (pss_b == PLAYER_SLOT_STATE_EMPTY) or (pss_b == PLAYER_SLOT_STATE_LEFT) then
        set INCOME[pn_a] = (INCOME[pn_a] + INCOME[playerID])
    elseif (pss_b == PLAYER_SLOT_STATE_PLAYING) and (pss_a == PLAYER_SLOT_STATE_EMPTY) or (pss_a == PLAYER_SLOT_STATE_LEFT) then
        set INCOME[pn_b] = (INCOME[pn_b] + INCOME[playerID])
    endif
//--Reset income and money.
    set INCOME[playerID] = 0
    call SetResourceState(Player(playerID), GOLD, SET, 0)
//--Update the Multiboard for Income.
    if (playerID < 3) then
        call UpdateBoard(MULTIBOARD, 2, (playerID+2), I2S(R2I(INCOME[x])))
    else
        call UpdateBoard(MULTIBOARD, 2, (playerID+5), I2S(R2I(INCOME[x])))
    endif
    set pss_a = null
    set pss_b = null
endfunction

function TradeTowers takes nothing returns nothing
    local player p = ForcePickRandomPlayer(TEMPFORCE)
    local unit   u = GetEnumUnit()
    call TowerAdd(u, p, true)
    call SetUnitOwner(u, p, true)
    set u = null
    set p = null
endfunction
function PlayerRemove takes integer playerID returns nothing
//--Check Menu Player status, give Snowman and income to other players.
    if (Player(playerID) == P_MENUPLAYER) then
        call SetMenuPlayer()
    endif
    call DistributeIncome(playerID)
    call UpdateSnowmanOwnership()
//--Display the player leave text.
    if (IsPlayerInForce(Player(playerID), F_TOPTEAM)) then
        set TEMPFORCE = F_TOPTEAM
        call DisplayMessageTeam(F_TOPTEAM, 7.5, "|c003399ffIncome has been distributed to the team.|r")
    else
        set TEMPFORCE = F_BOTTEAM
        call DisplayMessageTeam(F_BOTTEAM, 7.5, "|c003399ffIncome has been distributed to the team.|r")
    endif
//--Update player status.
    call UpdatePlayerStatus(playerID)
//--Gives towers to other players.
    call GroupEnumUnitsOfPlayer(G_TOWERTRADE, Player(playerID), X_TOWERUNITS) // Links to TradeTowers.
    call ForGroup(G_TOWERTRADE, function TradeTowers)
    call GroupClear(G_TOWERTRADE)
//--Check to see if there are enough players, if not then end the game.
    if (EnoughPlayers() == false) then
        call DisplayMessage(2.00, " ")
        call DisplayMessage(2.00, "|c00ff0000There is not enough players to continue the game!|r")
        call TriggerExecute(T_GAMEOVER)
    endif
endfunction

The bug seems to happen in function UpdatePlayerStatus, where if playerslotstate is missing then it should do a bunch of stuff including remove player from forces. Basically its getting the slotstate as if the player was still playing, because nothing in the else is ever called (such as the SetUnitOwner and remove builder functions). I think this is why I was believed that somewhere the player variable was being nulled... which is strange, because the DistributeIncome function is called before it and it distributes the income perfectly everytime, and uses the native GetPlayerSlotState which is working...

Edit: Maybe I should try changing the else to "elseif (s == PLAYER_SLOT_STATE_EMPTY) or (s == PLAYER_SLOT_STATE_LEFT) then" and see if that works? I'm almost definite this is where everything is going wrong.
01-05-2010, 12:50 AM#4
StRoNgFoE_2000
I finally figured out the issue. It seems if you try to get a player's slot status in the action function of player leaving trigger event, all calls to GetPlayerSlotState and all other functions called within that function that use GetPlayerSlotState act as if the player was still playing, until the action func ends. This only seems to apply to human controlled players, so it was impossible to spot in single player. I guess most people in their right mind wouldn't use this function in an event like this anyway.
01-05-2010, 08:29 AM#5
Troll-Brain
Quote:
I guess most people in their right mind wouldn't use this function in an event like this anyway.
Yep, but it's still good to know :)