fortressforever-scripts/maps/includes/base_adzone.lua

1105 lines
42 KiB
Lua

-- base_adzone.lua
-- Attack and Defend the Zone gametype
-----------------------------------------------------------------------------
-- includes
-----------------------------------------------------------------------------
IncludeScript("base_teamplay")
-----------------------------------------------------------------------------
-- global overrides that you can do what you want with
-----------------------------------------------------------------------------
FORT_POINTS_PER_INITIAL_TOUCH = 200
FORT_POINTS_PER_PERIOD = 50
FORT_POINTS_PER_DEFEND = 100
POINTS_PER_INITIAL_TOUCH = 1
POINTS_PER_PERIOD = 1
DELAY_BEFORE_PERIOD_POINTS = 2
PERIOD_TIME = 1
FLAG_RETURN_TIME = 0
INITIAL_ROUND_PERIOD = 60
DELAY_BEFORE_DEFENSE_PERIOD_SCORING = 30
DEFENSE_PERIOD_TIME = 10
POINTS_PER_DEFENSE_PERIOD = POINTS_PER_PERIOD -- same as attackers
POINTS_PER_DEFENSE_60SEC_BONUS = POINTS_PER_PERIOD * 5 -- attackers period points * 5
POINTS_PER_DEFENSE_SHUTOUT = POINTS_PER_DEFENSE_60SEC_BONUS * 10 --default, not used if GET_ROUND_PERIOD_FROM_TIMELIMIT is set to true
ATTACKERS_OBJECTIVE_ENTITY = nil
DEFENDERS_OBJECTIVE_ENTITY = nil
ENABLE_ATTACKERS_OBJECTIVE = true -- puts attackers objective on the zone
ENABLE_DEFENDERS_OBJECTIVE = true -- puts defenders objective on the zone
GET_ROUND_PERIOD_FROM_TIMELIMIT = true
NUMBER_OF_ROUNDS = 4
ROUND_PERIOD = 600 --default, not used if GET_ROUND_PERIOD_FROM_TIMELIMIT is set to true
ZONE_COLOR = "green"
USE_ZONE_AREA = true
NUM_DEFENDER_ONLY_PACKS = 0
-----------------------------------------------------------------------------
-- global variables and other shit that shouldn't be messed with
-----------------------------------------------------------------------------
phase = 1
zone_status = false
zone_area_status = false
gates_open = false
current_timer = DELAY_BEFORE_DEFENSE_PERIOD_SCORING
current_seconds = 0
attackers = Team.kBlue
defenders = Team.kRed
scoring_team = Team.kRed
local teamdata = {
[Team.kBlue] = { skin = "0", beamcolour = "0 0 255" },
[Team.kRed] = { skin = "1", beamcolour = "255 0 0" }
}
-- stores attackers in the zone
local zone_collection = Collection()
-- stores attackers in the zone area
local zone_area_collection = Collection()
-- stores if the player has touched the cap point (for 1 touch per death)
local playerTouchedTable = {}
-----------------------------------------------------------------------------
-- Entity definitions (flags/command points/backpacks etc.)
-----------------------------------------------------------------------------
-- zone
base_zone_trigger = trigger_ff_script:new({})
zone = base_zone_trigger:new({})
-- area around zone
base_zone_area_trigger = trigger_ff_script:new({})
zone_area = base_zone_area_trigger:new({})
-- respawns
attacker_spawn = info_ff_teamspawn:new({ validspawn = function(self,player)
return player:GetTeamId() == attackers
end })
defender_spawn = info_ff_teamspawn:new({ validspawn = function(self,player)
return player:GetTeamId() == defenders
end })
-----------------------------------------------------------------------------
-- functions that do sh... stuff
-----------------------------------------------------------------------------
-- sounds, right?
function precache()
PrecacheSound("otherteam.flagstolen") -- doors open sound
PrecacheSound("otherteam.drop") -- warning sound
PrecacheSound("yourteam.flagreturn") -- scoring sound
PrecacheSound("misc.bloop") -- minutes remaining
PrecacheSound("misc.doop") -- attackers capping sound
end
-- pretty standard setup, aside from scoring starting
function startup()
SetGameDescription( "Attack Defend the Zone" )
-- set up team limits on each team
SetPlayerLimit( Team.kBlue, 0 )
SetPlayerLimit( Team.kRed, 0 )
SetPlayerLimit( Team.kYellow, -1 )
SetPlayerLimit( Team.kGreen, -1 )
SetTeamName( attackers, "Attackers" )
SetTeamName( defenders, "Defenders" )
-- set class limits
set_classlimits()
AddSchedule( "round_start", INITIAL_ROUND_PERIOD, round_start)
if INITIAL_ROUND_PERIOD > 30 then AddSchedule( "dooropen30sec" , INITIAL_ROUND_PERIOD - 30 , schedulemessagetoall, "#ADZ_30SecWarning" ) end
if INITIAL_ROUND_PERIOD > 10 then AddSchedule( "dooropen10sec" , INITIAL_ROUND_PERIOD - 10 , schedulemessagetoall, "#ADZ_10SecWarning" ) end
if INITIAL_ROUND_PERIOD > 5 then AddSchedule( "dooropen5sec" , INITIAL_ROUND_PERIOD - 5 , schedulemessagetoall, "5" ) end
if INITIAL_ROUND_PERIOD > 4 then AddSchedule( "dooropen4sec" , INITIAL_ROUND_PERIOD - 4 , schedulemessagetoall, "4" ) end
if INITIAL_ROUND_PERIOD > 3 then AddSchedule( "dooropen3sec" , INITIAL_ROUND_PERIOD - 3, schedulemessagetoall, "3" ) end
if INITIAL_ROUND_PERIOD > 2 then AddSchedule( "dooropen2sec" , INITIAL_ROUND_PERIOD - 2, schedulemessagetoall, "2" ) end
if INITIAL_ROUND_PERIOD > 1 then AddSchedule( "dooropen1sec" , INITIAL_ROUND_PERIOD - 1, schedulemessagetoall, "1" ) end
-- sounds
if INITIAL_ROUND_PERIOD > 10 then AddSchedule( "dooropen30secsound" , INITIAL_ROUND_PERIOD - 30 , schedulesound, "misc.bloop" ) end
if INITIAL_ROUND_PERIOD > 10 then AddSchedule( "dooropen10secsound" , INITIAL_ROUND_PERIOD - 10 , schedulesound, "misc.bloop" ) end
if INITIAL_ROUND_PERIOD > 5 then AddSchedule( "dooropen5seccount" , INITIAL_ROUND_PERIOD - 5 , schedulecountdown, 5 ) end
if INITIAL_ROUND_PERIOD > 4 then AddSchedule( "dooropen4seccount" , INITIAL_ROUND_PERIOD - 4 , schedulecountdown, 4 ) end
if INITIAL_ROUND_PERIOD > 3 then AddSchedule( "dooropen3seccount" , INITIAL_ROUND_PERIOD - 3 , schedulecountdown, 3 ) end
if INITIAL_ROUND_PERIOD > 2 then AddSchedule( "dooropen2seccount" , INITIAL_ROUND_PERIOD - 2 , schedulecountdown, 2 ) end
if INITIAL_ROUND_PERIOD > 1 then AddSchedule( "dooropen1seccount" , INITIAL_ROUND_PERIOD - 1 , schedulecountdown, 1 ) end
-- get round times if its set to
if GET_ROUND_PERIOD_FROM_TIMELIMIT == true then
local timelimit = GetConvar( "mp_timelimit" )
-- convert mp_timelimit from minutes to seconds and divide by the number of rounds minus initial round period
ROUND_PERIOD = timelimit * 60 / NUMBER_OF_ROUNDS - INITIAL_ROUND_PERIOD - 1
POINTS_PER_DEFENSE_SHUTOUT = ROUND_PERIOD / ( 3 / ( POINTS_PER_DEFENSE_PERIOD / 4 ) )
-- now lock mp_timelimit, so things don't get weird
AddScheduleRepeating( "set_cvar-mp_timelimit", 1, set_cvar, "mp_timelimit", timelimit )
end
if ENABLE_ATTACKERS_OBJECTIVE then ATTACKERS_OBJECTIVE_ENTITY = GetEntityByName( "zone" ) end
if ENABLE_DEFENDERS_OBJECTIVE then DEFENDERS_OBJECTIVE_ENTITY = GetEntityByName( "zone" ) end
custom_startup()
current_timer = INITIAL_ROUND_PERIOD
AddScheduleRepeatingNotInfinitely( "timer_schedule", 1, timer_schedule, current_timer )
update_zone_text( nil )
update_zone_status( false )
end
-----------------------------------------------------------------------------
-- player_ functions
-----------------------------------------------------------------------------
-- spawns attackers with flags
function player_spawn( player_entity )
local player = CastToPlayer( player_entity )
player:AddHealth( 100 )
player:AddArmor( 300 )
player:AddAmmo( Ammo.kNails, 400 )
player:AddAmmo( Ammo.kShells, 400 )
player:AddAmmo( Ammo.kRockets, 400 )
player:AddAmmo( Ammo.kCells, 400 )
player:SetCloakable( true )
player:SetDisguisable( true )
-- nade/detpack limits
set_itemlimits( player )
-- wtf, scout or med on d? are you mental?
if (player:GetClass() == Player.kScout or player:GetClass() == Player.kMedic) and (player:GetTeamId() == defenders) then
local classt = "Scout"
if player:GetClass() == Player.kMedic then classt = "Medic" end
local id = player:GetId()
AddSchedule("force_changemessage"..id, 2, schedulechangemessage, player, "No "..classt.."s on defense. Autoswitching to Soldier." )
AddSchedule("force_change"..id, 2, forcechange, player)
end
-- objective icon
if player:GetTeamId() == attackers then
UpdateObjectiveIcon( player, ATTACKERS_OBJECTIVE_ENTITY )
elseif player:GetTeamId() == defenders then
UpdateObjectiveIcon( player, DEFENDERS_OBJECTIVE_ENTITY )
end
-- remove any players not on a team from playertouchedtable
for playerx, recordx in pairs(playerTouchedTable) do
if GetPlayerByID( playerx ) then
local playert = GetPlayerByID( playerx )
if playert:GetTeamId() ~= attackers then
playerTouchedTable[playerx] = nil
end
end
end
if player:GetTeamId() ~= attackers then return end
-- add to table and reset touched to 0
playerTouchedTable[player:GetId()] = {touched = false, allowed = true, points = 0}
end
function player_killed( player, damageinfo )
-- if no damageinfo do nothing
if not damageinfo then return end
-- Entity that is attacking
local attacker = damageinfo:GetAttacker()
-- If no attacker do nothing
if not attacker then return end
local player_attacker = nil
-- get the attacking player
if IsPlayer(attacker) then
attacker = CastToPlayer(attacker)
player_attacker = attacker
elseif IsSentrygun(attacker) then
attacker = CastToSentrygun(attacker)
player_attacker = attacker:GetOwner()
elseif IsDetpack(attacker) then
attacker = CastToDetpack(attacker)
player_attacker = attacker:GetOwner()
elseif IsDispenser(attacker) then
attacker = CastToDispenser(attacker)
player_attacker = attacker:GetOwner()
else
return
end
-- if still no attacking player after all that, forget about it
if not player_attacker then return end
-- If player killed self or teammate do nothing
if (player:GetId() == player_attacker:GetId()) or (player:GetTeamId() == player_attacker:GetTeamId()) then
return
end
-- If player is an attacker, then do stuff
if player:GetTeamId() == attackers then
-- show scored points
BroadCastMessageToPlayer( player, "You scored "..playerTouchedTable[player:GetId()].points.." team points that run" )
AddScheduleRepeatingNotInfinitely( "timer_return_schedule", .5, BroadCastMessageToPlayer, 4, player, "You scored "..playerTouchedTable[player:GetId()].points.." team points that run")
-- Check if he's in the zone
for playerx in zone_collection.items do
playerx = CastToPlayer(playerx)
if playerx:GetId() == player:GetId() then
player_attacker:AddFortPoints( FORT_POINTS_PER_DEFEND, "Defending the Zone" )
return
end
end
-- Check if he's in the zone area
for playerx in zone_area_collection.items do
playerx = CastToPlayer(playerx)
if playerx:GetId() == player:GetId() then
if playerTouchedTable[player:GetId()].touched == false then
player_attacker:AddFortPoints( FORT_POINTS_PER_DEFEND * 2, "Denying Attacker from Scoring" )
else
player_attacker:AddFortPoints( FORT_POINTS_PER_DEFEND / 2, "Defending the Zone Area" )
end
return
end
end
end
end
function player_ondamage( player, damageinfo )
-- if no damageinfo do nothing
if not damageinfo then return end
-- Get Damage Force
local damage = damageinfo:GetDamage()
-- Entity that is attacking
local attacker = damageinfo:GetAttacker()
-- If no attacker do nothing
if not attacker then return end
local player_attacker = nil
-- get the attacking player
if IsPlayer(attacker) then
attacker = CastToPlayer(attacker)
player_attacker = attacker
elseif IsSentrygun(attacker) then
attacker = CastToSentrygun(attacker)
player_attacker = attacker:GetOwner()
elseif IsDetpack(attacker) then
attacker = CastToDetpack(attacker)
player_attacker = attacker:GetOwner()
elseif IsDispenser(attacker) then
attacker = CastToDispenser(attacker)
player_attacker = attacker:GetOwner()
else
return
end
-- if still no attacking player after all that, forget about it
if not player_attacker then return end
-- If player killed self or teammate do nothing
if (player:GetId() == player_attacker:GetId()) or (player:GetTeamId() == player_attacker:GetTeamId()) then
return
end
-- If player (victim) is an attacker, then do stuff
if player:GetTeamId() == attackers then
-- Check if he's in the zone
for playerx in zone_collection.items do
playerx = CastToPlayer(playerx)
if playerx:GetId() == player:GetId() then
if (damage > 100) then damage = 100 end
player_attacker:AddFortPoints( damage, "Protecting the Zone" )
return
end
end
-- Check if he's in the zone area
for playerx in zone_area_collection.items do
playerx = CastToPlayer(playerx)
if playerx:GetId() == player:GetId() then
if (damage > 50) then damage = 50 end
player_attacker:AddFortPoints( damage, "Protecting the Zone Area" )
return
end
end
end
end
-----------------------------------------------------------------------------
-- zone triggers
-----------------------------------------------------------------------------
-- only attackers!
function base_zone_trigger:allowed( allowed_entity )
if IsPlayer( allowed_entity ) then
local player = CastToPlayer( allowed_entity )
if player:GetTeamId() == attackers then
if not gates_open then return EVENT_DISALLOWED end
return EVENT_ALLOWED
end
if player:GetTeamId() == defenders then
BroadCastMessageToPlayer( player, "ADZ_Defend" )
return EVENT_DISALLOWED
end
end
return EVENT_DISALLOWED
end
-- registers attackers as they enter the zone
function base_zone_trigger:ontouch( trigger_entity )
if IsPlayer( trigger_entity ) then
local player = CastToPlayer( trigger_entity )
player:SetCloakable( false )
player:SetDisguisable( false )
local playerid = player:GetId()
zone_collection:AddItem( player )
local team = GetTeam(attackers)
-- if it's the first touch, give points and stuff
if playerTouchedTable[playerid].touched == false then
team:AddScore( POINTS_PER_INITIAL_TOUCH )
player:AddFortPoints( FORT_POINTS_PER_INITIAL_TOUCH, "Initial Point Touch" )
RemoveSchedule( "shutout" ) -- O scores, no D shutout (put in all O scoring spots for safety, haha)
SmartTeamSound( GetTeam(defenders), "yourteam.flagreturn", "misc.doop" )
playerTouchedTable[playerid].touched = true
playerTouchedTable[playerid].points = playerTouchedTable[playerid].points + POINTS_PER_INITIAL_TOUCH
if zone_collection:Count() == 1 then
AddSchedule( "period_init", DELAY_BEFORE_PERIOD_POINTS, init_scoring, team )
end
elseif zone_collection:Count() == 1 then
SmartTeamSound( GetTeam(defenders), "otherteam.drop", nil )
end
if zone_collection:Count() == 1 then
-- activate the cap point, bro
zone_turnon()
end
update_zone_status( true )
end
end
-- deregisters attackers as they leave the zone
function base_zone_trigger:onendtouch( trigger_entity )
if IsPlayer( trigger_entity ) then
local player = CastToPlayer( trigger_entity )
player:SetCloakable( true )
player:SetDisguisable( true )
zone_collection:RemoveItem( player )
end
end
-- clear collection and start defender points when everyone's left
function base_zone_trigger:oninactive( )
-- Clear out the flags in the collection
zone_collection:RemoveAllItems()
init_defender_countdown()
zone_turnoff()
update_zone_status( false )
end
-----------------------------------------------------------------------------
-- zone area triggers
-----------------------------------------------------------------------------
-- only attackers!
function base_zone_area_trigger:allowed( allowed_entity )
if IsPlayer( allowed_entity ) then
local player = CastToPlayer( allowed_entity )
if player:GetTeamId() == attackers then
return EVENT_ALLOWED
end
end
return EVENT_DISALLOWED
end
-- registers attackers as they enter the zone area
function base_zone_area_trigger:ontouch( trigger_entity )
if IsPlayer( trigger_entity ) then
local player = CastToPlayer( trigger_entity )
if player:GetTeamId() == defenders then return end
update_zone_area_status( true )
zone_area_collection:AddItem( player )
end
end
-- registers attackers as they enter the zone area
function base_zone_area_trigger:onendtouch( trigger_entity )
if IsPlayer( trigger_entity ) then
local player = CastToPlayer( trigger_entity )
if player:GetTeamId() == defenders then return end
zone_area_collection:RemoveItem( player )
end
end
-- updates the hud if no one is in the zone area.
function base_zone_area_trigger:oninactive()
update_zone_area_status( false )
zone_area_collection:RemoveAllItems()
end
-----------------------------------------------------------------------------
-- zone functions
-----------------------------------------------------------------------------
function update_zone_status( on )
RemoveHudItemFromAll( "Zone_Status" )
if on then
AddHudIconToAll( "hud_zone_on_"..ZONE_COLOR..".vtf", "Zone_Status", -64, 32, 88, 88, 3 )
zone_status = true;
else
AddHudIconToAll( "hud_zone_off.vtf", "Zone_Status", -64, 32, 88, 88, 3 )
zone_status = false;
end
update_zone_text( nil )
end
function update_zone_area_status( on )
if USE_ZONE_AREA then
RemoveHudItemFromAll( "Zone_Area_Status" )
if on then
AddHudIconToAll( "hud_zone_area_active_"..ZONE_COLOR..".vtf", "Zone_Area_Status", -56, 40, 72, 72, 3 )
zone_area_status = true;
else
AddHudIconToAll( "hud_zone_area_inactive.vtf", "Zone_Area_Status", -56, 40, 72, 72, 3 )
zone_area_status = false;
end
end
end
function flaginfo( player_entity )
local player = CastToPlayer( player_entity )
RemoveHudItem( player, "Zone_Status" )
RemoveHudItem( player, "Zone_Area_Status" )
if USE_ZONE_AREA then
if zone_area_status then
AddHudIcon( player, "hud_zone_area_active_"..ZONE_COLOR..".vtf", "Zone_Area_Status", -56, 40, 72, 72, 3 )
else
AddHudIcon( player, "hud_zone_area_inactive.vtf", "Zone_Area_Status", -56, 40, 72, 72, 3 )
end
end
if zone_status then
AddHudIcon( player, "hud_zone_on_"..ZONE_COLOR..".vtf", "Zone_Status", -64, 32, 88, 88, 3 )
else
AddHudIcon( player, "hud_zone_off.vtf", "Zone_Status", -64, 32, 88, 88, 3 )
end
update_zone_text( player )
update_round_info( player )
end
function zone_turnon( )
zone_on_outputs()
-- init attacker scoring
AddSchedule( "period_init", DELAY_BEFORE_PERIOD_POINTS, init_scoring, team )
AddSchedule( "period_init_alarm", DELAY_BEFORE_PERIOD_POINTS - 1, init_scoring_alarm )
-- stop defender point countdown
DeleteSchedule( "timer_schedule" )
RemoveSchedule( "defenders_period_scoring" )
RemoveSchedule( "init_defenders_period_scoring" )
end
function zone_turnoff( )
zone_off_outputs()
-- stop attacker scoring
DeleteSchedule( "period_init" )
DeleteSchedule( "period_init_alarm" )
DeleteSchedule( "period_scoring" )
zone_scoring = false
end
function update_zone_text( player )
local text_align = 4
local text_x = 40
local text_line1y = 84
local text_line2y = text_line1y + 8
local text_line3y = text_line2y + 8
if IsPlayer( player ) then
-- defender period scoring text and timer
RemoveHudItem(player, "defender_points_timer")
RemoveHudItem(player, "defender_points_text")
RemoveHudItem(player, "defender_points_text2")
-- attackers in the zone text
RemoveHudItem(player, "attackers_in_text")
RemoveHudItem(player, "attackers_in_text2")
RemoveHudItem(player, "attackers_in_text3")
-- gates open in text and timer
RemoveHudItem(player, "gates_open_text")
RemoveHudItem(player, "gates_open_text2")
RemoveHudItem(player, "gates_open_timer")
if gates_open == true then
if not zone_status then
AddHudText( player, "defender_points_text", "#FF_Defenders", text_x, text_line1y, text_align )
AddHudText( player, "defender_points_text2", "#ADZ_ScoreNotice", text_x, text_line2y, text_align )
AddHudTimer( player, "defender_points_timer", current_timer, -1, text_x, text_line3y, text_align )
else
AddHudText( player, "attackers_in_text", "#FF_Attackers", text_x, text_line1y, text_align )
AddHudText( player, "attackers_in_text2", "#ADZ_AreIn", text_x, text_line2y, text_align )
AddHudText( player, "attackers_in_text3", "#ADZ_TheZone", text_x, text_line3y, text_align )
end
else
AddHudText( player, "gates_open_text", "#ADZ_GATES", text_x, text_line1y, text_align )
AddHudText( player, "gates_open_text2", "#ADZ_OPENIN", text_x, text_line2y, text_align )
AddHudTimer( player, "gates_open_timer", current_timer, -1, text_x, text_line3y, text_align )
end
else
-- defender period scoring text and timer
RemoveHudItemFromAll("defender_points_timer")
RemoveHudItemFromAll("defender_points_text")
RemoveHudItemFromAll("defender_points_text2")
-- attackers in the zone text
RemoveHudItemFromAll("attackers_in_text")
RemoveHudItemFromAll("attackers_in_text2")
RemoveHudItemFromAll("attackers_in_text3")
-- gates open in text and timer
RemoveHudItemFromAll("gates_open_text")
RemoveHudItemFromAll("gates_open_text2")
RemoveHudItemFromAll("gates_open_timer")
if gates_open == true then
if not zone_status then
AddHudTextToAll( "defender_points_text", "#FF_Defenders", text_x, text_line1y, text_align )
AddHudTextToAll( "defender_points_text2", "#ADZ_ScoreNotice", text_x, text_line2y, text_align )
AddHudTimerToAll( "defender_points_timer", current_timer, -1, text_x, text_line3y, text_align )
else
AddHudTextToAll( "attackers_in_text", "#FF_Attackers", text_x, text_line1y, text_align )
AddHudTextToAll( "attackers_in_text2", "#ADZ_AreIn", text_x, text_line2y, text_align )
AddHudTextToAll( "attackers_in_text3", "#ADZ_TheZone", text_x, text_line3y, text_align )
end
else
AddHudTextToAll( "gates_open_text", "#ADZ_GATES", text_x, text_line1y, text_align )
AddHudTextToAll( "gates_open_text2", "#ADZ_OPENIN", text_x, text_line2y, text_align )
AddHudTimerToAll( "gates_open_timer", current_timer, -1, text_x, text_line3y, text_align )
end
end
end
function update_round_info( player )
RemoveHudItem( player, "Zone_Round" )
RemoveHudItem( player, "Zone_Team"..attackers )
RemoveHudItem( player, "Zone_Team"..defenders )
RemoveHudItem( player, "Zone_Phase"..attackers )
RemoveHudItem( player, "Zone_Phase"..defenders )
od_hudstatusiconx = 28
od_hudstatusicony = 48
od_hudstatusiconw = 24
od_hudstatusiconh = 24
od_hudstatusiconalign = 3
AddHudText( player, "Zone_Round", "#ADZ_Round", od_hudstatusiconx + od_hudstatusiconw / 2, od_hudstatusicony - 10, 4 )
if player:GetTeamId() == attackers then
AddHudIcon( player, "hud_offense.vtf", "Zone_Team"..attackers, od_hudstatusiconx, od_hudstatusicony, od_hudstatusiconw, od_hudstatusiconh, od_hudstatusiconalign )
AddHudIcon( player, "hud_cp_"..phase..".vtf", "Zone_Phase"..attackers, od_hudstatusiconx + 2, od_hudstatusicony + 2, 20, 20, od_hudstatusiconalign )
elseif player:GetTeamId() == defenders then
AddHudIcon( player, "hud_defense.vtf", "Zone_Team"..defenders, od_hudstatusiconx, od_hudstatusicony, od_hudstatusiconw, od_hudstatusiconh, od_hudstatusiconalign )
AddHudIcon( player, "hud_cp_"..phase..".vtf", "Zone_Phase"..defenders, od_hudstatusiconx + 2, od_hudstatusicony + 2, 20, 20, od_hudstatusiconalign )
end
end
function init_defender_countdown()
-- init defender scoring
current_timer = DELAY_BEFORE_DEFENSE_PERIOD_SCORING
RemoveSchedule( "timer_schedule" )
AddScheduleRepeatingNotInfinitely( "timer_schedule", 1, timer_schedule, current_timer )
AddSchedule( "init_defenders_period_scoring", current_timer, init_defenders_period_scoring )
end
-----------------------------------------------------------------------------
-- Scheduled functions that do stuff
-----------------------------------------------------------------------------
-- Sends a message to all after the determined time
function schedulechangemessage( player, message )
if (player:GetClass() == Player.kScout or player:GetClass() == Player.kMedic) and (player:GetTeamId() == defenders) then
BroadCastMessageToPlayer( player, message )
end
end
-- force a scout/med to switch to soli if they haven't
function forcechange( player )
if (player:GetClass() == Player.kScout or player:GetClass() == Player.kMedic) and (player:GetTeamId() == defenders) then
ApplyToPlayer( player, { AT.kChangeClassSoldier, AT.kRespawnPlayers } )
end
end
-- Sends a message to all after the determined time
function schedulemessagetoall( message )
BroadCastMessage( message )
end
-- Plays a sound to all after the determined time
function schedulesound( sound )
BroadCastSound( sound )
end
function schedulecountdown( time )
BroadCastMessage( ""..time.."" )
SpeakAll( "AD_" .. time .. "SEC" )
end
function timer_schedule()
current_timer = current_timer -1
end
-----------------------------------------------------------------------------
-- Scoring
-----------------------------------------------------------------------------
-- Adds points based on time inside cap room and number of attackers inside cap room
function period_scoring( team )
team:AddScore( POINTS_PER_PERIOD )
SmartTeamSound( GetTeam(defenders), "yourteam.flagreturn", "misc.doop" )
for player in zone_collection.items do
player = CastToPlayer(player)
if player ~= nil then
player:AddFortPoints( FORT_POINTS_PER_PERIOD, "Touching the Point" )
playerTouchedTable[player:GetId()].points = playerTouchedTable[player:GetId()].points + POINTS_PER_PERIOD
else
ConsoleToAll("LUA ERROR: player_addfortpoints: Unable to find player")
end
end
end
-- Initializes the period_scoring (allows for a delay after initial touch)
function init_scoring( team )
if zone_collection:Count() > 0 then
team:AddScore( POINTS_PER_PERIOD )
AddScheduleRepeating( "period_scoring", PERIOD_TIME, period_scoring, team)
for player in zone_collection.items do
player = CastToPlayer(player)
if player ~= nil then
player:AddFortPoints( FORT_POINTS_PER_PERIOD, "Touching the Point" )
playerTouchedTable[player:GetId()].points = playerTouchedTable[player:GetId()].points + POINTS_PER_PERIOD
else
ConsoleToAll("LUA ERROR: player_addfortpoints: Unable to find player")
end
end
end
end
-- Initializes the period_scoring (allows for a delay after initial touch)
function init_scoring_alarm( )
if zone_collection:Count() > 0 then
SmartTeamSound( GetTeam(defenders), "otherteam.drop", nil )
end
end
function init_defenders_period_scoring()
local team = GetTeam( defenders )
team:AddScore( POINTS_PER_DEFENSE_PERIOD )
SmartTeamSound( GetTeam(attackers), "yourteam.flagreturn", "misc.doop" )
current_seconds = 30
AddScheduleRepeating( "defenders_period_scoring", DEFENSE_PERIOD_TIME, defenders_period_scoring )
current_timer = DEFENSE_PERIOD_TIME
RemoveSchedule( "timer_schedule" )
AddScheduleRepeatingNotInfinitely( "timer_schedule", 1, timer_schedule, current_timer )
update_zone_text( nil )
end
function defenders_period_scoring( )
local team = GetTeam( defenders )
team:AddScore( POINTS_PER_DEFENSE_PERIOD )
SmartTeamSound( GetTeam(attackers), "yourteam.flagreturn", "misc.doop" )
if current_seconds >= 60 then
BroadCastMessage( "Defenders get "..POINTS_PER_DEFENSE_60SEC_BONUS.." bonus points" )
team:AddScore( POINTS_PER_DEFENSE_60SEC_BONUS )
current_seconds = 0
else
current_seconds = current_seconds + 10
end
current_timer = DEFENSE_PERIOD_TIME
RemoveSchedule( "timer_schedule" )
AddScheduleRepeatingNotInfinitely( "timer_schedule", 1, timer_schedule, current_timer )
update_zone_text( nil )
end
function shutout( )
-- attackers instead of defenders, because the teams switched
local teamid = attackers
-- but after the last round, use defenders
if phase >= NUMBER_OF_ROUNDS then
teamid = defenders
end
local team = GetTeam( teamid )
AddSchedule( "defenders_shutout_msg", 3, BroadCastMessage, "#ADZ_NoScore" )
team:AddScore( POINTS_PER_DEFENSE_SHUTOUT )
end
-----------------------------------------------------------------------------
-- Round start/end
-----------------------------------------------------------------------------
-- Opens the gates and schedules the round's end.
function round_start()
-- Opens the gates and all that lovely stuff
OpenDoor("frontgate")
BroadCastMessage( "#FF_AD_GATESOPEN" )
BroadCastSound( "otherteam.flagstolen" )
SpeakAll( "AD_GATESOPEN" )
gates_open = true
openstartdoor()
AddSchedule( "round_end", ROUND_PERIOD, round_end)
AddSchedule( "shutout", ROUND_PERIOD, shutout)
init_defender_countdown()
update_zone_status( false )
if phase < NUMBER_OF_ROUNDS then
-- Sets up the end of a round, and the appropriate timed messages
if ROUND_PERIOD > 300 then AddSchedule( "phase" .. phase .. "5minwarn" , ROUND_PERIOD - 300 , schedulemessagetoall, "#ADZ_Switch5Min" ) end
if ROUND_PERIOD > 120 then AddSchedule( "phase" .. phase .. "2minwarn" , ROUND_PERIOD - 120 , schedulemessagetoall, "#ADZ_Switch2Min" ) end
if ROUND_PERIOD > 60 then AddSchedule( "phase" .. phase .. "1minwarn" , ROUND_PERIOD - 60 , schedulemessagetoall, "#ADZ_Switch1Min" ) end
if ROUND_PERIOD > 30 then AddSchedule( "phase" .. phase .. "30secwarn" , ROUND_PERIOD - 30 , schedulemessagetoall, "#ADZ_Switch30Sec" ) end
if ROUND_PERIOD > 10 then AddSchedule( "phase" .. phase .. "10secwarn" , ROUND_PERIOD - 10 , schedulemessagetoall, "#ADZ_Switch10Sec" ) end
if ROUND_PERIOD > 5 then AddSchedule( "phase" .. phase .. "5secwarn" , ROUND_PERIOD - 5 , schedulemessagetoall, "5" ) end
if ROUND_PERIOD > 4 then AddSchedule( "phase" .. phase .. "4secwarn" , ROUND_PERIOD - 4 , schedulemessagetoall, "4" ) end
if ROUND_PERIOD > 3 then AddSchedule( "phase" .. phase .. "3secwarn" , ROUND_PERIOD - 3, schedulemessagetoall, "3" ) end
if ROUND_PERIOD > 2 then AddSchedule( "phase" .. phase .. "2secwarn" , ROUND_PERIOD - 2, schedulemessagetoall, "2" ) end
if ROUND_PERIOD > 1 then AddSchedule( "phase" .. phase .. "1secwarn" , ROUND_PERIOD - 1, schedulemessagetoall, "1" ) end
AddSchedule( "phase" .. phase .. "switchmessage" , ROUND_PERIOD, schedulemessagetoall, "#ADZ_Switch" )
else
if ROUND_PERIOD > 300 then AddSchedule( "phase" .. phase .. "5minwarn" , ROUND_PERIOD - 300 , schedulemessagetoall, "#ADZ_End5Min" ) end
if ROUND_PERIOD > 120 then AddSchedule( "phase" .. phase .. "2minwarn" , ROUND_PERIOD - 120 , schedulemessagetoall, "#ADZ_End2Min" ) end
if ROUND_PERIOD > 60 then AddSchedule( "phase" .. phase .. "1minwarn" , ROUND_PERIOD - 60 , schedulemessagetoall, "#ADZ_End1Min" ) end
if ROUND_PERIOD > 30 then AddSchedule( "phase" .. phase .. "30secwarn" , ROUND_PERIOD - 30 , schedulemessagetoall, "#ADZ_End30Sec" ) end
if ROUND_PERIOD > 10 then AddSchedule( "phase" .. phase .. "10secwarn" , ROUND_PERIOD - 10 , schedulemessagetoall, "#ADZ_End10Sec" ) end
if ROUND_PERIOD > 5 then AddSchedule( "phase" .. phase .. "5secwarn" , ROUND_PERIOD - 5 , schedulemessagetoall, "5" ) end
if ROUND_PERIOD > 4 then AddSchedule( "phase" .. phase .. "4secwarn" , ROUND_PERIOD - 4 , schedulemessagetoall, "4" ) end
if ROUND_PERIOD > 3 then AddSchedule( "phase" .. phase .. "3secwarn" , ROUND_PERIOD - 3, schedulemessagetoall, "3" ) end
if ROUND_PERIOD > 2 then AddSchedule( "phase" .. phase .. "2secwarn" , ROUND_PERIOD - 2, schedulemessagetoall, "2" ) end
if ROUND_PERIOD > 1 then AddSchedule( "phase" .. phase .. "1secwarn" , ROUND_PERIOD - 1, schedulemessagetoall, "1" ) end
end
-- sounds
if ROUND_PERIOD > 300 then AddSchedule( "phase" .. phase .. "5minwarnsound" , ROUND_PERIOD - 300 , schedulesound, "misc.bloop" ) end
if ROUND_PERIOD > 120 then AddSchedule( "phase" .. phase .. "2minwarnsound" , ROUND_PERIOD - 120 , schedulesound, "misc.bloop" ) end
if ROUND_PERIOD > 60 then AddSchedule( "phase" .. phase .. "1minwarnsound" , ROUND_PERIOD - 60 , schedulesound, "misc.bloop" ) end
if ROUND_PERIOD > 30 then AddSchedule( "phase" .. phase .. "30secwarnsound" , ROUND_PERIOD - 30 , schedulesound, "misc.bloop" ) end
if ROUND_PERIOD > 10 then AddSchedule( "phase" .. phase .. "10secwarnsound" , ROUND_PERIOD - 10 , schedulesound, "misc.bloop" ) end
if ROUND_PERIOD > 5 then AddSchedule( "phase" .. phase .. "5secwarnsound" , ROUND_PERIOD - 5 , schedulecountdown, 5 ) end
if ROUND_PERIOD > 4 then AddSchedule( "phase" .. phase .. "4secwarnsound" , ROUND_PERIOD - 4 , schedulecountdown, 4 ) end
if ROUND_PERIOD > 3 then AddSchedule( "phase" .. phase .. "3secwarnsound" , ROUND_PERIOD - 3 , schedulecountdown, 3 ) end
if ROUND_PERIOD > 2 then AddSchedule( "phase" .. phase .. "2secwarnsound" , ROUND_PERIOD - 2 , schedulecountdown, 2 ) end
if ROUND_PERIOD > 1 then AddSchedule( "phase" .. phase .. "1secwarnsound" , ROUND_PERIOD - 1 , schedulecountdown, 1 ) end
end
-- Checks to see if it's the first or second round, then either swaps teams, or ends the game.
function round_end()
if phase == NUMBER_OF_ROUNDS then
DeleteSchedule( "period_scoring" )
DeleteSchedule( "defenders_period_scoring" )
DeleteSchedule( "init_defenders_period_scoring" )
DeleteSchedule( "set_cvar-mp_timelimit" )
update_zone_text( nil )
GoToIntermission()
return
else
phase = phase + 1
gates_open = false
end
if attackers == Team.kBlue then
attackers = Team.kRed
defenders = Team.kBlue
onswitch_bluetodef()
else
attackers = Team.kBlue
defenders = Team.kRed
onswitch_redtodef()
end
-- switches some prop model's skins so teams spawn in appropriatly-coloured rooms.
OutputEvent( "prop_defender", "Skin", teamdata[defenders].skin )
OutputEvent( "prop_attacker", "Skin", teamdata[attackers].skin )
-- reset the doors
CloseDoor("frontgate")
attacker_door_trigger = adz_door:new({ team = attackers, door = "attacker_door" })
defender_door_trigger = adz_door:new({ team = defenders, door = "defender_door" })
-- switch them team names
SetTeamName( attackers, "Attackers" )
SetTeamName( defenders, "Defenders" )
-- reset schedules
DeleteSchedule( "period_scoring" )
DeleteSchedule( "period_init" )
DeleteSchedule( "defenders_period_scoring" )
DeleteSchedule( "init_defenders_period_scoring" )
AddSchedule( "round_start", INITIAL_ROUND_PERIOD, round_start)
-- gate timer
current_timer = INITIAL_ROUND_PERIOD
AddScheduleRepeatingNotInfinitely( "timer_schedule", 1, timer_schedule, current_timer )
-- reset player touched table
playerTouchedTable = {}
-- remove all leftovers from the cap point collection
zone_collection:RemoveAllItems()
zone_area_collection:RemoveAllItems()
-- respawn, obviously
RespawnAllPlayers()
-- switch pack touchflags
if NUM_DEFENDER_ONLY_PACKS > 0 then
-- get correct allow flags
if defenders == Team.kRed then pack_allowflags = AllowFlags.kRed
elseif defenders == Team.kBlue then pack_allowflags = AllowFlags.kBlue
elseif defenders == Team.kGreen then pack_allowflags = AllowFlags.kGreen
elseif defenders == Team.kYellow then pack_allowflags = AllowFlags.kYellow end
-- this is a workaround due to how the touchflags are set in base.lua
for i=1,NUM_DEFENDER_ONLY_PACKS do
entity = GetEntityByName( "adz_pack_defender"..i )
local info = CastToInfoScript( entity )
info:SetTouchFlags({ pack_allowflags })
end
end
-- MORE scheduled message loveliness.
if INITIAL_ROUND_PERIOD > 30 then AddSchedule( "dooropen30sec" , INITIAL_ROUND_PERIOD - 30 , schedulemessagetoall, "#ADZ_30SecWarning" ) end
if INITIAL_ROUND_PERIOD > 10 then AddSchedule( "dooropen10sec" , INITIAL_ROUND_PERIOD - 10 , schedulemessagetoall, "#ADZ_10SecWarning" ) end
if INITIAL_ROUND_PERIOD > 5 then AddSchedule( "dooropen5sec" , INITIAL_ROUND_PERIOD - 5 , schedulemessagetoall, "5" ) end
if INITIAL_ROUND_PERIOD > 4 then AddSchedule( "dooropen4sec" , INITIAL_ROUND_PERIOD - 4 , schedulemessagetoall, "4" ) end
if INITIAL_ROUND_PERIOD > 3 then AddSchedule( "dooropen3sec" , INITIAL_ROUND_PERIOD - 3, schedulemessagetoall, "3" ) end
if INITIAL_ROUND_PERIOD > 2 then AddSchedule( "dooropen2sec" , INITIAL_ROUND_PERIOD - 2, schedulemessagetoall, "2" ) end
if INITIAL_ROUND_PERIOD > 1 then AddSchedule( "dooropen1sec" , INITIAL_ROUND_PERIOD - 1, schedulemessagetoall, "1" ) end
-- sounds
if INITIAL_ROUND_PERIOD > 10 then AddSchedule( "dooropen30secsound" , INITIAL_ROUND_PERIOD - 30 , schedulesound, "misc.bloop" ) end
if INITIAL_ROUND_PERIOD > 10 then AddSchedule( "dooropen10secsound" , INITIAL_ROUND_PERIOD - 10 , schedulesound, "misc.bloop" ) end
if INITIAL_ROUND_PERIOD > 5 then AddSchedule( "dooropen5seccount" , INITIAL_ROUND_PERIOD - 5 , schedulecountdown, 5 ) end
if INITIAL_ROUND_PERIOD > 4 then AddSchedule( "dooropen4seccount" , INITIAL_ROUND_PERIOD - 4 , schedulecountdown, 4 ) end
if INITIAL_ROUND_PERIOD > 3 then AddSchedule( "dooropen3seccount" , INITIAL_ROUND_PERIOD - 3 , schedulecountdown, 3 ) end
if INITIAL_ROUND_PERIOD > 2 then AddSchedule( "dooropen2seccount" , INITIAL_ROUND_PERIOD - 2 , schedulecountdown, 2 ) end
if INITIAL_ROUND_PERIOD > 1 then AddSchedule( "dooropen1seccount" , INITIAL_ROUND_PERIOD - 1 , schedulecountdown, 1 ) end
-- clear them zones
update_zone_status( false )
zone_turnoff()
set_classlimits()
onswitch()
end
-- I dunno, does something, not sure what!
function RespawnAllPlayers()
ApplyToAll({ AT.kRemovePacks, AT.kRemoveProjectiles, AT.kRespawnPlayers, AT.kRemoveBuildables, AT.kRemoveRagdolls, AT.kStopPrimedGrens, AT.kReloadClips, AT.kAllowRespawn, AT.kReturnDroppedItems })
end
-----------------------------------------------------------------------------
-- output functions
-----------------------------------------------------------------------------
function custom_startup()
return
end
function zone_on_outputs()
OutputEvent( "zone_alarm", "PlaySound" )
OutputEvent( "zone_light", "TurnOn" )
OutputEvent( "zone_spot", "LightOn" )
OutputEvent( "zone_rotate_clock", "Start" )
OutputEvent( "zone_rotate_counterclock", "Start" )
OutputEvent( "zone_tesla", "DoSpark" )
end
function zone_off_outputs()
OutputEvent( "zone_alarm", "StopSound" )
OutputEvent( "zone_light", "TurnOff" )
OutputEvent( "zone_spot", "LightOff" )
OutputEvent( "zone_rotate_clock", "Stop" )
OutputEvent( "zone_rotate_counterclock", "Stop" )
end
function onswitch_bluetodef()
end
function onswitch_redtodef()
return
end
function onswitch()
return
end
function openstartdoor()
return
end
function onreset_outputs()
return
end
function set_classlimits()
-- reset them limits
local team = GetTeam(attackers)
team:SetClassLimit(Player.kCivilian, -1)
team:SetClassLimit(Player.kScout, 0)
team:SetClassLimit(Player.kMedic, 0)
team:SetClassLimit(Player.kSniper, 1)
team:SetClassLimit(Player.kEngineer, 2)
team:SetClassLimit(Player.kDemoman, 2)
team:SetClassLimit(Player.kHwguy, 2)
team:SetClassLimit(Player.kPyro, 2)
team = GetTeam(defenders)
team:SetClassLimit(Player.kCivilian, -1)
team:SetClassLimit(Player.kScout, -1)
team:SetClassLimit(Player.kMedic, -1)
team:SetClassLimit(Player.kSniper, 1)
team:SetClassLimit(Player.kEngineer, 2)
team:SetClassLimit(Player.kDemoman, 2)
team:SetClassLimit(Player.kHwguy, 2)
team:SetClassLimit(Player.kPyro, 2)
end
function set_itemlimits( player )
player:RemoveAmmo( Ammo.kManCannon, 1 )
-- give demo 1 mirv, and only 1 mirv
if player:GetClass() == Player.kDemoman or player:GetClass() == Player.kEngineer then
player:RemoveAmmo( Ammo.kGren2, 4 )
player:AddAmmo( Ammo.kGren2, 1 )
end
if player:GetTeamId() == defenders then
player:RemoveAmmo( Ammo.kDetpack, 1 )
end
end
-----------------------------------------------------------------------------
-- respawn shields
-----------------------------------------------------------------------------
hurt = trigger_ff_script:new({ team = Team.kUnassigned })
function hurt:allowed( allowed_entity )
if IsPlayer( allowed_entity ) then
local player = CastToPlayer( allowed_entity )
if player:GetTeamId() == attackers then
return EVENT_ALLOWED
end
end
return EVENT_DISALLOWED
end
-- red lasers hurt blue and vice-versa
red_laser_hurt = hurt:new({ team = Team.kBlue })
blue_laser_hurt = hurt:new({ team = Team.kRed })
-----------------------------------------------------------------------------
-- backpacks, doors, etc. etc.
-----------------------------------------------------------------------------
adz_pack = genericbackpack:new({
health = 35,
armor = 35,
grenades = 20,
nails = 50,
shells = 300,
rockets = 15,
gren1 = 1,
gren2 = 0,
cells = 120,
respawntime = 10,
model = "models/items/backpack/backpack.mdl",
materializesound = "Item.Materialize",
touchsound = "Backpack.Touch"})
function adz_pack:dropatspawn() return false end
if defenders == Team.kRed then pack_allowflags = AllowFlags.kRed
elseif defenders == Team.kBlue then pack_allowflags = AllowFlags.kBlue
elseif defenders == Team.kGreen then pack_allowflags = AllowFlags.kGreen
elseif defenders == Team.kYellow then pack_allowflags = AllowFlags.kYellow end
adz_pack_defender1 = adz_pack:new({ touchflags = {pack_allowflags} })
adz_pack_defender2 = adz_pack:new({ touchflags = {pack_allowflags} })
adz_pack_defender3 = adz_pack:new({ touchflags = {pack_allowflags} })
adz_pack_defender4 = adz_pack:new({ touchflags = {pack_allowflags} })
adz_pack_defender5 = adz_pack:new({ touchflags = {pack_allowflags} })
adz_pack_defender6 = adz_pack:new({ touchflags = {pack_allowflags} })
adz_pack_defender7 = adz_pack:new({ touchflags = {pack_allowflags} })
adz_pack_defender8 = adz_pack:new({ touchflags = {pack_allowflags} })
adz_pack_defender9 = adz_pack:new({ touchflags = {pack_allowflags} })
adz_defender_pack1 = adz_pack_defender1
adz_defender_pack2 = adz_pack_defender2
adz_defender_pack3 = adz_pack_defender3
adz_defender_pack4 = adz_pack_defender4
adz_defender_pack5 = adz_pack_defender5
adz_defender_pack6 = adz_pack_defender6
adz_defender_pack7 = adz_pack_defender7
adz_defender_pack8 = adz_pack_defender8
adz_defender_pack9 = adz_pack_defender9
------------------------------------------------------------------
--Resup Doors
------------------------------------------------------------------
adz_door = trigger_ff_script:new({ team = Team.kUnassigned, door = nil })
function adz_door:allowed( touch_entity )
if IsPlayer( touch_entity ) then
local player = CastToPlayer( touch_entity )
return player:GetTeamId() == self.team
end
return EVENT_DISALLOWED
end
function adz_door:ontrigger( touch_entity )
if IsPlayer( touch_entity ) then
OutputEvent(self.door, "Open")
end
end
attacker_door_trigger = adz_door:new({ team = attackers, door = "attacker_door" })
defender_door_trigger = adz_door:new({ team = defenders, door = "defender_door" })