diff --git a/maps/includes/base_cp.lua b/maps/includes/base_cp.lua index 3d89d88..08cd4f4 100644 --- a/maps/includes/base_cp.lua +++ b/maps/includes/base_cp.lua @@ -1,1620 +1,1624 @@ --- base_cp.lua - --- if you want base cp with the default setup, --- include base_cp_default.lua in your map's lua file --- and then include base_cp.lua - -function startup() - - SetGameDescription( "Control Points" ) - - -- disable certain teams - for i,v in pairs(disabled_teams) do - SetPlayerLimit( v, -1 ) - end - - -- set up team limits - for i1,v1 in pairs(teams) do - local team = GetTeam(v1) - for i2,v2 in ipairs(team_info[team:GetTeamId()].class_limits) do - team:SetClassLimit( i2, v2 ) - end - end - - RemoveAllCPAmmoAndArmor() - - for i,v in ipairs(command_points) do - RemoveSchedule( "cp" .. v.cp_number .. "_cap_timer" ) - ResetCPCapping( v ) - AddScheduleRepeating( "cp" .. v.cp_number .. "_cap_zone_timer", CAP_ZONE_TIMER_INTERVAL, cap_zone_timer, v ) - end -end - -function precache() - - -- precache the cap sounds - for i in pairs(good_cap_sounds) do - PrecacheSound(good_cap_sounds[i]) - PrecacheSound(bad_cap_sounds[i]) - end - - PrecacheSound("misc.thunder") - - PrecacheSound("Buttons.snd9") - PrecacheSound("Buttons.snd45") - - PrecacheSound("ff_cz2.teleport_exit") - - PrecacheSound("k_lab.teleport_post_winddown") - PrecacheSound("novaprospekt.teleport_post_thunder") - PrecacheSound("NPC_Ichthyosaur.AttackGrowl") - PrecacheSound("Streetwar.d3_c17_11_die") - PrecacheSound("streetwar.Ba_UseConsoleSounds") - - PrecacheSound( "yourteam.flagcap" ) - PrecacheSound( "otherteam.flagcap" ) -end - -function PlayerStartTouchingCapZone( touch_entity, cp ) - - local player = CastToPlayer(touch_entity) - - if PLAYER_TOUCHING_CP_ZONE[player:GetId()] == cp then return end - - local team_number = player:GetTeamId() - - PLAYER_TOUCHING_CP_ZONE[player:GetId()] = cp - - cp.touching_players[team_number]:AddItem( player ) - cp.former_touching_players[team_number]:RemoveItem( player ) - cp.cap_speed[team_number] = cp.cap_speed[team_number] + ( player:MaxSpeed() / 10 ) - - if team_number ~= cp.defending_team then - player:SetCloakable( false ) - end - - local cp_zone_hudicon = cp_zone_icons[team_number] - AddHudIcon( player, cp_zone_hudicon.hudicon, cp_zone_hudicon.hudicon, cp_zone_hudicon.hudx, cp_zone_hudicon.hudy, cp_zone_hudicon.hudwidth, cp_zone_hudicon.hudheight, cp_zone_hudicon.hudalign ) - -end - -function PlayerStopTouchingCapZone( touch_entity, cp ) - - local player = CastToPlayer(touch_entity) - - if PLAYER_TOUCHING_CP_ZONE[player:GetId()] == nil then return end - - local team_number = player:GetTeamId() - - PLAYER_TOUCHING_CP_ZONE[player:GetId()] = nil - - cp.touching_players[team_number]:RemoveItem( player ) - cp.former_touching_players[team_number]:AddItem( player ) - cp.cap_speed[team_number] = cp.cap_speed[team_number] - ( player:MaxSpeed() / 10 ) - - -- clamp - if cp.cap_speed[team_number] < 0 then - cp.cap_speed[team_number] = 0 - end - - player:SetCloakable( true ) - - RemoveHudItem( player, cp_zone_icons[team_number].hudicon ) - -end - - -function DrawCCAlarmIcon( cc_team_number ) - - -- check whether command centers are enabled - if not ENABLE_CC then return end - - -- turn on alarm - if team_info[cc_team_number].cc_touch_count > 0 then - - RemoveHudItemFromAll( cc_team_number .. "-ccalarmicon_neutral" ) - AddHudIconToAll( team_info[cc_team_number].ccalarmicon, cc_team_number .. "-ccalarmicon", team_info[cc_team_number].ccalarmiconx, team_info[cc_team_number].ccalarmicony, team_info[cc_team_number].ccalarmiconwidth, team_info[cc_team_number].ccalarmiconheight, team_info[cc_team_number].ccalarmiconalign ) - - -- turn off alarm - else - - RemoveHudItemFromAll( cc_team_number .. "-ccalarmicon" ) - AddHudIconToAll( team_info[Team.kUnassigned].ccalarmicon, cc_team_number .. "-ccalarmicon_neutral", team_info[cc_team_number].ccalarmiconx, team_info[cc_team_number].ccalarmicony, team_info[cc_team_number].ccalarmiconwidth, team_info[cc_team_number].ccalarmiconheight, team_info[cc_team_number].ccalarmiconalign ) - - end - -end - -function EntityStartTouchingCC( touch_entity, cc_team_number ) - - if ENTITY_TOUCHING_CC[touch_entity:GetId()] ~= nil then return end - - ENTITY_TOUCHING_CC[touch_entity:GetId()] = cc_team_number - - team_info[cc_team_number].cc_touch_count = team_info[cc_team_number].cc_touch_count + 1 - - -- turn on alarm - if team_info[cc_team_number].cc_touch_count > 0 then - - OutputEvent( team_info[cc_team_number].team_name .. "_cc_alarm_sound", "PlaySound" ) - OutputEvent( team_info[cc_team_number].team_name .. "_cc_alarm_light", "TurnOn" ) - OutputEvent( team_info[cc_team_number].team_name .. "_cc_alarm_beam", "Color", team_info[touch_entity:GetTeamId()].skybeam_color ) - - end - - DrawCCAlarmIcon( cc_team_number ) - -end - -function EntityStopTouchingCC( touch_entity, cc_team_number ) - - if ENTITY_TOUCHING_CC[touch_entity:GetId()] == nil then return end - - ENTITY_TOUCHING_CC[touch_entity:GetId()] = nil - - team_info[cc_team_number].cc_touch_count = team_info[cc_team_number].cc_touch_count - 1 - - -- turn off alarm - if team_info[cc_team_number].cc_touch_count <= 0 then - - team_info[cc_team_number].cc_touch_count = 0 - - OutputEvent( team_info[cc_team_number].team_name .. "_cc_alarm_sound", "StopSound" ) - OutputEvent( team_info[cc_team_number].team_name .. "_cc_alarm_light", "TurnOff" ) - OutputEvent( team_info[cc_team_number].team_name .. "_cc_alarm_beam", "Color", team_info[Team.kUnassigned].skybeam_color ) - - end - - DrawCCAlarmIcon( cc_team_number ) - -end - -function player_disconnected( player ) - - if PLAYER_TOUCHING_CP_ZONE[player:GetId()] ~= nil then - PlayerStopTouchingCapZone( player, PLAYER_TOUCHING_CP_ZONE[player:GetId()] ) - end - - if ENTITY_TOUCHING_CC[player:GetId()] ~= nil then - EntityStopTouchingCC( player, ENTITY_TOUCHING_CC[player:GetId()] ) - end - -end - -function player_switchteam( player, currentteam, desiredteam ) - - if PLAYER_TOUCHING_CP_ZONE[player:GetId()] ~= nil then - PlayerStopTouchingCapZone( player, PLAYER_TOUCHING_CP_ZONE[player:GetId()] ) - end - - if ENTITY_TOUCHING_CC[player:GetId()] ~= nil then - EntityStopTouchingCC( player, ENTITY_TOUCHING_CC[player:GetId()] ) - end - - return true - -end - ------------------------------------------------------------------------------ --- timed scoring ------------------------------------------------------------------------------ -function cp_score_timer( cp_number, team_number ) - - local team = GetTeam(team_number) - team:AddScore(command_points[cp_number].point_value[team_number]) - -end - ------------------------------------------------------------------------------ --- notify the players of the total cap. --- Also, create a logic_relay in your map named fullcap_trigger to pass outputs to your entities. ------------------------------------------------------------------------------ -function complete_control_notification ( team_number ) - - local team = GetTeam(team_number) - SmartTeamSound(team, "yourteam.flagcap", "otherteam.flagcap") - SmartTeamSpeak(team, "CZ_GOTALL", "CZ_THEYGOTALL") - SmartTeamMessage(team, "#FF_CZ2_YOURTEAM_COMPLETE", "#FF_CZ2_OTHERTEAM_COMPLETE", Color.kGreen, Color.kRed) - OutputEvent( "fullcap_trigger", "Trigger" ) - -end - ------------------------------------------------------------------------------ --- reset everything after the total cap. ------------------------------------------------------------------------------ -function complete_control_respawn () - ApplyToAll( { AT.kRemovePacks, AT.kRemoveProjectiles, AT.kRespawnPlayers, AT.kRemoveBuildables, AT.kRemoveRagdolls, kReloadClips } ) -end - ------------------------------------------------------------------------------ --- emit a sound from an entity ------------------------------------------------------------------------------ -function EmitSound( entity, sound ) - - entity:EmitSound(sound) - -end - ------------------------------------------------------------------------------ --- remove all the ammo and armor from the entire map ------------------------------------------------------------------------------ -function RemoveAllCPAmmoAndArmor() - - -- Remove all ammo and armor from CPs - local c = Collection() - c:GetByName(cp_ammo_and_armor_names, { CF.kNone }) - for item in c.items do - item = CastToInfoScript(item) - item:Remove() - end - -end - ------------------------------------------------------------------------------ --- does the player have a flag? ------------------------------------------------------------------------------ -function PlayerHasFlag( player ) - - -- check if the player has a flag - for i,v in ipairs(flags) do - if player:HasItem(v) then - -- player has a flag - return true - end - end - - -- player doesn't have a flag - return false - -end - ------------------------------------------------------------------------------ --- return carried flags ------------------------------------------------------------------------------ -function ReturnFlagFromPlayer( player ) - - -- Get all carried flags and ... - local c = Collection() - c:GetByName(flags, { CF.kInfoScript_Carried, }) - - -- ... return the flag that the player is carrying. - for item in c.items do - item = CastToInfoScript(item) - carrier = item:GetCarrier() - if player:GetId() == carrier:GetId() then - item:Return() - end - end - -end - ------------------------------------------------------------------------------ --- resupply a player when a cp is capped ------------------------------------------------------------------------------ -function CapResupply( player, scale, givethegoodshit ) - - -- give the player health and armor - if cap_resupply.health ~= nil and cap_resupply.health ~= 0 then player:AddHealth( cap_resupply.health * scale ) end - if cap_resupply.armor ~= nil and cap_resupply.armor ~= 0 then player:AddArmor( cap_resupply.armor * scale ) end - - -- give the player ammo - if cap_resupply.nails ~= nil and cap_resupply.nails ~= 0 then player:AddAmmo( Ammo.kNails, cap_resupply.nails * scale ) end - if cap_resupply.shells ~= nil and cap_resupply.shells ~= 0 then player:AddAmmo( Ammo.kShells, cap_resupply.shells * scale ) end - if cap_resupply.rockets ~= nil and cap_resupply.rockets ~= 0 then player:AddAmmo( Ammo.kRockets, cap_resupply.rockets * scale ) end - if cap_resupply.cells ~= nil and cap_resupply.cells ~= 0 then player:AddAmmo( Ammo.kCells, cap_resupply.cells * scale ) end - - if givethegoodshit then - -- give the player the good shit - if cap_resupply.detpacks ~= nil and cap_resupply.detpacks ~= 0 then player:AddAmmo( Ammo.kDetpack, cap_resupply.detpacks * scale ) end - if cap_resupply.mancannons ~= nil and cap_resupply.mancannons ~= 0 then player:AddAmmo( Ammo.kManCannon, cap_resupply.mancannons * scale ) end - if cap_resupply.gren1 ~= nil and cap_resupply.gren1 ~= 0 then player:AddAmmo( Ammo.kGren1, cap_resupply.gren1 * scale ) end - if cap_resupply.gren2 ~= nil and cap_resupply.gren2 ~= 0 then player:AddAmmo( Ammo.kGren2, cap_resupply.gren2 * scale ) end - end - -end - -function player_killed ( player_victim, 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() - end - - -- if still no attacking player after all that, try the inflictor - if not player_attacker then - - -- Entity that is attacking - local inflictor = damageinfo:GetInflictor() - - if inflictor then - if IsSentrygun(inflictor) then - inflictor = CastToSentrygun(inflictor) - player_attacker = inflictor:GetOwner() - elseif IsDetpack(inflictor) then - inflictor = CastToDetpack(inflictor) - player_attacker = inflictor:GetOwner() - elseif IsDispenser(inflictor) then - inflictor = CastToDispenser(inflictor) - player_attacker = inflictor:GetOwner() - end - end - - end - - -- if still no attacking player after all that, forget about it - if not player_attacker then return end - - -- if victim killed self or teammate do nothing - if (player_victim:GetId() == player_attacker:GetId()) or (player_victim:GetTeamId() == player_attacker:GetTeamId()) then return end - - local player_victim_touching_cp = PLAYER_TOUCHING_CP_ZONE[player_victim:GetId()] - local player_attacker_touching_cp = PLAYER_TOUCHING_CP_ZONE[player_attacker:GetId()] - - -- the victim is standing in a zone - if player_victim_touching_cp ~= nil then - - -- the victim is defending a cp or trying to capture a neutral cp - if player_victim:GetTeamId() == player_victim_touching_cp.defending_team or player_victim_touching_cp.defending_team == Team.kUnassigned then - - CapResupply( player_attacker, 0.25, false ) - player_attacker:AddFortPoints((player_victim_touching_cp.point_value[player_attacker:GetTeamId()]) * 50, "#FF_FORTPOINTS_CAPTUREPOINT_ASSIST") - - -- the victim is trying to capture the attacker's cp - else - - CapResupply( player_attacker, 0.25, false ) - player_attacker:AddFortPoints((player_victim_touching_cp.point_value[player_attacker:GetTeamId()]) * 50, "#FF_FORTPOINTS_DEFENDPOINT") - - end - - end - - -- the attacker is standing in a zone - if player_attacker_touching_cp ~= nil then - - -- the attacker is defending a cp - if player_attacker:GetTeamId() == player_attacker_touching_cp.defending_team then - - CapResupply( player_attacker, 0.25, false ) - player_attacker:AddFortPoints((player_attacker_touching_cp.point_value[player_attacker:GetTeamId()]) * 50, "#FF_FORTPOINTS_DEFENDPOINT") - - -- the attacker is trying to capture a cp - else - - CapResupply( player_attacker, 0.25, false ) - player_attacker:AddFortPoints((player_attacker_touching_cp.point_value[player_attacker:GetTeamId()]) * 50, "#FF_FORTPOINTS_CAPTUREPOINT_ASSIST") - - end - - end - - -- loop through all former players of each command point - for k,v in ipairs(command_points) do - - -- victim's team - for i in v.former_touching_players[player_victim:GetTeamId()].items do - - i = CastToPlayer( i ) - - -- the victim was in an active zone - if i:GetId() == player_victim:GetId() then - - -- the victim is defending a cp or trying to capture a neutral cp - if player_victim:GetTeamId() == v.defending_team or v.defending_team == Team.kUnassigned then - - CapResupply( player_attacker, 0.25, false ) - player_attacker:AddFortPoints((v.point_value[player_attacker:GetTeamId()]) * 25, "#FF_FORTPOINTS_CAPTUREPOINT_ASSIST") - - -- the victim is trying to capture the attacker's cp - else - - CapResupply( player_attacker, 0.25, false ) - player_attacker:AddFortPoints((v.point_value[player_attacker:GetTeamId()]) * 25, "#FF_FORTPOINTS_DEFENDPOINT_ASSIST") - - end - - end - - end - - -- attacker's team - for i in v.former_touching_players[player_attacker:GetTeamId()].items do - - i = CastToPlayer( i ) - - -- the attacker was in an active zone - if i:GetId() == player_attacker:GetId() then - - -- the attacker is defending a cp - if player_attacker:GetTeamId() == v.defending_team then - - CapResupply( player_attacker, 0.25, false ) - player_attacker:AddFortPoints((v.point_value[player_attacker:GetTeamId()]) * 25, "#FF_FORTPOINTS_DEFENDPOINT_ASSIST") - - -- the attacker is trying to capture a cp - else - - CapResupply( player_attacker, 0.25, false ) - player_attacker:AddFortPoints((v.point_value[player_attacker:GetTeamId()]) * 25, "#FF_FORTPOINTS_CAPTUREPOINT_ASSIST") - - end - - end - - end - - end - -end - ------------------------------------------------------------------------------ --- change the cp's defending team, its related visuals, and its scoring ------------------------------------------------------------------------------ -function ChangeCPDefendingTeam( cp_number, new_defending_team ) - - local cp = command_points[cp_number] - - -- Change the skybeam color - OutputEvent( "cp" .. cp_number .. "_skybeam", "Color", team_info[new_defending_team].skybeam_color ) - - -- Change the light color - for i in pairs(team_info) do - -- turn off all other lights as well - local input_name = "TurnOff" - local input2_name = "LightOff" - if i == new_defending_team then - input_name = "TurnOn" - input2_name = "LightOn" - end - OutputEvent( "cp" .. cp_number .. "_light_" .. team_info[i].team_name, input_name ) - OutputEvent( "cp" .. cp_number .. "_spotlight_" .. team_info[i].team_name, input2_name ) - end - - -- Change the rotating flag around - OutputEvent( "cp" .. cp_number .. "_flag_rotator", "Reverse") - OutputEvent( "cp" .. cp_number .. "_flag", "Skin", team_info[new_defending_team].skin ) - OutputEvent( "cp" .. cp_number .. "_flag", team_info[new_defending_team].flag_visibility) - - -- remove old flaginfo icons and add new ones - RemoveHudItemFromAll( cp_number .. "-background-" .. cp.defending_team ) - RemoveHudItemFromAll( cp_number .. "-foreground-" .. cp.defending_team ) - - AddHudIconToAll( icons[ new_defending_team ].teamicon, cp_number .. "-background-" .. new_defending_team, cp.hudposx, cp.hudposy, cp.hudwidth, cp.hudheight, cp.hudalign) - AddHudIconToAll( cp.hudstatusicon, cp_number .. "-foreground-" .. new_defending_team, cp.hudposx, cp.hudposy, cp.hudwidth, cp.hudheight, cp.hudalign) - - local schedule_name = "cp" .. cp_number .. "_score_timer" - - -- stop an existing timer - if cp.defending_team ~= Team.kUnassigned then - RemoveSchedule( schedule_name ) - end - - -- only worry with score timer for TEAM1 and TEAM2 - if new_defending_team ~= Team.kUnassigned then - - -- start the score timer - AddScheduleRepeating( schedule_name, cp.score_timer_interval[new_defending_team], cp_score_timer, cp_number, new_defending_team ) - - end - - cp.defending_team = new_defending_team - -end - ------------------------------------------------------------------------------ --- restore all items in a CP ------------------------------------------------------------------------------ -function RestoreCPItems( cp_number, old_defending_team, new_defending_team ) - - local c = Collection() - c:GetByName( { "cp_cp" .. cp_number .. "_ammo", "cz2_cp" .. cp_number .. "_ammo", "cp_cp" .. cp_number .. "_armor", "cz2_cp" .. cp_number .. "_armor" }, { CF.kNone } ) - for item in c.items do - item = CastToInfoScript(item) - - -- restore this CP's ammo and armor - item:Restore() - - -- Also set the touchflags so only the defending team can use the packs - item:SetTouchFlags(team_info[new_defending_team].touchflags) - end - -end - ------------------------------------------------------------------------------ --- reset team cp capping stuff ------------------------------------------------------------------------------ -function ResetTeamCPCapping( cp, team_number, do_total_reset, set_next_cap_zone_timer ) - - cp.cap_status[team_number] = 0 - cp.next_cap_zone_timer[team_number] = set_next_cap_zone_timer - - RemoveHudItemFromAll( cp.cp_number .. "-capstatusicon-" .. team_number ) - RemoveHudItemFromAll( cp.cp_number .. "-caplockicon-" .. team_number ) - OutputEvent( "cp" .. cp.cp_number .. "_" .. team_info[team_number].team_name .. "_capsprites", "HideSprite" ) - OutputEvent( "cp" .. cp.cp_number .. "_" .. team_info[team_number].team_name .. "_capsound", "StopSound" ) - - if cp.former_touching_players[team_number]:Count() > 0 then - cp.former_touching_players[team_number]:RemoveAllItems() - end - - if do_total_reset then - if cp.touching_players[team_number]:Count() > 0 then - cp.touching_players[team_number]:RemoveAllItems() - end - - cp.cap_speed[team_number] = 0 - end - -end - ------------------------------------------------------------------------------ --- reset all cp capping stuff ------------------------------------------------------------------------------ -function ResetCPCapping( cp ) - - for i,v in pairs(teams) do - ResetTeamCPCapping( cp, v, true, 0 ) - end - -end - ------------------------------------------------------------------------------ --- the cp has definitely been captured ------------------------------------------------------------------------------ -function CaptureCP( cp_number, new_defending_team ) - - local cp = command_points[cp_number] - local old_defending_team = cp.defending_team - - RestoreCPItems(cp_number, old_defending_team, new_defending_team) - - -- Give points to team and player - local team = GetTeam(new_defending_team) - team:AddScore(cp.point_value[new_defending_team]) - - -- Find out if any team has complete control - local team_with_complete_control = Team.kUnassigned - local control_count = { [TEAM1] = 0, [TEAM2] = 0 } - control_count[new_defending_team] = 1 - for i,v in ipairs(command_points) do - if v.defending_team ~= Team.kUnassigned and v.cp_number ~= cp_number then - control_count[v.defending_team] = control_count[v.defending_team] + 1 - end - if control_count[v.defending_team] == CP_COUNT then - team_with_complete_control = v.defending_team - break - end - end - - if team_with_complete_control ~= Team.kUnassigned then - - if ENABLE_COMPLETE_CONTROL_POINTS then - -- Bonus points for complete control - team:AddScore(POINTS_FOR_COMPLETE_CONTROL) - end - - if ENABLE_COMPLETE_CONTROL_RESET then - - AddSchedule("complete_control_notification", 0.1, complete_control_notification, team_with_complete_control) - - -- Reset all command points - for i,v in ipairs(command_points) do - ChangeCPDefendingTeam(v.cp_number, Team.kUnassigned) - ResetCPCapping( v ) - end - - -- reset colors of respawn beams - --OutputEvent( team_info[TEAM1].team_name .. "_respawn_beam", "Color", team_info[Team.kUnassigned].respawnbeam_color[0] .. " " .. team_info[Team.kUnassigned].respawnbeam_color[1] .. " " .. team_info[Team.kUnassigned].respawnbeam_color[2] ) - --OutputEvent( team_info[TEAM2].team_name .. "_respawn_beam", "Color", team_info[Team.kUnassigned].respawnbeam_color[0] .. " " .. team_info[Team.kUnassigned].respawnbeam_color[1] .. " " .. team_info[Team.kUnassigned].respawnbeam_color[2] ) - - if ENABLE_FLAGS then - -- Return all flags - local c = Collection() - c:GetByName(flags, { CF.kNone }) - for item in c.items do - item = CastToInfoScript(item) - item:Return() - end - end - - RemoveAllCPAmmoAndArmor() - - if ENABLE_COMPLETE_CONTROL_RESPAWN then - AddSchedule("complete_control_respawn", 1.0, complete_control_respawn) - end - - -- get out now if resetting - return - - end - - end - - ChangeCPDefendingTeam(cp_number, new_defending_team) - - -- change the colors this team's respawn beams - --local beam_team = team_info[new_defending_team] - --beam_team.respawnbeam_color[beam_team.color_index] = beam_team.respawnbeam_color[Team.kUnassigned] + (control_count[new_defending_team] * 35) - --OutputEvent( beam_team.team_name .. "_respawn_beam", "Color", beam_team.respawnbeam_color[0] .. " " .. beam_team.respawnbeam_color[1] .. " " .. beam_team.respawnbeam_color[2] ) - - SmartTeamMessage( team, "#FF_CZ2_YOURTEAM_CP" .. cp_number, "#FF_CZ2_OTHERTEAM_CP" .. cp_number, Color.kGreen, Color.kRed ) - - -- sounds will get more and more crazy - --SmartTeamSound( team, good_cap_sounds[control_count[new_defending_team]], bad_cap_sounds[control_count[new_defending_team]] ) - - -- caes: changed it to announce the cp number captured/lost - SmartTeamSpeak( team, good_cap_sounds[cp_number], bad_cap_sounds[cp_number] ) -end - - ------------------------------------------------------------------------------ --- a cp's defending team successfully defended or capped ------------------------------------------------------------------------------ -function SuccessfulCPDefense( cp, team_number, is_a_cap ) - - -- reward the touching players - for i in cp.touching_players[team_number].items do - i = CastToPlayer( i ) - if is_a_cap then - CapResupply( i, 1.00, is_a_cap ) - i:AddFortPoints((cp.point_value[team_number]) * 100, "#FF_FORTPOINTS_CAPTUREPOINT") - i:SetCloakable( true ) - else - CapResupply( i, 0.50, is_a_cap ) - i:AddFortPoints((cp.point_value[team_number]) * 50, "#FF_FORTPOINTS_DEFENDPOINT") - end - end - - -- reward the former touching players - for i in cp.former_touching_players[team_number].items do - i = CastToPlayer( i ) - if is_a_cap then - CapResupply( i, 0.50, is_a_cap ) - i:AddFortPoints((cp.point_value[team_number]) * 50, "#FF_FORTPOINTS_CAPTUREPOINT_ASSIST") - else - CapResupply( i, 0.25, is_a_cap ) - i:AddFortPoints((cp.point_value[team_number]) * 25, "#FF_FORTPOINTS_DEFENDPOINT_ASSIST") - end - end - - -- no need to keep them around for future rewards - cp.former_touching_players[team_number]:RemoveAllItems() - -end - - ------------------------------------------------------------------------------ --- timed cp capping ------------------------------------------------------------------------------ -function cap_zone_timer( cp ) - - local new_defending_team = Team.kUnassigned - local other_team = Team.kUnassigned - local last_cap_status = {} - local total_cap_speed = 0 - local total_cap_status = 0 - - for i,v in pairs(teams) do - total_cap_speed = total_cap_speed + cp.cap_speed[v] - total_cap_status = total_cap_status + cp.cap_status[v] - end - - for i,v in pairs(teams) do - - -- don't bother doing some stuff if nothing has changed - last_cap_status[v] = cp.cap_status[v] - - -- after one team caps a cp, the other team can't touch that cp for X seconds - if cp.next_cap_zone_timer[v] > 0 then - - cp.next_cap_zone_timer[v] = cp.next_cap_zone_timer[v] - CAP_ZONE_TIMER_INTERVAL - - local lock_percent = math.min( 1.0, cp.next_cap_zone_timer[v] / cp.delay_before_retouch[v] ) - local minlockhudwidth = cp.hudwidth * 0.333 - local minlockhudheight = cp.hudheight * 0.333 - - AddHudIconToAll( icons[v].lockicon, cp.cp_number .. "-caplockicon-" .. v, cp.hudposx, cp.hudposy + cp_zone_icons[v].hudposy_offset, minlockhudwidth + ( (cp.hudwidth - minlockhudwidth) * lock_percent ), minlockhudheight + ( (cp.hudheight - minlockhudheight) * lock_percent ), cp.hudalign) - - -- clamp - if cp.next_cap_zone_timer[v] <= 0 then - cp.next_cap_zone_timer[v] = 0 - RemoveHudItemFromAll( cp.cp_number .. "-caplockicon-" .. v ) - end - - -- this team is standing in the zone - elseif cp.cap_speed[v] > 0 then - - -- don't bother with cap_status calculations for the defending team - if v == cp.defending_team then - - cp.cap_status[v] = cp.cap_requirement[v] - - -- calculate cap status - else - - -- every vote counts - local affected_cap_speed = cp.cap_speed[v] - ( total_cap_speed - cp.cap_speed[v] ) - - cp.cap_status[v] = cp.cap_status[v] + affected_cap_speed - - -- clamp - if cp.cap_status[v] < 0 then - - cp.cap_status[v] = 0 - - -- potential capping team - elseif cp.cap_status[v] >= cp.cap_requirement[v] then - - new_defending_team = v - - -- clamp - cp.cap_status[v] = cp.cap_requirement[v] - - end - end - - -- this team is not standing in the zone - else - if v == cp.defending_team then - -- don't bother with cap_status calculations for the defending team - cp.cap_status[v] = 0 - else - -- decrease cap status - cp.cap_status[v] = cp.cap_status[v] - ( CAP_ZONE_NOTOUCH_SPEED + total_cap_speed ) - - -- clamp - if cp.cap_status[v] < 0 then - cp.cap_status[v] = 0 - end - end - end - - -- don't bother doing some stuff if nothing has changed - if cp.cap_status[v] ~= last_cap_status[v] then - - -- draw the cap status icon - if cp.cap_status[v] > 0 then - - local cap_percent = cp.cap_status[v] / cp.cap_requirement[v] - local minhudwidth = cp.hudwidth * 0.333 - local minhudheight = cp.hudheight * 0.333 - AddHudIconToAll( cp_zone_icons[v].hudicon, cp.cp_number .. "-capstatusicon-" .. v, cp.hudposx, cp.hudposy + cp_zone_icons[v].hudposy_offset, minhudwidth + ( (cp.hudwidth - minhudwidth) * cap_percent ), minhudheight + ( (cp.hudheight - minhudheight) * cap_percent ), cp.hudalign) - OutputEvent( "cp" .. cp.cp_number .. "_" .. team_info[v].team_name .. "_capsprites", "ShowSprite" ) - OutputEvent( "cp" .. cp.cp_number .. "_" .. team_info[v].team_name .. "_capsound", "PlaySound" ) - - -- remove the cap status icon, remove former touching players, and reward defenders - else - - -- reward the defenders - if v ~= cp.defending_team and cp.defending_team ~= Team.kUnassigned then - SuccessfulCPDefense( cp, cp.defending_team, false ) - end - - -- reset the other team's cp capping stuff - ResetTeamCPCapping( cp, v, false, 0 ) - - end - - end - - if new_defending_team ~= v then - other_team = v - end - - end - - -- someone capped this cp - if new_defending_team ~= Team.kUnassigned then - - -- cap the cp - SuccessfulCPDefense( cp, new_defending_team, true ) - CaptureCP( cp.cp_number, new_defending_team ) - - -- reset the other team's cp capping stuff - ResetTeamCPCapping( cp, other_team, false, cp.delay_before_retouch[other_team] ) - - end - -end - - ------------------------------------------------------------------------------ --- triggers ------------------------------------------------------------------------------ - -cp_base_trigger = trigger_ff_script:new({ team = Team.kUnassigned, failtouch_message = "" }) - -function cp_base_trigger:allowed( allowed_entity ) - - if IsPlayer( allowed_entity ) then - local player = CastToPlayer( allowed_entity ) - if player:GetTeamId() == self.team then - return EVENT_ALLOWED - end - end - return EVENT_DISALLOWED -end - -function cp_base_trigger:onfailtouch( touch_entity ) - - if IsPlayer( touch_entity ) then - local player = CastToPlayer( touch_entity ) - BroadCastMessageToPlayer( player, failtouch_message ) - end -end - -cp_team1_door_trigger = cp_base_trigger:new({ team = TEAM1 , failtouch_message = "#FF_NOTALLOWEDDOOR" }) -cp_team2_door_trigger = cp_base_trigger:new({ team = TEAM2 , failtouch_message = "#FF_NOTALLOWEDDOOR" }) - - ------------------------------------------------------------------------------ --- packs ------------------------------------------------------------------------------ -cp_base_pack = genericbackpack:new({ - health = 100, - armor = 300, - nails = 200, - shells = 200, - rockets = 200, - cells = 200, - detpacks = 0, - mancannons = 0, - gren1 = 0, - gren2 = 0, - respawntime = 1, - touchflags = team_info[Team.kUnassigned].touchflags, - model = "models/items/backpack/backpack.mdl", - materializesound = "Item.Materialize", - touchsound = "Backpack.Touch", - cp_number = 0, - botgoaltype = Bot.kBackPack_Ammo, -}) - -function cp_base_pack:dropatspawn() return false end - -cp_team1_respawn_pack = cp_base_pack:new( { touchflags = team_info[TEAM1].touchflags } ) -cp_team2_respawn_pack = cp_base_pack:new( { touchflags = team_info[TEAM2].touchflags } ) - -cp_cp1_ammo = ammobackpack:new({cp_number = 1}) -cp_cp2_ammo = ammobackpack:new({cp_number = 2}) -cp_cp3_ammo = ammobackpack:new({cp_number = 3}) -cp_cp4_ammo = ammobackpack:new({cp_number = 4}) -cp_cp5_ammo = ammobackpack:new({cp_number = 5}) - -cp_cp1_armor = armorkit:new({cp_number = 1}) -cp_cp2_armor = armorkit:new({cp_number = 2}) -cp_cp3_armor = armorkit:new({cp_number = 3}) -cp_cp4_armor = armorkit:new({cp_number = 4}) -cp_cp5_armor = armorkit:new({cp_number = 5}) - - ------------------------------------------------------------------------------ --- grenade packs ------------------------------------------------------------------------------ -cp_base_grenade_pack = cp_base_pack:new({ - detpacks = 1, - mancannons = 1, - gren1 = 4, - gren2 = 4, - respawntime = 15, - touchflags = team_info[Team.kUnassigned].touchflags, - botgoaltype = Bot.kBackPack_Grenades, -}) - -cp_team1_grenade_pack = cp_base_grenade_pack:new( { touchflags = team_info[TEAM1].touchflags } ) -cp_team2_grenade_pack = cp_base_grenade_pack:new( { touchflags = team_info[TEAM2].touchflags } ) - - ------------------------------------------------------------------------------ --- cp zones ------------------------------------------------------------------------------ - -cp_base_cp_zone = trigger_ff_script:new({ - item = "", - team = 0, - botgoaltype = Bot.kFlagCap, - cp_number = 0, -}) - -function cp_base_cp_zone:ontrigger( trigger_entity ) - - -- check whether flags are used, and in turn wheter these triggers are used - if ENABLE_FLAGS or not ENABLE_CP_TELEPORTERS then return end - - if IsPlayer( trigger_entity ) then - local player = CastToPlayer( trigger_entity ) - - -- Allow players on defending team to teleport back to base - if player:GetTeamId() == command_points[self.cp_number].defending_team then - - if player:IsInUse() then - -- respawn the player - ApplyToPlayer( player, { AT.kRespawnPlayers, kReloadClips } ) - - OutputEvent( "cp" .. self.cp_number .. "_respawn_enter_sound", "PlaySound" ) - AddSchedule("cp" .. self.cp_number .. "_respawn_" .. player:GetId(), 0.1, EmitSound, player, "ff_cz2.teleport_exit") - else - BroadCastMessageToPlayer(player, "#FF_CZ2_USE_RESPAWN") - end - - end - - end - -end - -function cp_base_cp_zone:ontouch( trigger_entity ) - - -- check whether flags are used, and in turn wheter these zones are used - if ENABLE_FLAGS then return end - - if IsPlayer( trigger_entity ) then - local player = CastToPlayer( trigger_entity ) - local cp = command_points[self.cp_number] - PlayerStartTouchingCapZone( player, cp ) - end - -end - -function cp_base_cp_zone:onendtouch( trigger_entity ) - - -- check whether flags are used, and in turn wheter these zones are used - if ENABLE_FLAGS then return end - - if IsPlayer( trigger_entity ) then - local player = CastToPlayer( trigger_entity ) - local cp = command_points[self.cp_number] - PlayerStopTouchingCapZone( player, cp ) - end -end - -cp_cp1_cp_zone = cp_base_cp_zone:new({ cp_number = 1 }) -cp_cp2_cp_zone = cp_base_cp_zone:new({ cp_number = 2 }) -cp_cp3_cp_zone = cp_base_cp_zone:new({ cp_number = 3 }) -cp_cp4_cp_zone = cp_base_cp_zone:new({ cp_number = 4 }) -cp_cp5_cp_zone = cp_base_cp_zone:new({ cp_number = 5 }) - - ------------------------------------------------------------------------------ --- cp triggers ------------------------------------------------------------------------------ - -cp_base_cp_trigger = trigger_ff_script:new({ - item = "", - team = 0, - botgoaltype = Bot.kFlagCap, - cp_number = 0, -}) - -function cp_base_cp_trigger:ontrigger( trigger_entity ) - - -- check whether flags are used, and in turn wheter these triggers are used - if not ENABLE_FLAGS or not ENABLE_CP_TELEPORTERS then return end - - if IsPlayer( trigger_entity ) then - local player = CastToPlayer( trigger_entity ) - - -- Allow players on defending team to teleport back to base - if player:GetTeamId() == command_points[self.cp_number].defending_team then - - if player:IsInUse() then - -- check if the player has a flag - for i,v in ipairs(flags) do - -- return the flag - if player:HasItem(v) then ReturnFlagFromPlayer(player) end - end - - -- respawn the player - ApplyToPlayer( player, { AT.kRespawnPlayers, kReloadClips } ) - - OutputEvent( "cp" .. self.cp_number .. "_respawn_enter_sound", "PlaySound" ) - AddSchedule("cp" .. self.cp_number .. "_respawn_" .. player:GetId(), 0.1, EmitSound, player, "ff_cz2.teleport_exit") - else - BroadCastMessageToPlayer(player, "#FF_CZ2_USE_RESPAWN") - end - - end - - end - -end - -function cp_base_cp_trigger:ontouch( trigger_entity ) - - -- check whether flags are used, and in turn wheter these triggers are used - if not ENABLE_FLAGS then return end - - if IsPlayer( trigger_entity ) then - local player = CastToPlayer( trigger_entity ) - local cp = command_points[self.cp_number] - - -- No capping if player's team already defends this CP - if player:GetTeamId() == cp.defending_team then return end - - -- get out if player doesn't have flag - if not PlayerHasFlag(player) then return end - - ReturnFlagFromPlayer(player) - - CaptureCP(self.cp_number, player:GetTeamId()) - player:AddFortPoints((cp.point_value[player:GetTeamId()]) * 100, "#FF_FORTPOINTS_CAPTUREPOINT") - end - -end - -cp_cp1_cp_trigger = cp_base_cp_trigger:new({ cp_number = 1 }) -cp_cp2_cp_trigger = cp_base_cp_trigger:new({ cp_number = 2 }) -cp_cp3_cp_trigger = cp_base_cp_trigger:new({ cp_number = 3 }) -cp_cp4_cp_trigger = cp_base_cp_trigger:new({ cp_number = 4 }) -cp_cp5_cp_trigger = cp_base_cp_trigger:new({ cp_number = 5 }) - - ------------------------------------------------------------------------------ --- flags ------------------------------------------------------------------------------ - -cp_base_flag = info_ff_script:new({ - name = "Base Flag", - team = 0, - model = "models/flag/flag.mdl", - tosssound = "Flag.Toss", - modelskin = 0, - dropnotouchtime = 2, - capnotouchtime = 2, - botgoaltype = Bot.kFlag, - hudicon = "", - hudx = 5, - hudy = 180, - hudalign = 1, - touchflags = team_info[Team.kUnassigned].touchflags -}) - -function cp_base_flag:precache() - PrecacheSound(self.tosssound) - info_ff_script.precache(self) -end - -function cp_base_flag:spawn() - self.notouch = { } - info_ff_script.spawn(self) -end - -function cp_base_flag:addnotouch(player_id, duration) - self.notouch[player_id] = duration - AddSchedule(self.name .. "-" .. player_id, duration, self.removenotouch, self, player_id) -end - -function cp_base_flag.removenotouch(self, player_id) - self.notouch[player_id] = nil -end - -function cp_base_flag:touch( touch_entity ) - local player = CastToPlayer( touch_entity ) - - if player:GetTeamId() ~= self.team then return end - - -- pickup if they can - if self.notouch[player:GetId()] then return end - - -- make sure they don't have any flags already - for i,v in ipairs(flags) do - if player:HasItem(v) then return end - end - - -- if the player is a spy, then force him to lose his disguise - player:SetDisguisable( false ) - player:SetCloakable( false ) - - -- note: this seems a bit backwards (Pickup verb fits Player better) - local flag = CastToInfoScript(entity) - flag:Pickup(player) - player:AddEffect( EF.kSpeedlua1, -1, 0, FLAG_CARRIER_SPEED ) - AddHudIcon( player, self.hudicon, flag:GetName(), self.hudx, self.hudy, self.hudwidth, self.hudheight, self.hudalign ) -end - -function cp_base_flag:onownerdie( owner_entity ) - -- drop the flag - local flag = CastToInfoScript(entity) - flag:Drop(FLAG_RETURN_TIME, 0.0) -end - -function cp_base_flag:onownerfeign( owner_entity ) - -- drop the flag - local flag = CastToInfoScript(entity) - flag:Drop(FLAG_RETURN_TIME, 0.0) -end -function cp_base_flag:onownercloak( owner_entity ) - -- drop the flag - local flag = CastToInfoScript(entity) - flag:Drop(FLAG_RETURN_TIME, 0.0) -end -function cp_base_flag:dropitemcmd( owner_entity ) - -- throw the flag - local flag = CastToInfoScript(entity) - flag:Drop(FLAG_RETURN_TIME, FLAG_THROW_SPEED) -end - -function cp_base_flag:ondrop( owner_entity ) - local flag = CastToInfoScript(entity) - flag:EmitSound(self.tosssound) -end - -function cp_base_flag:onloseitem( owner_entity ) - -- let the player that lost the flag put on a disguise - local player = CastToPlayer( owner_entity ) - player:SetDisguisable(true) - player:SetCloakable(true) - - self:addnotouch(player:GetId(), self.capnotouchtime) - - --player:RemoveEffect( EF.kSpeedlua1 ) - -- remove flag icon from hud - local flag = CastToInfoScript(entity) - RemoveHudItem( player, flag:GetName() ) -end - -function cp_base_flag:onreturn( ) -end - -cp_team1_flag = cp_base_flag:new({ - team = TEAM1, - modelskin = 0, - name = team_info[TEAM1].team_name .. " flag", - hudicon = "hud_flag_" .. team_info[TEAM1].team_name .. ".vtf", - hudx = 5, - hudy = 180, - hudwidth = 48, - hudheight = 48, - touchflags = team_info[TEAM1].touchflags -}) - -cp_team2_flag = cp_base_flag:new({ - team = TEAM2, - modelskin = 1, - name = team_info[TEAM2].team_name .. " flag", - hudicon = "hud_flag_" .. team_info[TEAM2].team_name .. ".vtf", - hudx = 5, - hudy = 180, - hudwidth = 48, - hudheight = 48, - touchflags = team_info[TEAM2].touchflags -}) - - ------------------------------------------------------------------------------ --- flag dispensers ------------------------------------------------------------------------------ -cp_base_flag_dispenser = trigger_ff_script:new({ - name = "Base Flag Dispenser", - team = Team.kUnassigned, - dropnotouchtime = 2, - botgoaltype = Bot.kFlag, - hudicon = "", - hudx = 5, - hudy = 180, - hudwidth = 48, - hudheight = 48, - hudalign = 1, - flags = {"flag"} -}) - -function cp_base_flag_dispenser:allowed ( allowed_entity ) - - -- check whether flags are used, and in turn wheter these triggers are used - if not ENABLE_FLAGS then return EVENT_DISALLOWED end - - if IsPlayer( allowed_entity ) then - local player = CastToPlayer( allowed_entity ) - if player:GetTeamId() == self.team then - - -- Player can't have a flag - local playerhasflag = false - - for i,v in ipairs(self.flags) do - if player:HasItem(v) then - playerhasflag = true - break - end - end - - -- get out if player doesn't have flag - if not playerhasflag then - return EVENT_ALLOWED - end - end - end - return EVENT_DISALLOWED -end - -function cp_base_flag_dispenser:ontouch( trigger_entity ) - - -- check whether flags are used, and in turn wheter these triggers are used - if not ENABLE_FLAGS then return end - - if IsPlayer( trigger_entity ) then - - local player = CastToPlayer( trigger_entity ) - - local c = Collection() - c:GetByName( self.flags, { CF.kNone } ) - -- give the player an inactive flag - for item in c.items do - item = CastToInfoScript(item) - if item:IsInactive() then - -- if the player is a spy, then force him to lose his disguise - player:SetDisguisable( false ) - player:SetCloakable( false ) - - -- note: this seems a bit backwards (Pickup verb fits Player better) - item:Pickup(player) - player:AddEffect( EF.kSpeedlua1, -1, 0, FLAG_CARRIER_SPEED ) - AddHudIcon( player, self.hudicon, item:GetName(), self.hudx, self.hudy, self.hudwidth, self.hudheight, self.hudalign ) - - player:EmitSound("Buttons.snd9") - - -- all done - break - end - end - end -end - -cp_team1_flag_dispenser = cp_base_flag_dispenser:new({ - name = team_info[TEAM1].team_name .. " flag dispenser", - team = TEAM1, - hudicon = "hud_flag_" .. team_info[TEAM1].team_name .. ".vtf", - flags = { team_info[TEAM1].team_name .. "_flag" } -}) - -cp_team2_flag_dispenser = cp_base_flag_dispenser:new({ - name = team_info[TEAM2].team_name .. " flag dispenser", - team = TEAM2, - hudicon = "hud_flag_" .. team_info[TEAM2].team_name .. ".vtf", - flags = { team_info[TEAM2].team_name .. "_flag" } -}) - - ------------------------------------------------------------------------------ --- command centers ------------------------------------------------------------------------------ - -cp_base_command_center = trigger_ff_script:new({ team = Team.kUnassigned, enemy_team = Team.kUnassigned }) -function cp_base_command_center:onexplode( explosion_entity ) - - -- check whether command centers are enabled - if not ENABLE_CC then return EVENT_ALLOWED end - - if IsDetpack( explosion_entity ) then - local detpack = CastToDetpack(explosion_entity) - - -- don't let assholes destroy their own team's command center - if detpack:GetTeamId() == self.team then return EVENT_ALLOWED end - - local points = CC_DESTROY_POINTS - for i,v in ipairs(command_points) do - if v.defending_team == self.team then - -- taking CP 1 away from team2 is worth more than taking CP 5 away from them - points = points + v.point_value[self.team] - - -- Remove all ammo and armor from CPs - local c = Collection() - c:GetByName({"cp_cp" .. v.cp_number .. "_ammo", "cz2_cp" .. v.cp_number .. "_ammo", "cp_cp" .. v.cp_number .. "_armor", "cz2_cp" .. v.cp_number .. "_armor"}, { CF.kNone }) - for item in c.items do - item = CastToInfoScript(item) - item:Remove() - end - - -- reset the CP - ChangeCPDefendingTeam(v.cp_number, Team.kUnassigned) - end - - -- reset the other team's cp capping stuff - ResetTeamCPCapping( v, self.team, false, v.delay_before_retouch[self.team] * 2.0 ) - end - - local team = detpack:GetTeam() - team:AddScore(points) - - local player = detpack:GetOwner() - player:AddFortPoints(points * 100, "#FF_FORTPOINTS_DESTROY_CC" ) - - SmartSound(player, "misc.thunder", "misc.thunder", "misc.thunder") - SmartMessage(player, "#FF_CZ2_YOU_CC", "#FF_CZ2_YOURTEAM_CC", "#FF_CZ2_OTHERTEAM_CC", Color.kGreen, Color.kGreen, Color.kRed) - SpeakAll( team_info[self.team].detcc_sentence ) - --- EntityStopTouchingCC( detpack, self.team ) - - end - - return EVENT_ALLOWED -end - -function cp_base_command_center:ontouch( trigger_entity ) - - -- check whether command centers are enabled - if not ENABLE_CC then return end - --- if IsDetpack( trigger_entity ) then --- local detpack = CastToDetpack( trigger_entity ) --- if detpack:GetTeamId() ~= self.team then --- EntityStartTouchingCC( detpack, self.team ) --- end --- end - - if IsPlayer( trigger_entity ) then - local player = CastToPlayer( trigger_entity ) - if player:GetTeamId() ~= self.team then - EntityStartTouchingCC( player, self.team ) - end - end - -end - -function cp_base_command_center:onendtouch( trigger_entity ) - - -- check whether command centers are enabled - if not ENABLE_CC then return end - --- if IsDetpack( trigger_entity ) then --- local detpack = CastToDetpack( trigger_entity ) --- if detpack:GetTeamId() ~= self.team then --- EntityStopTouchingCC( detpack, self.team ) --- end --- end - - if IsPlayer( trigger_entity ) then - local player = CastToPlayer( trigger_entity ) - if player:GetTeamId() ~= self.team then - EntityStopTouchingCC( player, self.team ) - end - end -end - -cp_team1_command_center = cp_base_command_center:new({ team = TEAM1, enemy_team = TEAM2 }) -cp_team2_command_center = cp_base_command_center:new({ team = TEAM2, enemy_team = TEAM1 }) - - -------------------------------------------- --- cc computers -------------------------------------------- - -cp_base_cc_computer = trigger_ff_script:new({ prefix = "unassigned", enemy_team = Team.kUnassigned }) - -function cp_base_cc_computer:ontrigger( trigger_entity ) - - -- check whether command centers are enabled - if not ENABLE_CC then return end - - if IsPlayer( trigger_entity ) then - local player = CastToPlayer( trigger_entity ) - - -- Allow spies to open the enemy doors - if player:GetTeamId() == self.enemy_team and player:GetClass() == Player.kSpy then - - if player:IsInUse() then - for i,v in ipairs(doors) do - -- open each enemy door - OutputEvent( self.prefix .. v, "Open" ) - end - else - -- tell the player they can open the enemy doors - BroadCastMessageToPlayer(player, "#FF_CZ2_USE_DOORS") - end - - end - end -end - -cp_team1_cc_computer = cp_base_cc_computer:new({ prefix = team_info[TEAM1].team_name, enemy_team = TEAM2 }) -cp_team2_cc_computer = cp_base_cc_computer:new({ prefix = team_info[TEAM2].team_name, enemy_team = TEAM1 }) - - -------------------------------------------- --- cp flaginfo -------------------------------------------- - -function flaginfo( player_entity ) - - local player = CastToPlayer( player_entity ) - - for i,v in ipairs(command_points) do - - AddHudIcon( player, icons[ v.defending_team ].teamicon , v.cp_number .. "-background-" .. v.defending_team , command_points[v.cp_number].hudposx, command_points[v.cp_number].hudposy, command_points[v.cp_number].hudwidth, command_points[v.cp_number].hudheight, command_points[v.cp_number].hudalign) - AddHudIcon( player, command_points[v.cp_number].hudstatusicon, v.cp_number .. "-foreground-" .. v.defending_team , command_points[v.cp_number].hudposx, command_points[v.cp_number].hudposy, command_points[v.cp_number].hudwidth, command_points[v.cp_number].hudheight, command_points[v.cp_number].hudalign) - - end - - DrawCCAlarmIcon( TEAM1 ) - DrawCCAlarmIcon( TEAM2 ) - -end - - -------------------------------------------- --- cp teleporters -------------------------------------------- - -trigger_teleport = trigger_ff_script:new({}) -cp_base_teleporter = trigger_teleport:new({ cp_number = 0, next_teleport_tick = 0 }) - -function cp_base_teleporter:allowed( allowed_entity ) - - -- check whether cc-to-cp teleporters are enabled - if not ENABLE_CC or not ENABLE_CC_TELEPORTERS then return EVENT_DISALLOWED end - - local stime = GetServerTime() - - if self.next_teleport_tick > stime then return end - - if IsPlayer( allowed_entity ) then - - local player = CastToPlayer( allowed_entity ) - -- Allow players on defending team to teleport to cp - if player:GetTeamId() == command_points[self.cp_number].defending_team then - - if player:IsInUse() then - -- teleport the player - local team_name = team_info[player:GetTeamId()].team_name - - if ENTITY_TOUCHING_CC[player:GetId()] ~= nil then - team_name = team_info[ENTITY_TOUCHING_CC[player:GetId()]].team_name - end - - OutputEvent( team_name .. "_cp" .. self.cp_number .. "_teleport_enter_sound", "PlaySound" ) - --OutputEvent( team_name .. "_cp" .. self.cp_number .. "_teleport_exit_sound", "PlaySound", "", 0.1 ) - OutputEvent( team_name .. "_cp" .. self.cp_number .. "_teleport_tesla", "DoSpark", "", 0.1 ) - - --self.next_teleport_tick = stime + 1.0 - - ApplyToPlayer( player, { AT.kStopPrimedGrens, kReloadClips } ) - - return EVENT_ALLOWED - else - -- tell the player they can teleport - BroadCastMessageToPlayer(player, "#FF_CZ2_USE_TELEPORT") - end - - end - end - - return EVENT_DISALLOWED - -end - --- team1 teleporters -cp_team1_teleporter_cp1 = cp_base_teleporter:new({ cp_number = 1 }) -cp_team1_teleporter_cp2 = cp_base_teleporter:new({ cp_number = 2 }) -cp_team1_teleporter_cp3 = cp_base_teleporter:new({ cp_number = 3 }) -cp_team1_teleporter_cp4 = cp_base_teleporter:new({ cp_number = 4 }) -cp_team1_teleporter_cp5 = cp_base_teleporter:new({ cp_number = 5 }) - --- team2 teleporters -cp_team2_teleporter_cp1 = cp_base_teleporter:new({ cp_number = 1 }) -cp_team2_teleporter_cp2 = cp_base_teleporter:new({ cp_number = 2 }) -cp_team2_teleporter_cp3 = cp_base_teleporter:new({ cp_number = 3 }) -cp_team2_teleporter_cp4 = cp_base_teleporter:new({ cp_number = 4 }) -cp_team2_teleporter_cp5 = cp_base_teleporter:new({ cp_number = 5 }) - - ------------------------------------------------------------------------------ --- locations ------------------------------------------------------------------------------ - -location_cp1 = location_info:new({ text = "#FF_LOCATION_COMMAND_POINT_ONE", team = NO_TEAM }) -location_cp2 = location_info:new({ text = "#FF_LOCATION_COMMAND_POINT_TWO", team = NO_TEAM }) -location_cp3 = location_info:new({ text = "#FF_LOCATION_COMMAND_POINT_THREE", team = NO_TEAM }) -location_cp4 = location_info:new({ text = "#FF_LOCATION_COMMAND_POINT_FOUR", team = NO_TEAM }) -location_cp5 = location_info:new({ text = "#FF_LOCATION_COMMAND_POINT_FIVE", team = NO_TEAM }) - -location_cp1_path = location_info:new({ text = "#FF_LOCATION_CP1_PATH", team = TEAM1 }) -location_cp2_path = location_info:new({ text = "#FF_LOCATION_CP2_PATH", team = TEAM1 }) -location_cp3_path = location_info:new({ text = "#FF_LOCATION_CP3_PATH", team = NO_TEAM }) -location_cp4_path = location_info:new({ text = "#FF_LOCATION_CP4_PATH", team = TEAM2 }) -location_cp5_path = location_info:new({ text = "#FF_LOCATION_CP5_PATH", team = TEAM2 }) - -location_catacombs = location_info:new({ text = "#FF_LOCATION_CATACOMBS", team = NO_TEAM }) - -location_blue_base = location_info:new({ text = "#FF_LOCATION_BASE", team = TEAM1 }) -location_blue_cc = location_info:new({ text = "#FF_LOCATION_COMMAND_CENTER", team = TEAM1 }) -location_blue_outside_base = location_info:new({ text = "#FF_LOCATION_OUTSIDE_BASE", team = TEAM1 }) -location_blue_canal = location_info:new({ text = "#FF_LOCATION_CANAL", team = TEAM1 }) -location_blue_catacombs = location_info:new({ text = "#FF_LOCATION_CATACOMBS", team = TEAM1 }) - -location_red_base = location_info:new({ text = "#FF_LOCATION_BASE", team = TEAM2 }) -location_red_cc = location_info:new({ text = "#FF_LOCATION_COMMAND_CENTER", team = TEAM2 }) -location_red_outside_base = location_info:new({ text = "#FF_LOCATION_OUTSIDE_BASE", team = TEAM2 }) -location_red_canal = location_info:new({ text = "#FF_LOCATION_CANAL", team = TEAM2 }) -location_red_catacombs = location_info:new({ text = "#FF_LOCATION_CATACOMBS", team = TEAM2 }) - - ------------------------------------------------------------------------------ --- backwards compatiblity - use "cp_*" names in your map instead! ------------------------------------------------------------------------------ -base_team_trigger = cp_base_trigger -blue_door_trigger = cp_team1_door_trigger -red_door_trigger = cp_team2_door_trigger - -cz2_base_pack = cp_base_pack -cz2_blue_respawn_pack = cp_team1_respawn_pack -cz2_red_respawn_pack = cp_team2_respawn_pack - -cz2_cp1_ammo = cp_cp1_ammo -cz2_cp2_ammo = cp_cp2_ammo -cz2_cp3_ammo = cp_cp3_ammo -cz2_cp4_ammo = cp_cp4_ammo -cz2_cp5_ammo = cp_cp5_ammo - -cz2_cp1_armor = cp_cp1_armor -cz2_cp2_armor = cp_cp2_armor -cz2_cp3_armor = cp_cp3_armor -cz2_cp4_armor = cp_cp4_armor -cz2_cp5_armor = cp_cp5_armor - -cz2_base_grenade_pack = cp_base_grenade_pack -cz2_blue_grenade_pack = cp_team1_grenade_pack -cz2_red_grenade_pack = cp_team2_grenade_pack - -base_cp_zone = cp_base_cp_zone -cp1_zone = cp_cp1_cp_zone -cp2_zone = cp_cp2_cp_zone -cp3_zone = cp_cp3_cp_zone -cp4_zone = cp_cp4_cp_zone -cp5_zone = cp_cp5_cp_zone - -base_cp_trigger = cp_base_cp_trigger -cp1_trigger = cp_cp1_cp_trigger -cp2_trigger = cp_cp2_cp_trigger -cp3_trigger = cp_cp3_cp_trigger -cp4_trigger = cp_cp4_cp_trigger -cp5_trigger = cp_cp5_cp_trigger - -base_cp_flag = cp_base_flag -blue_flag = cp_team1_flag -red_flag = cp_team2_flag - -cp_base_flag_dispenser = base_cp_flag_dispenser -blue_flag_dispenser = cp_team1_flag_dispenser -red_flag_dispenser = cp_team2_flag_dispenser - -base_command_center = cp_base_command_center -blue_command_center = cp_team1_command_center -red_command_center = cp_team2_command_center - -base_cp_cc_computer = cp_base_cc_computer -blue_cc_computer = cp_team1_cc_computer -red_cc_computer = cp_team2_cc_computer - -base_cp_teleporter = cp_base_teleporter -blue_teleporter_cp1 = cp_team1_teleporter_cp1 -blue_teleporter_cp2 = cp_team1_teleporter_cp2 -blue_teleporter_cp3 = cp_team1_teleporter_cp3 -blue_teleporter_cp4 = cp_team1_teleporter_cp4 -blue_teleporter_cp5 = cp_team1_teleporter_cp5 -red_teleporter_cp1 = cp_team2_teleporter_cp1 -red_teleporter_cp2 = cp_team2_teleporter_cp2 -red_teleporter_cp3 = cp_team2_teleporter_cp3 -red_teleporter_cp4 = cp_team2_teleporter_cp4 -red_teleporter_cp5 = cp_team2_teleporter_cp5 - - +-- base_cp.lua + +-- if you want base cp with the default setup, +-- include base_cp_default.lua in your map's lua file +-- and then include base_cp.lua + +function startup() + + SetGameDescription( "Control Points" ) + + -- disable certain teams + for i,v in pairs(disabled_teams) do + SetPlayerLimit( v, -1 ) + end + + -- set up team limits + for i1,v1 in pairs(teams) do + local team = GetTeam(v1) + for i2,v2 in ipairs(team_info[team:GetTeamId()].class_limits) do + team:SetClassLimit( i2, v2 ) + end + end + + RemoveAllCPAmmoAndArmor() + + for i,v in ipairs(command_points) do + RemoveSchedule( "cp" .. v.cp_number .. "_cap_timer" ) + ResetCPCapping( v ) + AddScheduleRepeating( "cp" .. v.cp_number .. "_cap_zone_timer", CAP_ZONE_TIMER_INTERVAL, cap_zone_timer, v ) + end +end + +function precache() + + -- precache the cap sounds + for i in pairs(good_cap_sounds) do + PrecacheSound(good_cap_sounds[i]) + PrecacheSound(bad_cap_sounds[i]) + end + + PrecacheSound("misc.thunder") + + PrecacheSound("Buttons.snd9") + PrecacheSound("Buttons.snd45") + + PrecacheSound("ff_cz2.teleport_exit") + + PrecacheSound("k_lab.teleport_post_winddown") + PrecacheSound("novaprospekt.teleport_post_thunder") + PrecacheSound("NPC_Ichthyosaur.AttackGrowl") + PrecacheSound("Streetwar.d3_c17_11_die") + PrecacheSound("streetwar.Ba_UseConsoleSounds") + + PrecacheSound( "yourteam.flagcap" ) + PrecacheSound( "otherteam.flagcap" ) +end + +function PlayerStartTouchingCapZone( touch_entity, cp ) + + local player = CastToPlayer(touch_entity) + + if PLAYER_TOUCHING_CP_ZONE[player:GetId()] == cp then return end + + local team_number = player:GetTeamId() + + PLAYER_TOUCHING_CP_ZONE[player:GetId()] = cp + + cp.touching_players[team_number]:AddItem( player ) + cp.former_touching_players[team_number]:RemoveItem( player ) + cp.cap_speed[team_number] = cp.cap_speed[team_number] + ( player:MaxSpeed() / 10 ) + + if team_number ~= cp.defending_team then + player:SetCloakable( false ) + end + + local cp_zone_hudicon = cp_zone_icons[team_number] + AddHudIcon( player, cp_zone_hudicon.hudicon, cp_zone_hudicon.hudicon, cp_zone_hudicon.hudx, cp_zone_hudicon.hudy, cp_zone_hudicon.hudwidth, cp_zone_hudicon.hudheight, cp_zone_hudicon.hudalign ) + +end + +function PlayerStopTouchingCapZone( touch_entity, cp ) + + local player = CastToPlayer(touch_entity) + + if PLAYER_TOUCHING_CP_ZONE[player:GetId()] == nil then return end + + local team_number = player:GetTeamId() + + PLAYER_TOUCHING_CP_ZONE[player:GetId()] = nil + + cp.touching_players[team_number]:RemoveItem( player ) + cp.former_touching_players[team_number]:AddItem( player ) + cp.cap_speed[team_number] = cp.cap_speed[team_number] - ( player:MaxSpeed() / 10 ) + + -- clamp + if cp.cap_speed[team_number] < 0 then + cp.cap_speed[team_number] = 0 + end + + player:SetCloakable( true ) + + RemoveHudItem( player, cp_zone_icons[team_number].hudicon ) + +end + + +function DrawCCAlarmIcon( cc_team_number ) + + -- check whether command centers are enabled + if not ENABLE_CC then return end + + -- turn on alarm + if team_info[cc_team_number].cc_touch_count > 0 then + + RemoveHudItemFromAll( cc_team_number .. "-ccalarmicon_neutral" ) + AddHudIconToAll( team_info[cc_team_number].ccalarmicon, cc_team_number .. "-ccalarmicon", team_info[cc_team_number].ccalarmiconx, team_info[cc_team_number].ccalarmicony, team_info[cc_team_number].ccalarmiconwidth, team_info[cc_team_number].ccalarmiconheight, team_info[cc_team_number].ccalarmiconalign ) + + -- turn off alarm + else + + RemoveHudItemFromAll( cc_team_number .. "-ccalarmicon" ) + AddHudIconToAll( team_info[Team.kUnassigned].ccalarmicon, cc_team_number .. "-ccalarmicon_neutral", team_info[cc_team_number].ccalarmiconx, team_info[cc_team_number].ccalarmicony, team_info[cc_team_number].ccalarmiconwidth, team_info[cc_team_number].ccalarmiconheight, team_info[cc_team_number].ccalarmiconalign ) + + end + +end + +function EntityStartTouchingCC( touch_entity, cc_team_number ) + + if ENTITY_TOUCHING_CC[touch_entity:GetId()] ~= nil then return end + + ENTITY_TOUCHING_CC[touch_entity:GetId()] = cc_team_number + + team_info[cc_team_number].cc_touch_count = team_info[cc_team_number].cc_touch_count + 1 + + -- turn on alarm + if team_info[cc_team_number].cc_touch_count > 0 then + + OutputEvent( team_info[cc_team_number].team_name .. "_cc_alarm_sound", "PlaySound" ) + OutputEvent( team_info[cc_team_number].team_name .. "_cc_alarm_light", "TurnOn" ) + OutputEvent( team_info[cc_team_number].team_name .. "_cc_alarm_beam", "Color", team_info[touch_entity:GetTeamId()].skybeam_color ) + + end + + DrawCCAlarmIcon( cc_team_number ) + +end + +function EntityStopTouchingCC( touch_entity, cc_team_number ) + + if ENTITY_TOUCHING_CC[touch_entity:GetId()] == nil then return end + + ENTITY_TOUCHING_CC[touch_entity:GetId()] = nil + + team_info[cc_team_number].cc_touch_count = team_info[cc_team_number].cc_touch_count - 1 + + -- turn off alarm + if team_info[cc_team_number].cc_touch_count <= 0 then + + team_info[cc_team_number].cc_touch_count = 0 + + OutputEvent( team_info[cc_team_number].team_name .. "_cc_alarm_sound", "StopSound" ) + OutputEvent( team_info[cc_team_number].team_name .. "_cc_alarm_light", "TurnOff" ) + OutputEvent( team_info[cc_team_number].team_name .. "_cc_alarm_beam", "Color", team_info[Team.kUnassigned].skybeam_color ) + + end + + DrawCCAlarmIcon( cc_team_number ) + +end + +function player_disconnected( player ) + + if PLAYER_TOUCHING_CP_ZONE[player:GetId()] ~= nil then + PlayerStopTouchingCapZone( player, PLAYER_TOUCHING_CP_ZONE[player:GetId()] ) + end + + if ENTITY_TOUCHING_CC[player:GetId()] ~= nil then + EntityStopTouchingCC( player, ENTITY_TOUCHING_CC[player:GetId()] ) + end + +end + +function player_switchteam( player, currentteam, desiredteam ) + + if PLAYER_TOUCHING_CP_ZONE[player:GetId()] ~= nil then + PlayerStopTouchingCapZone( player, PLAYER_TOUCHING_CP_ZONE[player:GetId()] ) + end + + if ENTITY_TOUCHING_CC[player:GetId()] ~= nil then + EntityStopTouchingCC( player, ENTITY_TOUCHING_CC[player:GetId()] ) + end + + return true + +end + +----------------------------------------------------------------------------- +-- timed scoring +----------------------------------------------------------------------------- +function cp_score_timer( cp_number, team_number ) + + local team = GetTeam(team_number) + team:AddScore(command_points[cp_number].point_value[team_number]) + +end + +----------------------------------------------------------------------------- +-- notify the players of the total cap. +-- Also, create a logic_relay in your map named fullcap_trigger to pass outputs to your entities. +----------------------------------------------------------------------------- +function complete_control_notification ( team_number ) + + local team = GetTeam(team_number) + SmartTeamSound(team, "yourteam.flagcap", "otherteam.flagcap") + SmartTeamSpeak(team, "CZ_GOTALL", "CZ_THEYGOTALL") + SmartTeamMessage(team, "#FF_CZ2_YOURTEAM_COMPLETE", "#FF_CZ2_OTHERTEAM_COMPLETE", Color.kGreen, Color.kRed) + OutputEvent( "fullcap_trigger", "Trigger" ) + +end + +----------------------------------------------------------------------------- +-- reset everything after the total cap. +----------------------------------------------------------------------------- +function complete_control_respawn () + ApplyToAll( { AT.kRemovePacks, AT.kRemoveProjectiles, AT.kRespawnPlayers, AT.kRemoveBuildables, AT.kRemoveRagdolls, kReloadClips } ) +end + +----------------------------------------------------------------------------- +-- emit a sound from an entity +----------------------------------------------------------------------------- +function EmitSound( entity, sound ) + + entity:EmitSound(sound) + +end + +----------------------------------------------------------------------------- +-- remove all the ammo and armor from the entire map +----------------------------------------------------------------------------- +function RemoveAllCPAmmoAndArmor() + + -- Remove all ammo and armor from CPs + local c = Collection() + c:GetByName(cp_ammo_and_armor_names, { CF.kNone }) + for item in c.items do + item = CastToInfoScript(item) + item:Remove() + end + +end + +----------------------------------------------------------------------------- +-- does the player have a flag? +----------------------------------------------------------------------------- +function PlayerHasFlag( player ) + + -- check if the player has a flag + for i,v in ipairs(flags) do + if player:HasItem(v) then + -- player has a flag + return true + end + end + + -- player doesn't have a flag + return false + +end + +----------------------------------------------------------------------------- +-- return carried flags +----------------------------------------------------------------------------- +function ReturnFlagFromPlayer( player ) + + -- Get all carried flags and ... + local c = Collection() + c:GetByName(flags, { CF.kInfoScript_Carried, }) + + -- ... return the flag that the player is carrying. + for item in c.items do + item = CastToInfoScript(item) + carrier = item:GetCarrier() + if player:GetId() == carrier:GetId() then + item:Return() + end + end + +end + +----------------------------------------------------------------------------- +-- resupply a player when a cp is capped +----------------------------------------------------------------------------- +function CapResupply( player, scale, givethegoodshit ) + + -- give the player health and armor + if cap_resupply.health ~= nil and cap_resupply.health ~= 0 then player:AddHealth( cap_resupply.health * scale ) end + if cap_resupply.armor ~= nil and cap_resupply.armor ~= 0 then player:AddArmor( cap_resupply.armor * scale ) end + + -- give the player ammo + if cap_resupply.nails ~= nil and cap_resupply.nails ~= 0 then player:AddAmmo( Ammo.kNails, cap_resupply.nails * scale ) end + if cap_resupply.shells ~= nil and cap_resupply.shells ~= 0 then player:AddAmmo( Ammo.kShells, cap_resupply.shells * scale ) end + if cap_resupply.rockets ~= nil and cap_resupply.rockets ~= 0 then player:AddAmmo( Ammo.kRockets, cap_resupply.rockets * scale ) end + if cap_resupply.cells ~= nil and cap_resupply.cells ~= 0 then player:AddAmmo( Ammo.kCells, cap_resupply.cells * scale ) end + + if givethegoodshit then + -- give the player the good shit + if cap_resupply.detpacks ~= nil and cap_resupply.detpacks ~= 0 then player:AddAmmo( Ammo.kDetpack, cap_resupply.detpacks * scale ) end + if cap_resupply.mancannons ~= nil and cap_resupply.mancannons ~= 0 then player:AddAmmo( Ammo.kManCannon, cap_resupply.mancannons * scale ) end + if cap_resupply.gren1 ~= nil and cap_resupply.gren1 ~= 0 then player:AddAmmo( Ammo.kGren1, cap_resupply.gren1 * scale ) end + if cap_resupply.gren2 ~= nil and cap_resupply.gren2 ~= 0 then player:AddAmmo( Ammo.kGren2, cap_resupply.gren2 * scale ) end + end + +end + +function player_killed ( player_victim, 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() + end + + -- if still no attacking player after all that, try the inflictor + if not player_attacker then + + -- Entity that is attacking + local inflictor = damageinfo:GetInflictor() + + if inflictor then + if IsSentrygun(inflictor) then + inflictor = CastToSentrygun(inflictor) + player_attacker = inflictor:GetOwner() + elseif IsDetpack(inflictor) then + inflictor = CastToDetpack(inflictor) + player_attacker = inflictor:GetOwner() + elseif IsDispenser(inflictor) then + inflictor = CastToDispenser(inflictor) + player_attacker = inflictor:GetOwner() + end + end + + end + + -- if still no attacking player after all that, forget about it + if not player_attacker then return end + + -- if victim killed self or teammate do nothing + if (player_victim:GetId() == player_attacker:GetId()) or (player_victim:GetTeamId() == player_attacker:GetTeamId()) then return end + + local player_victim_touching_cp = PLAYER_TOUCHING_CP_ZONE[player_victim:GetId()] + local player_attacker_touching_cp = PLAYER_TOUCHING_CP_ZONE[player_attacker:GetId()] + + -- the victim is standing in a zone + if player_victim_touching_cp ~= nil then + + -- the victim is defending a cp or trying to capture a neutral cp + if player_victim:GetTeamId() == player_victim_touching_cp.defending_team or player_victim_touching_cp.defending_team == Team.kUnassigned then + + CapResupply( player_attacker, 0.25, false ) + player_attacker:AddFortPoints((player_victim_touching_cp.point_value[player_attacker:GetTeamId()]) * 50, "#FF_FORTPOINTS_CAPTUREPOINT_ASSIST") + + -- the victim is trying to capture the attacker's cp + else + + CapResupply( player_attacker, 0.25, false ) + player_attacker:AddFortPoints((player_victim_touching_cp.point_value[player_attacker:GetTeamId()]) * 50, "#FF_FORTPOINTS_DEFENDPOINT") + + end + + end + + -- the attacker is standing in a zone + if player_attacker_touching_cp ~= nil then + + -- the attacker is defending a cp + if player_attacker:GetTeamId() == player_attacker_touching_cp.defending_team then + + CapResupply( player_attacker, 0.25, false ) + player_attacker:AddFortPoints((player_attacker_touching_cp.point_value[player_attacker:GetTeamId()]) * 50, "#FF_FORTPOINTS_DEFENDPOINT") + + -- the attacker is trying to capture a cp + else + + CapResupply( player_attacker, 0.25, false ) + player_attacker:AddFortPoints((player_attacker_touching_cp.point_value[player_attacker:GetTeamId()]) * 50, "#FF_FORTPOINTS_CAPTUREPOINT_ASSIST") + + end + + end + + -- loop through all former players of each command point + for k,v in ipairs(command_points) do + + -- victim's team + for i in v.former_touching_players[player_victim:GetTeamId()].items do + + i = CastToPlayer( i ) + + -- the victim was in an active zone + if i:GetId() == player_victim:GetId() then + + -- the victim is defending a cp or trying to capture a neutral cp + if player_victim:GetTeamId() == v.defending_team or v.defending_team == Team.kUnassigned then + + CapResupply( player_attacker, 0.25, false ) + player_attacker:AddFortPoints((v.point_value[player_attacker:GetTeamId()]) * 25, "#FF_FORTPOINTS_CAPTUREPOINT_ASSIST") + + -- the victim is trying to capture the attacker's cp + else + + CapResupply( player_attacker, 0.25, false ) + player_attacker:AddFortPoints((v.point_value[player_attacker:GetTeamId()]) * 25, "#FF_FORTPOINTS_DEFENDPOINT_ASSIST") + + end + + end + + end + + -- attacker's team + for i in v.former_touching_players[player_attacker:GetTeamId()].items do + + i = CastToPlayer( i ) + + -- the attacker was in an active zone + if i:GetId() == player_attacker:GetId() then + + -- the attacker is defending a cp + if player_attacker:GetTeamId() == v.defending_team then + + CapResupply( player_attacker, 0.25, false ) + player_attacker:AddFortPoints((v.point_value[player_attacker:GetTeamId()]) * 25, "#FF_FORTPOINTS_DEFENDPOINT_ASSIST") + + -- the attacker is trying to capture a cp + else + + CapResupply( player_attacker, 0.25, false ) + player_attacker:AddFortPoints((v.point_value[player_attacker:GetTeamId()]) * 25, "#FF_FORTPOINTS_CAPTUREPOINT_ASSIST") + + end + + end + + end + + end + +end + +----------------------------------------------------------------------------- +-- change the cp's defending team, its related visuals, and its scoring +----------------------------------------------------------------------------- +function ChangeCPDefendingTeam( cp_number, new_defending_team ) + + local cp = command_points[cp_number] + + -- Change the skybeam color + OutputEvent( "cp" .. cp_number .. "_skybeam", "Color", team_info[new_defending_team].skybeam_color ) + + -- Change the light color + for i in pairs(team_info) do + -- turn off all other lights as well + local input_name = "TurnOff" + local input2_name = "LightOff" + if i == new_defending_team then + input_name = "TurnOn" + input2_name = "LightOn" + end + OutputEvent( "cp" .. cp_number .. "_light_" .. team_info[i].team_name, input_name ) + OutputEvent( "cp" .. cp_number .. "_spotlight_" .. team_info[i].team_name, input2_name ) + end + + -- Change the rotating flag around + OutputEvent( "cp" .. cp_number .. "_flag_rotator", "Reverse") + OutputEvent( "cp" .. cp_number .. "_flag", "Skin", team_info[new_defending_team].skin ) + OutputEvent( "cp" .. cp_number .. "_flag", team_info[new_defending_team].flag_visibility) + + -- remove old flaginfo icons and add new ones + RemoveHudItemFromAll( cp_number .. "-background-" .. cp.defending_team ) + RemoveHudItemFromAll( cp_number .. "-foreground-" .. cp.defending_team ) + + AddHudIconToAll( icons[ new_defending_team ].teamicon, cp_number .. "-background-" .. new_defending_team, cp.hudposx, cp.hudposy, cp.hudwidth, cp.hudheight, cp.hudalign) + AddHudIconToAll( cp.hudstatusicon, cp_number .. "-foreground-" .. new_defending_team, cp.hudposx, cp.hudposy, cp.hudwidth, cp.hudheight, cp.hudalign) + + local schedule_name = "cp" .. cp_number .. "_score_timer" + + -- stop an existing timer + if cp.defending_team ~= Team.kUnassigned then + RemoveSchedule( schedule_name ) + end + + -- only worry with score timer for TEAM1 and TEAM2 + if new_defending_team ~= Team.kUnassigned then + + -- start the score timer + AddScheduleRepeating( schedule_name, cp.score_timer_interval[new_defending_team], cp_score_timer, cp_number, new_defending_team ) + + end + + cp.defending_team = new_defending_team + +end + +----------------------------------------------------------------------------- +-- restore all items in a CP +----------------------------------------------------------------------------- +function RestoreCPItems( cp_number, old_defending_team, new_defending_team ) + + local c = Collection() + c:GetByName( { "cp_cp" .. cp_number .. "_ammo", "cz2_cp" .. cp_number .. "_ammo", "cp_cp" .. cp_number .. "_armor", "cz2_cp" .. cp_number .. "_armor" }, { CF.kNone } ) + for item in c.items do + item = CastToInfoScript(item) + + -- restore this CP's ammo and armor + item:Restore() + + -- Also set the touchflags so only the defending team can use the packs + item:SetTouchFlags(team_info[new_defending_team].touchflags) + end + +end + +----------------------------------------------------------------------------- +-- reset team cp capping stuff +----------------------------------------------------------------------------- +function ResetTeamCPCapping( cp, team_number, do_total_reset, set_next_cap_zone_timer ) + + cp.cap_status[team_number] = 0 + cp.next_cap_zone_timer[team_number] = set_next_cap_zone_timer + + RemoveHudItemFromAll( cp.cp_number .. "-capstatusicon-" .. team_number ) + RemoveHudItemFromAll( cp.cp_number .. "-caplockicon-" .. team_number ) + OutputEvent( "cp" .. cp.cp_number .. "_" .. team_info[team_number].team_name .. "_capsprites", "HideSprite" ) + OutputEvent( "cp" .. cp.cp_number .. "_" .. team_info[team_number].team_name .. "_capsound", "StopSound" ) + + if cp.former_touching_players[team_number]:Count() > 0 then + cp.former_touching_players[team_number]:RemoveAllItems() + end + + if do_total_reset then + if cp.touching_players[team_number]:Count() > 0 then + cp.touching_players[team_number]:RemoveAllItems() + end + + cp.cap_speed[team_number] = 0 + end + +end + +----------------------------------------------------------------------------- +-- reset all cp capping stuff +----------------------------------------------------------------------------- +function ResetCPCapping( cp ) + + for i,v in pairs(teams) do + ResetTeamCPCapping( cp, v, true, 0 ) + end + +end + +----------------------------------------------------------------------------- +-- the cp has definitely been captured +----------------------------------------------------------------------------- +function CaptureCP( cp_number, new_defending_team ) + + local cp = command_points[cp_number] + local old_defending_team = cp.defending_team + + RestoreCPItems(cp_number, old_defending_team, new_defending_team) + + -- Give points to team and player + local team = GetTeam(new_defending_team) + team:AddScore(cp.point_value[new_defending_team]) + + -- Find out if any team has complete control + local team_with_complete_control = Team.kUnassigned + local control_count = { [TEAM1] = 0, [TEAM2] = 0 } + control_count[new_defending_team] = 1 + for i,v in ipairs(command_points) do + if v.defending_team ~= Team.kUnassigned and v.cp_number ~= cp_number then + control_count[v.defending_team] = control_count[v.defending_team] + 1 + end + if control_count[v.defending_team] == CP_COUNT then + team_with_complete_control = v.defending_team + break + end + end + + if team_with_complete_control ~= Team.kUnassigned then + + if ENABLE_COMPLETE_CONTROL_POINTS then + -- Bonus points for complete control + team:AddScore(POINTS_FOR_COMPLETE_CONTROL) + end + + if ENABLE_COMPLETE_CONTROL_RESET then + + AddSchedule("complete_control_notification", 0.1, complete_control_notification, team_with_complete_control) + + -- Reset all command points + for i,v in ipairs(command_points) do + ChangeCPDefendingTeam(v.cp_number, Team.kUnassigned) + ResetCPCapping( v ) + end + + -- reset colors of respawn beams + --OutputEvent( team_info[TEAM1].team_name .. "_respawn_beam", "Color", team_info[Team.kUnassigned].respawnbeam_color[0] .. " " .. team_info[Team.kUnassigned].respawnbeam_color[1] .. " " .. team_info[Team.kUnassigned].respawnbeam_color[2] ) + --OutputEvent( team_info[TEAM2].team_name .. "_respawn_beam", "Color", team_info[Team.kUnassigned].respawnbeam_color[0] .. " " .. team_info[Team.kUnassigned].respawnbeam_color[1] .. " " .. team_info[Team.kUnassigned].respawnbeam_color[2] ) + + if ENABLE_FLAGS then + -- Return all flags + local c = Collection() + c:GetByName(flags, { CF.kNone }) + for item in c.items do + item = CastToInfoScript(item) + item:Return() + end + end + + RemoveAllCPAmmoAndArmor() + + if ENABLE_COMPLETE_CONTROL_RESPAWN then + AddSchedule("complete_control_respawn", 1.0, complete_control_respawn) + end + + -- get out now if resetting + return + + end + + end + + ChangeCPDefendingTeam(cp_number, new_defending_team) + + -- change the colors this team's respawn beams + --local beam_team = team_info[new_defending_team] + --beam_team.respawnbeam_color[beam_team.color_index] = beam_team.respawnbeam_color[Team.kUnassigned] + (control_count[new_defending_team] * 35) + --OutputEvent( beam_team.team_name .. "_respawn_beam", "Color", beam_team.respawnbeam_color[0] .. " " .. beam_team.respawnbeam_color[1] .. " " .. beam_team.respawnbeam_color[2] ) + + SmartTeamMessage( team, "#FF_CZ2_YOURTEAM_CP" .. cp_number, "#FF_CZ2_OTHERTEAM_CP" .. cp_number, Color.kGreen, Color.kRed ) + + -- sounds will get more and more crazy + --SmartTeamSound( team, good_cap_sounds[control_count[new_defending_team]], bad_cap_sounds[control_count[new_defending_team]] ) + + -- caes: changed it to announce the cp number captured/lost + SmartTeamSpeak( team, good_cap_sounds[cp_number], bad_cap_sounds[cp_number] ) +end + + +----------------------------------------------------------------------------- +-- a cp's defending team successfully defended or capped +----------------------------------------------------------------------------- +function SuccessfulCPDefense( cp, team_number, is_a_cap ) + + -- reward the touching players + for i in cp.touching_players[team_number].items do + i = CastToPlayer( i ) + if is_a_cap then + CapResupply( i, 1.00, is_a_cap ) + i:AddFortPoints((cp.point_value[team_number]) * 100, "#FF_FORTPOINTS_CAPTUREPOINT") + i:SetCloakable( true ) + else + CapResupply( i, 0.50, is_a_cap ) + i:AddFortPoints((cp.point_value[team_number]) * 50, "#FF_FORTPOINTS_DEFENDPOINT") + end + end + + -- reward the former touching players + for i in cp.former_touching_players[team_number].items do + i = CastToPlayer( i ) + if is_a_cap then + CapResupply( i, 0.50, is_a_cap ) + i:AddFortPoints((cp.point_value[team_number]) * 50, "#FF_FORTPOINTS_CAPTUREPOINT_ASSIST") + else + CapResupply( i, 0.25, is_a_cap ) + i:AddFortPoints((cp.point_value[team_number]) * 25, "#FF_FORTPOINTS_DEFENDPOINT_ASSIST") + end + end + + -- no need to keep them around for future rewards + cp.former_touching_players[team_number]:RemoveAllItems() + +end + + +----------------------------------------------------------------------------- +-- timed cp capping +----------------------------------------------------------------------------- +function cap_zone_timer( cp ) + + local new_defending_team = Team.kUnassigned + local other_team = Team.kUnassigned + local last_cap_status = {} + local total_cap_speed = 0 + local total_cap_status = 0 + + for i,v in pairs(teams) do + total_cap_speed = total_cap_speed + cp.cap_speed[v] + total_cap_status = total_cap_status + cp.cap_status[v] + end + + for i,v in pairs(teams) do + + -- don't bother doing some stuff if nothing has changed + last_cap_status[v] = cp.cap_status[v] + + -- after one team caps a cp, the other team can't touch that cp for X seconds + if cp.next_cap_zone_timer[v] > 0 then + + cp.next_cap_zone_timer[v] = cp.next_cap_zone_timer[v] - CAP_ZONE_TIMER_INTERVAL + + local lock_percent = math.min( 1.0, cp.next_cap_zone_timer[v] / cp.delay_before_retouch[v] ) + local minlockhudwidth = cp.hudwidth * 0.333 + local minlockhudheight = cp.hudheight * 0.333 + + AddHudIconToAll( icons[v].lockicon, cp.cp_number .. "-caplockicon-" .. v, cp.hudposx, cp.hudposy + cp_zone_icons[v].hudposy_offset, minlockhudwidth + ( (cp.hudwidth - minlockhudwidth) * lock_percent ), minlockhudheight + ( (cp.hudheight - minlockhudheight) * lock_percent ), cp.hudalign) + + -- clamp + if cp.next_cap_zone_timer[v] <= 0 then + cp.next_cap_zone_timer[v] = 0 + RemoveHudItemFromAll( cp.cp_number .. "-caplockicon-" .. v ) + end + + -- this team is standing in the zone + elseif cp.cap_speed[v] > 0 then + + -- don't bother with cap_status calculations for the defending team + if v == cp.defending_team then + + cp.cap_status[v] = cp.cap_requirement[v] + + -- calculate cap status + else + + -- every vote counts + local affected_cap_speed = cp.cap_speed[v] - ( total_cap_speed - cp.cap_speed[v] ) + + cp.cap_status[v] = cp.cap_status[v] + affected_cap_speed + + -- clamp + if cp.cap_status[v] < 0 then + + cp.cap_status[v] = 0 + + -- potential capping team + elseif cp.cap_status[v] >= cp.cap_requirement[v] then + + new_defending_team = v + + -- clamp + cp.cap_status[v] = cp.cap_requirement[v] + + end + end + + -- this team is not standing in the zone + else + if v == cp.defending_team then + -- don't bother with cap_status calculations for the defending team + cp.cap_status[v] = 0 + else + -- decrease cap status + cp.cap_status[v] = cp.cap_status[v] - ( CAP_ZONE_NOTOUCH_SPEED + total_cap_speed ) + + -- clamp + if cp.cap_status[v] < 0 then + cp.cap_status[v] = 0 + end + end + end + + -- don't bother doing some stuff if nothing has changed + if cp.cap_status[v] ~= last_cap_status[v] then + + -- draw the cap status icon + if cp.cap_status[v] > 0 then + + local cap_percent = cp.cap_status[v] / cp.cap_requirement[v] + local minhudwidth = cp.hudwidth * 0.333 + local minhudheight = cp.hudheight * 0.333 + AddHudIconToAll( cp_zone_icons[v].hudicon, cp.cp_number .. "-capstatusicon-" .. v, cp.hudposx, cp.hudposy + cp_zone_icons[v].hudposy_offset, minhudwidth + ( (cp.hudwidth - minhudwidth) * cap_percent ), minhudheight + ( (cp.hudheight - minhudheight) * cap_percent ), cp.hudalign) + OutputEvent( "cp" .. cp.cp_number .. "_" .. team_info[v].team_name .. "_capsprites", "ShowSprite" ) + OutputEvent( "cp" .. cp.cp_number .. "_" .. team_info[v].team_name .. "_capsound", "PlaySound" ) + + -- remove the cap status icon, remove former touching players, and reward defenders + else + + -- reward the defenders + if v ~= cp.defending_team and cp.defending_team ~= Team.kUnassigned then + SuccessfulCPDefense( cp, cp.defending_team, false ) + end + + -- reset the other team's cp capping stuff + ResetTeamCPCapping( cp, v, false, 0 ) + + end + + end + + if new_defending_team ~= v then + other_team = v + end + + end + + -- someone capped this cp + if new_defending_team ~= Team.kUnassigned then + + -- cap the cp + SuccessfulCPDefense( cp, new_defending_team, true ) + CaptureCP( cp.cp_number, new_defending_team ) + + -- reset the other team's cp capping stuff + ResetTeamCPCapping( cp, other_team, false, cp.delay_before_retouch[other_team] ) + + end + +end + + +----------------------------------------------------------------------------- +-- triggers +----------------------------------------------------------------------------- + +cp_base_trigger = trigger_ff_script:new({ team = Team.kUnassigned, failtouch_message="#FF_NOTALLOWEDDOOR", allowdisguised = true }) + +function cp_base_trigger:allowed( allowed_entity ) + + if IsPlayer( allowed_entity ) then + local player = CastToPlayer( allowed_entity ) + if player:GetTeamId() == self.team then + return EVENT_ALLOWED + end + + if self.allowdisguised then + if player:IsDisguised() and player:GetDisguisedTeam() == self.team then + return EVENT_ALLOWED + end + end + end + return EVENT_DISALLOWED +end + +function cp_base_trigger:onfailtouch( touch_entity ) + + if IsPlayer( touch_entity ) then + local player = CastToPlayer( touch_entity ) + BroadCastMessageToPlayer( player, self.failtouch_message ) + end +end + +cp_team1_door_trigger = cp_base_trigger:new({ team = TEAM1 }) +cp_team2_door_trigger = cp_base_trigger:new({ team = TEAM2 }) + + +----------------------------------------------------------------------------- +-- packs +----------------------------------------------------------------------------- +cp_base_pack = genericbackpack:new({ + health = 100, + armor = 300, + nails = 200, + shells = 200, + rockets = 200, + cells = 200, + detpacks = 0, + mancannons = 0, + gren1 = 0, + gren2 = 0, + respawntime = 1, + touchflags = team_info[Team.kUnassigned].touchflags, + model = "models/items/backpack/backpack.mdl", + materializesound = "Item.Materialize", + touchsound = "Backpack.Touch", + cp_number = 0, + botgoaltype = Bot.kBackPack_Ammo, +}) + +function cp_base_pack:dropatspawn() return false end + +cp_team1_respawn_pack = cp_base_pack:new( { touchflags = team_info[TEAM1].touchflags } ) +cp_team2_respawn_pack = cp_base_pack:new( { touchflags = team_info[TEAM2].touchflags } ) + +cp_cp1_ammo = ammobackpack:new({cp_number = 1}) +cp_cp2_ammo = ammobackpack:new({cp_number = 2}) +cp_cp3_ammo = ammobackpack:new({cp_number = 3}) +cp_cp4_ammo = ammobackpack:new({cp_number = 4}) +cp_cp5_ammo = ammobackpack:new({cp_number = 5}) + +cp_cp1_armor = armorkit:new({cp_number = 1}) +cp_cp2_armor = armorkit:new({cp_number = 2}) +cp_cp3_armor = armorkit:new({cp_number = 3}) +cp_cp4_armor = armorkit:new({cp_number = 4}) +cp_cp5_armor = armorkit:new({cp_number = 5}) + + +----------------------------------------------------------------------------- +-- grenade packs +----------------------------------------------------------------------------- +cp_base_grenade_pack = cp_base_pack:new({ + detpacks = 1, + mancannons = 1, + gren1 = 4, + gren2 = 4, + respawntime = 15, + touchflags = team_info[Team.kUnassigned].touchflags, + botgoaltype = Bot.kBackPack_Grenades, +}) + +cp_team1_grenade_pack = cp_base_grenade_pack:new( { touchflags = team_info[TEAM1].touchflags } ) +cp_team2_grenade_pack = cp_base_grenade_pack:new( { touchflags = team_info[TEAM2].touchflags } ) + + +----------------------------------------------------------------------------- +-- cp zones +----------------------------------------------------------------------------- + +cp_base_cp_zone = trigger_ff_script:new({ + item = "", + team = 0, + botgoaltype = Bot.kFlagCap, + cp_number = 0, +}) + +function cp_base_cp_zone:ontrigger( trigger_entity ) + + -- check whether flags are used, and in turn wheter these triggers are used + if ENABLE_FLAGS or not ENABLE_CP_TELEPORTERS then return end + + if IsPlayer( trigger_entity ) then + local player = CastToPlayer( trigger_entity ) + + -- Allow players on defending team to teleport back to base + if player:GetTeamId() == command_points[self.cp_number].defending_team then + + if player:IsInUse() then + -- respawn the player + ApplyToPlayer( player, { AT.kRespawnPlayers, kReloadClips } ) + + OutputEvent( "cp" .. self.cp_number .. "_respawn_enter_sound", "PlaySound" ) + AddSchedule("cp" .. self.cp_number .. "_respawn_" .. player:GetId(), 0.1, EmitSound, player, "ff_cz2.teleport_exit") + else + BroadCastMessageToPlayer(player, "#FF_CZ2_USE_RESPAWN") + end + + end + + end + +end + +function cp_base_cp_zone:ontouch( trigger_entity ) + + -- check whether flags are used, and in turn wheter these zones are used + if ENABLE_FLAGS then return end + + if IsPlayer( trigger_entity ) then + local player = CastToPlayer( trigger_entity ) + local cp = command_points[self.cp_number] + PlayerStartTouchingCapZone( player, cp ) + end + +end + +function cp_base_cp_zone:onendtouch( trigger_entity ) + + -- check whether flags are used, and in turn wheter these zones are used + if ENABLE_FLAGS then return end + + if IsPlayer( trigger_entity ) then + local player = CastToPlayer( trigger_entity ) + local cp = command_points[self.cp_number] + PlayerStopTouchingCapZone( player, cp ) + end +end + +cp_cp1_cp_zone = cp_base_cp_zone:new({ cp_number = 1 }) +cp_cp2_cp_zone = cp_base_cp_zone:new({ cp_number = 2 }) +cp_cp3_cp_zone = cp_base_cp_zone:new({ cp_number = 3 }) +cp_cp4_cp_zone = cp_base_cp_zone:new({ cp_number = 4 }) +cp_cp5_cp_zone = cp_base_cp_zone:new({ cp_number = 5 }) + + +----------------------------------------------------------------------------- +-- cp triggers +----------------------------------------------------------------------------- + +cp_base_cp_trigger = trigger_ff_script:new({ + item = "", + team = 0, + botgoaltype = Bot.kFlagCap, + cp_number = 0, +}) + +function cp_base_cp_trigger:ontrigger( trigger_entity ) + + -- check whether flags are used, and in turn wheter these triggers are used + if not ENABLE_FLAGS or not ENABLE_CP_TELEPORTERS then return end + + if IsPlayer( trigger_entity ) then + local player = CastToPlayer( trigger_entity ) + + -- Allow players on defending team to teleport back to base + if player:GetTeamId() == command_points[self.cp_number].defending_team then + + if player:IsInUse() then + -- check if the player has a flag + for i,v in ipairs(flags) do + -- return the flag + if player:HasItem(v) then ReturnFlagFromPlayer(player) end + end + + -- respawn the player + ApplyToPlayer( player, { AT.kRespawnPlayers, kReloadClips } ) + + OutputEvent( "cp" .. self.cp_number .. "_respawn_enter_sound", "PlaySound" ) + AddSchedule("cp" .. self.cp_number .. "_respawn_" .. player:GetId(), 0.1, EmitSound, player, "ff_cz2.teleport_exit") + else + BroadCastMessageToPlayer(player, "#FF_CZ2_USE_RESPAWN") + end + + end + + end + +end + +function cp_base_cp_trigger:ontouch( trigger_entity ) + + -- check whether flags are used, and in turn wheter these triggers are used + if not ENABLE_FLAGS then return end + + if IsPlayer( trigger_entity ) then + local player = CastToPlayer( trigger_entity ) + local cp = command_points[self.cp_number] + + -- No capping if player's team already defends this CP + if player:GetTeamId() == cp.defending_team then return end + + -- get out if player doesn't have flag + if not PlayerHasFlag(player) then return end + + ReturnFlagFromPlayer(player) + + CaptureCP(self.cp_number, player:GetTeamId()) + player:AddFortPoints((cp.point_value[player:GetTeamId()]) * 100, "#FF_FORTPOINTS_CAPTUREPOINT") + end + +end + +cp_cp1_cp_trigger = cp_base_cp_trigger:new({ cp_number = 1 }) +cp_cp2_cp_trigger = cp_base_cp_trigger:new({ cp_number = 2 }) +cp_cp3_cp_trigger = cp_base_cp_trigger:new({ cp_number = 3 }) +cp_cp4_cp_trigger = cp_base_cp_trigger:new({ cp_number = 4 }) +cp_cp5_cp_trigger = cp_base_cp_trigger:new({ cp_number = 5 }) + + +----------------------------------------------------------------------------- +-- flags +----------------------------------------------------------------------------- + +cp_base_flag = info_ff_script:new({ + name = "Base Flag", + team = 0, + model = "models/flag/flag.mdl", + tosssound = "Flag.Toss", + modelskin = 0, + dropnotouchtime = 2, + capnotouchtime = 2, + botgoaltype = Bot.kFlag, + hudicon = "", + hudx = 5, + hudy = 180, + hudalign = 1, + touchflags = team_info[Team.kUnassigned].touchflags +}) + +function cp_base_flag:precache() + PrecacheSound(self.tosssound) + info_ff_script.precache(self) +end + +function cp_base_flag:spawn() + self.notouch = { } + info_ff_script.spawn(self) +end + +function cp_base_flag:addnotouch(player_id, duration) + self.notouch[player_id] = duration + AddSchedule(self.name .. "-" .. player_id, duration, self.removenotouch, self, player_id) +end + +function cp_base_flag.removenotouch(self, player_id) + self.notouch[player_id] = nil +end + +function cp_base_flag:touch( touch_entity ) + local player = CastToPlayer( touch_entity ) + + if player:GetTeamId() ~= self.team then return end + + -- pickup if they can + if self.notouch[player:GetId()] then return end + + -- make sure they don't have any flags already + for i,v in ipairs(flags) do + if player:HasItem(v) then return end + end + + -- if the player is a spy, then force him to lose his disguise + player:SetDisguisable( false ) + player:SetCloakable( false ) + + -- note: this seems a bit backwards (Pickup verb fits Player better) + local flag = CastToInfoScript(entity) + flag:Pickup(player) + player:AddEffect( EF.kSpeedlua1, -1, 0, FLAG_CARRIER_SPEED ) + AddHudIcon( player, self.hudicon, flag:GetName(), self.hudx, self.hudy, self.hudwidth, self.hudheight, self.hudalign ) +end + +function cp_base_flag:onownerdie( owner_entity ) + -- drop the flag + local flag = CastToInfoScript(entity) + flag:Drop(FLAG_RETURN_TIME, 0.0) +end + +function cp_base_flag:onownerfeign( owner_entity ) + -- drop the flag + local flag = CastToInfoScript(entity) + flag:Drop(FLAG_RETURN_TIME, 0.0) +end +function cp_base_flag:onownercloak( owner_entity ) + -- drop the flag + local flag = CastToInfoScript(entity) + flag:Drop(FLAG_RETURN_TIME, 0.0) +end +function cp_base_flag:dropitemcmd( owner_entity ) + -- throw the flag + local flag = CastToInfoScript(entity) + flag:Drop(FLAG_RETURN_TIME, FLAG_THROW_SPEED) +end + +function cp_base_flag:ondrop( owner_entity ) + local flag = CastToInfoScript(entity) + flag:EmitSound(self.tosssound) +end + +function cp_base_flag:onloseitem( owner_entity ) + -- let the player that lost the flag put on a disguise + local player = CastToPlayer( owner_entity ) + player:SetDisguisable(true) + player:SetCloakable(true) + + self:addnotouch(player:GetId(), self.capnotouchtime) + + --player:RemoveEffect( EF.kSpeedlua1 ) + -- remove flag icon from hud + local flag = CastToInfoScript(entity) + RemoveHudItem( player, flag:GetName() ) +end + +function cp_base_flag:onreturn( ) +end + +cp_team1_flag = cp_base_flag:new({ + team = TEAM1, + modelskin = 0, + name = team_info[TEAM1].team_name .. " flag", + hudicon = "hud_flag_" .. team_info[TEAM1].team_name .. ".vtf", + hudx = 5, + hudy = 180, + hudwidth = 48, + hudheight = 48, + touchflags = team_info[TEAM1].touchflags +}) + +cp_team2_flag = cp_base_flag:new({ + team = TEAM2, + modelskin = 1, + name = team_info[TEAM2].team_name .. " flag", + hudicon = "hud_flag_" .. team_info[TEAM2].team_name .. ".vtf", + hudx = 5, + hudy = 180, + hudwidth = 48, + hudheight = 48, + touchflags = team_info[TEAM2].touchflags +}) + + +----------------------------------------------------------------------------- +-- flag dispensers +----------------------------------------------------------------------------- +cp_base_flag_dispenser = trigger_ff_script:new({ + name = "Base Flag Dispenser", + team = Team.kUnassigned, + dropnotouchtime = 2, + botgoaltype = Bot.kFlag, + hudicon = "", + hudx = 5, + hudy = 180, + hudwidth = 48, + hudheight = 48, + hudalign = 1, + flags = {"flag"} +}) + +function cp_base_flag_dispenser:allowed ( allowed_entity ) + + -- check whether flags are used, and in turn wheter these triggers are used + if not ENABLE_FLAGS then return EVENT_DISALLOWED end + + if IsPlayer( allowed_entity ) then + local player = CastToPlayer( allowed_entity ) + if player:GetTeamId() == self.team then + + -- Player can't have a flag + local playerhasflag = false + + for i,v in ipairs(self.flags) do + if player:HasItem(v) then + playerhasflag = true + break + end + end + + -- get out if player doesn't have flag + if not playerhasflag then + return EVENT_ALLOWED + end + end + end + return EVENT_DISALLOWED +end + +function cp_base_flag_dispenser:ontouch( trigger_entity ) + + -- check whether flags are used, and in turn wheter these triggers are used + if not ENABLE_FLAGS then return end + + if IsPlayer( trigger_entity ) then + + local player = CastToPlayer( trigger_entity ) + + local c = Collection() + c:GetByName( self.flags, { CF.kNone } ) + -- give the player an inactive flag + for item in c.items do + item = CastToInfoScript(item) + if item:IsInactive() then + -- if the player is a spy, then force him to lose his disguise + player:SetDisguisable( false ) + player:SetCloakable( false ) + + -- note: this seems a bit backwards (Pickup verb fits Player better) + item:Pickup(player) + player:AddEffect( EF.kSpeedlua1, -1, 0, FLAG_CARRIER_SPEED ) + AddHudIcon( player, self.hudicon, item:GetName(), self.hudx, self.hudy, self.hudwidth, self.hudheight, self.hudalign ) + + player:EmitSound("Buttons.snd9") + + -- all done + break + end + end + end +end + +cp_team1_flag_dispenser = cp_base_flag_dispenser:new({ + name = team_info[TEAM1].team_name .. " flag dispenser", + team = TEAM1, + hudicon = "hud_flag_" .. team_info[TEAM1].team_name .. ".vtf", + flags = { team_info[TEAM1].team_name .. "_flag" } +}) + +cp_team2_flag_dispenser = cp_base_flag_dispenser:new({ + name = team_info[TEAM2].team_name .. " flag dispenser", + team = TEAM2, + hudicon = "hud_flag_" .. team_info[TEAM2].team_name .. ".vtf", + flags = { team_info[TEAM2].team_name .. "_flag" } +}) + + +----------------------------------------------------------------------------- +-- command centers +----------------------------------------------------------------------------- + +cp_base_command_center = trigger_ff_script:new({ team = Team.kUnassigned, enemy_team = Team.kUnassigned }) +function cp_base_command_center:onexplode( explosion_entity ) + + -- check whether command centers are enabled + if not ENABLE_CC then return EVENT_ALLOWED end + + if IsDetpack( explosion_entity ) then + local detpack = CastToDetpack(explosion_entity) + + -- don't let assholes destroy their own team's command center + if detpack:GetTeamId() == self.team then return EVENT_ALLOWED end + + local points = CC_DESTROY_POINTS + for i,v in ipairs(command_points) do + if v.defending_team == self.team then + -- taking CP 1 away from team2 is worth more than taking CP 5 away from them + points = points + v.point_value[self.team] + + -- Remove all ammo and armor from CPs + local c = Collection() + c:GetByName({"cp_cp" .. v.cp_number .. "_ammo", "cz2_cp" .. v.cp_number .. "_ammo", "cp_cp" .. v.cp_number .. "_armor", "cz2_cp" .. v.cp_number .. "_armor"}, { CF.kNone }) + for item in c.items do + item = CastToInfoScript(item) + item:Remove() + end + + -- reset the CP + ChangeCPDefendingTeam(v.cp_number, Team.kUnassigned) + end + + -- reset the other team's cp capping stuff + ResetTeamCPCapping( v, self.team, false, v.delay_before_retouch[self.team] * 2.0 ) + end + + local team = detpack:GetTeam() + team:AddScore(points) + + local player = detpack:GetOwner() + player:AddFortPoints(points * 100, "#FF_FORTPOINTS_DESTROY_CC" ) + + SmartSound(player, "misc.thunder", "misc.thunder", "misc.thunder") + SmartMessage(player, "#FF_CZ2_YOU_CC", "#FF_CZ2_YOURTEAM_CC", "#FF_CZ2_OTHERTEAM_CC", Color.kGreen, Color.kGreen, Color.kRed) + SpeakAll( team_info[self.team].detcc_sentence ) + +-- EntityStopTouchingCC( detpack, self.team ) + + end + + return EVENT_ALLOWED +end + +function cp_base_command_center:ontouch( trigger_entity ) + + -- check whether command centers are enabled + if not ENABLE_CC then return end + +-- if IsDetpack( trigger_entity ) then +-- local detpack = CastToDetpack( trigger_entity ) +-- if detpack:GetTeamId() ~= self.team then +-- EntityStartTouchingCC( detpack, self.team ) +-- end +-- end + + if IsPlayer( trigger_entity ) then + local player = CastToPlayer( trigger_entity ) + if player:GetTeamId() ~= self.team then + EntityStartTouchingCC( player, self.team ) + end + end + +end + +function cp_base_command_center:onendtouch( trigger_entity ) + + -- check whether command centers are enabled + if not ENABLE_CC then return end + +-- if IsDetpack( trigger_entity ) then +-- local detpack = CastToDetpack( trigger_entity ) +-- if detpack:GetTeamId() ~= self.team then +-- EntityStopTouchingCC( detpack, self.team ) +-- end +-- end + + if IsPlayer( trigger_entity ) then + local player = CastToPlayer( trigger_entity ) + if player:GetTeamId() ~= self.team then + EntityStopTouchingCC( player, self.team ) + end + end +end + +cp_team1_command_center = cp_base_command_center:new({ team = TEAM1, enemy_team = TEAM2 }) +cp_team2_command_center = cp_base_command_center:new({ team = TEAM2, enemy_team = TEAM1 }) + + +------------------------------------------- +-- cc computers +------------------------------------------- + +cp_base_cc_computer = trigger_ff_script:new({ prefix = "unassigned", enemy_team = Team.kUnassigned }) + +function cp_base_cc_computer:ontrigger( trigger_entity ) + + -- check whether command centers are enabled + if not ENABLE_CC then return end + + if IsPlayer( trigger_entity ) then + local player = CastToPlayer( trigger_entity ) + + -- Allow spies to open the enemy doors + if player:GetTeamId() == self.enemy_team and player:GetClass() == Player.kSpy then + + if player:IsInUse() then + for i,v in ipairs(doors) do + -- open each enemy door + OutputEvent( self.prefix .. v, "Open" ) + end + else + -- tell the player they can open the enemy doors + BroadCastMessageToPlayer(player, "#FF_CZ2_USE_DOORS") + end + + end + end +end + +cp_team1_cc_computer = cp_base_cc_computer:new({ prefix = team_info[TEAM1].team_name, enemy_team = TEAM2 }) +cp_team2_cc_computer = cp_base_cc_computer:new({ prefix = team_info[TEAM2].team_name, enemy_team = TEAM1 }) + + +------------------------------------------- +-- cp flaginfo +------------------------------------------- + +function flaginfo( player_entity ) + + local player = CastToPlayer( player_entity ) + + for i,v in ipairs(command_points) do + + AddHudIcon( player, icons[ v.defending_team ].teamicon , v.cp_number .. "-background-" .. v.defending_team , command_points[v.cp_number].hudposx, command_points[v.cp_number].hudposy, command_points[v.cp_number].hudwidth, command_points[v.cp_number].hudheight, command_points[v.cp_number].hudalign) + AddHudIcon( player, command_points[v.cp_number].hudstatusicon, v.cp_number .. "-foreground-" .. v.defending_team , command_points[v.cp_number].hudposx, command_points[v.cp_number].hudposy, command_points[v.cp_number].hudwidth, command_points[v.cp_number].hudheight, command_points[v.cp_number].hudalign) + + end + + DrawCCAlarmIcon( TEAM1 ) + DrawCCAlarmIcon( TEAM2 ) + +end + + +------------------------------------------- +-- cp teleporters +------------------------------------------- + +trigger_teleport = trigger_ff_script:new({}) +cp_base_teleporter = trigger_teleport:new({ cp_number = 0, next_teleport_tick = 0 }) + +function cp_base_teleporter:allowed( allowed_entity ) + + -- check whether cc-to-cp teleporters are enabled + if not ENABLE_CC or not ENABLE_CC_TELEPORTERS then return EVENT_DISALLOWED end + + local stime = GetServerTime() + + if self.next_teleport_tick > stime then return end + + if IsPlayer( allowed_entity ) then + + local player = CastToPlayer( allowed_entity ) + -- Allow players on defending team to teleport to cp + if player:GetTeamId() == command_points[self.cp_number].defending_team then + + if player:IsInUse() then + -- teleport the player + local team_name = team_info[player:GetTeamId()].team_name + + if ENTITY_TOUCHING_CC[player:GetId()] ~= nil then + team_name = team_info[ENTITY_TOUCHING_CC[player:GetId()]].team_name + end + + OutputEvent( team_name .. "_cp" .. self.cp_number .. "_teleport_enter_sound", "PlaySound" ) + --OutputEvent( team_name .. "_cp" .. self.cp_number .. "_teleport_exit_sound", "PlaySound", "", 0.1 ) + OutputEvent( team_name .. "_cp" .. self.cp_number .. "_teleport_tesla", "DoSpark", "", 0.1 ) + + --self.next_teleport_tick = stime + 1.0 + + ApplyToPlayer( player, { AT.kStopPrimedGrens, kReloadClips } ) + + return EVENT_ALLOWED + else + -- tell the player they can teleport + BroadCastMessageToPlayer(player, "#FF_CZ2_USE_TELEPORT") + end + + end + end + + return EVENT_DISALLOWED + +end + +-- team1 teleporters +cp_team1_teleporter_cp1 = cp_base_teleporter:new({ cp_number = 1 }) +cp_team1_teleporter_cp2 = cp_base_teleporter:new({ cp_number = 2 }) +cp_team1_teleporter_cp3 = cp_base_teleporter:new({ cp_number = 3 }) +cp_team1_teleporter_cp4 = cp_base_teleporter:new({ cp_number = 4 }) +cp_team1_teleporter_cp5 = cp_base_teleporter:new({ cp_number = 5 }) + +-- team2 teleporters +cp_team2_teleporter_cp1 = cp_base_teleporter:new({ cp_number = 1 }) +cp_team2_teleporter_cp2 = cp_base_teleporter:new({ cp_number = 2 }) +cp_team2_teleporter_cp3 = cp_base_teleporter:new({ cp_number = 3 }) +cp_team2_teleporter_cp4 = cp_base_teleporter:new({ cp_number = 4 }) +cp_team2_teleporter_cp5 = cp_base_teleporter:new({ cp_number = 5 }) + + +----------------------------------------------------------------------------- +-- locations +----------------------------------------------------------------------------- + +location_cp1 = location_info:new({ text = "#FF_LOCATION_COMMAND_POINT_ONE", team = NO_TEAM }) +location_cp2 = location_info:new({ text = "#FF_LOCATION_COMMAND_POINT_TWO", team = NO_TEAM }) +location_cp3 = location_info:new({ text = "#FF_LOCATION_COMMAND_POINT_THREE", team = NO_TEAM }) +location_cp4 = location_info:new({ text = "#FF_LOCATION_COMMAND_POINT_FOUR", team = NO_TEAM }) +location_cp5 = location_info:new({ text = "#FF_LOCATION_COMMAND_POINT_FIVE", team = NO_TEAM }) + +location_cp1_path = location_info:new({ text = "#FF_LOCATION_CP1_PATH", team = TEAM1 }) +location_cp2_path = location_info:new({ text = "#FF_LOCATION_CP2_PATH", team = TEAM1 }) +location_cp3_path = location_info:new({ text = "#FF_LOCATION_CP3_PATH", team = NO_TEAM }) +location_cp4_path = location_info:new({ text = "#FF_LOCATION_CP4_PATH", team = TEAM2 }) +location_cp5_path = location_info:new({ text = "#FF_LOCATION_CP5_PATH", team = TEAM2 }) + +location_catacombs = location_info:new({ text = "#FF_LOCATION_CATACOMBS", team = NO_TEAM }) + +location_blue_base = location_info:new({ text = "#FF_LOCATION_BASE", team = TEAM1 }) +location_blue_cc = location_info:new({ text = "#FF_LOCATION_COMMAND_CENTER", team = TEAM1 }) +location_blue_outside_base = location_info:new({ text = "#FF_LOCATION_OUTSIDE_BASE", team = TEAM1 }) +location_blue_canal = location_info:new({ text = "#FF_LOCATION_CANAL", team = TEAM1 }) +location_blue_catacombs = location_info:new({ text = "#FF_LOCATION_CATACOMBS", team = TEAM1 }) + +location_red_base = location_info:new({ text = "#FF_LOCATION_BASE", team = TEAM2 }) +location_red_cc = location_info:new({ text = "#FF_LOCATION_COMMAND_CENTER", team = TEAM2 }) +location_red_outside_base = location_info:new({ text = "#FF_LOCATION_OUTSIDE_BASE", team = TEAM2 }) +location_red_canal = location_info:new({ text = "#FF_LOCATION_CANAL", team = TEAM2 }) +location_red_catacombs = location_info:new({ text = "#FF_LOCATION_CATACOMBS", team = TEAM2 }) + + +----------------------------------------------------------------------------- +-- backwards compatiblity - use "cp_*" names in your map instead! +----------------------------------------------------------------------------- +base_team_trigger = cp_base_trigger +blue_door_trigger = cp_team1_door_trigger +red_door_trigger = cp_team2_door_trigger + +cz2_base_pack = cp_base_pack +cz2_blue_respawn_pack = cp_team1_respawn_pack +cz2_red_respawn_pack = cp_team2_respawn_pack + +cz2_cp1_ammo = cp_cp1_ammo +cz2_cp2_ammo = cp_cp2_ammo +cz2_cp3_ammo = cp_cp3_ammo +cz2_cp4_ammo = cp_cp4_ammo +cz2_cp5_ammo = cp_cp5_ammo + +cz2_cp1_armor = cp_cp1_armor +cz2_cp2_armor = cp_cp2_armor +cz2_cp3_armor = cp_cp3_armor +cz2_cp4_armor = cp_cp4_armor +cz2_cp5_armor = cp_cp5_armor + +cz2_base_grenade_pack = cp_base_grenade_pack +cz2_blue_grenade_pack = cp_team1_grenade_pack +cz2_red_grenade_pack = cp_team2_grenade_pack + +base_cp_zone = cp_base_cp_zone +cp1_zone = cp_cp1_cp_zone +cp2_zone = cp_cp2_cp_zone +cp3_zone = cp_cp3_cp_zone +cp4_zone = cp_cp4_cp_zone +cp5_zone = cp_cp5_cp_zone + +base_cp_trigger = cp_base_cp_trigger +cp1_trigger = cp_cp1_cp_trigger +cp2_trigger = cp_cp2_cp_trigger +cp3_trigger = cp_cp3_cp_trigger +cp4_trigger = cp_cp4_cp_trigger +cp5_trigger = cp_cp5_cp_trigger + +base_cp_flag = cp_base_flag +blue_flag = cp_team1_flag +red_flag = cp_team2_flag + +cp_base_flag_dispenser = base_cp_flag_dispenser +blue_flag_dispenser = cp_team1_flag_dispenser +red_flag_dispenser = cp_team2_flag_dispenser + +base_command_center = cp_base_command_center +blue_command_center = cp_team1_command_center +red_command_center = cp_team2_command_center + +base_cp_cc_computer = cp_base_cc_computer +blue_cc_computer = cp_team1_cc_computer +red_cc_computer = cp_team2_cc_computer + +base_cp_teleporter = cp_base_teleporter +blue_teleporter_cp1 = cp_team1_teleporter_cp1 +blue_teleporter_cp2 = cp_team1_teleporter_cp2 +blue_teleporter_cp3 = cp_team1_teleporter_cp3 +blue_teleporter_cp4 = cp_team1_teleporter_cp4 +blue_teleporter_cp5 = cp_team1_teleporter_cp5 +red_teleporter_cp1 = cp_team2_teleporter_cp1 +red_teleporter_cp2 = cp_team2_teleporter_cp2 +red_teleporter_cp3 = cp_team2_teleporter_cp3 +red_teleporter_cp4 = cp_team2_teleporter_cp4 +red_teleporter_cp5 = cp_team2_teleporter_cp5