Racer: Fix weird water splashes after waypoint placement
Does not affect official racer, as only waypoint placement is touched.
The reason was that the air attack gear sometimes was not deleted fast enough so it might occassionally drop some air bombs (these are deleted now). Also, the airplane position was set to water level, which caused another water splash.
---------------------------------------
-- CAPTURE_THE_FLAG GAMEPLAY MODE 0.5
-- by mikade
---------------------------------------
---- Script parameter
-- With “captures=<number>” you can set your own capture limit, e.g. “captures=5” for 5 captures.
-- 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")
HedgewarsScriptLoad("/Scripts/Params.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 gameOver = false
local winningClan = -1
local captureLimit = 3
--------------------------
-- hog and team tracking variales
--------------------------
local numhhs = 0 -- store number of hedgehogs
local hhs = {} -- store hedgehog gears
local teamSize = {} -- store how many hogs per team
local teamIndex = {} -- at what point in the hhs{} does each team begin
local mostCapturesHogName = nil -- name of hog who holds the record of most flags captured
local mostCapturesHogTeam = nil -- name of team who holds the record of most flags captured
local mostCaptures = 0 -- number of most per-hog captures
local capturesPerHog = {}
-------------------
-- flag variables
-------------------
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 fThiefFlag = {} -- contains the stolen flag type of fThief
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 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
------------------------
local RankTeams = function(teamList)
local teamRank = function(a, b)
if a.score ~= b.score then
return a.score > b.score
else
return a.clan > b.clan
end
end
table.sort(teamList, teamRank)
local rank, plusRank, score, clan
for i=1, #teamList do
if i == 1 then
rank = 1
plusRank = 1
score = teamList[i].score
clan = teamList[i].clan
end
if (teamList[i].score < score) then
rank = rank + plusRank
plusRank = 1
end
if (teamList[i].score == score and teamList[i].clan ~= clan) then
plusRank = plusRank + 1
end
teamList[i].rank = rank
score = teamList[i].score
clan = teamList[i].clan
end
for i=1, #teamList do
SendStat(siPointType, "!POINTS")
SendStat(siTeamRank, tostring(teamList[i].rank))
SendStat(siPlayerKills, tostring(teamList[i].score), teamList[i].name)
end
end
function CheckScore(clanID)
if fCaptures[clanID] == captureLimit then
gameOver = true
winningClan = clanID
-- Capture limit reached! We have a winner!
for i = 0, (numhhs-1) do
if hhs[i] ~= nil then
-- Kill all losers
if GetHogClan(hhs[i]) ~= winningClan then
SetEffect(hhs[i], heResurrectable, 0)
SetHealth(hhs[i],0)
end
end
end
if CurrentHedgehog ~= nil then
AddCaption(string.format(loc("Victory for %s!"), GetHogTeamName(CurrentHedgehog)), capcolDefault, capgrpGameState)
updateScores()
end
-- Calculate team rankings
local teamList = {}
for i=0, TeamsCount-1 do
local name = GetTeamName(i)
local clan = GetTeamClan(name)
table.insert(teamList, { score = fCaptures[clan], name = name, clan = clan })
end
RankTeams(teamList)
if mostCaptures >= 2 then
SendStat(siCustomAchievement, string.format(loc("%s (%s) has captured the flag %d times."), mostCapturesHogName, mostCapturesHogTeam, mostCaptures))
end
end
end
function DoFlagStuff(flag, flagClan)
if not CurrentHedgehog then
return
end
local wtf = flagClan
local thiefClan
for i=0, ClansCount - 1 do
if CurrentHedgehog == fThief[i] then
thiefClan = i
end
end
-- player has successfully captured the enemy flag
if (GetHogClan(CurrentHedgehog) == flagClan) and (thiefClan ~= nil) and (fIsMissing[flagClan] == false) then
fIsMissing[thiefClan] = false
fNeedsRespawn[thiefClan] = true
fCaptures[flagClan] = fCaptures[flagClan] +1
AddCaption(string.format(loc("%s has scored!"), GetHogName(CurrentHedgehog)), capcolDefault, capgrpGameState)
updateScores()
PlaySound(sndHomerun)
fThief[thiefClan] = nil -- player no longer has the enemy flag
fThiefFlag[flagClan] = nil
capturesPerHog[CurrentHedgehog] = capturesPerHog[CurrentHedgehog] + 1
if capturesPerHog[CurrentHedgehog] > mostCaptures then
mostCaptures = capturesPerHog[CurrentHedgehog]
mostCapturesHogName = GetHogName(CurrentHedgehog)
mostCapturesHogTeam = GetHogTeamName(CurrentHedgehog)
end
CheckScore(flagClan)
--if the player is returning the flag
elseif (GetHogClan(CurrentHedgehog) == flagClan) and (fIsMissing[flagClan] == true) then
DeleteVisualGear(fGear[flagClan])
fGear[flagClan] = nil -- the flag has now disappeared
fNeedsRespawn[flagClan] = true
HandleRespawns() -- this will set fIsMissing[flagClan] to false :)
AddCaption(loc("Flag returned!"), capcolDefault, capgrpMessage2)
--if the player is taking the enemy flag (not possible if already holding a flag)
elseif GetHogClan(CurrentHedgehog) ~= flagClan and (thiefClan == nil) then
DeleteVisualGear(fGear[flagClan])
fGear[flagClan] = nil -- the flag has now disappeared
fIsMissing[flagClan] = true
for i = 0,numhhs-1 do
if CurrentHedgehog ~= nil then
if CurrentHedgehog == hhs[i] then
fThief[flagClan] = hhs[i]
fThiefFlag[flagClan] = flagClan
end
end
end
AddCaption(loc("Flag captured!"), capcolDefault, capgrpMessage2)
end
end
function CheckFlagProximity()
for i = 0, ClansCount-1 do
if fGear[i] ~= nil then
local g1X = fGearX[i]
local g1Y = fGearY[i]
local g2X, g2Y = GetGearPosition(CurrentHedgehog)
local q = g1X - g2X
local w = g1Y - g2Y
local dist = (q*q) + (w*w)
if dist < 500 then
DoFlagStuff(fGear[i], i)
end
end
end
end
function HandleRespawns()
for i = 0, ClansCount-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!"), capcolDefault, capgrpMessage2)
end
end
end
-- Advance the clan score graph by one step
function DrawScores()
local clansUsed = {}
for i=0, TeamsCount-1 do
local team = GetTeamName(i)
local clan = GetTeamClan(team)
if not clansUsed[clan] then
local captures = fCaptures[clan]
SendStat(siClanHealth, captures, team)
clansUsed[clan] = true
end
end
end
function FlagThiefDead(gear)
local thiefClan
local stolenFlagClan
for i=0, ClansCount-1 do
if (gear == fThief[i]) then
thiefClan = i
stolenFlagClan = fThiefFlag[i]
break
end
end
if stolenFlagClan ~= nil then
-- falls into water
if (LAND_HEIGHT - fThiefY[thiefClan]) < 15 then
fIsMissing[stolenFlagClan] = true
fNeedsRespawn[stolenFlagClan] = true
HandleRespawns()
else --normally
fGearX[stolenFlagClan] = fThiefX[thiefClan]
fGearY[stolenFlagClan] = fThiefY[thiefClan]
fGear[stolenFlagClan] = AddVisualGear(fGearX[stolenFlagClan], fGearY[stolenFlagClan], vgtCircle, 0, true)
end
AddVisualGear(fThiefX[thiefClan], fThiefY[thiefClan], vgtBigExplosion, 0, false)
fThief[thiefClan] = 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, ClansCount-1 do
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])
elseif fThief[i] == nil then -- draw cirle round dropped flag
SetVisualGearValues(fCirc[i], fGearX[i], fGearY[i], 20, 200, 0, 0, 100, 33, 3, fCol[i])
if fGear[i] ~= nil then -- flag gear itself
SetVisualGearValues(fGear[i], fGearX[i], fGearY[i], 20, 200, 0, 0, 100, fGearRad, 2, fCol[i])
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])
end
end
end
------------------------
-- general methods
------------------------
function CheckDistance(gear1, gear2)
local g1X, g1Y = GetGearPosition(gear1)
local g2X, g2Y = GetGearPosition(gear2)
g1X = g1X - g2X
g1Y = g1Y - g2Y
local dist = (g1X*g1X) + (g1Y*g1Y)
return dist
end
function RebuildTeamInfo()
-- make a list of teams
for i = 0, (TeamsCount-1) do
teamSize[i] = 0
teamIndex[i] = 0
end
-- find out how many hogs per team, and the index of the first hog in hhs
for i = 0, (TeamsCount-1) do
for z = 0, numhhs-1 do
if GetHogTeamName(hhs[z]) == GetTeamName(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!"), capcolDefault, capgrpGameState)
for i = 0, ClansCount-1 do
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(fSpawnC[i], fSpawnX[i],fSpawnY[i], 20, 100, 0, 10, 0, 75, 5, fCol[i])
end
end
------------------------
-- game methods
------------------------
function onParameters()
parseParams()
if params["captures"] ~= nil then
local s = string.match(params["captures"], "(%d*)")
if s ~= nil then
captureLimit = math.max(1, tonumber(s))
end
end
end
function onGameInit()
DisableGameFlags(gfKing, gfAISurvival)
EnableGameFlags(gfDivideTeams)
-- Disable Sudden Death
WaterRise = 0
HealthDecrease = 0
end
function showCTFMission()
local captures
if captureLimit == 1 then
captures = string.format(loc("- First clan to capture the flag wins"), captureLimit)
else
captures = string.format(loc("- First clan to score %d captures wins"), captureLimit)
end
local rules = loc("Rules:") .. "|" ..
loc("- Place your clan flag at the end of your first turn") .. "|" ..
loc("- Return the enemy flag to your base to score") .."|"..
captures .. "|" ..
loc("- You may only score when your flag is in your base") .."|"..
loc("- Hogs will drop the flag when killed") .."|"..
loc("- Dropped flags may be returned or recaptured").."|"..
loc("- Hogs will be revived")
ShowMission(loc("Capture The Flag"), loc("A Hedgewars minigame"), rules, 11, 0)
end
function updateScores()
for i=0, TeamsCount-1 do
local team = GetTeamName(i)
local clan = GetTeamClan(team)
SetTeamLabel(team, tostring(fCaptures[clan]))
end
end
function onGameStart()
showCTFMission()
RebuildTeamInfo()
for i=0, ClansCount-1 do
fCaptures[i] = 0
end
for h=0, numhhs-1 do
-- Hogs are resurrected for free, so this is pointless
AddAmmo(hhs[h], amResurrector, 0)
-- Remove suicidal weapons as they might wipe out the team
AddAmmo(hhs[h], amKamikaze, 0)
AddAmmo(hhs[h], amPiano, 0)
end
updateScores()
SendStat(siGraphTitle, loc("Score graph"))
SendHealthStatsOff()
SendRankingStatsOff()
end
function onNewTurn()
if gameStarted == true and not gameOver then
HandleRespawns()
end
local flagsPlaced = 0
for i=0, ClansCount-1 do
if fSpawnX[i] and fSpawnY[i] then
flagsPlaced = flagsPlaced + 1
end
end
if not gameStarted and flagsPlaced == ClansCount then
StartTheGame()
end
end
function onEndTurn()
-- if the game hasn't started yet, keep track of where we are gonna put the flags on turn end
if not gameStarted and CurrentHedgehog ~= nil then
local clan = GetHogClan(CurrentHedgehog)
if GetX(CurrentHedgehog) and not fSpawnX[clan] then
fSpawnX[clan] = GetX(CurrentHedgehog)
fSpawnY[clan] = GetY(CurrentHedgehog)
end
end
if gameStarted == true then
DrawScores()
end
end
function onGameTick()
for i = 0, ClansCount-1 do
if fThief[i] ~= nil then
fThiefX[i] = GetX(fThief[i])
fThiefY[i] = GetY(fThief[i])
end
end
if gameStarted == true and not gameOver then
HandleCircles()
if CurrentHedgehog ~= nil then
CheckFlagProximity()
end
end
end
function onGearResurrect(gear)
if GetGearType(gear) == gtHedgehog then
-- mark the flag thief as dead if he needed a respawn
for i = 0, ClansCount-1 do
if gear == fThief[i] then
FlagThiefDead(gear)
end
end
end
end
function InABetterPlaceNow(gear)
for h = 0, (numhhs-1) do
if gear == hhs[h] then
for i = 0, ClansCount-1 do
if gear == fThief[i] then
FlagThiefDead(gear)
end
end
hhs[h] = nil
end
end
end
function onHogHide(gear)
InABetterPlaceNow(gear)
end
function onHogRestore(gear)
for i = 0, (numhhs-1) do
if (hhs[i] == nil) then
hhs[i] = gear
break
end
end
if gameOver and GetHogClan(gear) ~= winningClan then
SetEffect(gear, heResurrectable, 0)
SetHealth(gear, 0)
end
end
function onHogAttack(ammoType)
if not gameStarted and ammoType == amTardis then
local i = GetHogClan(CurrentHedgehog)
fSpawnX[i] = GetX(CurrentHedgehog)
fSpawnY[i] = GetY(CurrentHedgehog)
end
end
function onGearAdd(gear)
if GetGearType(gear) == gtHedgehog then
hhs[numhhs] = gear
capturesPerHog[gear] = 0
numhhs = numhhs + 1
SetEffect(gear, heResurrectable, 1)
elseif GetGearType(gear) == gtPiano then
for i = 0, ClansCount-1 do
if CurrentHedgehog == fThief[i] then
FlagThiefDead(CurrentHedgehog)
end
end
end
end
function onGearDelete(gear)
if GetGearType(gear) == gtHedgehog then
InABetterPlaceNow(gear)
elseif GetGearType(gear) == gtKamikaze and not gameStarted then
local i = GetHogClan(CurrentHedgehog)
if i <= 1 then
fSpawnX[i] = GetX(CurrentHedgehog)
fSpawnY[i] = GetY(CurrentHedgehog)
end
end
end