//==============================================================================================//
// WARNING: YOU MUST PASTE THE FOLLOWING CODE IN A PLACE WHERE YOUR "INITIALIZATION TRIGGER"... //
// IS CAPABLE OF ACCESSING IT. IT'S RECOMMENDED THAT YOU PASTE IT IN YOUR MAP HEADER //
// //
// The main purpose of this is to just get rid of the bug where custom units flagged as //
// town hall doesn't count for the CripplePlayer function. I also removed a few leaks generated //
// by Blizzard. //
// //
//==============================================================================================//
// Count units flagged as UNIT_TYPE_TOWNHALL
function GetAllyKeyStructureCount takes player whichPlayer returns integer
local unit fog = null
local group g = CreateGroup()
local integer result = 0
local integer playerIndex = 0
loop
exitwhen playerIndex == bj_MAX_PLAYERS
if PlayersAreCoAllied(whichPlayer, Player(playerIndex)) then
call GroupEnumUnitsOfPlayer(g, Player(playerIndex), null)
loop
set fog = FirstOfGroup(g)
exitwhen fog == null
call GroupRemoveUnit(g, fog)
if IsUnitType(fog, UNIT_TYPE_TOWNHALL) and not IsUnitType(fog, UNIT_TYPE_DEAD) and GetUnitTypeId(fog) != 0 then
set result = result + 1
endif
endloop
endif
set playerIndex = playerIndex + 1
endloop
call DestroyGroup(g)
set g = null
return result
endfunction
function CheckForVictors takes force opponentlessPlayers returns force
local integer playerIndex
local integer opponentIndex
local boolean gameOver = false
// Check to see if any players have opponents remaining.
set playerIndex = 0
loop
if (not bj_meleeDefeated[playerIndex]) then
// Determine whether or not this player has any remaining opponents.
set opponentIndex = 0
loop
// If anyone has an opponent, noone can be victorious yet.
if MeleePlayerIsOpponent(playerIndex, opponentIndex) then
call DestroyForce(opponentlessPlayers)
set opponentlessPlayers = null
return null
endif
set opponentIndex = opponentIndex + 1
exitwhen opponentIndex == bj_MAX_PLAYERS
endloop
// Keep track of each opponentless player so that we can give
// them a victory later.
call ForceAddPlayer(opponentlessPlayers, Player(playerIndex))
set gameOver = true
endif
set playerIndex = playerIndex + 1
exitwhen playerIndex == bj_MAX_PLAYERS
endloop
// Set the game over global flag
set bj_meleeGameOver = gameOver
return opponentlessPlayers
endfunction
// Find opponentless players
function CheckForLosersAndVictors takes nothing returns nothing
local integer playerIndex
local player indexPlayer
local force defeatedPlayers = CreateForce()
local force victoriousPlayers = null
local boolean gameOver = false
// If the game is already over, do nothing
if (bj_meleeGameOver) then
return
endif
// If the game was disconnected then it is over, in this case we
// don't want to report results for anyone as they will most likely
// conflict with the actual game results
if (GetIntegerGameState(GAME_STATE_DISCONNECTED) != 0) then
set bj_meleeGameOver = true
return
endif
// Check each player to see if he or she has been defeated yet.
set playerIndex = 0
loop
set indexPlayer = Player(playerIndex)
if (not bj_meleeDefeated[playerIndex] and not bj_meleeVictoried[playerIndex]) then
//call DisplayTimedTextToPlayer(GetLocalPlayer(), 0, 0, 60, "Player"+I2S(playerIndex)+" has "+I2S(MeleeGetAllyStructureCount(indexPlayer))+" ally buildings.")
if (MeleeGetAllyStructureCount(indexPlayer) <= 0) then
// Keep track of each defeated player so that we can give
// them a defeat later.
call ForceAddPlayer(defeatedPlayers, Player(playerIndex))
// Set their defeated flag now so MeleeCheckForVictors
// can detect victors.
set bj_meleeDefeated[playerIndex] = true
endif
endif
set playerIndex = playerIndex + 1
exitwhen playerIndex == bj_MAX_PLAYERS
endloop
// Now that the defeated flags are set, check if there are any victors
set victoriousPlayers = CheckForVictors(CreateForce())
// Defeat all defeated players
call ForForce(defeatedPlayers, function MeleeDoDefeatEnum)
// Give victory to all victorious players
call ForForce(victoriousPlayers, function MeleeDoVictoryEnum)
// If the game is over we should remove all observers
if (bj_meleeGameOver) then
call MeleeRemoveObservers()
endif
// Destroy and null handles
call DestroyForce(defeatedPlayers)
if victoriousPlayers != null then
call DestroyForce(victoriousPlayers)
set victoriousPlayers = null
endif
set defeatedPlayers = null
set indexPlayer = null
endfunction
// CRIPPLE
function CheckForCrippledPlayers takes nothing returns nothing
local integer playerIndex
local player indexPlayer
local boolean isNowCrippled
// The "finish soon" exposure of all players overrides any "crippled" exposure
if bj_finishSoonAllExposed then
return
endif
// Check each player to see if he or she has been crippled or uncrippled.
set playerIndex = 0
loop
set indexPlayer = Player(playerIndex)
set isNowCrippled = (MeleeGetAllyStructureCount(indexPlayer) > 0) and (GetAllyKeyStructureCount(indexPlayer) <= 0)
if (not bj_playerIsCrippled[playerIndex] and isNowCrippled) then
// Player became crippled; start their cripple timer.
set bj_playerIsCrippled[playerIndex] = true
call TimerStart(bj_crippledTimer[playerIndex], bj_MELEE_CRIPPLE_TIMEOUT, false, function MeleeCrippledPlayerTimeout)
if (GetLocalPlayer() == indexPlayer) then
// Use only local code (no net traffic) within this block to avoid desyncs.
// Show the timer window.
call TimerDialogDisplay(bj_crippledTimerWindows[playerIndex], true)
// Display a warning message.
call DisplayTimedTextToPlayer(indexPlayer, 0, 0, bj_MELEE_CRIPPLE_MSG_DURATION, MeleeGetCrippledWarningMessage(indexPlayer))
endif
elseif (bj_playerIsCrippled[playerIndex] and not isNowCrippled) then
// Player became uncrippled; stop their cripple timer.
set bj_playerIsCrippled[playerIndex] = false
call PauseTimer(bj_crippledTimer[playerIndex])
if (GetLocalPlayer() == indexPlayer) then
// Use only local code (no net traffic) within this block to avoid desyncs.
// Hide the timer window for this player.
call TimerDialogDisplay(bj_crippledTimerWindows[playerIndex], false)
// Display a confirmation message if the player's team is still alive.
if (MeleeGetAllyStructureCount(indexPlayer) > 0) then
if (bj_playerIsExposed[playerIndex]) then
call DisplayTimedTextToPlayer(indexPlayer, 0, 0, bj_MELEE_CRIPPLE_MSG_DURATION, GetLocalizedString("CRIPPLE_UNREVEALED"))
else
call DisplayTimedTextToPlayer(indexPlayer, 0, 0, bj_MELEE_CRIPPLE_MSG_DURATION, GetLocalizedString("CRIPPLE_UNCRIPPLED"))
endif
endif
endif
// If the player granted shared vision, deny that vision now.
call MeleeExposePlayer(indexPlayer, false)
endif
set playerIndex = playerIndex + 1
exitwhen playerIndex == bj_MAX_PLAYERS
endloop
set indexPlayer = null
endfunction
// UNIT DIES
function TriggerActionCheckLostUnit takes nothing returns nothing
if IsUnitType(GetTriggerUnit(), UNIT_TYPE_STRUCTURE) then
// We only need to check for mortality if this was the last building.
if (GetPlayerStructureCount(GetOwningPlayer(GetTriggerUnit()), true) <= 0) then
call CheckForLosersAndVictors()
endif
// Check if the lost unit has crippled or uncrippled the player.
// (A team with 0 units is dead, and thus considered uncrippled.)
call CheckForCrippledPlayers()
endif
endfunction
function TriggerActionAllianceChange takes nothing returns nothing
call CheckForLosersAndVictors()
call CheckForCrippledPlayers()
endfunction
function TriggerActionCheckAddedUnit takes nothing returns nothing
// If the player was crippled, this unit may have uncrippled him/her.
if (bj_playerIsCrippled[GetPlayerId(GetOwningPlayer(GetTriggerUnit()))]) then
call CheckForCrippledPlayers()
endif
endfunction
function TriggerActionPlayerDefeated takes nothing returns nothing
local player thePlayer = GetTriggerPlayer()
call CachePlayerHeroData(thePlayer)
if (MeleeGetAllyCount(thePlayer) > 0) then
// If at least one ally is still alive and kicking, share units with
// them and proceed with death.
call ShareEverythingWithTeam(thePlayer)
if (not bj_meleeDefeated[GetPlayerId(thePlayer)]) then
call MeleeDoDefeat(thePlayer)
endif
else
// If no living allies remain, swap all units and buildings over to
// neutral_passive and proceed with death.
call MakeUnitsPassiveForTeam(thePlayer)
if (not bj_meleeDefeated[GetPlayerId(thePlayer)]) then
call MeleeDoDefeat(thePlayer)
endif
endif
call CheckForLosersAndVictors()
set thePlayer = null
endfunction
function TriggerActionPlayerLeft takes nothing returns nothing
local player thePlayer = GetTriggerPlayer()
// Just show game over for observers when they leave
if (IsPlayerObserver(thePlayer)) then
call RemovePlayerPreserveUnitsBJ(thePlayer, PLAYER_GAME_RESULT_NEUTRAL, false)
set thePlayer = null
return
endif
call CachePlayerHeroData(thePlayer)
// This is the same as defeat except the player generates the message
// "player left the game" as opposed to "player was defeated".
if (MeleeGetAllyCount(thePlayer) > 0) then
// If at least one ally is still alive and kicking, share units with
// them and proceed with death.
call ShareEverythingWithTeam(thePlayer)
call MeleeDoLeave(thePlayer)
else
// If no living allies remain, swap all units and buildings over to
// neutral_passive and proceed with death.
call MakeUnitsPassiveForTeam(thePlayer)
call MeleeDoLeave(thePlayer)
endif
call CheckForLosersAndVictors()
set thePlayer = null
endfunction
function MeleeVictoryDefeat takes nothing returns nothing
local trigger trig
local integer index
local player indexPlayer
// Create a timer window for the "finish soon" timeout period, it has no timer
// because it is driven by real time (outside of the game state to avoid desyncs)
set bj_finishSoonTimerDialog = CreateTimerDialog(null)
// Set a trigger to fire when we receive a "finish soon" game event
set trig = CreateTrigger()
call TriggerRegisterGameEvent(trig, EVENT_GAME_TOURNAMENT_FINISH_SOON)
call TriggerAddAction(trig, function MeleeTriggerTournamentFinishSoon)
// Set a trigger to fire when we receive a "finish now" game event
set trig = CreateTrigger()
call TriggerRegisterGameEvent(trig, EVENT_GAME_TOURNAMENT_FINISH_NOW)
call TriggerAddAction(trig, function MeleeTriggerTournamentFinishNow)
// Set up each player's mortality code.
set index = 0
loop
set indexPlayer = Player(index)
// Make sure this player slot is playing.
if (GetPlayerSlotState(indexPlayer) == PLAYER_SLOT_STATE_PLAYING) then
set bj_meleeDefeated[index] = false
set bj_meleeVictoried[index] = false
// Create a timer and timer window in case the player is crippled.
set bj_playerIsCrippled[index] = false
set bj_playerIsExposed[index] = false
set bj_crippledTimer[index] = CreateTimer()
set bj_crippledTimerWindows[index] = CreateTimerDialog(bj_crippledTimer[index])
call TimerDialogSetTitle(bj_crippledTimerWindows[index], MeleeGetCrippledTimerMessage(indexPlayer))
// Set a trigger to fire whenever a building is cancelled for this player.
set trig = CreateTrigger()
call TriggerRegisterPlayerUnitEvent(trig, indexPlayer, EVENT_PLAYER_UNIT_CONSTRUCT_CANCEL, null)
call TriggerAddAction(trig, function TriggerActionCheckLostUnit)
// Set a trigger to fire whenever a unit dies for this player.
call TriggerRegisterPlayerUnitEvent(trig, indexPlayer, EVENT_PLAYER_UNIT_DEATH, null)
call TriggerAddAction(trig, function TriggerActionCheckLostUnit)
// Set a trigger to fire whenever a unit begins construction for this player
set trig = CreateTrigger()
call TriggerRegisterPlayerUnitEvent(trig, indexPlayer, EVENT_PLAYER_UNIT_CONSTRUCT_START, null)
call TriggerAddAction(trig, function TriggerActionCheckAddedUnit)
// Set a trigger to fire whenever this player defeats-out
set trig = CreateTrigger()
call TriggerRegisterPlayerEvent(trig, indexPlayer, EVENT_PLAYER_DEFEAT)
call TriggerAddAction(trig, function TriggerActionPlayerDefeated)
// Set a trigger to fire whenever this player leaves
set trig = CreateTrigger()
call TriggerRegisterPlayerEvent(trig, indexPlayer, EVENT_PLAYER_LEAVE)
call TriggerAddAction(trig, function TriggerActionPlayerLeft)
// Set a trigger to fire whenever this player changes his/her alliances.
set trig = CreateTrigger()
call TriggerRegisterPlayerAllianceChange(trig, indexPlayer, ALLIANCE_PASSIVE)
call TriggerRegisterPlayerStateEvent(trig, indexPlayer, PLAYER_STATE_ALLIED_VICTORY, EQUAL, 1)
call TriggerAddAction(trig, function TriggerActionAllianceChange)
else
set bj_meleeDefeated[index] = true
set bj_meleeVictoried[index] = false
// Handle leave events for observers
if (IsPlayerObserver(indexPlayer)) then
// Set a trigger to fire whenever this player leaves
set trig = CreateTrigger()
call TriggerRegisterPlayerEvent(trig, indexPlayer, EVENT_PLAYER_LEAVE)
call TriggerAddAction(trig, function TriggerActionPlayerLeft)
endif
endif
set index = index + 1
exitwhen index == bj_MAX_PLAYERS
endloop
// Test for victory / defeat at startup, in case the user has already won / lost.
// Allow for a short time to pass first, so that the map can finish loading.
call TimerStart(CreateTimer(), 2.0, false, function TriggerActionAllianceChange)
endfunction
//==============================================================================================//