-------------------------------
-- CTF_BLIZZARD 0.9
--------------------------------
---------
-- 0.2
---------
-- disabled super weapons
-- theme modifications
-- improved hog placement system: teams can now be put
-- in any order and be of any size
---------
-- 0.3
---------
-- In this version:
-- changed starting weapons
-- changed crate drop contents and rate of drops
-- completely removed super weapons and super weapon scripts
-- removed custom respawning
-- removed set respawn points
-- added AIRespawn-esque respawning
-- added simple left vs right respawn points
-- added non-lethal poison to flag carriers as an indicator
-- improved flag mechanics and player-flag feedback
-- flag now instantly respawns if you kill enemy hog and return it,
-- or if the flag falls in water, _BUT_ not if it is blown up
---------
-- 0.4
---------
-- tweaked crate drop rates and crate contents
-- improved the teleporters, they should now be able to handle rope... hopefully
-- updated SetEffect calls to be in line with 0.9.15 definitions
-- added visual gears when hogs respawn
-- added visual gears when hogs teleport
-- added visual gear to track flag and flag carriers
-- removed poisoning of flag carriers
-- removed health adjustments for flag carriers due to aforementioned poisons
---------
-- 0.5
---------
-- added translation support, hopefully
-- added ctf rules
-- added effects to the teleporters
-- added aura round spawning area
-- changed the aura around the flag carrier / flag to an aura and added some support for this
-- changed things so the seed is no longer always the same...
---------
-- 0.6
---------
-- removed branding and version number
-- removed teleport from starting weapons
-- increased captures to 3
------------
-- 0.7
------------
-- hopefully fixed a bug with the teleporters
-- added a fix for crate possibly getting imbedded in land when it was near the water line
------------
-- 0.8
------------
-- fixed version control fail with missing check on onGearDelete
-- changed hog placements code so that they start in the same place for both teams
-- and hogs move in the same order, not backwards to each other.
-----------
-- 0.9
------------
-- add support for more players
-- re-enable sudden death, but set water rise to 0
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 actionReset = 0 -- used in CheckTeleporters()
local roundsCounter = 0 -- used to determine when to spawn more crates
-- currently every 6 TURNS, should this work
-- on ROUNDS instead?
local effectTimer = 0
local gameEnded = false
local ropeGear = nil
--------------------------
-- hog and team tracking variales
--------------------------
local numhhs = 0 -- store number of hedgehogs
local hhs = {} -- store hedgehog gears
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
local clanTeams = {} -- list of teams per clan
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 case gears that represent the flag
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 fSpawnC = {}
local fCirc = {} -- flag/carrier marker circles
local fCol = {} -- colour of the clans
local vCircX = {}
local vCircY = {}
local vCircMinA = {}
local vCircMaxA = {}
local vCircType = {}
local vCircPulse = {}
local vCircFuckAll = {}
local vCircRadius = {}
local vCircWidth = {}
local vCircCol = {}
--------------------------------
--zone and teleporter variables
--------------------------------
local leftTel
local rightTel
local zXMin = {}
local zWidth = {}
local zYMin = {}
local zHeight = {}
local zOccupied = {}
local zCount = 0
------------------------
-- zone methods
------------------------
-- see on gameTick also
function ManageTeleporterEffects()
effectTimer = effectTimer + 1
if effectTimer > 50 then
effectTimer = 0
local i = GetHogClan(CurrentHedgehog)
if i ~= 0 and i ~= 1 then
return
end
local eX = 10 + zXMin[i] + GetRandom(zWidth[i]-10)
local eY = 50 + zYMin[i] + GetRandom(zHeight[i]-110)
-- steam and smoke and DUST look good, smokering looks trippy
-- smoketrace and eviltrace are not effected by wind?
-- chunk is a LR falling gear
local tempE = AddVisualGear(eX, eY, vgtDust, 0, false)
SetVisualGearValues(tempE, eX, eY, nil, nil, nil, nil, nil, nil, nil, fCol[i])
end
end
function CreateZone(xMin, yMin, width, height)
zXMin[zCount] = xMin
zYMin[zCount] = yMin
zWidth[zCount] = width
zHeight[zCount] = height
zOccupied[zCount] = false
zCount = zCount + 1
return (zCount-1)
end
function GearIsInZone(gear, zI)
if (GetX(gear) > zXMin[zI]) and (GetX(gear) < (zXMin[zI]+zWidth[zI])) and (GetY(gear) > zYMin[zI]) and (GetY(gear) < (zYMin[zI]+zHeight[zI])) then
zOccupied[zI] = true
else
zOccupied[zI] = false
end
return zOccupied[zI]
end
------------------------
--flag methods
------------------------
function CheckScore(teamID)
local alt
if teamID == 0 then
alt = 1
elseif teamID == 1 then
alt = 0
end
if fCaptures[teamID] == 3 and not gameEnded then
gameEnded = true
for i = 0, (numhhs-1) do
if GetHogClan(hhs[i]) == alt then
SetEffect(hhs[i], heResurrectable, 0)
SetHealth(hhs[i],0)
end
end
local victoryMsg = string.format(loc("Victory for %s!"), GetHogTeamName(CurrentHedgehog))
AddCaption(victoryMsg, capcolDefault, capgrpGameState)
-- Calculate team rankings
local teamList = {}
for i=0, TeamsCount-1 do
local name = GetTeamName(i)
local clan = GetTeamClan(name)
if fCaptures[clan] ~= nil then
table.insert(teamList, { score = fCaptures[clan], name = name, clan = clan })
end
end
local teamRank = function(a, b)
return a.score > b.score
end
table.sort(teamList, teamRank)
for i=1, #teamList do
SendStat(siPointType, "!POINTS")
SendStat(siPlayerKills, tostring(teamList[i].score), teamList[i].name)
end
if mostCaptures >= 2 then
SendStat(siCustomAchievement, string.format(loc("%s (%s) has captured the flag %d times."), mostCapturesHogName, mostCapturesHogTeam, mostCaptures))
end
end
end
function HandleRespawns()
for i = 0, 1 do
if fNeedsRespawn[i] == true then
fGear[i] = SpawnFakeAmmoCrate(fSpawnX[i],fSpawnY[i],false,false)
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, capgrpAmmoinfo)
end
end
end
function FlagDeleted(gear)
local wtf, bbq
if (gear == fGear[0]) then
wtf = 0
bbq = 1
elseif (gear == fGear[1]) then
wtf = 1
bbq = 0
end
if CurrentHedgehog ~= nil then
--if the player picks up the flag
if band(GetGearMessage(gear), gmDestroy) ~= 0 then
fGear[wtf] = nil -- the flag has now disappeared and we shouldnt be pointing to it
-- player has successfully captured the enemy flag
if (GetHogClan(CurrentHedgehog) == wtf) and (CurrentHedgehog == fThief[bbq]) and (fIsMissing[wtf] == false) then
PlaySound(sndShotgunReload)
fIsMissing[wtf] = false
fNeedsRespawn[wtf] = true
fIsMissing[bbq] = false
fNeedsRespawn[bbq] = true
fCaptures[wtf] = fCaptures[wtf] +1
AddCaption(string.format(loc("%s has scored!"), GetHogTeamName(CurrentHedgehog)), capcolDefault, capgrpGameState)
for i=1, #clanTeams[wtf] do
SetTeamLabel(clanTeams[wtf][i], fCaptures[wtf])
end
capturesPerHog[CurrentHedgehog] = capturesPerHog[CurrentHedgehog] + 1
if capturesPerHog[CurrentHedgehog] > mostCaptures then
mostCaptures = capturesPerHog[CurrentHedgehog]
mostCapturesHogName = GetHogName(CurrentHedgehog)
mostCapturesHogTeam = GetHogTeamName(CurrentHedgehog)
end
PlaySound(sndHomerun)
fThief[bbq] = nil -- player no longer has the enemy flag
CheckScore(wtf)
--if the player is returning the flag
elseif GetHogClan(CurrentHedgehog) == wtf then
PlaySound(sndShotgunReload)
fNeedsRespawn[wtf] = true
-- NEW ADDIITON, does this work? Should make it possible to return your flag and then score in the same turn
if fIsMissing[wtf] == true then
HandleRespawns() -- this will set fIsMissing[wtf] to false :)
AddCaption(loc("Flag returned!"), capcolDefault, capgrpAmmoinfo)
elseif fIsMissing[wtf] == false then
AddCaption(loc("That was pointless. The flag will respawn next round."))
end
--if the player is taking the enemy flag
elseif GetHogClan(CurrentHedgehog) == bbq then
PlaySound(sndShotgunReload)
fIsMissing[wtf] = true
for i = 0,numhhs-1 do
if CurrentHedgehog == hhs[i] then
fThief[wtf] = hhs[i]
end
end
AddCaption(loc("Flag captured!"))
else --below line doesnt usually get called
AddCaption("Hmm... that wasn't supposed to happen...")
end
-- if flag has been destroyed
else
if GetY(fGear[wtf]) > 2025 then
fGear[wtf] = nil
fIsMissing[wtf] = true
fNeedsRespawn[wtf] = true
HandleRespawns()
else
fGear[wtf] = nil
fIsMissing[wtf] = true
fNeedsRespawn[wtf] = true
AddCaption(loc("Boom!") .. " " .. loc("The flag will respawn next round."))
end
end
-- if flag has been destroyed deep underwater and player is now nil
-- probably only gets called if the flag thief drowns himself
-- otherwise the above one will work fine
else
fGear[wtf] = nil
fIsMissing[wtf] = true
fNeedsRespawn[wtf] = true
AddCaption(loc("The flag will respawn next round."))
end
end
function FlagThiefDead(gear)
local wtf, bbq
if (gear == fThief[0]) then
wtf = 0
bbq = 1
elseif (gear == fThief[1]) then
wtf = 1
bbq = 0
end
if fThief[wtf] ~= nil then
if fThiefY[wtf] > 2040 then
fGear[wtf] = SpawnFakeAmmoCrate(fThiefX[wtf],(fThiefY[wtf]+10),false,false)
else
fGear[wtf] = SpawnFakeAmmoCrate(fThiefX[wtf],(fThiefY[wtf]-50),false,false)
end
AddCaption(string.format(loc("%s has dropped the flag!"), GetHogName(gear)), capcolDefault, capgrpAmmoinfo)
AddVisualGear(fThiefX[wtf], fThiefY[wtf], vgtBigExplosion, 0, false)
fThief[wtf] = nil
end
end
function HandleCircles()
for i = 0, 1 do
if fIsMissing[i] == false then -- draw a circle at the flag's spawning place
SetVisualGearValues(fCirc[i], fSpawnX[i],fSpawnY[i], vCircMinA[i], vCircMaxA[i], vCircType[i], vCircPulse[i], vCircFuckAll[i], vCircRadius[i], vCircWidth[i], vCircCol[i])
elseif (fIsMissing[i] == true) and (fNeedsRespawn[i] == false) then
if fThief[i] ~= nil then -- draw circle round flag carrier
SetVisualGearValues(fCirc[i], fThiefX[i], fThiefY[i], vCircMinA[i], vCircMaxA[i], vCircType[i], vCircPulse[i], vCircFuckAll[i], vCircRadius[i], vCircWidth[i], vCircCol[i])
elseif fThief[i] == nil then -- draw cirle round dropped flag
SetVisualGearValues(fCirc[i], GetX(fGear[i]),GetY(fGear[i]), vCircMinA[i], vCircMaxA[i], vCircType[i], vCircPulse[i], vCircFuckAll[i], vCircRadius[i], vCircWidth[i], vCircCol[i])
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 CheckTeleporters()
local teleportActive = false
if (GearIsInZone(CurrentHedgehog, leftTel) == true) and (GetHogClan(CurrentHedgehog) == 0) then
teleportActive = true
destinationX = 1402
destinationY = 321
elseif (GearIsInZone(CurrentHedgehog, rightTel) == true) and (GetHogClan(CurrentHedgehog) == 1) then
teleportActive = true
destinationX = 2692
destinationY = 321
end
if teleportActive == true then
if actionReset == 0 then
if ropeGear ~= nil then
if GetGearElasticity(ropeGear) ~= 0 then
SetGearMessage(CurrentHedgehog, gmAttack)
end
end
elseif actionReset == 10 then
SetGearMessage(CurrentHedgehog, 0)
elseif actionReset == 20 then
AddVisualGear(GetX(CurrentHedgehog), GetY(CurrentHedgehog), vgtBigExplosion, 0, false)
SetGearPosition(CurrentHedgehog,destinationX,destinationY)
PlaySound(sndWarp)
AddVisualGear(GetX(CurrentHedgehog), GetY(CurrentHedgehog), vgtBigExplosion, 0, false)
end
actionReset = actionReset + 1
if actionReset >= 30 then
actionReset = 0
end
end
end
function RebuildTeamInfo()
-- make a list of individual team names
for i = 0, (TeamsCount-1) do
teamNameArr[i] = GetTeamName(i)
teamSize[i] = 0
teamIndex[i] = 0
SetTeamLabel(teamNameArr[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]) == teamNameArr[i] then
if teamSize[i] == 0 then
teamIndex[i] = z -- should give starting index
end
teamSize[i] = teamSize[i] + 1
local clan = GetHogClan(hhs[z])
-- Also remember the clan to which the team belongs to
if not clanTeams[clan] then
clanTeams[clan] = {}
end
table.insert(clanTeams[clan], teamNameArr[i])
end
end
end
end
function HandleCrateDrops()
roundsCounter = roundsCounter +1
if roundsCounter == 5 then
roundsCounter = 0
r = GetRandom(8)
if r == 0 then
SpawnSupplyCrate(0,0,amSwitch)
elseif r == 1 then
SpawnSupplyCrate(0,0,amTeleport)
elseif r == 2 then
SpawnSupplyCrate(0,0,amJetpack)
elseif r == 3 then
SpawnSupplyCrate(0,0,amExtraTime)
elseif r == 4 then
SpawnSupplyCrate(0,0,amGirder)
elseif r == 5 then
SpawnSupplyCrate(0,0,amDynamite)
elseif r == 6 then
SpawnSupplyCrate(0,0,amFlamethrower)
elseif r == 7 then
SpawnSupplyCrate(0,0,amPortalGun)
end
PlaySound(sndReinforce, CurrentHedgehog)
end
end
------------------------
-- game methods
------------------------
function onGameInit()
-- Things we don't modify here will use their default values.
GameFlags = gfDivideTeams -- Game settings and rules
TurnTime = 30000 -- The time the player has to move each round (in ms)
CaseFreq = 0 -- The frequency of crate drops
MinesNum = 0 -- The number of mines being placed
Explosives = 0 -- The number of explosives being placed
-- Disable Sudden Death
WaterRise = 0
HealthDecrease = 0
Map = "Blizzard" -- The map to be played
Theme = "Snow" -- The theme to be used
SendHealthStatsOff()
SendRankingStatsOff()
end
function onGameStart()
ShowMission(loc("CTF_Blizzard"), loc("Capture The Flag"),
loc("- Return the enemy flag to your base to score") .."|"..
string.format(loc("- First clan to score %d captures wins"), 3) .. "|"..
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") .."|"..
loc("- Touch the sparkles near your base to teleport"), 11, 0)
-- initialize teleporters
leftTel = CreateZone(342,1316,42,449) -- left teleporter (clan 0)
rightTel = CreateZone(3719,1330,45,449) -- right teleporter (clan 1)
--new improved placement schematics aw yeah
RebuildTeamInfo()
local team1Placed = 0
local team2Placed = 0
for i = 0, (TeamsCount-1) do
for g = teamIndex[i], (teamIndex[i]+teamSize[i]-1) do
if GetHogClan(hhs[g]) == 0 then
SetGearPosition(hhs[g],1403+ ((team1Placed+1)*50),1570)
team1Placed = team1Placed +1
if team1Placed > 6 then
team1Placed = 0
end
elseif GetHogClan(hhs[g]) == 1 then
SetGearPosition(hhs[g],2691- ((team2Placed+1)*50),1570)
team2Placed = team2Placed +1
if team2Placed > 6 then
team2Placed = 0
end
end
end
end
--spawn starting ufos and or super weapons
SpawnSupplyCrate(2048,1858,amJetpack)
--set flag spawn points and spawn the flags
fSpawnX[0] = 957
fSpawnY[0] = 1747
fSpawnX[1] = 3123
fSpawnY[1] = 1747
if ClansCount < 2 then
return
end
for i = 0, 1 do
fGear[i] = SpawnFakeAmmoCrate(fSpawnX[i],fSpawnY[i],false,false)
fCirc[i] = AddVisualGear(fSpawnX[i],fSpawnY[i],vgtCircle,0,true)
fCol[i] = GetClanColor(i)
fSpawnC[i] = AddVisualGear(fSpawnX[i],fSpawnY[i],vgtCircle,0,true)
SetVisualGearValues(fSpawnC[i], fSpawnX[i],fSpawnY[i], 10, 200, 1, 10, 0, 300, 5, fCol[i])
fIsMissing[i] = false
fNeedsRespawn[i] = false
fCaptures[i] = 0
vCircMinA[i] = 20
vCircMaxA[i] = 255
vCircType[i] = 1
vCircPulse[i] = 10
vCircFuckAll[i] = 0
vCircRadius[i] = 150
vCircWidth[i] = 5
vCircCol[i] = fCol[i]
SetVisualGearValues(fCirc[i], fSpawnX[i],fSpawnY[i], vCircMinA[i], vCircMaxA[i], vCircType[i], vCircPulse[i], vCircFuckAll[i], vCircRadius[i], vCircWidth[i], vCircCol[i])
end
end
function onNewTurn()
HandleRespawns()
end
function onCaseDrop()
HandleCrateDrops()
end
function onGameTick()
-- onRessurect calls AFTER you have resurrected,
-- so keeping track of x,y a few milliseconds before
-- is useful
for i = 0,1 do
if fThief[i] ~= nil then
fThiefX[i] = GetX(fThief[i])
fThiefY[i] = GetY(fThief[i])
end
end
-- things we wanna check often
if (CurrentHedgehog ~= nil) then
CheckTeleporters()
end
HandleCircles()
if (CurrentHedgehog ~= nil) then
ManageTeleporterEffects()
end
end
function onAmmoStoreInit()
SetAmmo(amDrill,9,0,0,0)
SetAmmo(amMortar,9,0,0,0)
SetAmmo(amGrenade,9,0,0,0)
SetAmmo(amClusterBomb,4,0,0,0)
SetAmmo(amShotgun, 9, 0, 0, 0)
SetAmmo(amFlamethrower, 1, 0, 0, 1)
SetAmmo(amFirePunch, 9, 0, 0, 0)
SetAmmo(amBaseballBat, 2, 0, 0, 0)
SetAmmo(amDynamite,2,0,0,1)
SetAmmo(amSMine,4,0,0,0)
SetAmmo(amBlowTorch, 9, 0, 0, 0)
SetAmmo(amPickHammer, 9, 0, 0, 0)
SetAmmo(amGirder, 2, 0, 0, 2)
SetAmmo(amPortalGun, 2, 0, 0, 2)
SetAmmo(amParachute, 9, 0, 0, 0)
SetAmmo(amRope, 9, 0, 0, 0)
SetAmmo(amTeleport, 0, 0, 0, 1)
SetAmmo(amJetpack, 1, 0, 0, 1)
SetAmmo(amSwitch, 2, 0, 0, 1)
SetAmmo(amExtraTime,1,0,0,1)
SetAmmo(amLowGravity,1,0,0,0)
SetAmmo(amSkip, 9, 0, 0, 0)
end
function onGearResurrect(gear, vGear)
-- 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
-- place hogs belonging to each clan either left or right side of map
if GetHogClan(gear) == 0 then
FindPlace(gear, false, 0, 2048)
elseif GetHogClan(gear) == 1 then
FindPlace(gear, false, 2048, LAND_WIDTH)
end
if vGear then
SetVisualGearValues(vGear, GetX(gear), GetY(gear))
end
end
local excessHogsWarning = false
function onGearAdd(gear)
if GetGearType(gear) == gtHedgehog then
capturesPerHog[gear] = 0
if GetHogClan(gear) > 1 then
DeleteGear(gear)
if not excessHogsWarning then
WriteLnToChat(loc("Only two clans allowed! Excess hedgehogs will be removed."))
excessHogsWarning = true
end
else
hhs[numhhs] = gear
numhhs = numhhs + 1
SetEffect(gear, heResurrectable, 1)
end
elseif GetGearType(gear) == gtRope then
ropeGear = gear
end
end
function onGearDelete(gear)
if (gear == fGear[0]) or (gear == fGear[1]) then
FlagDeleted(gear)
end
if GetGearType(gear) == gtRope then
ropeGear = nil
end
if GetGearType(gear) == gtHedgehog then
for i = 0, (numhhs-1) do
if gear == hhs[i] then
for k = 0,1 do
if gear == fThief[k] then
FlagThiefDead(gear)
end
end
hhs[i] = nil
end
end
end
end