--------------------------------------- -- CAPTURE_THE_FLAG GAMEPLAY MODE 0.5 -- by mikade --------------------------------------- -- Version History --------- -- 0.1 --------- -- [conversion from map-dependant CTF_Blizzard to map independant Capture the Flag] -- added an intial starting stage where flagspawn is decided by the players (weapon set will require a jetpack unless I set) -- changed the flag from a crate to a visual gear, and all associated methods and checks relating to flags (five hours later, lol) -- changed starting/respawning positioning to accommodate different map sizes -- added another circle to mark flag spawn -- added gameFlag filter -- changed scoring feedback -- cleaned up some code -- removing own flag from spawning point no longer possible -- destroying flags no longer possible. -- added basic glowing circle effect to spawn area -- added expanding circle to fgear itself -- removed teleporters -- removed random crate drops (this should be decided by scheme) -- removed set map criteria like minesNum, turnTime, explosives etc. except for sudden death -- removed weapon defintions -- removed placement and respawning methods, hopefully divideTeams will have this covered --------- -- 0.2 --------- -- [now with user friendliness] -- flag is now placed wherever you end up at the end of your first turn, this ensures that it is always placed by turn 3 -- removed a bunch of backup code and no-longer needed variables / methods from CTF_Blizzard days -- removed an aura that was still mistakenly hanging about -- added an in-game note about placements -- added an in-game note about the rules of the game -- added translation support and loc()'ed everything -- changed things so the seed is no longer always the same... -- In this version: --------- -- 0.3 --------- -- [fufufufu kamikaze fix] -- added nill checks to make sure the player doesn't generate errors by producing a nil value in hhs[] when he uses kamikaze -- added a check to make sure the player doesn't kamikaze straight down and make the flag's starting point underwater -- added a check to make sure the player drops the flag if he has it and he uses kamikaze -------- -- 0.4 -------- -- remove user-branding and version numbers -- removed some stuff that wasn't needed -- fix piano strike exploit -- changed delay to allow for better portals -- changed starting feedback a little -- increased the radius around the circle indicating the flag thief so that it doesn't obscure his health -------- -- 0.5 -------- -- add support for more players -- allow limited sudden death -- stop TimeBox ruining my life -- profit??? ----------------- --SCRIPT BEGINS ----------------- -- enable awesome translaction support so we can use loc() wherever we want HedgewarsScriptLoad("/Scripts/Locale.lua") --------------------------------------------------------------- ----------lots of bad variables and things ----------because someone is too lazy ----------to read about tables properly ------------------ "Oh well, they probably have the memory" local gameStarted = false local gameTurns = 0 -------------------------- -- hog and team tracking variales -------------------------- local numhhs = 0 -- store number of hedgehogs local hhs = {} -- store hedgehog gears local numTeams -- store the number of teams in the game local teamNameArr = {} -- store the list of teams local teamSize = {} -- store how many hogs per team local teamIndex = {} -- at what point in the hhs{} does each team begin ------------------- -- flag variables ------------------- local fPlaced = {} -- has the flag been placed TRUE/FALSE local fGear = {} -- pointer to the visual gears that represent the flag local fGearX = {} local fGearY = {} local fThief = {} -- pointer to the hogs who stole the flags local fIsMissing = {} -- have the flags been destroyed or captured local fNeedsRespawn = {} -- do the flags need to be respawned local fCaptures = {} -- the team "scores" how many captures local fSpawnX = {} -- spawn X for flags local fSpawnY = {} -- spawn Y for flags local fThiefX = {} local fThiefY = {} local FTTC = 0 -- flag thief tracker counter local fSpawnC = {} -- spawn circle marker local fCirc = {} -- flag/carrier marker circles local fCol = {} -- colour of the clans local fGearRad = 0 local fGearRadMin = 5 local fGearRadMax = 33 local fGearTimer = 0 ------------------------ --flag methods ------------------------ function CheckScore(teamID) if teamID == 0 then alt = 1 elseif teamID == 1 then alt = 0 end if fCaptures[teamID] == 3 then for i = 0, (numhhs-1) do if hhs[i] ~= nil then if GetHogClan(hhs[i]) == alt then SetEffect(hhs[i], heResurrectable, 0) SetHealth(hhs[i],0) end end end if CurrentHedgehog ~= nil then ShowMission(loc("GAME OVER!"), loc("Victory for the ") .. GetHogTeamName(CurrentHedgehog), loc("Hooray!"), 0, 0) end end end function DoFlagStuff(gear) if (gear == fGear[0]) then wtf = 0 bbq = 1 elseif (gear == fGear[1]) then wtf = 1 bbq = 0 end -- player has successfully captured the enemy flag if (GetHogClan(CurrentHedgehog) == wtf) and (CurrentHedgehog == fThief[bbq]) and (fIsMissing[wtf] == false) then DeleteVisualGear(fGear[wtf]) fGear[wtf] = nil -- the flag has now disappeared fIsMissing[wtf] = false fNeedsRespawn[wtf] = true fIsMissing[bbq] = false fNeedsRespawn[bbq] = true fCaptures[wtf] = fCaptures[wtf] +1 ShowMission(loc("You have SCORED!!"), GetHogTeamName(CurrentHedgehog) .. ": " .. fCaptures[wtf], loc("Opposing Team: ") .. fCaptures[bbq], 0, 0) PlaySound(sndVictory) fThief[bbq] = nil -- player no longer has the enemy flag CheckScore(wtf) --if the player is returning the flag elseif (GetHogClan(CurrentHedgehog) == wtf) and (fIsMissing[wtf] == true) then DeleteVisualGear(fGear[wtf]) fGear[wtf] = nil -- the flag has now disappeared fNeedsRespawn[wtf] = true HandleRespawns() -- this will set fIsMissing[wtf] to false :) AddCaption(loc("Flag returned!")) --if the player is taking the enemy flag elseif GetHogClan(CurrentHedgehog) == bbq then DeleteVisualGear(fGear[wtf]) fGear[wtf] = nil -- the flag has now disappeared fIsMissing[wtf] = true for i = 0,numhhs-1 do if CurrentHedgehog ~= nil then if CurrentHedgehog == hhs[i] then fThief[wtf] = hhs[i] end end end AddCaption(loc("Flag captured!")) end end function CheckFlagProximity() for i = 0, 1 do if fGear[i] ~= nil then g1X = fGearX[i] g1Y = fGearY[i] g2X, g2Y = GetGearPosition(CurrentHedgehog) q = g1X - g2X w = g1Y - g2Y dist = (q*q) + (w*w) if dist < 500 then --1600 DoFlagStuff(fGear[i]) end end end end function HandleRespawns() for i = 0, 1 do if fNeedsRespawn[i] == true then fGear[i] = AddVisualGear(fSpawnX[i],fSpawnY[i],vgtCircle,0,true) fGearX[i] = fSpawnX[i] fGearY[i] = fSpawnY[i] fNeedsRespawn[i] = false fIsMissing[i] = false -- new, this should solve problems of a respawned flag being "returned" when a player tries to score AddCaption(loc("Flag respawned!")) end end end function FlagThiefDead(gear) if (gear == fThief[0]) then wtf = 0 bbq = 1 elseif (gear == fThief[1]) then wtf = 1 bbq = 0 end if fThief[wtf] ~= nil then -- falls into water --ShowMission(LAND_HEIGHT, fThiefY[wtf], (LAND_HEIGHT - fThiefY[wtf]), 0, 0) if (LAND_HEIGHT - fThiefY[wtf]) < 15 then fIsMissing[wtf] = true fNeedsRespawn[wtf] = true HandleRespawns() else --normally fGearX[wtf] = fThiefX[wtf] fGearY[wtf] = fThiefY[wtf] fGear[wtf] = AddVisualGear(fGearX[wtf],fGearY[wtf],vgtCircle,0,true) end AddVisualGear(fThiefX[wtf], fThiefY[wtf], vgtBigExplosion, 0, false) fThief[wtf] = nil end end function HandleCircles() fGearTimer = fGearTimer + 1 if fGearTimer == 50 then fGearTimer = 0 fGearRad = fGearRad + 1 if fGearRad > fGearRadMax then fGearRad = fGearRadMin end end for i = 0, 1 do --SetVisualGearValues(fSpawnC[i], fSpawnX[i],fSpawnY[i], 20, 200, 0, 0, 100, 50, 3, fCol[i]) -- draw a circ for spawning area if fIsMissing[i] == false then -- draw a flag marker at the flag's spawning place SetVisualGearValues(fCirc[i], fSpawnX[i],fSpawnY[i], 20, 20, 0, 10, 0, 33, 3, fCol[i]) if fGear[i] ~= nil then -- draw the flag gear itself SetVisualGearValues(fGear[i], fSpawnX[i],fSpawnY[i], 20, 200, 0, 0, 100, fGearRad, 2, fCol[i]) end elseif (fIsMissing[i] == true) and (fNeedsRespawn[i] == false) then if fThief[i] ~= nil then -- draw circle round flag carrier -- 33 SetVisualGearValues(fCirc[i], fThiefX[i], fThiefY[i], 20, 200, 0, 0, 100, 50, 3, fCol[i]) --AddCaption("circle marking carrier") elseif fThief[i] == nil then -- draw cirle round dropped flag --g1X,g1Y,g4,g5,g6,g7,g8,g9,g10,g11 = GetVisualGearValues(fGear[i]) --SetVisualGearValues(fCirc[i], g1X, g1Y, 20, 200, 0, 0, 100, 33, 2, fCol[i]) SetVisualGearValues(fCirc[i], fGearX[i], fGearY[i], 20, 200, 0, 0, 100, 33, 3, fCol[i]) --AddCaption('dropped circle marker') if fGear[i] ~= nil then -- flag gear itself --SetVisualGearValues(fGear[i], g1X, g1Y, 20, 200, 0, 0, 100, 10, 4, fCol[i]) SetVisualGearValues(fGear[i], fGearX[i], fGearY[i], 20, 200, 0, 0, 100, fGearRad, 2, fCol[i]) --AddCaption('dropped flag itself') end end end if fNeedsRespawn[i] == true then -- if the flag has been destroyed, no need for a circle SetVisualGearValues(fCirc[i], fSpawnX[i],fSpawnY[i], 20, 200, 0, 0, 100, 0, 0, fCol[i]) --AddCaption("needs respawn = true. flag 'destroyed'?") end end end ------------------------ -- general methods ------------------------ function CheckDistance(gear1, gear2) g1X, g1Y = GetGearPosition(gear1) g2X, g2Y = GetGearPosition(gear2) g1X = g1X - g2X g1Y = g1Y - g2Y z = (g1X*g1X) + (g1Y*g1Y) dist = z return dist end function RebuildTeamInfo() -- make a list of individual team names for i = 0, (TeamsCount-1) do teamNameArr[i] = i teamSize[i] = 0 teamIndex[i] = 0 end numTeams = 0 for i = 0, (numhhs-1) do z = 0 unfinished = true while(unfinished == true) do newTeam = true tempHogTeamName = GetHogTeamName(hhs[i]) -- this is the new name if tempHogTeamName == teamNameArr[z] then newTeam = false unfinished = false end z = z + 1 if z == TeamsCount then unfinished = false if newTeam == true then teamNameArr[numTeams] = tempHogTeamName numTeams = numTeams + 1 end end end end -- find out how many hogs per team, and the index of the first hog in hhs for i = 0, numTeams-1 do for z = 0, numhhs-1 do if GetHogTeamName(hhs[z]) == teamNameArr[i] then if teamSize[i] == 0 then teamIndex[i] = z -- should give starting index end teamSize[i] = teamSize[i] + 1 --add a pointer so this hog appears at i in hhs end end end end function StartTheGame() gameStarted = true AddCaption(loc("Game Started!")) for i = 0, 1 do -- if someone uses kamikaze downwards, this can happen as the hog won't respawn if (LAND_HEIGHT - fSpawnY[i]) < 0 then tempG = AddGear(0, 0, gtTarget, 0, 0, 0, 0) FindPlace(tempG, true, 0, LAND_WIDTH, true) fSpawnX[i], fSpawnY[i] = GetGearPosition(tempG) DeleteGear(tempG) end fGear[i] = AddVisualGear(fSpawnX[i],fSpawnY[i],vgtCircle,0,true) fCirc[i] = AddVisualGear(fSpawnX[i],fSpawnY[i],vgtCircle,0,true) fSpawnC[i] = AddVisualGear(fSpawnX[i],fSpawnY[i],vgtCircle,0,true) fGearX[i] = fSpawnX[i] fGearY[i] = fSpawnY[i] fCol[i] = GetClanColor(i) fIsMissing[i] = false fNeedsRespawn[i] = false fCaptures[i] = 0 --SetVisualGearValues(zxc, 1000,1000, 20, 100, 0, 10, 1, 100, 5, GetClanColor(0)) SetVisualGearValues(fSpawnC[i], fSpawnX[i],fSpawnY[i], 20, 100, 0, 10, 0, 75, 5, fCol[i]) end end ------------------------ -- game methods ------------------------ function onGameInit() DisableGameFlags(gfKing, gfForts) EnableGameFlags(gfDivideTeams) --SuddenDeathTurns = 999 -- suddendeath is off, effectively WaterRise = 0 Delay = 10 end function onGameStart() --ShowMission(loc(caption), loc(subcaption), loc(goal), 0, 0) ShowMission(loc("CAPTURE THE FLAG"), loc("Flags, and their home base will be placed where each team ends their first turn."), "", 0, 0) RebuildTeamInfo() -- should gfDivideTeams do this automatically? --[[for i = 0, (TeamsCount-1) do for g = teamIndex[i], (teamIndex[i]+teamSize[i]-1) do if GetHogClan(hhs[g]) == 0 then FindPlace(hhs[g], false, 0, LAND_WIDTH/2) elseif GetHogClan(hhs[g]) == 1 then FindPlace(hhs[g], false, LAND_WIDTH/2, LAND_WIDTH) end end end]] fPlaced[0] = false fPlaced[1] = false --zxc = AddVisualGear(fSpawnX[i],fSpawnY[i],vgtCircle,0,true) --SetVisualGearValues(zxc, 1000,1000, 20, 255, 1, 10, 0, 200, 1, GetClanColor(0)) --minO,max0 -glowyornot --pulsate timer -- fuckall -- radius -- width -- colour end function onNewTurn() gameTurns = gameTurns + 1 if lastTeam ~= GetHogTeamName(CurrentHedgehog) then lastTeam = GetHogTeamName(CurrentHedgehog) end --AddCaption("Handling respawns") if gameStarted == true then HandleRespawns() --new method of placing starting flags elseif gameTurns == 1 then ShowMission(loc("CAPTURE THE FLAG"), loc("Flags, and their home base will be placed where each team ends their first turn."), "", 0, 0) elseif gameTurns == 2 then fPlaced[0] = true ShowMission(loc("CAPTURE THE FLAG"), loc("RULES OF THE GAME [Press ESC to view]"), loc(" - Return the enemy flag to your base to score | - First team to 3 captures wins | - You may only score when your flag is in your base | - Hogs will drop the flag if killed, or drowned | - Dropped flags may be returned or recaptured | - Hogs respawn when killed"), 0, 0) elseif gameTurns == 3 then fPlaced[1] = true StartTheGame() end end function onGameTick() -- onRessurect calls AFTER you have resurrected, -- so keeping track of x,y a few milliseconds before -- is useful --FTTC = FTTC + 1 --if FTTC == 100 then -- FTTC = 0 for i = 0,1 do if fThief[i] ~= nil then fThiefX[i] = GetX(fThief[i]) fThiefY[i] = GetY(fThief[i]) end end --end -- things we wanna check often if (CurrentHedgehog ~= nil) then --AddCaption(LAND_HEIGHT - GetY(CurrentHedgehog)) --AddCaption(GetX(CurrentHedgehog) .. "; " .. GetY(CurrentHedgehog)) --CheckTeleporters() end if gameStarted == true then HandleCircles() if CurrentHedgehog ~= nil then CheckFlagProximity() end elseif CurrentHedgehog ~= nil then -- if the game hasn't started yet, keep track of where we are gonna put the flags on turn end if GetHogClan(CurrentHedgehog) == 0 then i = 0 elseif GetHogClan(CurrentHedgehog) == 1 then i = 1 end fSpawnX[i] = GetX(CurrentHedgehog) fSpawnY[i] = GetY(CurrentHedgehog) end end function onGearResurrect(gear) --AddCaption("A gear has been resurrected!") -- mark the flag thief as dead if he needed a respawn for i = 0,1 do if gear == fThief[i] then FlagThiefDead(gear) end end -- should be covered by gfDivideTeams, actually -- place hogs belonging to each clan either left or right side of map --if GetHogClan(gear) == 0 then -- FindPlace(gear, false, 0, LAND_WIDTH/2) --elseif GetHogClan(gear) == 1 then -- FindPlace(gear, false, LAND_WIDTH/2, LAND_WIDTH) --end AddVisualGear(GetX(gear), GetY(gear), vgtBigExplosion, 0, false) end function InABetterPlaceNow(gear) for i = 0, (numhhs-1) do if gear == hhs[i] then for i = 0,1 do if gear == fThief[i] then FlagThiefDead(gear) end end hhs[i] = nil end end end function onHogHide(gear) InABetterPlaceNow(gear) end function onHogRestore(gear) match = false for i = 0, (numhhs-1) do if (hhs[i] == nil) and (match == false) then hhs[i] = gear --AddCaption(GetHogName(gear) .. " has reappeared it seems!") match = true end end end function onGearAdd(gear) if GetGearType(gear) == gtHedgehog then hhs[numhhs] = gear numhhs = numhhs + 1 SetEffect(gear, heResurrectable, 1) elseif GetGearType(gear) == gtPiano then for i = 0, 1 do if CurrentHedgehog == fThief[i] then FlagThiefDead(gear) end end end end function onGearDelete(gear) if GetGearType(gear) == gtHedgehog then InABetterPlaceNow(gear) end end