Name | Type | is_array | initial_value |
library CabinDefense initializer InitCabinDefense
globals
// Coordinates
real map_min_x
real map_max_x
real map_min_y
real map_max_y
real bandit_camp1_center_x
real bandit_camp1_center_y
real bandit_camp2_center_x
real bandit_camp2_center_y
real bandit_camp3_center_x
real bandit_camp3_center_y
real bandit_camp4_center_x
real bandit_camp4_center_y
// Critter/creep arrays
integer array critters
integer critters_max = 0
integer array creeps1
integer creeps1_max = 0
integer array creeps2
integer creeps2_max = 0
integer array creeps3
integer creeps3_max = 0
integer array creeps4
integer creeps4_max = 0
integer array creeps5
integer creeps5_max = 0
integer array creeps6
integer creeps6_max = 0
// Create stuff constants
constant integer TREE = 0
constant integer CRITTER = 1
constant integer CREEP1 = 2
constant integer CREEP2 = 3
constant integer CREEP3 = 4
constant integer CREEP4 = 5
constant integer CREEP5 = 6
constant integer CREEP6 = 7
// Attack waves
integer currentWave = 0
timer tmrAttackWaves = CreateTimer()
timerdialog tmrdgAttackWaves = CreateTimerDialog(tmrAttackWaves)
// Bandits
boolean enableBribes = true
boolean enemiesHaveUnits
force enemyPlayers = CreateForce()
// Game
boolean gameOver = false
constant player THE_PLAYER = Player(0)
constant player PLAYER_BANDITS1 = Player(1)
constant player PLAYER_BANDITS2 = Player(2)
constant player PLAYER_BANDITS3 = Player(3)
constant player PLAYER_BANDITS4 = Player(4)
constant player PLAYER_HOSTILE = Player(PLAYER_NEUTRAL_AGGRESSIVE)
endglobals
//=========================================================
// Util
//=========================================================
// Check if coordinates are valid
private function ValidCoords takes real x, real y returns boolean
if RectContainsCoords(gg_rct_CabinBase, x, y) then
return false
elseif RectContainsCoords(gg_rct_BanditCamp1, x, y) then
return false
elseif RectContainsCoords(gg_rct_BanditCamp2, x, y) then
return false
elseif RectContainsCoords(gg_rct_BanditCamp3, x, y) then
return false
elseif RectContainsCoords(gg_rct_BanditCamp4, x, y) then
return false
elseif RectContainsCoords(gg_rct_MercCamp1, x, y) then
return false
elseif RectContainsCoords(gg_rct_MercCamp2, x, y) then
return false
elseif RectContainsCoords(gg_rct_MercCamp3, x, y) then
return false
elseif RectContainsCoords(gg_rct_MercCamp4, x, y) then
return false
endif
return true
endfunction
// Filter for alive units (not structures)
private function AliveUnitFilter takes nothing returns boolean
local unit filterUnit = GetFilterUnit()
local boolean result = not IsUnitType(filterUnit, UNIT_TYPE_STRUCTURE) and GetUnitState(filterUnit, UNIT_STATE_LIFE) > 0
set filterUnit = null
return result
endfunction
//=========================================================
// Create stuff
//=========================================================
private function CreateStuff takes integer createWhat, boolean checkVisibility returns nothing
local real x
local real y
local unit creep = null
loop
set x = GetRandomReal(map_min_x, map_max_x)
set y = GetRandomReal(map_min_y, map_max_y)
exitwhen ValidCoords(x, y)
endloop
if not checkVisibility or not IsVisibleToPlayer(x, y, THE_PLAYER) then
if createWhat == TREE then
call CreateDestructable('LTlt', x, y, GetRandomReal(0, 360), GetRandomReal(0.75, 1.25), GetRandomInt(0, 9))
elseif createWhat == CRITTER then
call CreateUnit(PLAYER_HOSTILE, critters[GetRandomInt(0, critters_max)], x, y, GetRandomReal(0, 360))
elseif createWhat == CREEP1 then
set creep = CreateUnit(PLAYER_HOSTILE, creeps1[GetRandomInt(0, creeps1_max)], x, y, GetRandomReal(0, 360))
elseif createWhat == CREEP2 then
set creep = CreateUnit(PLAYER_HOSTILE, creeps2[GetRandomInt(0, creeps2_max)], x, y, GetRandomReal(0, 360))
elseif createWhat == CREEP3 then
set creep = CreateUnit(PLAYER_HOSTILE, creeps3[GetRandomInt(0, creeps3_max)], x, y, GetRandomReal(0, 360))
elseif createWhat == CREEP4 then
set creep = CreateUnit(PLAYER_HOSTILE, creeps4[GetRandomInt(0, creeps4_max)], x, y, GetRandomReal(0, 360))
elseif createWhat == CREEP5 then
set creep = CreateUnit(PLAYER_HOSTILE, creeps5[GetRandomInt(0, creeps5_max)], x, y, GetRandomReal(0, 360))
elseif createWhat == CREEP6 then
set creep = CreateUnit(PLAYER_HOSTILE, creeps6[GetRandomInt(0, creeps6_max)], x, y, GetRandomReal(0, 360))
endif
endif
if creep != null then
call SetUnitAcquireRange(creep, 200)
set creep = null
endif
endfunction
//=========================================================
// VICTORY/DEFEAT
//=========================================================
private function DefeatPlayer takes player whichPlayer returns nothing
call RemovePlayer(whichPlayer, PLAYER_GAME_RESULT_DEFEAT)
call DisplayTimedTextFromPlayer(whichPlayer, 0, 0, 60, GetLocalizedString( "PLAYER_DEFEATED" ))
// Display dialog if it's the player
if whichPlayer == THE_PLAYER then
set gameOver = true
call MeleeDefeatDialogBJ(THE_PLAYER, false)
// If it's a computer, remove from group and check for victory
else
call ForceRemovePlayer(enemyPlayers, whichPlayer)
if CountPlayersInForceBJ(enemyPlayers) == 0 then
set gameOver = true
call RemovePlayer(THE_PLAYER, PLAYER_GAME_RESULT_VICTORY)
call MeleeVictoryDialogBJ(THE_PLAYER, false)
endif
endif
endfunction
//=========================================================
// ATTACK WAVES
//=========================================================
// Initialize the next attack wave
private function InitNextWave takes nothing returns nothing
local real dur
set currentWave = currentWave + 1
if currentWave == 1 then
set dur = 60
elseif currentWave == 2 then
set dur = 90
elseif currentWave == 3 then
set dur = 120
elseif currentWave == 4 then
set dur = 150
elseif currentWave == 5 then
set dur = 180
elseif currentWave == 6 then
set dur = 210
elseif currentWave == 7 then
set dur = 240
elseif currentWave >= 8 then
set dur = 270
endif
call TimerDialogSetTitle(tmrdgAttackWaves, "Wave " + I2S(currentWave))
call TimerDialogDisplay(tmrdgAttackWaves, true)
call TimerStart(tmrAttackWaves, dur, false, null)
endfunction
//=========================================================
// TRIGGERS
//=========================================================
// Create new stuff periodically
private function CreateNewStuff takes nothing returns boolean
local integer randomInt = GetRandomInt(1, 100)
if randomInt <= 20 then
call CreateStuff(TREE, true)
elseif randomInt <= 53 then
call CreateStuff(CRITTER, true)
elseif randomInt <= 73 then
call CreateStuff(CREEP1, true)
elseif randomInt <= 83 then
call CreateStuff(CREEP2, true)
elseif randomInt <= 90 then
call CreateStuff(CREEP3, true)
elseif randomInt <= 95 then
call CreateStuff(CREEP4, true)
elseif randomInt <= 98 then
call CreateStuff(CREEP5, true)
elseif randomInt <= 100 then
call CreateStuff(CREEP6, true)
endif
return false
endfunction
// Neutral hostile unit dies, award food to killing player
private function HostileUnitDies takes nothing returns boolean
local texttag tt
local unit killingUnit = GetKillingUnit()
local unit dyingUnit
local player killingPlayer = GetOwningPlayer(killingUnit)
local integer foodGained
local integer foodUsed = GetPlayerState(killingPlayer, PLAYER_STATE_RESOURCE_FOOD_USED)
local integer foodCap = GetPlayerState(killingPlayer, PLAYER_STATE_RESOURCE_FOOD_CAP)
// Only hunters can provide food
if GetUnitTypeId(killingUnit) == 'nhea' and foodUsed < foodCap then
set dyingUnit = GetDyingUnit()
set foodGained = GetUnitLevel(dyingUnit)
if foodUsed+foodGained > foodCap then
set foodGained = foodCap - foodUsed
endif
call SetPlayerState(killingPlayer, PLAYER_STATE_RESOURCE_FOOD_USED, foodUsed+foodGained)
// Create floating text
set tt = CreateTextTag()
call SetTextTagText(tt, "+"+I2S(foodGained), 0.025)
call SetTextTagPosUnit(tt, dyingUnit, -30)
call SetTextTagVelocityBJ(tt, 64, 90)
call SetTextTagPermanent(tt, false)
call SetTextTagLifespan(tt, 3)
call SetTextTagFadepoint(tt, 2)
call SetTextTagColor(tt, 188, 100, 57, 255)
endif
set tt = null
set killingUnit = null
set dyingUnit = null
set killingPlayer = null
return false
endfunction
// Check if enumerated player has units
private function PlayerHasUnitsEnum takes nothing returns nothing
local group grp
if not enemiesHaveUnits then // No need to proceed if units have already been found
set grp = CreateGroup()
call GroupEnumUnitsOfPlayer(grp, GetEnumPlayer(), function AliveUnitFilter)
set enemiesHaveUnits = CountUnitsInGroup(grp) > 0
call DestroyGroup(grp)
endif
set grp = null
endfunction
// Enemy unit dies: if it's the bandit camp, defeat the enemy
private function EnemyUnitDies takes nothing returns boolean
local unit dyingUnit = GetDyingUnit()
// Bandit camp dies: defeat player
if GetUnitTypeId(dyingUnit) == 'hbar' then
call DefeatPlayer(GetOwningPlayer(dyingUnit))
// Unit dies: check if wave is done
elseif not gameOver then
set enemiesHaveUnits = false
call ForForce(enemyPlayers, function PlayerHasUnitsEnum)
if not enemiesHaveUnits then
call InitNextWave()
endif
endif
set dyingUnit = null
return false
endfunction
// Player unit dies
private function PlayerUnitDies takes nothing returns boolean
local integer typeId = GetUnitTypeId(GetDyingUnit())
local integer foodCap
// if it's the cabin, defeat the player
if typeId == 'htow' then
call DefeatPlayer(THE_PLAYER)
// If it's a storehouse, check if we have sufficient storage
elseif typeId == 'hhou' or typeId == 'h001' or typeId == 'h000' then
set foodCap = GetPlayerState(THE_PLAYER, PLAYER_STATE_RESOURCE_FOOD_CAP)
if GetPlayerState(THE_PLAYER, PLAYER_STATE_RESOURCE_FOOD_USED) > foodCap then
call SetPlayerState(THE_PLAYER, PLAYER_STATE_RESOURCE_FOOD_USED, foodCap)
endif
endif
return false
endfunction
// Subtract food per unit, damage units if insufficient
private function PlayerEats takes nothing returns boolean
local integer playerFood = GetPlayerState(THE_PLAYER, PLAYER_STATE_RESOURCE_FOOD_USED)
local integer unitCount
local integer index = 0
local group playerUnits = CreateGroup()
local unit pickedUnit
call GroupEnumUnitsOfPlayer(playerUnits, THE_PLAYER, function AliveUnitFilter)
set unitCount = CountUnitsInGroup(playerUnits)
// Player has enough food
if playerFood >= unitCount then
call SetPlayerState(THE_PLAYER, PLAYER_STATE_RESOURCE_FOOD_USED, playerFood-unitCount)
// Player has insufficient food, damage units
else
call SetPlayerState(THE_PLAYER, PLAYER_STATE_RESOURCE_FOOD_USED, 0)
call DisplayTextToPlayer(THE_PLAYER, 0, 0, "Insufficient food! Some of your units lost health.")
loop
set pickedUnit = GroupPickRandomUnit(playerUnits)
if pickedUnit != null then
call GroupRemoveUnit(playerUnits, pickedUnit)
call SetUnitState(pickedUnit, UNIT_STATE_LIFE, GetUnitState(pickedUnit, UNIT_STATE_LIFE)-GetUnitState(pickedUnit, UNIT_STATE_MAX_LIFE)*0.25)
endif
set index = index - 1
exitwhen index <= playerFood-unitCount or pickedUnit == null
endloop
endif
call DestroyGroup(playerUnits)
set playerUnits = null
set pickedUnit = null
return false
endfunction
// Bribe player: convert all units
private function BribePlayerFilter takes nothing returns nothing
call SetUnitOwner(GetFilterUnit(), THE_PLAYER, true)
endfunction
// Player attemps a bribe
private function AttemptBribe takes nothing returns boolean
local string chatMessage
local integer stringLength
local integer offer
local integer playerGold
local player pickedEnemy
local group enemyUnits
if not gameOver then
if enableBribes then
set chatMessage = GetEventPlayerChatString()
set stringLength = StringLength(chatMessage)
if SubString(chatMessage, 0, 6) == "bribe " and stringLength > 6 then
set offer = S2I(SubString(chatMessage, 6, stringLength))
set playerGold = GetPlayerState(THE_PLAYER, PLAYER_STATE_RESOURCE_GOLD)
if offer <= playerGold then
set enableBribes = false
// Bribe successful: subtract offer and convert units
if I2R(offer)/300*100 >= GetRandomReal(1, 100) then
call DisplayTextToPlayer(THE_PLAYER, 0, 0, "Bribe successful!")
call SetPlayerState(THE_PLAYER, PLAYER_STATE_RESOURCE_GOLD, playerGold-offer)
set pickedEnemy = ForcePickRandomPlayer(enemyPlayers)
call DefeatPlayer(pickedEnemy)
set enemyUnits = CreateGroup()
call GroupEnumUnitsOfPlayer(enemyUnits, pickedEnemy, function BribePlayerFilter)
call DestroyGroup(enemyUnits)
else
call DisplayTextToPlayer(THE_PLAYER, 0, 0, "Bribe unsuccessful.")
endif
else
call DisplayTextToPlayer(THE_PLAYER, 0, 0, "Not enough gold for that bribe.")
endif
endif
else
call DisplayTextToPlayer(THE_PLAYER, 0, 0, "You can only attempt one bribe a day.")
endif
endif
set pickedEnemy = null
set enemyUnits = null
return false
endfunction
// Re-enable bribes at midnight
private function EnableBribes takes nothing returns boolean
set enableBribes = true
return false
endfunction
// Create units for the next wave
private function CreateUnitsEnum takes nothing returns nothing
local player enumPlayer = GetEnumPlayer()
local real x
local real y
if enumPlayer == PLAYER_BANDITS1 then
set x = bandit_camp1_center_x
set y = bandit_camp1_center_y
elseif enumPlayer == PLAYER_BANDITS2 then
set x = bandit_camp2_center_x
set y = bandit_camp2_center_y
elseif enumPlayer == PLAYER_BANDITS3 then
set x = bandit_camp3_center_x
set y = bandit_camp3_center_y
elseif enumPlayer == PLAYER_BANDITS4 then
set x = bandit_camp4_center_x
set y = bandit_camp4_center_y
endif
call CreateUnit(enumPlayer, 'nban', x, y, GetRandomReal(0, 360))
if currentWave >= 2 then
call CreateUnit(enumPlayer, 'nbrg', x, y, GetRandomReal(0, 360))
endif
if currentWave >= 3 then
call CreateUnit(enumPlayer, 'nban', x, y, GetRandomReal(0, 360))
endif
if currentWave >= 4 then
call CreateUnit(enumPlayer, 'nbrg', x, y, GetRandomReal(0, 360))
endif
if currentWave >= 5 then
call CreateUnit(enumPlayer, 'nwzg', x, y, GetRandomReal(0, 360))
endif
if currentWave >= 6 then
call CreateUnit(enumPlayer, 'nwzg', x, y, GetRandomReal(0, 360))
endif
if currentWave >= 7 then
call CreateUnit(enumPlayer, 'nbld', x, y, GetRandomReal(0, 360))
endif
if currentWave >= 8 then
call CreateUnit(enumPlayer, 'nbld', x, y, GetRandomReal(0, 360))
endif
set enumPlayer = null
endfunction
// Send each player's units
private function SendWaveEnum takes nothing returns nothing
local player enumPlayer = GetEnumPlayer()
local group grp = CreateGroup()
call GroupEnumUnitsOfPlayer(grp, enumPlayer, function AliveUnitFilter)
call GroupPointOrder(grp, "attack", GetUnitX(gg_unit_htow_0000), GetUnitY(gg_unit_htow_0000))
call DestroyGroup(grp)
set grp = null
set enumPlayer = null
endfunction
// Send attack wave
private function SendWave takes nothing returns nothing
call ForForce(enemyPlayers, function CreateUnitsEnum)
call TriggerSleepAction(0.1) // Make sure we can enumerate all player units
call ForForce(enemyPlayers, function SendWaveEnum)
call TimerDialogDisplay(tmrdgAttackWaves, false)
endfunction
// Initialize attack waves
private function InitAttackWaves takes nothing returns nothing
// We need to sleep for the timer dialog to display
call TriggerSleepAction(0.1)
call InitNextWave()
call DestroyTrigger(GetTriggeringTrigger())
endfunction
//=========================================================
// Initializer
//=========================================================
private function InitCabinDefense takes nothing returns nothing
local integer index
local trigger trg
set map_min_x = GetRectMinX(bj_mapInitialPlayableArea)
set map_max_x = GetRectMaxX(bj_mapInitialPlayableArea)
set map_min_y = GetRectMinY(bj_mapInitialPlayableArea)
set map_max_y = GetRectMaxY(bj_mapInitialPlayableArea)
set bandit_camp1_center_x = GetRectCenterX(gg_rct_BanditCamp1)
set bandit_camp1_center_y = GetRectCenterY(gg_rct_BanditCamp1)
set bandit_camp2_center_x = GetRectCenterX(gg_rct_BanditCamp2)
set bandit_camp2_center_y = GetRectCenterY(gg_rct_BanditCamp2)
set bandit_camp3_center_x = GetRectCenterX(gg_rct_BanditCamp3)
set bandit_camp3_center_y = GetRectCenterY(gg_rct_BanditCamp3)
set bandit_camp4_center_x = GetRectCenterX(gg_rct_BanditCamp4)
set bandit_camp4_center_y = GetRectCenterY(gg_rct_BanditCamp4)
// Set critters & creeps to be used
set critters[0] = 'nalb'
set critters[1] = 'nech'
set critters[2] = 'ndog'
set critters[3] = 'nfro'
set critters[4] = 'npig'
set critters[5] = 'necr'
set critters[6] = 'nrac'
set critters[7] = 'nrat'
set critters[8] = 'nshe'
set critters[9] = 'nskk'
set critters[10] = 'nsno'
set critters[11] = 'nder'
set critters[12] = 'nvul'
set critters_max = 12
set creeps1[0] = 'nspr'
set creeps1[1] = 'nanb'
set creeps1[2] = 'nanc'
set creeps1[3] = 'nspb'
set creeps1[4] = 'nspg'
set creeps1_max = 4
set creeps2[0] = 'nwlt'
set creeps2_max = 0
set creeps3[0] = 'nanw'
set creeps3[1] = 'nssp'
set creeps3[2] = 'nmam'
set creeps3_max = 2
set creeps4[0] = 'nane'
set creeps4[1] = 'nsgt'
set creeps4[2] = 'nwlg'
set creeps4_max = 2
set creeps5[0] = 'nano'
set creeps5[1] = 'nmit'
set creeps5_max = 1
set creeps6[0] = 'nsbm'
set creeps6[1] = 'nwld'
set creeps6_max = 1
// Create trees
set index = 0
loop
call CreateStuff(TREE, false)
set index = index + 1
exitwhen index == 7000
endloop
// Create critters
set index = 0
loop
call CreateStuff(CRITTER, false)
set index = index + 1
exitwhen index == 400
endloop
// Create creeps level 1
set index = 0
loop
call CreateStuff(CREEP1, false)
set index = index + 1
exitwhen index == 175
endloop
// Create creeps level 2
set index = 0
loop
call CreateStuff(CREEP2, false)
set index = index + 1
exitwhen index == 100
endloop
// Create creeps level 3
set index = 0
loop
call CreateStuff(CREEP3, false)
set index = index + 1
exitwhen index == 75
endloop
// Create creeps level 4
set index = 0
loop
call CreateStuff(CREEP4, false)
set index = index + 1
exitwhen index == 30
endloop
// Create creeps level 5
set index = 0
loop
call CreateStuff(CREEP5, false)
set index = index + 1
exitwhen index == 10
endloop
// Create creeps level 6
set index = 0
loop
call CreateStuff(CREEP6, false)
set index = index + 1
exitwhen index == 5
endloop
// Add enemies to force
call ForceAddPlayer(enemyPlayers, PLAYER_BANDITS1)
call ForceAddPlayer(enemyPlayers, PLAYER_BANDITS2)
call ForceAddPlayer(enemyPlayers, PLAYER_BANDITS3)
call ForceAddPlayer(enemyPlayers, PLAYER_BANDITS4)
// Create new stuff periodically
set trg = CreateTrigger()
call TriggerRegisterTimerEvent(trg, 20, true)
call TriggerAddCondition(trg, function CreateNewStuff)
// Neutral hostile unit dies
set trg = CreateTrigger()
call TriggerRegisterPlayerUnitEvent(trg, PLAYER_HOSTILE, EVENT_PLAYER_UNIT_DEATH, null)
call TriggerAddCondition(trg, function HostileUnitDies)
// Enemy unit dies
set trg = CreateTrigger()
call TriggerRegisterPlayerUnitEvent(trg, PLAYER_BANDITS1, EVENT_PLAYER_UNIT_DEATH, null)
call TriggerRegisterPlayerUnitEvent(trg, PLAYER_BANDITS2, EVENT_PLAYER_UNIT_DEATH, null)
call TriggerRegisterPlayerUnitEvent(trg, PLAYER_BANDITS3, EVENT_PLAYER_UNIT_DEATH, null)
call TriggerRegisterPlayerUnitEvent(trg, PLAYER_BANDITS4, EVENT_PLAYER_UNIT_DEATH, null)
call TriggerAddCondition(trg, function EnemyUnitDies)
// Player unit dies
set trg = CreateTrigger()
call TriggerRegisterPlayerUnitEvent(trg, THE_PLAYER, EVENT_PLAYER_UNIT_DEATH, null)
call TriggerAddCondition(trg, function PlayerUnitDies)
// Three meals a day
set trg = CreateTrigger()
call TriggerRegisterGameStateEvent(trg, GAME_STATE_TIME_OF_DAY, EQUAL, 6)
call TriggerRegisterGameStateEvent(trg, GAME_STATE_TIME_OF_DAY, EQUAL, 12)
call TriggerRegisterGameStateEvent(trg, GAME_STATE_TIME_OF_DAY, EQUAL, 18)
call TriggerAddCondition(trg, function PlayerEats)
// Bribe
set trg = CreateTrigger()
call TriggerRegisterPlayerChatEvent(trg, THE_PLAYER, "bribe ", false)
call TriggerAddCondition(trg, function AttemptBribe)
// Re-enable bribes at midnight
set trg = CreateTrigger()
call TriggerRegisterGameStateEvent(trg, GAME_STATE_TIME_OF_DAY, EQUAL, 0)
call TriggerAddCondition(trg, function EnableBribes)
// Attack waves
set trg = CreateTrigger()
call TriggerRegisterTimerExpireEvent(trg, tmrAttackWaves)
call TriggerAddAction(trg, function SendWave)
set trg = CreateTrigger()
call TriggerAddAction(trg, function InitAttackWaves)
call TriggerExecute(trg)
set trg = null
endfunction
endlibrary