Difference between revisions of "Map Template:Sequential Territory Control"
Line 554: | Line 554: | ||
| | ||
=Downloads= | =Downloads= | ||
− | * | + | *[http://www.dcpaterson.ukfsn.org/tutorials/warpath_example/warpath_example_v1.rar Source .vmf] (Includes .vmf of an example map, the Lua Script, and a custom HUD graphic used): |
[[Category:Map Templates]] [[Category:Mapping]] | [[Category:Map Templates]] [[Category:Mapping]] |
Revision as of 22:50, 27 November 2007
Foreword
This is likely a temporary script/page until an offical Lua for this gametype is released. As such, the Lua script itself likely isn't up to the same standard as the official ones. It does work as intended, though.
It is set up to behave as close to the TFC version of warpath as I could get it, with my limited mapping experience.
Introduction
In this game mode, each team must capture Command Points in order (no flag, just touch the Command Point), typically the Blue team capture 1 through 5, and the Red team 5 through 1. Upon a team capturing their final point, the round is reset.
An example of this style of map is Warpath.
Entities
Start Gates
- startgate_blue (func_door): Start gate for Blue team
- startgate_red (func_door): Start gate for Red team
Spawns
- bluespawn_cp1 (info_ff_teamspawn): Initial Blue team spawn
- bluespawn_cp2 (info_ff_teamspawn): --\
- bluespawn_cp3 (info_ff_teamspawn): -- Progressive spawns for the Blue team. "cp#" denotes Command Point control nessecary to be active(only current cp# spawns are active)
- bluespawn_cp4 (info_ff_teamspawn): --/
- redspawn_cp5 (info_ff_teamspawn): Initial Blue team spawn
- redspawn_cp4 (info_ff_teamspawn): --\
- redspawn_cp3 (info_ff_teamspawn): -- Progressive spawns for the Red team. "cp#" denotes Command Point control nessecary to be active (only current cp# spawns are active)
- redspawn_cp2 (info_ff_teamspawn): --/
Respawn Doors
- bluerespawn_cp2_actual (func_door): --\
- bluerespawn_cp3_actual (func_door): -- Physical door for Blue spawns. All flags should be off, opening is controlled by another entity
- bluerespawn_cp4_actual (func_door): --/
- redrespawn_cp4_actual (func_door): --\
- redrespawn_cp3_actual (func_door): -- Physical door for Red spawns. All flags should be off, opening is controlled by another entity
- redrespawn_cp2_actual (func_door): --/
- bluerespawn_cp2 (trigger_ff_script): --\
- bluerespawn_cp3 (trigger_ff_script): -- Trigger for the respawn doors above. Fires output "OnStartTouch:Open" to corresponding "_actual" door
- bluerespawn_cp4 (trigger_ff_script): --/
- bluerespawn_cp4 (trigger_ff_script): --\
- bluerespawn_cp3 (trigger_ff_script): -- Trigger for the respawn doors above. Fires output "OnStartTouch:Open" to corresponding "_actual" door
- bluerespawn_cp2 (trigger_ff_script): --/
Command Points
- command_point_one (trigger_ff_script): Location for Command Point One
- command_point_two (trigger_ff_script): ... and
- command_point_three (trigger_ff_script): ... so
- command_point_four (trigger_ff_script): ... on
- command_point_five (trigger_ff_script): ... etc.
Flags
- cp1_flag (prop_dynamic_override): Flag used to denote CP ownership. Cannot be picked up.
- cp2_flag (prop_dynamic_override): ... and
- cp3_flag (prop_dynamic_override): ... so
- cp4_flag (prop_dynamic_override): ... on
- cp5_flag (prop_dynamic_override): ... etc.
Flag Rotators
- cp1_flag_rotator (func_rotating): Optional entity used to rotate flag on CP. Flag entity must have this entity as parent if used.
- cp2_flag_rotator (func_rotating): ... and
- cp3_flag_rotator (func_rotating): ... so
- cp4_flag_rotator (func_rotating): ... on
- cp5_flag_rotator (func_rotating): ... etc.
Lua Script
(NOTE: Uses a custom vgui graphic. The graphic is included in the source .vmf download linked to below the script, along with the below script)
------------------------------------------------ -- This started as cz2.lua, along with some other bits of lua from other official files, and then altered by myself -- to accomodate warpath-style gameplay. -- -- Pon.id -- warpath_example.lua v1.00 ------------------------------------------------ ----------------------------------------------------------------------------- -- includes ----------------------------------------------------------------------------- IncludeScript("base_teamplay") IncludeScript("base_location") IncludeScript("base_respawnturret") ----------------------------------------------------------------------------- -- globals ----------------------------------------------------------------------------- -- Scoring globals NUMBER_OF_COMMAND_POINTS = 5 POINTS_FOR_COMPLETE_CONTROL = 30 FORTPOINTS_FOR_COMPLETE_CONTROL = 1000 FORTPOINTS_FOR_CAP = 200 -- Other Globals (Initial round delay used only for first round, give people time to log in) INITIAL_ROUND_DELAY = 45 RECAPTURE_DELAY = 15 NORMAL_ROUND_DELAY = 30 -- Counters for spawn validty cp_blue = 1 cp_red = 5 -- A global table for storing some team info team_info = { [Team.kUnassigned] = { team_name = "neutral", color_index = 1, skin = "0", flag_visibility = "TurnOff" }, [Team.kBlue] = { team_name = "blue", color_index = 2, skin = "0", flag_visibility = "TurnOn" }, [Team.kRed] = { team_name = "red", color_index = 0, skin = "1", flag_visibility = "TurnOn" } } -- This table is for keeping track of which team controls which CP command_points = { [1] = { controlling_team = Team.kBlue, cp_number = 1, disable_capture = 0, hudstatusicon = "hud_cp_1.vtf", hudposx = -40, hudposy = 36, hudalign = 4, hudwidth = 16, hudheight = 16 }, [2] = { controlling_team = Team.kUnassigned, cp_number = 2, disable_capture = 0, hudstatusicon = "hud_cp_2.vtf", hudposx = -20, hudposy = 36, hudalign = 4, hudwidth = 16, hudheight = 16 }, [3] = { controlling_team = Team.kUnassigned, cp_number = 3, disable_capture = 0, hudstatusicon = "hud_cp_3.vtf", hudposx = 0, hudposy = 36, hudalign = 4, hudwidth = 16, hudheight = 16 }, [4] = { controlling_team = Team.kUnassigned, cp_number = 4, disable_capture = 0, hudstatusicon = "hud_cp_4.vtf", hudposx = 20, hudposy = 36, hudalign = 4, hudwidth = 16, hudheight = 16 }, [5] = { controlling_team = Team.kRed, cp_number = 5, disable_capture = 0, hudstatusicon = "hud_cp_5.vtf", hudposx = 40, hudposy = 36, hudalign = 4, hudwidth = 16, hudheight = 16 } } icons = { [Team.kBlue] = { teamicon = "hud_cp_blue.vtf", disabled = "hud_disabled.vtf" }, [Team.kRed] = { teamicon = "hud_cp_red.vtf", disabled = "hud_disabled.vtf" }, [Team.kUnassigned] = { teamicon = "hud_cp_neutral.vtf", disabled = "hud_disabled.vtf" } } function startup() -- set up team limits SetPlayerLimit( Team.kYellow, -1 ) SetPlayerLimit( Team.kGreen, -1 ) local team = GetTeam(Team.kBlue) team:SetClassLimit( Player.kScout, 0 ) team:SetClassLimit( Player.kSniper, 0 ) team:SetClassLimit( Player.kSoldier, 0 ) team:SetClassLimit( Player.kDemoman, 0 ) team:SetClassLimit( Player.kMedic, 0 ) team:SetClassLimit( Player.kHwguy, 0 ) team:SetClassLimit( Player.kPyro, 0 ) team:SetClassLimit( Player.kSpy, 0 ) team:SetClassLimit( Player.kEngineer, 0 ) team:SetClassLimit( Player.kCivilian, -1 ) local team = GetTeam(Team.kRed) team:SetClassLimit( Player.kScout, 0 ) team:SetClassLimit( Player.kSniper, 0 ) team:SetClassLimit( Player.kSoldier, 0 ) team:SetClassLimit( Player.kDemoman, 0 ) team:SetClassLimit( Player.kMedic, 0 ) team:SetClassLimit( Player.kHwguy, 0 ) team:SetClassLimit( Player.kPyro, 0 ) team:SetClassLimit( Player.kSpy, 0 ) team:SetClassLimit( Player.kEngineer, 0 ) team:SetClassLimit( Player.kCivilian, -1 ) -- Reset all command points command_point_one:ChangeControllingTeam(Team.kBlue) command_point_two:ChangeControllingTeam(Team.kUnassigned) command_point_three:ChangeControllingTeam(Team.kUnassigned) command_point_four:ChangeControllingTeam(Team.kUnassigned) command_point_five:ChangeControllingTeam(Team.kRed) -- Setup Doors for first round setup_door_timer("startgate_blue", INITIAL_ROUND_DELAY) setup_door_timer("startgate_red", INITIAL_ROUND_DELAY) end function precache() -- precache sounds PrecacheSound("yourteam.flagcap") PrecacheSound("otherteam.flagcap") PrecacheSound("otherteam.flagstolen") PrecacheSound("misc.bizwarn") PrecacheSound("misc.bloop") PrecacheSound("misc.buzwarn") PrecacheSound("misc.dadeda") PrecacheSound("misc.deeoo") PrecacheSound("misc.doop") PrecacheSound("misc.woop") -- Unagi Power! Unagi! PrecacheSound("misc.unagi") end ----------------------------------------------------------------------------- -- Round Completion ----------------------------------------------------------------------------- function complete_control_notification ( player ) SmartSound(player, "yourteam.flagcap", "yourteam.flagcap", "otherteam.flagcap") SmartMessage(player, "Your team captured ALL Command Points!", "Your team captured ALL Command Points!", "The enemy team captured ALL Command Points!") end ----------------------------------------------------------------------------- -- Command Points ----------------------------------------------------------------------------- base_cp_trigger = trigger_ff_script:new({ health = 100, armor = 300, grenades = 200, nails = 200, shells = 200, rockets = 200, cells = 200, detpacks = 1, gren1 = 4, gren2 = 4, item = "", team = 0, botgoaltype = Bot.kFlagCap, cp_number = 0, }) function base_cp_trigger:ontrigger( trigger_entity ) if IsPlayer( trigger_entity ) then local player = CastToPlayer( trigger_entity ) local cp = command_points[self.cp_number] local new_controlling_team = player:GetTeamId() local old_controlling_team = cp.controlling_team local team = GetTeam(new_controlling_team) -- No capping if player's team already controls this CP if player:GetTeamId() == cp.controlling_team then return end -- No Capping if team doesn't own preceeding point if new_controlling_team == Team.kBlue then local last_blue_cp = self.cp_number - 1 if command_points[last_blue_cp].controlling_team ~= new_controlling_team then return end elseif new_controlling_team == Team.kRed then local last_red_cp = self.cp_number + 1 if command_points[last_red_cp].controlling_team ~= new_controlling_team then return end end -- No Capping if disabled due to recent capture if cp.disable_capture == 1 then return end -- Find out if any team has complete control local team_with_complete_control = Team.kUnassigned local control_count = { [Team.kBlue] = 0, [Team.kRed] = 0 } control_count[new_controlling_team] = 1 for i,v in ipairs(command_points) do if v.controlling_team ~= Team.kUnassigned and v.cp_number ~= self.cp_number then control_count[v.controlling_team] = control_count[v.controlling_team] + 1 end if control_count[v.controlling_team] == NUMBER_OF_COMMAND_POINTS then team_with_complete_control = v.controlling_team end end -- Ends round if a team has all cp's, else just sorts out a normal cp capture. if team_with_complete_control ~= Team.kUnassigned then -- Team points for complete control, more FortPoints too team:AddScore(POINTS_FOR_COMPLETE_CONTROL) player:AddFortPoints(FORTPOINTS_FOR_COMPLETE_CONTROL, "Final CP Captured") AddSchedule("complete_control_notification", 0.1, complete_control_notification, player) -- Reset all command points command_point_one:ChangeControllingTeam(Team.kBlue) command_point_two:ChangeControllingTeam(Team.kUnassigned) command_point_three:ChangeControllingTeam(Team.kUnassigned) command_point_four:ChangeControllingTeam(Team.kUnassigned) command_point_five:ChangeControllingTeam(Team.kRed) -- Reset extended spawn areas and door cp_blue = 1 cp_red = 5 -- Reset doors and set up timers for the next round setup_door_timer("startgate_blue", NORMAL_ROUND_DELAY) setup_door_timer("startgate_red", NORMAL_ROUND_DELAY) -- Clean up HUD and capture disabled status for all CP's for i,v in ipairs(command_points) do RemoveHudItemFromAll( v.cp_number .. "-disabled-" .. Team.kRed ) RemoveHudItemFromAll( v.cp_number .. "-disabled-" .. Team.kBlue ) v.disable_capture = 0 end -- Respawns everyone/clean up map. Done in schedule to give delay AddSchedule( "new_round_respawn", 0.1, new_round_respawn) else -- Give points to player for single cap player:AddFortPoints(FORTPOINTS_FOR_CAP, "Captured CP" .. self.cp_number) -- Set new owning team, change spawn validity, then disable capture for a bit self:ChangeControllingTeam(new_controlling_team, old_controlling_team) cp.disable_capture = 1 AddSchedule ("cp" .. self.cp_number .. "_reenable", RECAPTURE_DELAY, cp_reenable, cp, new_controlling_team) -- have to do messages here since player is here -- could just pass player to ChangeControllingTeam, but fuck you SmartMessage(player, "You captured Command Point " .. self.cp_number, "Your team captured Command Point " .. self.cp_number, "The enemy team captured Command Point " .. self.cp_number) -- sounds will get more and more crazy -- NOTE: These checks are hardcoded for 5 CPs...if you have more CPs, change how these are checked if control_count[new_controlling_team] == 4 then SmartSound(player, "misc.unagi", "misc.unagi", "misc.bizwarn") elseif control_count[new_controlling_team] == 3 then SmartSound(player, "misc.woop", "misc.woop", "misc.buzwarn") elseif control_count[new_controlling_team] == 2 then SmartSound(player, "misc.doop", "misc.doop", "misc.dadeda") else SmartSound(player, "misc.bloop", "misc.bloop", "misc.deeoo") end end -- give player some health and armor if self.health ~= nil and self.health ~= 0 then player:AddHealth( self.health ) end if self.armor ~= nil and self.armor ~= 0 then player:AddArmor( self.armor ) end -- give player ammo if self.nails ~= nil and self.nails ~= 0 then player:AddAmmo(Ammo.kNails, self.nails) end if self.shells ~= nil and self.shells ~= 0 then player:AddAmmo(Ammo.kShells, self.shells) end if self.rockets ~= nil and self.rockets ~= 0 then player:AddAmmo(Ammo.kRockets, self.rockets) end if self.cells ~= nil and self.cells ~= 0 then player:AddAmmo(Ammo.kCells, self.cells) end if self.detpacks ~= nil and self.detpacks ~= 0 then player:AddAmmo(Ammo.kDetpack, self.detpacks) end if self.gren1 ~= nil and self.gren1 ~= 0 then player:AddAmmo(Ammo.kGren1, self.gren1) end if self.gren2 ~= nil and self.gren2 ~= 0 then player:AddAmmo(Ammo.kGren2, self.gren2) end end end function base_cp_trigger:ChangeControllingTeam( new_controlling_team, old_controlling_team ) -- Change the cap flag around OutputEvent( "cp" .. self.cp_number .. "_flag", "Skin", team_info[new_controlling_team].skin ) OutputEvent( "cp" .. self.cp_number .. "_flag", team_info[new_controlling_team].flag_visibility) local cp = command_points[self.cp_number] -- remove old flaginfo icons and add new ones RemoveHudItemFromAll( self.cp_number .. "-background-" .. cp.controlling_team ) RemoveHudItemFromAll( self.cp_number .. "-foreground-" .. cp.controlling_team ) AddHudIconToAll( icons[ new_controlling_team ].teamicon , self.cp_number .. "-background-" .. new_controlling_team , cp.hudposx, cp.hudposy, cp.hudwidth, cp.hudheight, cp.hudalign) AddHudIconToAll( cp.hudstatusicon, self.cp_number .. "-foreground-" .. new_controlling_team , cp.hudposx, cp.hudposy, cp.hudwidth, cp.hudheight, cp.hudalign) -- if (new_controlling_team ~= Team.kUnassigned) then AddHudIconToAll( icons[ new_controlling_team ].disabled, self.cp_number .. "-disabled-" .. new_controlling_team , cp.hudposx, cp.hudposy, cp.hudwidth, cp.hudheight, cp.hudalign) end -- Change valid spawns if new_controlling_team == Team.kBlue then cp_blue = self.cp_number if old_controlling_team == Team.kRed then cp_red = self.cp_number + 1 end elseif new_controlling_team == Team.kRed then cp_red = self.cp_number if old_controlling_team == Team.kBlue then cp_blue = self.cp_number - 1 end end cp.controlling_team = new_controlling_team end command_point_one = base_cp_trigger:new({ cp_number = 1 }) command_point_two = base_cp_trigger:new({ cp_number = 2 }) command_point_three = base_cp_trigger:new({ cp_number = 3 }) command_point_four = base_cp_trigger:new({ cp_number = 4 }) command_point_five = base_cp_trigger:new({ cp_number = 5 }) ------------------------- -- Re-enable disabled CP after RECAPTURE_DELAY (default 15 seconds) ------------------------- function cp_reenable (cp, team) RemoveHudItemFromAll( cp.cp_number .. "-disabled-" .. team ) cp.disable_capture = 0 end function new_round_respawn() ApplyToAll({ AT.kRemovePacks, AT.kRemoveProjectiles, AT.kRespawnPlayers, AT.kRemoveBuildables, AT.kRemoveRagdolls, kReloadClips }) end ------------------------------------------- -- HUD information ------------------------------------------- function flaginfo( player_entity ) local player = CastToPlayer( player_entity ) for i,v in ipairs(command_points) do AddHudIcon( player, icons[ v.controlling_team ].teamicon , v.cp_number .. "-background-" .. v.controlling_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.controlling_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 end ------------------------------------------- -- Round start functions ------------------------------------------- function setup_door_timer(doorname, duration) CloseDoor(doorname) AddSchedule("round_opendoor_" .. doorname, duration, round_start, doorname) AddSchedule("round_10secwarn", duration-10, round_10secwarn) end function round_start(doorname) BroadCastMessage("Gates are now open!") BroadCastSound( "otherteam.flagstolen" ) OpenDoor(doorname) end function round_10secwarn() BroadCastMessage("10 Seconds until round starts") end ------------------------------------------- -- Spawnpoints + Respawn door Stuff ------------------------------------------- -- Spawn Points base_blue_spawn = info_ff_teamspawn:new({ cp = 0, validspawn = function(self,player) return player:GetTeamId() == Team.kBlue and self.cp == cp_blue end }) base_red_spawn = info_ff_teamspawn:new({ cp = 0, validspawn = function(self,player) return player:GetTeamId() == Team.kRed and self.cp == cp_red end }) bluespawn_cp1 = base_blue_spawn:new({cp=1}) bluespawn_cp2 = base_blue_spawn:new({cp=2}) bluespawn_cp3 = base_blue_spawn:new({cp=3}) bluespawn_cp4 = base_blue_spawn:new({cp=4}) redspawn_cp5 = base_red_spawn:new({cp=5}) redspawn_cp4 = base_red_spawn:new({cp=4}) redspawn_cp3 = base_red_spawn:new({cp=3}) redspawn_cp2 = base_red_spawn:new({cp=2}) -- Spawn Doors (base entity) blue_respawn_door = trigger_ff_script:new({cp = 0}) red_respawn_door = trigger_ff_script:new({cp = 0}) -- Spawn Doors (validity checks) function blue_respawn_door:allowed( allowed_entity ) if IsPlayer( allowed_entity ) then local player = CastToPlayer( allowed_entity ) if player:GetTeamId() == Team.kBlue and self.cp <= cp_blue then return EVENT_ALLOWED end end return EVENT_DISALLOWED end function red_respawn_door:allowed( allowed_entity ) if IsPlayer( allowed_entity ) then local player = CastToPlayer( allowed_entity ) if player:GetTeamId() == Team.kRed and self.cp >= cp_red then return EVENT_ALLOWED end end return EVENT_DISALLOWED end --Spawn Doors (Validity checks failure) function blue_respawn_door:onfailtouch( touch_entity ) if IsPlayer( touch_entity ) then local player = CastToPlayer( touch_entity ) if player:GetTeamId() == Team.kBlue then BroadCastMessageToPlayer( player, "You need to capture Command Point ".. self.cp .. " before you can use this respawn!" ) else BroadCastMessageToPlayer( player, "Your team cannot use this respawn." ) end end end function red_respawn_door:onfailtouch( touch_entity ) if IsPlayer( touch_entity ) then local player = CastToPlayer( touch_entity ) if player:GetTeamId() == Team.kRed then BroadCastMessageToPlayer( player, "You need to capture Command Point ".. self.cp .." before you can use this respawn!" ) else BroadCastMessageToPlayer( player, "Your team cannot use this respawn." ) end end end -- Spawn Doors (actual entities with command point condition attached) bluerespawn_cp2 = blue_respawn_door:new({cp=2}) bluerespawn_cp3 = blue_respawn_door:new({cp=3}) bluerespawn_cp4 = blue_respawn_door:new({cp=4}) redrespawn_cp2 = red_respawn_door:new({cp=2}) redrespawn_cp3 = red_respawn_door:new({cp=3}) redrespawn_cp4 = red_respawn_door:new({cp=4})
Downloads
- Source .vmf (Includes .vmf of an example map, the Lua Script, and a custom HUD graphic used):