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.
--[[-----------------------------------------------------
-- CONSTRUCTION MODE --
---------------------------------------------------------
A Hedgewars gameplay mode by mikade.
Special thanks to all who helped test and offered suggestions.
Additional thanks to sheepluva/nemo for adding some extra hooks.
---------------------
-- STRUCTURES LIST --
---------------------
* Healing Station: Heals hogs to 150 health
* Teleportation Node: Allows teleporting to any other teleporter nodes
* Bio-filter: Explodes enemy hogs
* Respawner: If you have one of these, any slain hogs are resurrected here
* Generator: Generates power (used to buy stuff)
* Support Station: Allows purchasing crates
* Construction Station: Allows purchasing girders, rubber, mines, sticky mines, barrels
* Reflector Shield: Reflect projectiles
* Weapon Filter: Removes all equipement of enemy hogs passing through this area
---------------------------------------------------------
-- SCRIPT PARAMETER
---------------------------------------------------------
The script parameter can be used to configure the energy
of the game. It is a comma-seperated list of key=value pairs, where each
key is a word and each value is an integer between 0 and 4294967295.
Possible keys:
* initialenergy: Amount of energy that each team starts with (default: 550)
Note: Must be smaller than or equal to maxenergy
* energyperround: Amount of energy that each team gets per round (default: 50)
* maxenergy: Maximum amount of energy each team can hold (default: 1000)
* cratesperround: Maximum number of crates you can place per round (default: 5)
For the previous 2 keys, you can use the value “inf” for an unlimited amount.
Example: “initialenergy=750, maxenergy=2000” starts thee game with 750 energy
and sets the maximum energy to 2000.
Example: “craterperround=inf” disables the crate placement limit.
---------------------------------------------------------
-- Ideas list --
---------------------------------------------------------
* To make the weapon filter more attractive, make it vaporize flying saucers
and also rope, and maybe incoming gears
* Make healing thing also cure poison?
* Maybe make poison more virulent and dangerous
]]
HedgewarsScriptLoad("/Scripts/Locale.lua")
HedgewarsScriptLoad("/Scripts/Tracker.lua")
HedgewarsScriptLoad("/Scripts/Params.lua")
-- Structures stuff
local strucID = {}
local strucGear = {}
local strucClan = {}
local strucType = {}
local strucCost = {}
local strucHealth = {}
local strucCirc = {}
local strucCircCol = {}
local strucCircRadius = {}
local strucAltDisplay = {}
-- Clan stuff
local clanPower = {} -- current power for each clan. Used to build stuff
local clanPowerTag = nil -- visual gear ID of displayed clan power
local clanUsedExtraTime = {} -- has used extra time in this round?
local clanCratesSpawned = {} -- number of crates spawned in this round
local clanFirstTurn = {}
local clanBoundsSX = {}
local clanBoundsSY = {}
local clanBoundsEX = {}
local clanBoundsEY = {}
-- For tracking previous mode selection per-team
local teamLStructIndex = {}
local teamLObjectMode = {}
local teamLCrateMode = {}
local teamLMineIndex = {}
local teamLWeapIndex = {}
local teamLUtilIndex = {}
-- Wall stuff
local wallsVisible = false
local wX = {}
local wY = {}
local wWidth = {}
local wHeight = {}
local wCol = {}
local wMargin = 20
local borderEffectTimer = 0 -- timer for border clan sparkles
-- Other stuff
local placedExpense = 0 -- Cost of current selected thing
local curWep = amNothing -- current weapon, used to reduce # of calls to GetCurAmmoType()
local fortMode = false -- is using a fort map?
local tempID_CheckProximity = nil -- temporary structure variable for CheckProximity
local cGear = nil -- detects placement of girders and objects (using airattack)
local cGearPlacementDone = false
local uniqueStructureID = 0 -- Counter and ID for structures. Is incremented each time a structure spawns
-- Colors
local colorSupportStation = 0xFFFF00FF
local colorConstructionStation = 0xFFFFFFFF
local colorTeleportationNode = 0x0000FFFF
local colorHealingStation = 0xFF808040 -- Just a slight glow
local colorBioFilter = 0xFF0000FF
local colorReflectorShield = 0xFFAE00FF
local colorWeaponFilter = 0xA800FFFF
local colorHealingStationParticle = 0x00FF0080
local colorGeneratorParticle = 0xFFFF00FF
local colorMessageError = capcolDefault
-- Fake ammo types, for the overwritten weapons in Construction Mode
local amCMStructurePlacer = amAirAttack
local amCMCratePlacer = amMineStrike
local amCMObjectPlacer = amNapalm
-- Config variables (script parameter)
-- NOTE: If you change this, also change the default game scheme “Construction Mode”
local conf_initialEnergy = 550
local conf_energyPerRound = 50
local conf_maxEnergy = 1000
local conf_cratesPerRound = 5
-----------------------
-- CRATE DEFINITIONS --
-----------------------
-- format:
-- { ammoType, cost }
local costFactor = 20
-- WEAPON CRATES
-- Weapons which shouldn't be aded:
-- Air attack, napalm, drillstrike: Overwritten weapons for the Construction Mode tools
-- Mine strike: Is currently broken
-- Piano strike: Hog is resurrected by respawner. Not strictly prohibited, however.
local atkArray = {
{amBazooka, 2*costFactor},
--{amBee, 4*costFactor},
{amMortar, 1*costFactor},
{amDrill, 3*costFactor},
{amSnowball, 3*costFactor},
{amKnife, 2*costFactor},
{amGrenade, 2*costFactor},
{amClusterBomb, 3*costFactor},
{amWatermelon, 25*costFactor},
{amHellishBomb, 25*costFactor},
{amMolotov, 3*costFactor},
{amGasBomb, 3*costFactor},
{amShotgun, 2*costFactor},
{amDEagle, 2*costFactor},
{amSniperRifle, 3*costFactor},
--{amSineGun, 6*costFactor},
{amIceGun, 15*costFactor},
{amMinigun, 13*costFactor},
{amFirePunch, 3*costFactor},
{amWhip, 1*costFactor},
{amBaseballBat, 7*costFactor},
--{amKamikaze, 1*costFactor},
{amSeduction, 1*costFactor},
{amHammer, 1*costFactor},
{amMine, 1*costFactor},
{amDynamite, 9*costFactor},
{amCake, 25*costFactor},
{amBallgun, 40*costFactor},
--{amRCPlane, 25*costFactor},
{amSMine, 5*costFactor},
--{amPiano, 40*costFactor},
{amPickHammer, 2*costFactor},
{amBlowTorch, 4*costFactor},
{amFlamethrower, 4*costFactor},
{amBirdy, 7*costFactor},
}
-- UTILITY CRATES --
-- Utilities which shouldn't be added:
-- * Teleport: We have teleportation node
-- * Switch: Infinite in default Construction Mode weapons scheme
-- * Girder, rubber: Requires construction station
-- * Resurrector: We have the resurrector structure for this
-- Utilities which might be weird for this mode:
-- * Tardis: Randomly teleports hog, maybe even into enemy clan's area
local utilArray = {
{amLandGun, 5*costFactor},
{amRope, 7*costFactor},
{amParachute, 2*costFactor},
{amJetpack, 8*costFactor},
{amPortalGun, 15*costFactor},
{amInvulnerable, 5*costFactor},
{amLaserSight, 2*costFactor},
{amVampiric, 6*costFactor},
{amLowGravity, 4*costFactor},
{amExtraDamage, 6*costFactor},
{amExtraTime, 8*costFactor}
}
----------------------------
-- Placement stuff
----------------------------
-- primary placement categories
local cIndex = 1 -- category index
local cat = {
loc_noop("Girder Placement Mode"),
loc_noop("Rubber Placement Mode"),
loc_noop("Mine Placement Mode"),
loc_noop("Sticky Mine Placement Mode"),
loc_noop("Barrel Placement Mode"),
loc_noop("Weapon Crate Placement Mode"),
loc_noop("Utility Crate Placement Mode"),
loc_noop("Health Crate Placement Mode"),
loc_noop("Structure Placement Mode"),
}
-- Frames in sprTarget for the structure images
local catFrames = {
["Respawner"] = 1,
["Generator"] = 2,
["Healing Station"] = 3,
["Support Station"] = 4,
["Weapon Filter"] = 5,
["Teleportation Node"] = 6,
["Bio-Filter"] = 7,
["Construction Station"] = 8,
["Reflector Shield"] = 9,
}
local catReverse = {}
for c=1, #cat do
catReverse[cat[c]] = c
end
-- Track girders in proximity of CurrentHedgehog
local sProx = {
["Girder Placement Mode"] = false,
["Rubber Placement Mode"] = false,
["Mine Placement Mode"] = false,
["Sticky Mine Placement Mode"] = false,
["Barrel Placement Mode"] = false,
["Weapon Crate Placement Mode"] = false,
["Utility Crate Placement Mode"] = false,
["Health Crate Placement Mode"] = false,
["Structure Placement Mode"] = false,
["Teleportation Mode"] = false,
}
local pMode = {} -- pMode contains custom subsets of the main categories
local pIndex = 1
local currentGirderRotation = 1 -- current girder rotation, we actually need this as HW remembers what rotation you last used
-- Returns true if ammoType is an ammo type with a special meaning
-- in Construction Mode.
function IsConstructionModeAmmo(ammoType)
return ammoType == amCMStructurePlacer or
ammoType == amCMObjectPlacer or
ammoType == amCMCratePlacer or
ammoType == amGirder or
ammoType == amRubber or
ammoType == amTeleport
end
function RenderClanPower()
DrawClanPowerTag()
end
function UpdateTeamLabels()
for i=0, TeamsCount-1 do
local name = GetTeamName(i)
SetTeamLabel(name, clanPower[GetTeamClan(name)])
end
end
function DrawClanPowerTag()
local zoomL = 1.1
local xOffset, yOffset
if INTERFACE == "touch" then
xOffset = 126
yOffset = ScreenHeight - 32
else
xOffset = 45
yOffset = 70
end
local tValue = clanPower[GetHogClan(CurrentHedgehog)]
local tCol = GetClanColor(GetHogClan(CurrentHedgehog))
DeleteVisualGear(clanPowerTag)
clanPowerTag = AddVisualGear(-div(ScreenWidth, 2) + xOffset, ScreenHeight - yOffset, vgtHealthTag, tValue, false)
SetVisualGearValues(
clanPowerTag, -- id
nil, -- x offset (set above)
nil, -- y offset (set above)
0, -- dx
0, -- dy
zoomL, -- zoom
1, -- ~= 0 means align to screen
nil, -- frameticks
nil, -- value (set above)
240000, -- timer
tCol -- color
)
end
function DeleteClanPowerTag()
DeleteVisualGear(clanPowerTag)
clanPowerTag = nil
end
function XYisInRect(px, py, psx, psy, pex, pey)
if (px > psx) and (px < pex) and (py > psy) and (py < pey) then
return(true)
else
return(false)
end
end
function AddWall(zXMin, zYMin, zWidth, zHeight, zCol)
table.insert(wX, zXMin)
table.insert(wY, zYMin)
table.insert(wWidth, zWidth)
table.insert(wHeight, zHeight)
table.insert(wCol, zCol)
end
function BorderSpark(zXMin,zYMin, zWidth, zHeight, bCol)
local eX = zXMin + GetRandom(zWidth+10)
local eY = zYMin + GetRandom(zHeight+10)
local tempE = AddVisualGear(eX, eY, vgtDust, 0, false)
if tempE ~= 0 then
SetVisualGearValues(tempE, eX, eY, nil, nil, nil, nil, nil, 1, nil, bCol)
end
end
function HandleBorderEffects()
borderEffectTimer = borderEffectTimer + 1
if borderEffectTimer > 15 then
borderEffectTimer = 1
for i = 1, #wX do
BorderSpark(wX[i],wY[i],wWidth[i],wHeight[i], wCol[i])
end
end
end
----
-- old reflecting stuff from like 3 years ago lol
---
function gearCanBeDeflected(gear)
if (GetGearType(gear) == gtShell) or
(GetGearType(gear) == gtGrenade) or
(GetGearType(gear) == gtAirBomb) or
(GetGearType(gear) == gtClusterBomb) or
(GetGearType(gear) == gtCluster) or
(GetGearType(gear) == gtGasBomb) or
(GetGearType(gear) == gtMine) or
(GetGearType(gear) == gtMortar) or
(GetGearType(gear) == gtHellishBomb) or
(GetGearType(gear) == gtWatermelon) or
(GetGearType(gear) == gtMelonPiece) or
(GetGearType(gear) == gtEgg) or
(GetGearType(gear) == gtDrill) or
(GetGearType(gear) == gtBall) or
(GetGearType(gear) == gtExplosives) or
(GetGearType(gear) == gtFlame) or
(GetGearType(gear) == gtPortal) or
(GetGearType(gear) == gtDynamite) or
(GetGearType(gear) == gtSMine) or
(GetGearType(gear) == gtKnife) or
(GetGearType(gear) == gtJetpack) or
(GetGearType(gear) == gtBirdy) or
(GetGearType(gear) == gtSnowball) or
(GetGearType(gear) == gtMolotov)
then
return(true)
else
return(false)
end
end
function getThreatDamage(gear)
local dmg
--- damage amounts for weapons
if (GetGearType(gear) == gtGrenade) or
(GetGearType(gear) == gtClusterBomb) or
(GetGearType(gear) == gtGasBomb) or
(GetGearType(gear) == gtKnife) or
(GetGearType(gear) == gtEgg) or
(GetGearType(gear) == gtMolotov) or
(GetGearType(gear) == gtHellishBomb) or
(GetGearType(gear) == gtWatermelon) or
(GetGearType(gear) == gtSMine) then
dmg = 30
elseif (GetGearType(gear) == gtMelonPiece) then
dmg = 40
elseif (GetGearType(gear) == gtAirBomb) or
(GetGearType(gear) == gtDrill) or
(GetGearType(gear) == gtMine) or
(GetGearType(gear) == gtCluster) then
dmg = 20
elseif (GetGearType(gear) == gtFlame) or
(GetGearType(gear) == gtPortal) or
(GetGearType(gear) == gtDynamite) then
dmg = 0
elseif (GetGearType(gear) == gtBall) then
dmg = 1
else -- normal shell, snowball etc
dmg = 65
end
return(dmg)
end
function setGearReflectionValues(gear)
local dmg = getThreatDamage(gear)
setGearValue(gear,"damage",dmg)
setGearValue(gear,"deflects",0)
if (CurrentHedgehog ~= nil) then
setGearValue(gear,"owner",GetHogClan(CurrentHedgehog)) -- NEW NEEDS CHANGE?
else
setGearValue(gear,"owner",10)
end
end
function isATrackedGear(gear)
if (GetGearType(gear) == gtHedgehog) or
(GetGearType(gear) == gtTarget) or
(GetGearType(gear) == gtCase)
then
return(true)
else
return(false)
end
end
function AddStruc(pX,pY, pType, pClan)
uniqueStructureID = uniqueStructureID + 1
local tempG = AddGear(0, 0, gtTarget, 0, 0, 0, 0)
SetGearPosition(tempG, pX, pY)
setGearValue(tempG, "uniqueStructureID", uniqueStructureID)
local tempCirc = AddVisualGear(0,0,vgtCircle,0,true)
if pType ~= "Respawner" and pType ~= "Generator" then
SetVisualGearValues(tempCirc, 0, 0, 100, 255, 1, 100, 0, 500, 1, 0xFFFFFF00)
table.insert(strucCirc, tempCirc)
else
table.insert(strucCirc, false)
end
table.insert(strucID, uniqueStructureID)
table.insert(strucType, pType)
table.insert(strucGear,tempG)
table.insert(strucClan,pClan)
table.insert(strucCost,2)
local frameID = 0
local visualSprite = sprTarget
local madness = AddVisualGear(GetX(tempG), GetY(tempG), vgtStraightShot, 1, true,1)
if pType == "Reflector Shield" then
table.insert(strucHealth,255)
else
table.insert(strucHealth,1)
end
if pType == "Bio-Filter" then
table.insert(strucCircCol, colorBioFilter)
table.insert(strucCircRadius,1000)
elseif pType == "Healing Station" then
table.insert(strucCircCol, colorHealingStation)
table.insert(strucCircRadius,500)
elseif pType == "Respawner" then
table.insert(strucCircCol, 0)
table.insert(strucCircRadius,0)
runOnHogs(EnableHogResurrectionForThisClan)
elseif pType == "Teleportation Node" then
table.insert(strucCircCol, colorTeleportationNode)
table.insert(strucCircRadius,350)
elseif pType == "Generator" then
table.insert(strucCircCol, 0)
table.insert(strucCircRadius,0)
setGearValue(tempG, "power", 0)
elseif pType == "Support Station" then
table.insert(strucCircCol, colorSupportStation)
table.insert(strucCircRadius,500)
elseif pType == "Construction Station" then
table.insert(strucCircCol, colorConstructionStation)
table.insert(strucCircRadius,500)
elseif pType == "Reflector Shield" then
table.insert(strucCircCol, colorReflectorShield)
table.insert(strucCircRadius,750)
elseif pType == "Weapon Filter" then
table.insert(strucCircCol, colorWeaponFilter)
table.insert(strucCircRadius,750)
end
if catFrames[pType] then
frameID = catFrames[pType]
end
SetVisualGearValues(madness, nil, nil, 0, 0, nil, frameID, nil, visualSprite, nil, nil)
SetState(tempG, bor(GetState(tempG),gstInvisible) )
table.insert(strucAltDisplay, madness)
end
-- this is basically onStructureDelete
-- we may need to expand it for non-gear structures later
function CheckGearForStructureLink(gear)
local respawnerDestroyed = false
for i = 1, #strucID do
if strucID[i] == getGearValue(gear,"uniqueStructureID") then
if strucType[i] == "Respawner" then
respawnerDestroyed = true
end
table.remove(strucID,i)
table.remove(strucGear,i)
table.remove(strucClan,i)
table.remove(strucType,i)
table.remove(strucCost,i)
table.remove(strucHealth,i)
DeleteVisualGear(strucCirc[i])
table.remove(strucCirc,i)
table.remove(strucCircCol,i)
table.remove(strucCircRadius,i)
if strucAltDisplay[i] ~= 1 then
DeleteVisualGear(strucAltDisplay[i])
end
table.remove(strucAltDisplay,i)
end
end
if respawnerDestroyed == true then
runOnHogs(RecalibrateRespawn)
end
end
-- called when we add a new respawner
function EnableHogResurrectionForThisClan(gear)
if GetHogClan(gear) == GetHogClan(CurrentHedgehog) then
SetEffect(gear, heResurrectable, 1)
end
end
-- this is called when a respawner blows up
function RecalibrateRespawn(gear)
local respawnerList = {}
for i = 1, #strucID do
if (strucType[i] == "Respawner") and (strucClan[i] == GetHogClan(gear)) then
table.insert(respawnerList, i)
end
end
if #respawnerList >= 1 then
SetEffect(gear, heResurrectable, 1)
else
SetEffect(gear, heResurrectable, 0)
end
end
--resposition dead hogs at a respawner if they own one
function FindRespawner(gear)
local respawnerList = {}
for i = 1, #strucID do
if (strucType[i] == "Respawner") and (strucClan[i] == GetHogClan(gear)) then
table.insert(respawnerList, i)
end
end
if #respawnerList >= 1 then
local i = GetRandom(#respawnerList)+1
SetGearPosition(gear,GetX(strucGear[respawnerList[i]]),GetY(strucGear[respawnerList[i]])-25)
AddVisualGear(GetX(gear), GetY(gear), vgtExplosion, 0, false)
local msgs = {
loc("The respawner respawns %s"),
loc("%s died … and lives again!"),
loc("%s gets an extra life"),
loc("%s is now a zombie hedgehog"),
loc("%s has been rescued from death"),
}
local r = math.random(1, #msgs)
AddCaption(string.format(msgs[r], GetHogName(gear)))
else -- (this should never happen, but just in case)
SetEffect(gear, heResurrectable, 0)
DeleteGear(gear)
end
end
function CheckTeleport(gear, tX, tY)
local teleportOriginSuccessful = false
local teleportDestinationSuccessful = false
for i = 1, #strucID do
if (strucType[i] == "Teleportation Node") and (strucClan[i] == GetHogClan(CurrentHedgehog)) then
local dist = GetDistFromGearToXY(CurrentHedgehog,GetX(strucGear[i]), GetY(strucGear[i]))
local NR
NR = (48/100*strucCircRadius[i])/2
if dist <= NR*NR then
teleportOriginSuccessful = true
end
dist = GetDistFromXYtoXY(tX,tY,GetX(strucGear[i]), GetY(strucGear[i]))
NR = (48/100*strucCircRadius[i])/2
if dist <= NR*NR then
teleportDestinationSuccessful = true
end
end
end
if ((teleportDestinationSuccessful == false) or (teleportOriginSuccessful == false)) then
if IsHogLocal(CurrentHedgehog) then
AddCaption(loc("Teleport unsuccessful. Please teleport within a clan teleporter's sphere of influence."), colorMessageError, capgrpMessage)
end
SetGearTarget(gear, GetX(CurrentHedgehog), GetY(CurrentHedgehog))
end
end
--Check for proximity of gears to structures, and make structures behave accordingly
function CheckProximity(gear)
local sID = tempID_CheckProximity
local dist = GetDistFromGearToXY(gear, GetX(strucGear[sID]), GetY(strucGear[sID]))
if not dist then
return
end
-- calculate my real radius if I am an aura
local NR
NR = (48/100*strucCircRadius[sID])/2
-- we're in business
if dist <= NR*NR then
-- heal clan hogs
if strucType[sID] == "Healing Station" then
if GetGearType(gear) == gtHedgehog then
if GetHogClan(gear) == strucClan[sID] then
local hogLife = GetHealth(gear)
-- Heal hog by 1 HP, up to 150 HP total
if hogLife < 150 then
if ((hogLife + 1) % 5) == 0 then
-- Health anim every 5 HP
HealHog(gear, 1, false)
else
SetHealth(gear, hogLife+1)
end
end
-- Maybe find better animation?
local tempE = AddVisualGear(GetX(strucGear[sID]), GetY(strucGear[sID]), vgtSmoke, 0, false)
SetVisualGearValues(tempE, nil, nil, nil, nil, nil, nil, nil, nil, nil, colorHealingStationParticle)
end
end
-- explode enemy clan hogs
elseif strucType[sID] == "Bio-Filter" then
if GetGearType(gear) == gtHedgehog then
if (GetHogClan(gear) ~= strucClan[sID]) and (GetHealth(gear) > 0) then
AddGear(GetX(gear), GetY(gear), gtGrenade, 0, 0, 0, 1)
end
end
-- were those weapons in your pocket, or were you just happy to see me?
elseif strucType[sID] == "Weapon Filter" then
if GetGearType(gear) == gtHedgehog then
if (GetHogClan(gear) ~= strucClan[sID]) then
-- Vaporize (almost) all of the hog's ammo
local ammosDestroyed = 0
for wpnIndex = 0, AmmoTypeMax do
if (not IsConstructionModeAmmo(wpnIndex)) and wpnIndex ~= amSkip and wpnIndex ~= amNothing then
local count = GetAmmoCount(gear, wpnIndex)
-- Infinite ammos are spared
if count ~= 100 then
ammosDestroyed = ammosDestroyed + count
AddAmmo(gear, wpnIndex, 0)
end
end
end
if ammosDestroyed > 0 then
-- Vaporize effects
if gear == CurrentHedgehog then
local r = math.random(1, 2)
if r == 1 then
PlaySound(sndNutter, gear)
else
PlaySound(sndOops, gear)
end
end
PlaySound(sndVaporize)
for i=1, 5 do
AddVisualGear(GetX(gear), GetY(gear), vgtSmoke, 0, false)
end
local msgs = {
loc("%s lost all the weapons"),
loc("The ammo of %s has been vaporized"),
loc("%s fell victim to a weapon filter"),
loc("%s is suddenly low on ammo"),
loc("%s is now as poor as a church mouse"),
}
local r = math.random(1, #msgs)
AddCaption(string.format(msgs[r], GetHogName(gear)), capcolDefault, capgrpAmmoinfo)
end
end
end
-- BOUNCE! POGO! POGO! POGO! POGO!
elseif strucType[sID] == "Reflector Shield" then
-- add check for whose projectile it is
if gearCanBeDeflected(gear) == true then
local gOwner = getGearValue(gear,"owner")
local gDeflects = getGearValue(gear,"deflects")
local gDmg = getGearValue(gear,"damage")
if gDeflects >= 3 then
DeleteGear(gear)
AddVisualGear(GetX(gear), GetY(gear), vgtSmoke, 0, false)
PlaySound(sndVaporize)
elseif gOwner ~= strucClan[sID] then
--whether to vaporize gears or bounce them
if gDmg ~= 0 then
local dx, dy = GetGearVelocity(gear)
if (dx == 0) and (dy == 0) then
-- static mine, explosive, etc encountered
-- do nothing
else
--let's bounce something!
dx = dx*(-1)
dy = dy*(-1)
SetGearVelocity(gear,dx,dy)
setGearValue(gear,"deflects",(gDeflects+1))
AddVisualGear(GetX(gear), GetY(gear), vgtExplosion, 0, false)
PlaySound(sndExplosion)
strucHealth[sID] = strucHealth[sID] - gDmg
if strucCirc[sID] then
strucCircCol[sID] = strucCircCol[sID] - gDmg
end
if strucHealth[sID] <= 0 then
AddVisualGear(GetX(strucGear[sID]), GetY(strucGear[sID]), vgtExplosion, 0, false)
DeleteGear(strucGear[sID])
PlaySound(sndExplosion)
end
end
else
DeleteGear(gear)
AddVisualGear(GetX(gear), GetY(gear), vgtSmoke, 0, false)
PlaySound(sndVaporize)
end
end
end
--mark as within range of a teleporter node
elseif strucType[sID] == "Teleportation Node" then
if GetGearType(gear) == gtHedgehog then
if GetHogClan(gear) == strucClan[sID] then
sProx["Teleportation Mode"] = true
end
end
-- mark as within range of construction station
-- and thus allow menu access to placement modes
-- for girders, mines, sticky mines and barrels
elseif strucType[sID] == "Construction Station" then
if GetGearType(gear) == gtHedgehog then
if GetHogClan(gear) == strucClan[sID] then
AddVisualGear(GetX(strucGear[sID]), GetY(strucGear[sID]), vgtSmoke, 0, false)
sProx["Girder Placement Mode"] = true
sProx["Rubber Placement Mode"] = true
sProx["Mine Placement Mode"] = true
sProx["Sticky Mine Placement Mode"] = true
sProx["Barrel Placement Mode"] = true
end
end
-- mark as within stupport station range
-- and thus allow menu access to placement modes
-- for weapon, utility, and med crates
elseif strucType[sID] == "Support Station" then
if GetGearType(gear) == gtHedgehog then
if GetHogClan(gear) == strucClan[sID] then
AddVisualGear(GetX(strucGear[sID]), GetY(strucGear[sID]), vgtSmoke, 0, false)
sProx["Health Crate Placement Mode"] = true
sProx["Weapon Crate Placement Mode"] = true
sProx["Utility Crate Placement Mode"] = true
end
end
end
end
end
-- used to check if we need to run through all hogs or just currenthedgehog
function isAStructureThatAppliesToMultipleGears(pID)
if strucType[pID] == "Healing Station" or
strucType[pID] == "Reflector Shield" or
strucType[pID] == "Weapon Filter" or
strucType[pID] == "Bio-Filter"
then
return(true)
else
return(false)
end
end
function HandleStructures()
if GameTime % 100 == 0 then
for k, _ in pairs(sProx) do
if k ~= "Structure Placement Mode" then
sProx[k] = false
end
end
end
for i = 1, #strucID do
if strucCirc[i] then
SetVisualGearValues(strucCirc[i], GetX(strucGear[i]), GetY(strucGear[i]), nil, nil, nil, nil, nil, strucCircRadius[i], nil, strucCircCol[i])
end
tempID_CheckProximity = i
SetVisualGearValues(strucAltDisplay[i], GetX(strucGear[i]), GetY(strucGear[i]), 0, 0, nil, nil, 800000, sprTarget)
if GameTime % 100 == 0 then
-- Check For proximity of stuff to our structures
if isAStructureThatAppliesToMultipleGears(i) then
runOnGears(CheckProximity)
else -- only check prox on CurrentHedgehog
if CurrentHedgehog ~= nil then
CheckProximity(CurrentHedgehog)
end
end
if strucType[i] == "Generator" then
for z = 0, ClansCount-1 do
if z == strucClan[i] then
increaseGearValue(strucGear[i],"power")
if getGearValue(strucGear[i],"power") == 10 then
setGearValue(strucGear[i],"power",0)
-- Add 1 energy (if not at max. already)
if not (conf_maxEnergy ~= "inf" and clanPower[z] + 1 > conf_maxEnergy) then
clanPower[z] = clanPower[z] + 1
-- Spawn one particle per energy added
local particle = AddVisualGear(GetX(strucGear[i]), GetY(strucGear[i])-16, vgtStraightShot, sprStar, false)
SetVisualGearValues(particle, nil, nil, math.random(-100, 100)*0.00005, 0.02, math.random(360), 0, 900, nil, 0, colorGeneratorParticle)
else
SetVisualGearValues(strucAltDisplay[i], GetX(strucGear[i]), GetY(strucGear[i]), 0, 0, nil, nil, 800000, sprTarget)
end
end
end
end
end
end
end
-- Add and remove ammo based on structure proximity
if GameTime % 100 == 0 and CurrentHedgehog ~= nil then
if sProx["Girder Placement Mode"] then
AddAmmo(CurrentHedgehog, amGirder, 100)
else
AddAmmo(CurrentHedgehog, amGirder, 0)
end
if sProx["Rubber Placement Mode"] then
AddAmmo(CurrentHedgehog, amRubber, 100)
else
AddAmmo(CurrentHedgehog, amRubber, 0)
end
if sProx["Mine Placement Mode"] or sProx["Sticky Mine Placement Mode"] or sProx["Barrel Placement Mode"] then
AddAmmo(CurrentHedgehog, amCMObjectPlacer, 100)
else
AddAmmo(CurrentHedgehog, amCMObjectPlacer, 0)
end
if sProx["Teleportation Mode"] then
AddAmmo(CurrentHedgehog, amTeleport, 100)
else
AddAmmo(CurrentHedgehog, amTeleport, 0)
end
if sProx["Weapon Crate Placement Mode"] or sProx["Utility Crate Placement Mode"] or sProx["Health Crate Placement Mode"] then
AddAmmo(CurrentHedgehog, amCMCratePlacer, 100)
else
AddAmmo(CurrentHedgehog, amCMCratePlacer, 0)
end
end
end
------------------------
-- SOME GENERAL METHODS
------------------------
function GetDistFromGearToXY(gear, g2X, g2Y)
local g1X, g1Y = GetGearPosition(gear)
if not g1X then
return nil
end
local q = g1X - g2X
local w = g1Y - g2Y
return ( (q*q) + (w*w) )
end
function GetDistFromXYtoXY(a, b, c, d)
local q = a - c
local w = b - d
return ( (q*q) + (w*w) )
end
-- essentially called when user clicks the mouse
-- with girders or an airattack
function PlaceObject(x,y)
if (clanUsedExtraTime[GetHogClan(CurrentHedgehog)] == true) and (cat[cIndex] == "Utility Crate Placement Mode") and (utilArray[pIndex][1] == amExtraTime) then
if IsHogLocal(CurrentHedgehog) then
AddCaption(loc("You may only place 1 Extra Time crate per turn."), colorMessageError, capgrpVolume)
end
PlaySound(sndDenied)
elseif (conf_cratesPerRound ~= "inf" and clanCratesSpawned[GetHogClan(CurrentHedgehog)] >= conf_cratesPerRound) and ( (cat[cIndex] == "Health Crate Placement Mode") or (cat[cIndex] == "Utility Crate Placement Mode") or (cat[cIndex] == "Weapon Crate Placement Mode") ) then
if IsHogLocal(CurrentHedgehog) then
AddCaption(string.format(loc("You may only place %d crates per round."), conf_cratesPerRound), colorMessageError, capgrpVolume)
end
PlaySound(sndDenied)
elseif (XYisInRect(x,y, clanBoundsSX[GetHogClan(CurrentHedgehog)],clanBoundsSY[GetHogClan(CurrentHedgehog)],clanBoundsEX[GetHogClan(CurrentHedgehog)],clanBoundsEY[GetHogClan(CurrentHedgehog)]) == true)
and (clanPower[GetHogClan(CurrentHedgehog)] >= placedExpense)
then
-- For checking if the actual placement succeeded
local placed = false
local gear
if cat[cIndex] == "Girder Placement Mode" then
placed = PlaceGirder(x, y, currentGirderRotation)
elseif cat[cIndex] == "Rubber Placement Mode" then
placed = PlaceRubber(x, y, currentGirderRotation)
elseif cat[cIndex] == "Health Crate Placement Mode" then
gear = SpawnHealthCrate(x,y)
if gear ~= nil then
placed = true
SetHealth(gear, pMode[pIndex])
clanCratesSpawned[GetHogClan(CurrentHedgehog)] = clanCratesSpawned[GetHogClan(CurrentHedgehog)] +1
end
elseif cat[cIndex] == "Weapon Crate Placement Mode" then
gear = SpawnAmmoCrate(x, y, atkArray[pIndex][1])
if gear ~= nil then
placed = true
clanCratesSpawned[GetHogClan(CurrentHedgehog)] = clanCratesSpawned[GetHogClan(CurrentHedgehog)] +1
end
elseif cat[cIndex] == "Utility Crate Placement Mode" then
gear = SpawnUtilityCrate(x, y, utilArray[pIndex][1])
if gear ~= nil then
placed = true
if utilArray[pIndex][1] == amExtraTime then
clanUsedExtraTime[GetHogClan(CurrentHedgehog)] = true
end
clanCratesSpawned[GetHogClan(CurrentHedgehog)] = clanCratesSpawned[GetHogClan(CurrentHedgehog)] +1
end
elseif cat[cIndex] == "Barrel Placement Mode" then
gear = AddGear(x, y, gtExplosives, 0, 0, 0, 0)
if gear ~= nil then
placed = true
SetHealth(gear, pMode[pIndex])
end
elseif cat[cIndex] == "Mine Placement Mode" then
gear = AddGear(x, y, gtMine, 0, 0, 0, 0)
if gear ~= nil then
placed = true
SetTimer(gear, pMode[pIndex])
end
elseif cat[cIndex] == "Sticky Mine Placement Mode" then
gear = AddGear(x, y, gtSMine, 0, 0, 0, 0)
placed = gear ~= nil
elseif cat[cIndex] == "Structure Placement Mode" then
AddStruc(x,y, pMode[pIndex],GetHogClan(CurrentHedgehog))
placed = true
end
if placed then
-- Pay the price
clanPower[GetHogClan(CurrentHedgehog)] = clanPower[GetHogClan(CurrentHedgehog)] - placedExpense
RenderClanPower()
UpdateTeamLabels()
if cat[cIndex] == "Girder Placement Mode" or cat[cIndex] == "Rubber Placement Mode" then
PlaySound(sndPlaced)
end
else
if IsHogLocal(CurrentHedgehog) then
AddCaption(loc("Invalid Placement"), colorMessageError, capgrpVolume)
end
PlaySound(sndDenied)
end
else
if (clanPower[GetHogClan(CurrentHedgehog)] >= placedExpense) then
if IsHogLocal(CurrentHedgehog) then
AddCaption(loc("Invalid Placement"), colorMessageError, capgrpVolume)
end
else
if IsHogLocal(CurrentHedgehog) then
AddCaption(loc("Insufficient Power"), colorMessageError, capgrpVolume)
end
end
PlaySound(sndDenied)
end
end
-- called when user changes primary selection
-- either via up/down keys
-- or selecting girder/airattack
function RedefineSubset()
pIndex = 1
pMode = {}
if (CurrentHedgehog == nil or band(GetState(CurrentHedgehog), gstHHDriven) == 0) then
return false
end
local team = GetHogTeamName(CurrentHedgehog)
if cat[cIndex] == "Girder Placement Mode" then
pIndex = currentGirderRotation
pMode = {amGirder}
elseif cat[cIndex] == "Rubber Placement Mode" then
pIndex = currentGirderRotation
pMode = {amRubber}
elseif cat[cIndex] == "Barrel Placement Mode" then
pMode = {60}
teamLObjectMode[team] = cat[cIndex]
elseif cat[cIndex] == "Health Crate Placement Mode" then
pMode = {HealthCaseAmount}
teamLCrateMode[team] = cat[cIndex]
elseif cat[cIndex] == "Weapon Crate Placement Mode" then
for i = 1, #atkArray do
pMode[i] = atkArray[i][1]
end
teamLCrateMode[team] = cat[cIndex]
pIndex = teamLWeapIndex[team]
elseif cat[cIndex] == "Utility Crate Placement Mode" then
for i = 1, #utilArray do
pMode[i] = utilArray[i][1]
end
teamLCrateMode[team] = cat[cIndex]
pIndex = teamLUtilIndex[team]
elseif cat[cIndex] == "Mine Placement Mode" then
pMode = {0,1000,2000,3000,4000,5000}
teamLObjectMode[team] = cat[cIndex]
pIndex = teamLMineIndex[team]
elseif cat[cIndex] == "Sticky Mine Placement Mode" then
pMode = {amSMine}
teamLObjectMode[team] = cat[cIndex]
elseif cat[cIndex] == "Structure Placement Mode" then
pMode = {
loc_noop("Support Station"),
loc_noop("Construction Station"),
loc_noop("Healing Station"),
loc_noop("Teleportation Node"),
loc_noop("Weapon Filter"),
loc_noop("Bio-Filter"),
loc_noop("Reflector Shield"),
loc_noop("Respawner"),
loc_noop("Generator"),
}
pIndex = teamLStructIndex[team]
end
return true
end
-- Updates the handling of the main construction mode tools:
-- Structure Placer, Crate Placer, Object Placer.
-- This handles the internal category state,
-- the HUD display and the clans outline.
function HandleConstructionModeTools()
-- Update display selection criteria
if (CurrentHedgehog ~= nil and band(GetState(CurrentHedgehog), gstHHDriven) ~= 0) then
curWep = GetCurAmmoType()
local updated = false
local team = GetHogTeamName(CurrentHedgehog)
if (curWep == amGirder) then
cIndex = 1
RedefineSubset()
updateCost()
updated = true
elseif (curWep == amRubber) then
cIndex = 2
RedefineSubset()
updateCost()
updated = true
elseif (curWep == amCMStructurePlacer) then
cIndex = 9
RedefineSubset()
updateCost()
updated = true
elseif (curWep == amCMCratePlacer) then
cIndex = catReverse[teamLCrateMode[team]]
RedefineSubset()
updateCost()
updated = true
elseif (curWep == amCMObjectPlacer) then
cIndex = catReverse[teamLObjectMode[team]]
RedefineSubset()
updateCost()
updated = true
end
if curWep == amCMStructurePlacer or curWep == amCMCratePlacer or curWep == amCMObjectPlacer then
SetSoundMask(sndIncoming, true)
else
SetSoundMask(sndIncoming, false)
end
if curWep == amGirder or curWep == amRubber then
SetSoundMask(sndDenied, true)
else
SetSoundMask(sndDenied, false)
end
if updated then
AddCaption(loc(cat[cIndex]), GetClanColor(GetHogClan(CurrentHedgehog)), capgrpMessage)
showModeMessage()
wallsVisible = true
else
wallsVisible = false
end
else
curWep = amNothing
wallsVisible = false
end
end
local cursorIcon = nil
local ammoIcon = nil
local ammoIconBorder = nil
-- Handle cursor stuff. This displays a sprite under the cursor so you can see what you're going to place.
function HandleCursor()
if curWep == amCMStructurePlacer or curWep == amCMObjectPlacer or curWep == amCMCratePlacer then
local dFrame = 0
local dSprite
local yOffset = 0
if (cat[cIndex] == "Structure Placement Mode") then
dSprite = sprTarget
dFrame = catFrames[pMode[pIndex]]
elseif (cat[cIndex] == "Mine Placement Mode") then
dSprite = sprCustom2 -- sprMineOff
elseif (cat[cIndex] == "Sticky Mine Placement Mode") then
dSprite = sprCustom3 -- sprSMineOff
elseif (cat[cIndex] == "Barrel Placement Mode") then
dSprite = sprExplosives
elseif (cat[cIndex] == "Health Crate Placement Mode") then
dSprite = sprFAid
elseif (cat[cIndex] == "Weapon Crate Placement Mode") then
dSprite = sprCase
elseif (cat[cIndex] == "Utility Crate Placement Mode") then
dSprite = sprUtility
else
dSprite = sprArrow
end
-- Display the gear to be spawned under the cursor
if not cursorIcon then
cursorIcon = AddVisualGear(CursorX, CursorY, vgtStraightShot, dSprite, true, 3)
end
SetVisualGearValues(cursorIcon, CursorX, CursorY, 0, 0, 0, dFrame, 1000, dSprite, 1000)
-- Render ammo icon for weapon and utility crate.
-- But hide this from prying eyes of your enemies online!
if IsHogLocal(CurrentHedgehog) then
local ammoFrame
if (cat[cIndex] == "Weapon Crate Placement Mode") or (cat[cIndex] == "Utility Crate Placement Mode") then
local tArr
if (cat[cIndex] == "Weapon Crate Placement Mode") then
tArr = atkArray
else
tArr = utilArray
end
-- Get ammo icon
ammoFrame = tArr[pIndex][1] - 1
end
if ammoFrame then
local xDisplacement = 42
local yDisplacement = 42
local x = CursorX + yDisplacement
local y = CursorY + yDisplacement
-- Border around ammo icon
if not ammoIconBorder then
ammoIconBorder = AddVisualGear(x, y, vgtStraightShot, sprCustom1, true, 3)
end
SetVisualGearValues(ammoIconBorder, x, y, 0, 0, 0, 0, 1000, nil, 1000)
-- Ammo icon
if not ammoIcon then
ammoIcon = AddVisualGear(x, y, vgtStraightShot, sprAMAmmos, true, 3)
end
SetVisualGearValues(ammoIcon, x, y, 0, 0, 0, ammoFrame, 1000, nil, 1000)
else
-- Cleanup vgears if not placing ammo crates
if ammoIcon then
DeleteVisualGear(ammoIcon)
end
if ammoIconBorder then
DeleteVisualGear(ammoIconBorder)
end
end
end
else
-- Cleanup vgears
if cursorIcon then
DeleteVisualGear(cursorIcon)
end
if ammoIcon then
DeleteVisualGear(ammoIcon)
end
if ammoIconBorder then
DeleteVisualGear(ammoIconBorder)
end
end
end
function onVisualGearDelete(vg)
if vg ~= nil then
if vg == cursorIcon then
cursorIcon = nil
elseif vg == ammoIcon then
ammoIcon = nil
elseif vg == ammoIconBorder then
ammoIconBorder = nil
end
end
end
-- called in onGameTick()
function HandleConstructionMode()
HandleStructures()
if GameTime % 100 == 0 then
UpdateTeamLabels()
end
if CurrentHedgehog ~= nil then
if wallsVisible == true then
HandleBorderEffects()
end
HandleCursor()
if GameTime % 100 == 0 then
-- Force-update the construction mode tools every 100ms.
-- This makes sure the announcer messages don't disappear
-- while the tool is selected.
if (band(GetState(CurrentHedgehog), gstHHDriven) ~= 0) then
RenderClanPower()
curWep = GetCurAmmoType()
HandleConstructionModeTools()
else
DeleteClanPowerTag()
curWep = amNothing
end
end
end
-- some kind of target detected, tell me your story
if cGear ~= nil then
local x,y = GetGearTarget(cGear)
if GetGearType(cGear) == gtAirAttack then
SetGearMessage(cGear, bor(GetGearMessage(cGear), gmDestroy))
if not cGearPlacementDone then
PlaceObject(x, y)
cGearPlacementDone = true
end
elseif GetGearType(cGear) == gtTeleport then
CheckTeleport(cGear, x, y)
cGear = nil
cGearPlacementDone = true
elseif GetGearType(cGear) == gtGirder then
currentGirderRotation = GetState(cGear)
PlaceObject(x, y)
cGearPlacementDone = true
end
end
end
---------------------------------------------------------------
-- Cycle through selection subsets (by changing pIndex, pMode)
-- i.e health of barrels, medikits,
-- timer of mines
-- contents of crates
-- gears to reposition etc.
---------------------------------------------------------------
function updateCost()
if CurrentHedgehog == nil or band(GetState(CurrentHedgehog), gstHHDriven) == 0 then return end
-- Fallback cost
placedExpense = 1
if pMode[pIndex] == "Healing Station" then
placedExpense = 50
elseif pMode[pIndex] == "Weapon Filter" then
placedExpense = 50
elseif pMode[pIndex] == "Bio-Filter" then
placedExpense = 100
elseif pMode[pIndex] == "Respawner" then
placedExpense = 300
elseif pMode[pIndex] == "Teleportation Node" then
placedExpense = 30
elseif pMode[pIndex] == "Support Station" then
placedExpense = 50
elseif pMode[pIndex] == "Construction Station" then
placedExpense = 50
elseif pMode[pIndex] == "Generator" then
placedExpense = 300
elseif pMode[pIndex] == "Reflector Shield" then
placedExpense = 200
elseif cat[cIndex] == "Weapon Crate Placement Mode" then
placedExpense = atkArray[pIndex][2]
elseif cat[cIndex] == "Utility Crate Placement Mode" then
placedExpense = utilArray[pIndex][2]
elseif cat[cIndex] == "Health Crate Placement Mode" then
placedExpense = 5
elseif cat[cIndex] == "Mine Placement Mode" then
placedExpense = 15
elseif cat[cIndex] == "Sticky Mine Placement Mode" then
placedExpense = 20
elseif cat[cIndex] == "Barrel Placement Mode" then
placedExpense = 10
elseif cat[cIndex] == "Girder Placement Mode" then
placedExpense = 1
elseif cat[cIndex] == "Rubber Placement Mode" then
placedExpense = 3
end
-- Hide cost from spectators.
-- Also, this information is hidden cuz it could be used to infer e.g. crate contents.
if IsHogLocal(CurrentHedgehog) then
AddCaption(string.format(loc("Cost: %d"), placedExpense), GetClanColor(GetHogClan(CurrentHedgehog)), capgrpAmmostate)
end
end
-- Should be called when the index of the mode was changed by the player.
-- E.g. new weapon crate contents or structure type
function updateIndex()
if (curWep == amGirder) or (curWep == amRubber) or (curWep == amCMStructurePlacer) or (curWep == amCMCratePlacer) or (curWep == amCMObjectPlacer) then
showModeMessage()
updateCost()
end
-- Update team variables so the previous state can be restored later
if CurrentHedgehog == nil or band(GetState(CurrentHedgehog), gstHHDriven) == 0 then return end
local val = pMode[pIndex]
local team = GetHogTeamName(CurrentHedgehog)
if cat[cIndex] == "Structure Placement Mode" then
teamLStructIndex[team] = pIndex
elseif cat[cIndex] == "Mine Placement Mode" then
teamLMineIndex[team] = pIndex
elseif cat[cIndex] == "Weapon Crate Placement Mode" then
teamLWeapIndex[team] = pIndex
elseif cat[cIndex] == "Utility Crate Placement Mode" then
teamLUtilIndex[team] = pIndex
end
end
function showModeMessage()
if CurrentHedgehog == nil or band(GetState(CurrentHedgehog), gstHHDriven) == 0 then return end
local val = pMode[pIndex]
local str
if cat[cIndex] == "Mine Placement Mode" then
-- timer in seconds
str = string.format(loc("%d sec"), div(val, 1000))
elseif cat[cIndex] == "Structure Placement Mode" then
str = loc(val)
elseif cat[cIndex] == "Girder Placement Mode" then
str = GetAmmoName(amGirder)
elseif cat[cIndex] == "Rubber Placement Mode" then
str = GetAmmoName(amRubber)
elseif cat[cIndex] == "Sticky Mine Placement Mode" then
str = GetAmmoName(amSMine)
elseif cat[cIndex] == "Weapon Crate Placement Mode"
or cat[cIndex] == "Utility Crate Placement Mode" then
str = GetAmmoName(val)
elseif cat[cIndex] == "Health Crate Placement Mode" then
str = tostring(val)
else
str = tostring(val)
end
-- Hide the mode message from prying enemy eyes except for the structure placer.
-- So stuff like crate contents or mine timers are secret.
if cat[cIndex] == "Structure Placement Mode" or IsHogLocal(CurrentHedgehog) then
AddCaption(str, GetClanColor(GetHogClan(CurrentHedgehog)), capgrpMessage2)
end
end
function rotateMode(pDir)
curWep = GetCurAmmoType()
local foundMatch = false
while(foundMatch == false) do
cIndex = cIndex + pDir
if (cIndex == 1) or (cIndex == 2) then -- we no longer hit girder by normal means
cIndex = #cat
elseif cIndex > #cat then
cIndex = 3 -- we no longer hit girder by normal means
end
if (GetCurAmmoType() == amCMCratePlacer) then
if (cat[cIndex] == "Health Crate Placement Mode") or
(cat[cIndex] == "Weapon Crate Placement Mode") or
(cat[cIndex] == "Utility Crate Placement Mode") then
foundMatch = true
end
elseif (GetCurAmmoType() == amCMObjectPlacer) then
if (cat[cIndex] == "Mine Placement Mode") or
(cat[cIndex] == "Sticky Mine Placement Mode") or
(cat[cIndex] == "Barrel Placement Mode") then
foundMatch = true
end
elseif (GetCurAmmoType() == amCMStructurePlacer) then
if cat[cIndex] == "Structure Placement Mode" then
foundMatch = true
end
end
end
if foundMatch == true then
RedefineSubset()
HandleConstructionModeTools()
end
end
---------------------
-- PLAYER CONTROLS --
---------------------
-- [Timer X]: Used as shortcut key for faster selection of stuff
function onTimer(key)
curWep = GetCurAmmoType()
if (curWep == amCMStructurePlacer) then
-- Select structure directly in structure placer
-- [Timer X] selects structures 1-5
-- [Precise]+[Timer X] selects structures 6-10
local structureID = key
local precise = band(GetGearMessage(CurrentHedgehog), gmPrecise) ~= 0
if precise then
structureID = structureID + 5
end
-- Check for valid pIndex
if structureID <= #pMode then
pIndex = structureID
updateIndex()
end
elseif (curWep == amCMObjectPlacer) then
-- [Timer X]: Set mine time 1-5
if cat[cIndex] == "Mine Placement Mode" then
local index = key + 1
if key <= #pMode then
pIndex = index
updateIndex()
end
end
end
end
-- [Switch]: Set mine time to 0 (only in mine placement mode)
function onSwitch()
curWep = GetCurAmmoType()
if (curWep == amCMObjectPlacer) then
pIndex = 1
updateIndex()
end
end
-- [Left]/[Right]: Change submode (e.g. structure type) of any Construction Mode tool or rotate girder/rubber
function onLeft()
curWep = GetCurAmmoType()
if (curWep == amGirder) or (curWep == amRubber) or (curWep == amCMStructurePlacer) or (curWep == amCMCratePlacer) or (curWep == amCMObjectPlacer) then
pIndex = pIndex - 1
if pIndex == 0 then
pIndex = #pMode
end
updateIndex()
end
end
function onRight()
curWep = GetCurAmmoType()
if (curWep == amGirder) or (curWep == amRubber) or (curWep == amCMStructurePlacer) or (curWep == amCMCratePlacer) or (curWep == amCMObjectPlacer) then
pIndex = pIndex + 1
if pIndex > #pMode then
pIndex = 1
end
updateIndex()
end
end
-- [Up]/[Down]
-- Cycle through the primary categories
-- (by changing cIndex) i.e. mine, sticky mine,
-- barrels, health/weapon/utility crate.
function onUp()
curWep = GetCurAmmoType()
if ( (curWep == amCMCratePlacer) or (curWep == amCMObjectPlacer) ) then
if CurrentHedgehog ~= nil and band(GetState(CurrentHedgehog), gstHHDriven) ~= 0 then
rotateMode(-1)
end
end
end
function onDown()
curWep = GetCurAmmoType()
if ( (curWep == amCMCratePlacer) or (curWep == amCMObjectPlacer) ) then
if CurrentHedgehog ~= nil and band(GetState(CurrentHedgehog), gstHHDriven) ~= 0 then
rotateMode(1)
end
end
end
-- [Set weapon]/[Slot X]: Just update internal stuff
onSetWeapon = HandleConstructionModeTools()
onSlot = onSetWeapon
----------------------------
-- standard event handlers
----------------------------
-- Parses a positive integer
function parseInt(str, default, infinityPermitted)
if str == "inf" and infinityPermitted then
return "inf"
end
if str == nil then return default end
local s = string.match(str, "(%d*)")
if s ~= nil then
return math.min(4294967295, math.max(0, tonumber(s)))
else
return nil
end
end
-- Parse parameters
function onParameters()
parseParams()
conf_initialEnergy = parseInt(params["initialenergy"], conf_initialEnergy)
conf_energyPerRound = parseInt(params["energyperround"], conf_energyPerRound)
conf_maxEnergy = parseInt(params["maxenergy"], conf_maxEnergy, true)
conf_cratesPerRound = parseInt(params["cratesperround"], conf_cratesPerRound, true)
end
function onGameInit()
Explosives = 0
MinesNum = 0
EnableGameFlags(gfInfAttack)
-- This is a hack to make sure all girder/rubber placement is handled by Construction Mode to overwrite the default behaviour
SetMaxBuildDistance(1)
fortMode = MapGen == mgForts
-- if there are forts, let engine place the hogs on them
if fortMode then
EnableGameFlags(gfDivideTeams)
end
RedefineSubset()
end
function initialSetup(gear)
-- Engine already placed hogs in fort mode
if not fortMode then
FindPlace(gear, false, clanBoundsSX[GetHogClan(gear)], clanBoundsEX[GetHogClan(gear)],true)
end
-- Add core ammo
AddAmmo(gear, amCMStructurePlacer, 100)
AddAmmo(gear, amSkip, 100)
-- Remove special Construction Mode stuff.
-- This stuff is added and removed dynamically based on
-- proximity to structures.
AddAmmo(gear, amCMObjectPlacer, 0)
AddAmmo(gear, amCMCratePlacer, 0)
AddAmmo(gear, amGirder, 0)
AddAmmo(gear, amRubber, 0)
AddAmmo(gear, amTeleport, 0)
-- Drill strike is broken, so we force-remove it
AddAmmo(gear, amDrillStrike, 0)
-- Everything else is set by the weapon scheme.
-- Infinite switch is recommended.
end
function onGameStart()
trackTeams()
ShowMission (
loc("CONSTRUCTION MODE"),
loc("A Hedgewars mini-game"),
loc("Build a fortress and destroy your enemy.") .. "|" ..
loc("There are a variety of structures available to aid you.") .. "|" ..
loc("Use the structure placer to place structures.")
, -amCMStructurePlacer, 5000
)
SetAmmoTexts(amCMStructurePlacer, loc("Structure Placer"), loc("Construction Mode tool"), loc("Build one of multiple different structures|to aid you in victory, at the cost of energy.") .. "| |" ..
loc("Support Station: Allows placement of crates.") .. "|"..
loc("Construction Station: Allows placement of| girders, rubber, mines, sticky mines| and barrels.") .. "|" ..
loc("Healing Station: Heals nearby hogs.") .. "|" ..
loc("Teleportation Node: Allows teleportation| between other nodes.") .. "|" ..
loc("Weapon Filter: Dematerializes all ammo| carried by enemies entering it.") .. "|" ..
loc("Bio-Filter: Aggressively removes enemies.") .. "|" ..
loc("Reflector Shield: Reflects enemy projectiles.") .. "|" ..
loc("Respawner: Resurrects dead hogs.") .. "|" ..
loc("Generator: Generates energy.") .. "|" ..
" |" ..
loc("Left/right: Choose structure type").."|"..
loc("1-5, Precise + 1-4: Choose structure type").."|"..
loc("Cursor: Build structure"))
local txt_crateLimit = ""
if conf_cratesPerRound ~= "inf" then
txt_crateLimit = string.format(loc("You may only place %d crates per round."), conf_cratesPerRound) .. "|"
end
SetAmmoTexts(amCMCratePlacer, loc("Crate Placer"), loc("Construction Mode tool"),
loc("This allows you to create a crate anywhere|within your clan's area of influence,|at the cost of energy.") .. "|" ..
txt_crateLimit ..
loc("Up/down: Choose crate type") .. "|" ..
loc("Left/right: Choose crate contents") .. "|" ..
loc("|Cursor: Place crate"))
SetAmmoTexts(amCMObjectPlacer, loc("Object Placer"), loc("Construction Mode tool"),
loc("This allows you to create and place mines,|sticky mines and barrels anywhere within your|clan's area of influence at the cost of energy.").."|"..
loc("Up/down: Choose object type|1-5/Switch/Left/Right: Choose mine timer|Cursor: Place object")
)
SetAmmoDescriptionAppendix(amTeleport, loc("It only works in teleportation nodes of your own clan."))
local sCirc = AddVisualGear(0,0,vgtCircle,0,true)
SetVisualGearValues(sCirc, 0, 0, 100, 255, 1, 10, 0, 40, 3, 0x00000000)
for i = 0, ClansCount-1 do
clanPower[i] = math.min(conf_initialEnergy, conf_maxEnergy)
clanUsedExtraTime[i] = false
clanCratesSpawned[i] = 0
clanFirstTurn[i] = true
end
for i = 0, TeamsCount-1 do
local team = GetTeamName(i)
teamLStructIndex[team] = 1
teamLObjectMode[team] = "Mine Placement Mode"
teamLCrateMode[team] = "Weapon Crate Placement Mode"
teamLMineIndex[team] = 1
teamLWeapIndex[team] = 1
teamLUtilIndex[team] = 1
SetTeamLabel(team, tostring(clanPower[GetTeamClan(team)]))
end
local tMapWidth = RightX - LeftX
local tMapHeight = WaterLine - TopY
local clanInterval = div(tMapWidth,ClansCount)
-- define construction areas for each clan
-- if there are forts-based spawn locations, adjust areas around them
for i = 0, ClansCount-1 do
local slot
if fortMode then
slot = div(GetX(getFirstHogOfClan(i))-LeftX,clanInterval)
else
slot = i
end
local color = GetClanColor(i)
clanBoundsSX[i] = LeftX+(clanInterval*slot)+20
clanBoundsSY[i] = TopY
clanBoundsEX[i] = LeftX+(clanInterval*slot)+clanInterval-20
clanBoundsEY[i] = WaterLine
--top and bottom
AddWall(LeftX+(clanInterval*slot),TopY,clanInterval,wMargin,color)
AddWall(LeftX+(clanInterval*slot),WaterLine-25,clanInterval,wMargin,color)
--add a wall to the left and right
AddWall(LeftX+(clanInterval*slot)+20,TopY,wMargin,WaterLine,color)
AddWall(LeftX+(clanInterval*slot)+clanInterval-20,TopY,wMargin,WaterLine,color)
end
runOnHogs(initialSetup)
end
function onNewTurn()
curWep = GetCurAmmoType()
HandleConstructionModeTools()
local clan = GetHogClan(CurrentHedgehog)
if clanFirstTurn[clan] then
clanFirstTurn[clan] = false
else
clanPower[clan] = clanPower[clan] + conf_energyPerRound
if conf_maxEnergy ~= "inf" and clanPower[clan] > conf_maxEnergy then
clanPower[clan] = conf_maxEnergy
end
end
clanUsedExtraTime[clan] = false
clanCratesSpawned[clan] = 0
RenderClanPower()
UpdateTeamLabels()
end
function onEndTurn()
curWep = amNothing
HandleConstructionModeTools()
DeleteClanPowerTag()
end
function onGameTick()
HandleConstructionMode()
end
function onScreenResize()
-- redraw Tags so that their screen locations are updated
if (CurrentHedgehog ~= nil) then
RenderClanPower()
end
end
function onGearResurrect(gear, vGear)
if GetGearType(gear) == gtHedgehog then
FindRespawner(gear)
if vGear then
SetVisualGearValues(vGear, GetX(gear), GetY(gear))
end
end
end
-- track hedgehogs and placement gears
function onGearAdd(gear)
local gt = GetGearType(gear)
if (gt == gtAirAttack) or (gt == gtTeleport) or (gt == gtGirder) then
cGear = gear
cGearPlacementDone = false
end
if isATrackedGear(gear) then
trackGear(gear)
elseif gearCanBeDeflected(gear) then
trackGear(gear)
setGearReflectionValues(gear)
end
end
function onGearDelete(gear)
if GetGearType(gear) == gtTarget then
CheckGearForStructureLink(gear)
end
if (GetGearType(gear) == gtAirAttack) or (GetGearType(gear) == gtTeleport) or (GetGearType(gear) == gtGirder) then
cGear = nil
end
if (isATrackedGear(gear) or gearCanBeDeflected(gear)) then
trackDeletion(gear)
end
end