share/hedgewars/Data/Scripts/Multiplayer/Construction_Mode.lua
author Wuzzy <Wuzzy2@mail.ru>
Fri, 09 Feb 2018 19:01:52 +0100
changeset 12945 0e698562d76d
parent 12944 712ae7ff8c3d
child 12946 1a1a514aef2e
permissions -rw-r--r--
More Construction Mode refactoring

---------------------------------------------------------
--- LE CONSTRUCTION MODE 0.7+ (badly adapted from Hedge Editor 0.5)
---------------------------------------------------------
-- 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

-- (to do)
-- investigate loc not working on addcaptions
-- check for parsecommands before porting to dev
-- test onUpDown more extensively as it may need revision (check for amRubber etc)
-- test localization of weapons and utils and stuff

-- try posistion grenades in Harmer so it blows hogs away from the struc
-- and don't explode too close to the struc

-- additional/previous balance ideas
-- based on your money?
-- based on the number of strucs/gens you own?
-- based on your existing arsenal?
-- limit number of crates spawned per round perhaps (done)
-- limit number of generators?

------------------------------------------------------------------------------
-- 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.

------------------------------------------------------------------------------
--version history
------------------------------------------------------------------------------
--v0.1
-- concept test

--v0.2
-- improved documentation (in script and in game)
-- improved localisation (or is it? at any rate, crate placement should now say e.g. Bazooka and not amBazooka)
-- added variable weapon costs (based on the values from Vatten's Consumerism script)

-- added reflector shield (still needs work and balancing)
-- added weapon-filter (probably ok)

-- enabled super weapons like ballgun, rcplane, watermelon, hellish to test balance
-- reduce max money to 1000

--v0.3
-- some /s removed

--v0.4
-- added support for per hog ammo (hopefully)

--v0.5 (dev)
-- added somewhat horribly implemented support for different structure sprites
-- added override pictures for ammo menu
-- added override message on wep select to aid understanding
-- split menu into/between weps/parts: struc, crates, gears
-- add a limit on crates per turn
-- add a limit on extra time per turn
-- add a test level
-- restored rubber placement
-- cleaned up some of the code a bit and removed about 280 lines of code I didn't need, lol

--v0.6 (dev)
-- added magic dance

--v0.7 (pushed to repo)
-- added a cfg file
-- removed another 903 lines of code we weren't using (lol)

--v0.7+ (merged in repo)
-- applied Wuzzy's patches:
--   script parameters: initialenergy, energyperround, maxenergy
--   fix crate costs
--   various minor tweaks and fixes
--   (see commits in official repo)
-- make Construction Mode play well together with fort mode (clan order = fort order)

--------------------------------
-- STRUCTURES LIST / IDEAS
--------------------------------

--Healing Station: heals hogs to 150 life
--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 :D
--Generator: generates energy (used to buy stuff, and possibly later other strucs might have upkeep costs)
--Support Station: allows purchasing of weapons, utilities, and med-crates
--Construction Station: allows purchasing of girders, rubber, mines, sticky mines, barrels
--Reflector Shield: reflect projectiles
--Weapon Filter: kill all equipement of enemy hogs passing through this area.


--to make the grill 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

--(not implemented / abandoned ideas)
-- Core: allows construction of other structures.
-- Automated Turret (think red drones from space invasion)
-- Canon (gives access to 3 fireballs per turn while near)
-- something that allows control of wind/water
-- Gravity Field generator : triggers world gravity change

-- structures consume power over time and
-- maybe you can turn structures OFF/ON, manually to save power.

-- hacking
-- allow hacking of structures, either being able to use enemy structures,
-- or turning a team's structures against them.

-- pylons
-- allow hogs to put down a pylon-like gear which then allows the core
-- to place other structures/objects within the pylon's sphere of influence
-- this would allow aggressive structure advancement

-- resouce mining?
-- you could designate something like mines, that you could get close to,
-- "pick up", and then "drop" back at a central location to simulate
-- resource mining. bit complicated/meh, normal power generators probably easier

-- it would be cool to have a red mask we could apply over girders
-- that would indicate they were Indestructible

HedgewarsScriptLoad("/Scripts/Locale.lua")
HedgewarsScriptLoad("/Scripts/Tracker.lua")
HedgewarsScriptLoad("/Scripts/Params.lua")

----------------------------------------------
-- STRUC CRAP
----------------------------------------------

strucID = {}
strucGear = {}
strucClan = {}
strucType = {}
strucCost = {}
strucHealth = {}

strucCirc = {}
strucCircCol = {}
strucCircRadius = {}
strucCircType = {}
strucAltDisplay = {}

fortMode = false

placedExpense = 0

tempID = nil

sUID = 0

colorRed = 0xff0000ff
colorGreen = 0x00ff00ff

clanBoundsSX = {}
clanBoundsSY = {}
clanBoundsEX = {}
clanBoundsEY = {}

clanPower = {}
clanID = {}

-- for ease of use let's track previous selection
teamLStructIndex = {}
teamLObjectMode = {}
teamLCrateMode = {}
teamLMineIndex = {}
teamLWeapIndex = {}
teamLUtilIndex = {}

clanUsedExtraTime = {}
clanCratesSpawned = {}
clanFirstTurn = {}

effectTimer = 0

wallsVisible = false
wX = {}
wY = {}
wWidth = {}
wHeight = {}
wCol = {}
margin = 20

clanPowerTag = nil
lastWep = nil

checkForSpecialWeaponsIn = -1

-- Fake ammo types, for the overwritten weapons in Construction Mode
amCMStructurePlacer = amAirAttack
amCMCratePlacer = amNapalm
amCMObjectPlacer = amDrillStrike

-- Config variables (script parameter)
conf_initialEnergy = 550
conf_energyPerRound = 50
conf_maxEnergy = 1000
conf_cratesPerRound = 5

function DrawClanPowerTag()

	zoomL = 1.3

	xOffset = 40

	zoomL = 1.1
	xOffset = 45
	yOffset = 70
	tCol = 0x00ff00ff
	tValue = clanPower[GetHogClan(CurrentHedgehog)]

	DeleteVisualGear(clanPowerTag)
	clanPowerTag = AddVisualGear(0, 0, vgtHealthTag, 0, false)
	g1, g2, g3, g4, g5, g6, g7, g8, g9, g10 = GetVisualGearValues(clanPowerTag)
	SetVisualGearValues	(
				clanPowerTag, 		--id
				-div(ScreenWidth,2) + xOffset,	--xoffset
				ScreenHeight - yOffset, --yoffset
				0, 			--dx
				0, 			--dy
				zoomL, 			--zoom
				1, 			--~= 0 means align to screen
				g7, 			--frameticks
				tValue, 		--value
				240000, 		--timer
				tCol		--GetClanColor( GetHogClan(CurrentHedgehog) )
				)

end

function onScreenResize()

	-- redraw Tags so that their screen locations are updated
	if (CurrentHedgehog ~= nil) then
		DrawClanPowerTag()
	end

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)

	eX = zXMin + GetRandom(zWidth+10)
	eY = zYMin + GetRandom(zHeight+10)
	tempE = AddVisualGear(eX, eY, vgtDust, 0, false)
	if tempE ~= 0 then
		g1, g2, g3, g4, g5, g6, g7, g8, g9, g10 = GetVisualGearValues(tempE)
		SetVisualGearValues(tempE, eX, eY, g3, g4, g5, g6, g7, 1, g9, bCol )
	end

end

function HandleBorderEffects()

	effectTimer = effectTimer + 1
	if effectTimer > 15 then
		effectTimer = 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 -- test this and birdy plz
		(GetGearType(gear) == gtBirdy) or -- test this and birdy plz
		(GetGearType(gear) == gtSnowball) or
		(GetGearType(gear) == gtMolotov)
	then
		return(true)
	else
		return(false)
	end

end

function getThreatDamage(gear)

	--- 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)

	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 AddStruc(pX,pY, pType, pClan)

	sUID = sUID + 1

	tempG = AddGear(0, 0, gtTarget, 0, 0, 0, 0)
	SetGearPosition(tempG, pX, pY)
	setGearValue(tempG, "sUID", sUID)

	tempCirc = AddVisualGear(0,0,vgtCircle,0,true)

	SetVisualGearValues(tempCirc, 0, 0, 100, 255, 1, 100, 0, 500, 1, 0xFFFFFF00)

	table.insert(strucID, sUID)
	table.insert(strucType, pType)
	table.insert(strucGear,tempG)
	table.insert(strucClan,pClan)
	table.insert(strucCost,2)

	frameID = 0
	visualSprite = sprTarget
	madness = AddVisualGear(GetX(tempG), GetY(tempG), vgtStraightShot, 1, true,1)
	g1, g2, g3, g4, g5, g6, g7, g8, g9, g10 = GetVisualGearValues(madness)	--g9


	if pType == loc("Reflector Shield") then
		table.insert(strucHealth,255)

	else
		table.insert(strucHealth,1)
	end

	table.insert(strucCirc,tempCirc)

	table.insert(strucCircType, 1)
	if pType == loc("Bio-Filter") then
		table.insert(strucCircCol,colorRed)
		table.insert(strucCircRadius,1000)
		frameID = 7
	elseif pType == loc("Healing Station") then
		table.insert(strucCircCol,0xFF00FF00)
		table.insert(strucCircRadius,500)
		frameID = 3
	elseif pType == loc("Respawner") then
		table.insert(strucCircCol,0xFF00FF00)
		table.insert(strucCircRadius,75)
		runOnHogs(EnableHogResurrectionForThisClan)
		frameID = 1
	elseif pType == loc("Teleportation Node") then
		table.insert(strucCircCol,0x0000FFFF)
		table.insert(strucCircRadius,350)
		frameID = 6
	elseif pType == loc("Generator") then
		table.insert(strucCircCol,0xFFFF00FF)
		table.insert(strucCircRadius,75)
		setGearValue(tempG, "power", 0)
		frameID = 2
	elseif pType == loc("Support Station") then
		table.insert(strucCircCol,0xFFFF00FF)
		table.insert(strucCircRadius,500)
		frameID = 4
	elseif pType == loc("Construction Station") then
		table.insert(strucCircCol,0xFFFFFFFF)
		table.insert(strucCircRadius,500)
		frameID = 8
	elseif pType == loc("Reflector Shield") then
		table.insert(strucCircCol,0xffae00ff)
		table.insert(strucCircRadius,750)
		frameID = 9
	elseif pType == loc("Weapon Filter") then
		table.insert(strucCircCol,0xa800ffff)
		table.insert(strucCircRadius,750)
		frameID = 5
	end


	SetVisualGearValues(madness, g1, g2, 0, 0, g5, frameID, g7, visualSprite, g9, g10 )
	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)

	respawnerDestroyed = false

	for i = 1, #strucID do
		if strucID[i] == getGearValue(gear,"sUID") then

			if strucType[i] == loc("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)
			table.remove(strucCircType,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)

	respawnerList = {}
	for i = 1, #strucID do
		if (strucType[i] == loc("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)

	respawnerList = {}
	for i = 1, #strucID do
		if (strucType[i] == loc("Respawner")) and (strucClan[i] == GetHogClan(gear)) then
			table.insert(respawnerList, i)
		end
	end

	if #respawnerList >= 1 then
		i = GetRandom(#respawnerList)+1
		SetGearPosition(gear,GetX(strucGear[respawnerList[i]]),GetY(strucGear[respawnerList[i]])-25)
		AddVisualGear(GetX(gear), GetY(gear), vgtExplosion, 0, false)
	else	-- (this should never happen, but just in case)
		SetEffect(gear, heResurrectable, 0)
		DeleteGear(gear)
	end

end

function onGearResurrect(gear)
	AddVisualGear(GetX(gear), GetY(gear), vgtExplosion, 0, false)
	FindRespawner(gear)
end


function CheckTeleport(gear, tX, tY)

	teleportOriginSuccessful = false
	teleportDestinationSuccessful = false

	for i = 1, #strucID do

		if (strucType[i] == loc("Teleportation Node")) and (strucClan[i] == GetHogClan(CurrentHedgehog)) then

			dist = GetDistFromGearToXY(CurrentHedgehog,GetX(strucGear[i]), GetY(strucGear[i]))
			if strucCircType[i] == 0 then
				NR = strucCircRadius[i]
			else
				NR = (48/100*strucCircRadius[i])/2
			end
			if dist <= NR*NR then
				teleportOriginSuccessful = true
			end

			dist = GetDistFromXYtoXY(tX,tY,GetX(strucGear[i]), GetY(strucGear[i]))
			if strucCircType[i] == 0 then
				NR = strucCircRadius[i]
			else
				NR = (48/100*strucCircRadius[i])/2
			end
			if dist <= NR*NR then
				teleportDestinationSuccessful = true
			end

		end


	end

	if ((teleportDestinationSuccessful == false) or (teleportOriginSuccessful == false)) then
		AddCaption(loc("Teleport Unsuccessful. Please teleport within a clan teleporter's sphere of influence."))
		SetGearTarget(gear, GetX(CurrentHedgehog), GetY(CurrentHedgehog))
	end

end

--Check for proximity of gears to structures, and make structures behave accordingly
function CheckProximity(gear)

	dist = GetDistFromGearToXY(gear, GetX(strucGear[tempID]), GetY(strucGear[tempID]))
	if not dist then
		return
	end

	-- calculate my real radius if I am an aura
	if strucCircType[tempID] == 0 then
		NR = strucCircRadius[tempID]
	else
		NR = (48/100*strucCircRadius[tempID])/2
	end

	-- we're in business
	if dist <= NR*NR then


		-- heal clan hogs
		if strucType[tempID] == loc("Healing Station") then

			if GetGearType(gear) == gtHedgehog then
				if GetHogClan(gear) == strucClan[tempID] 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

					-- change this to the med kit sprite health ++++s later
					tempE = AddVisualGear(GetX(strucGear[tempID]), GetY(strucGear[tempID]), vgtSmoke, 0, true)
					g1, g2, g3, g4, g5, g6, g7, g8, g9, g10 = GetVisualGearValues(tempE)
					SetVisualGearValues(tempE, g1, g2, g3, g4, g5, g6, g7, g8, g9, colorGreen )

				end
			end

		-- explode enemy clan hogs
		elseif strucType[tempID] == loc("Bio-Filter") then

			if GetGearType(gear) == gtHedgehog then
				if (GetHogClan(gear) ~= strucClan[tempID]) 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[tempID] == loc("Weapon Filter") then

			if GetGearType(gear) == gtHedgehog then
				if (GetHogClan(gear) ~= strucClan[tempID]) then

					for wpnIndex = 1, #atkArray do
						AddAmmo(gear, atkArray[wpnIndex][1], 0)
					end

					for wpnIndex = 1, #utilArray do
						AddAmmo(gear, utilArray[wpnIndex][1], 0)
					end

					AddAmmo(gear, amCMStructurePlacer, 100)
					AddAmmo(gear, amSwitch, 100)
					AddAmmo(gear, amSkip, 100)

				end
			end

		-- BOUNCE! POGO! POGO! POGO! POGO!
		elseif strucType[tempID] == loc("Reflector Shield") then

			-- add check for whose projectile it is
			if gearCanBeDeflected(gear) == true then

				gOwner = getGearValue(gear,"owner")
				gDeflects = getGearValue(gear,"deflects")
				gDmg = getGearValue(gear,"damage")

				if gDeflects >= 3 then
					DeleteGear(gear)
					AddVisualGear(GetX(gear), GetY(gear), vgtSmoke, 0, false)
					PlaySound(sndVaporize)
				elseif gOwner ~= strucClan[tempID] then
					--whether to vaporize gears or bounce them
					if gDmg ~= 0 then
						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[tempID] = strucHealth[tempID] - gDmg
							strucCircCol[tempID] = strucCircCol[tempID] - gDmg

							if strucHealth[tempID] <= 0 then
								AddVisualGear(GetX(strucGear[tempID]), GetY(strucGear[tempID]), vgtExplosion, 0, false)
								DeleteGear(strucGear[tempID])
								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[tempID] == loc("Teleportation Node") then

			if GetGearType(gear) == gtHedgehog then
				if GetHogClan(gear) == strucClan[tempID] then

					for i = 1, #sProx do
						if sProx[i][1] == loc("Teleportation Mode") then
							sProx[i][2] = true
						end
					end

				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[tempID] == loc("Construction Station") then

			if GetGearType(gear) == gtHedgehog then
				if GetHogClan(gear) == strucClan[tempID] then
					tempE = AddVisualGear(GetX(strucGear[tempID]), GetY(strucGear[tempID]), vgtSmoke, 0, true)

					for i = 1, #sProx do
						if ((sProx[i][1] == loc("Girder Placement Mode"))
						or (sProx[i][1] == loc("Rubber Placement Mode"))
						or (sProx[i][1] == loc("Mine Placement Mode"))
						or (sProx[i][1] == loc("Sticky Mine Placement Mode"))
						or (sProx[i][1] == loc("Barrel Placement Mode")))
						then
							sProx[i][2] = true
						end
					end


				end
			end

		-- mark as within stupport station range
		-- and thus allow menu access to placement modes
		-- for weapon, utility, and med crates
		elseif strucType[tempID] == loc("Support Station") then

			if GetGearType(gear) == gtHedgehog then
				if GetHogClan(gear) == strucClan[tempID] then
					tempE = AddVisualGear(GetX(strucGear[tempID]), GetY(strucGear[tempID]), vgtSmoke, 0, true)

					for i = 1, #sProx do
						if ((sProx[i][1] == loc("Health Crate Placement Mode"))
						or (sProx[i][1] == loc("Weapon Crate Placement Mode"))
						or (sProx[i][1] == loc("Utility Crate Placement Mode")))
						then
							sProx[i][2] = true
						end
					end


				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] == loc("Healing Station") or
		strucType[pID] == loc("Reflector Shield") or
		strucType[pID] == loc("Weapon Filter") or
		strucType[pID] == loc("Bio-Filter")
	then
		return(true)
	else
		return(false)
	end
end

function HandleStructures()

	if GameTime % 100 == 0 then
		for i = 1, #sProx do
			sProx[i][2] = false

			if sProx[i][1] == loc("Structure Placement Mode") then
				sProx[i][2] = true
			end

		end
	end

	for i = 1, #strucID do

		SetVisualGearValues(strucCirc[i], GetX(strucGear[i]), GetY(strucGear[i]), nil, nil, nil, nil, nil, strucCircRadius[i], nil, strucCircCol[i])

		tempID = 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] == loc("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)
							clanPower[z] = clanPower[z] + 1
							if conf_maxEnergy ~= "inf" and clanPower[z] > conf_maxEnergy then
								clanPower[z] = conf_maxEnergy
							end
						end

					end
				end
			end

		end

	end



	-- this is kinda messy and gross (even more than usual), fix it up at some point
	-- it just assumes that if you have access to girders, it works for rubbers
	-- as that is what the struc implemenation means due to construction station
	if GameTime % 100 == 0 and CurrentHedgehog ~= nil then
		anyUIProx = false
		for i = 1, #sProx do

			if sProx[i][1] == loc("Girder Placement Mode") then
				if sProx[i][2] == true then
					AddAmmo(CurrentHedgehog, amGirder, 100)
					AddAmmo(CurrentHedgehog, amRubber, 100)
					AddAmmo(CurrentHedgehog, amCMObjectPlacer, 100)
				else
					AddAmmo(CurrentHedgehog, amGirder, 0)
					AddAmmo(CurrentHedgehog, amRubber, 0)
					AddAmmo(CurrentHedgehog, amCMObjectPlacer, 0) -- new
				end
			elseif sProx[i][1] == loc("Teleportation Mode") then
				if sProx[i][2] == true then
					AddAmmo(CurrentHedgehog, amTeleport, 100)
				else
					AddAmmo(CurrentHedgehog, amTeleport, 0)
				end
			elseif sProx[i][1] == loc("Weapon Crate Placement Mode") then
				-- this is new stuff
				if sProx[i][2] == true then
					AddAmmo(CurrentHedgehog, amCMCratePlacer, 100)
				else
					AddAmmo(CurrentHedgehog, amCMCratePlacer, 0)
				end
			end

			if (sProx[i][2] == true) then
				anyUIProx = true
			end

		end
	end

end


function checkForSpecialWeapons()

	if (GetCurAmmoType() == amCMObjectPlacer) then
		AddCaption(loc("Object Placer"),GetClanColor(GetHogClan(CurrentHedgehog)),capgrpAmmoinfo)
	end

	lastWep = GetCurAmmoType()

end

----------------------------------------------------------
-- EXCERPTS OF ADAPTED HEDGE_EDITOR CODE FOLLOWS
----------------------------------------------------------
-- experimental crap

local landType = 0
-----------------------------------------
-- tracking vars for save slash load purposes
-----------------------------------------

local hhs = {}

---------------------------------
-- crates are made of this stuff
---------------------------------
placeholder = 20
 atkArray =
				{
				{amBazooka, 	"amBazooka",		0, 2*placeholder},
				--{amBee, 		"amBee",			0, loc("Homing Bee"), 		4*placeholder},
				{amMortar, 		"amMortar",			0, 1*placeholder},
				{amDrill, 		"amDrill",			0, 3*placeholder},
				{amSnowball, 	"amSnowball",		0, 3*placeholder},

				{amGrenade,		"amGrenade",		0, 2*placeholder},
				{amClusterBomb,	"amClusterBomb",	0, 3*placeholder},
				{amWatermelon, 	"amWatermelon",		0, 25*placeholder},
				{amHellishBomb,	"amHellishBomb",	0, 25*placeholder},
				{amMolotov, 	"amMolotov",		0, 3*placeholder},
				{amGasBomb, 	"amGasBomb",		0, 3*placeholder},

				{amShotgun,		"amShotgun",		0, 2*placeholder},
				{amDEagle,		"amDEagle",			0, 2*placeholder},
				{amSniperRifle,	"amSniperRifle",	0, 3*placeholder},
				--{amSineGun, 	"amSineGun",		0, loc("Sine Gun"), 			6*placeholder},
				{amFlamethrower,"amFlamethrower",	0, 4*placeholder},
				{amIceGun, 		"amIceGun",			0, 15*placeholder},

				{amFirePunch, 	"amFirePunch",		0, 3*placeholder},
				{amWhip,		"amWhip",			0, 1*placeholder},
				{amBaseballBat, "amBaseballBat",	0, 7*placeholder},
				--{amKamikaze, 	"amKamikaze",		0, loc("Kamikaze"),			1*placeholder},
				{amSeduction, 	"amSeduction",		0, 1*placeholder},
				{amHammer,		"amHammer",			0, 1*placeholder},

				{amMine, 		"amMine",			0, 1*placeholder},
				{amDynamite, 	"amDynamite",		0, 9*placeholder},
				{amCake, 		"amCake",			0, 25*placeholder},
				{amBallgun, 	"amBallgun",		0, 40*placeholder},
				--{amRCPlane,		"amRCPlane",		0, loc("RC Plane"), 	25*placeholder},
				{amSMine,		"amSMine",			0, 5*placeholder},

				-- Careful! Some airborne attacks are overwritten by the special Construction Mode tools

				--{amAirAttack,	"amAirAttack",		0, loc("Air Attack"), 		10*placeholder},
				--{amMineStrike,	"amMineStrike",		0, loc("Mine Strike"), 		15*placeholder},
				--{amNapalm, 		"amNapalm",			0, loc("Napalm"), 		15*placeholder},
				--{amPiano,		"amPiano",			0, loc("Piano Strike"), 	40*placeholder},
				--{amDrillStrike,	"amDrillStrike",	0, loc("Drill Strike"), 15*placeholder},

				{amPickHammer,		"amPickHammer",		0, 2*placeholder},
				{amBlowTorch, 		"amBlowTorch",		0, 4*placeholder},
				{amKnife,		"amKnife",			0, 2*placeholder},

				{amBirdy,		"amBirdy",			0, 7*placeholder},

				{amDuck,		"amDuck",			0, 2*placeholder}

				}

 utilArray =
				{
				--{amGirder, 			"amGirder",			0, loc("Girder"), 		4*placeholder},
				{amLandGun,		"amLandGun",		0, 5*placeholder},
				--{amRubber, 			"amRubber",			0, loc("Rubber"), 	5*placeholder},

				{amRope, 			"amRope",	0, 7*placeholder},
				{amParachute, 		"amParachute",		0, 2*placeholder},
				--{amTeleport,		"amTeleport",		0, loc("Teleport"), 		6*placeholder},
				{amJetpack,			"amJetpack",	0, 8*placeholder},
				{amPortalGun,		"amPortalGun",		0, 15*placeholder},

				{amInvulnerable,	"amInvulnerable",	0, 5*placeholder},
				{amLaserSight,		"amLaserSight",		0, 2*placeholder},
				{amVampiric,		"amVampiric",		0, 6*placeholder},
				--{amResurrector, 	"amResurrector",	0, loc("Resurrector"), 		8*placeholder},
				--{amTardis, 			"amTardis",			0, loc("Time Box"), 			2*placeholder},

				--{amSwitch,			"amSwitch",			0, loc("Switch Hog"), 		4*placeholder}
				{amLowGravity, 		"amLowGravity",		0, 4*placeholder},
				{amExtraDamage, 	"amExtraDamage",	0, 6*placeholder},
				{amExtraTime,		"amExtraTime",		0, 8*placeholder}

				}

----------------------------
-- placement shite
----------------------------

local cGear = nil -- detects placement of girders and objects (using airattack)
local curWep = amNothing

-- primary placement categories
local cIndex = 1 -- category index
local cat = {
	"Girder Placement Mode",
	"Rubber Placement Mode",
	"Mine Placement Mode",
	"Sticky Mine Placement Mode",
	"Barrel Placement Mode",
	"Weapon Crate Placement Mode",
	"Utility Crate Placement Mode",
	"Health Crate Placement Mode",
	"Structure Placement Mode"
}
local catReverse = {}
for c=1, #cat do
	catReverse[cat[c]] = c
end

sProx = {
	{loc("Girder Placement Mode"),false},
	{loc("Rubber Placement Mode"),false},
	{loc("Mine Placement Mode"),false},
	{loc("Sticky Mine Placement Mode"),false},
	{loc("Barrel Placement Mode"),false},
	{loc("Weapon Crate Placement Mode"),false},
	{loc("Utility Crate Placement Mode"),false},
	{loc("Health Crate Placement Mode"),false},
	{loc("Structure Placement Mode"),false},
	{loc("Teleportation Mode"),false},
}


local pMode = {}	-- pMode contains custom subsets of the main categories
local pIndex = 1

local CGR = 1 -- current girder rotation, we actually need this as HW remembers what rotation you last used

local placedX = {}
local placedY = {}
local placedSpec = {}
local placedSuperSpec = {}
local placedType = {}
local placedCount = 0

local sCirc -- circle that appears around selected gears
local sGear = nil
local closestDist
local closestGear = nil

local tCirc = {} -- array of circles that appear around tagged gears

------------------------
-- SOME GENERAL METHODS
------------------------

function GetDistFromGearToXY(gear, g2X, g2Y)

	g1X, g1Y = GetGearPosition(gear)
	if not g1X then
		return nil
	end
	q = g1X - g2X
	w = g1Y - g2Y

	return ( (q*q) + (w*w) )

end

function GetDistFromXYtoXY(a, b, c, d)
	q = a - c
	w = b - d
	return ( (q*q) + (w*w) )
end

function SelectGear(gear)

	d = GetDistFromGearToXY(gear, placedX[placedCount], placedY[placedCount])

	if d < closestDist then
		closestDist = d
		closestGear = gear
	end

end

-- essentially called when user clicks the mouse
-- with girders or an airattack
function PlaceObject(x,y)

	placedX[placedCount] = x
	placedY[placedCount] = y
	placedType[placedCount] = cat[cIndex]
	placedSpec[placedCount] = pMode[pIndex]

	if (clanUsedExtraTime[GetHogClan(CurrentHedgehog)] == true) and (cat[cIndex] == "Utility Crate Placement Mode") and (utilArray[pIndex][1] == amExtraTime) then
		AddCaption(loc("You may only place 1 Extra Time crate per turn."),0xffba00ff,capgrpVolume)
		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
		AddCaption(string.format(loc("You may only place %d crates per round."), conf_cratesPerRound),0xffba00ff,capgrpVolume)
		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
		if cat[cIndex] == "Girder Placement Mode" then
			placed = PlaceGirder(x, y, CGR)
			placedSpec[placedCount] = CGR
		elseif cat[cIndex] == "Rubber Placement Mode" then
			placed = PlaceRubber(x, y, CGR)
			placedSpec[placedCount] = CGR
		elseif cat[cIndex] == "Health Crate Placement Mode" then
			gear = SpawnHealthCrate(x,y)
			if gear ~= nil then
				placed = true
				SetHealth(gear, pMode[pIndex])
				setGearValue(gear,"caseType","med")
				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
				placedSpec[placedCount] = atkArray[pIndex][2]
				setGearValue(gear,"caseType","ammo")
				setGearValue(gear,"contents",atkArray[pIndex][2])
				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
				placedSpec[placedCount] = utilArray[pIndex][2]
				setGearValue(gear,"caseType","util")
				setGearValue(gear,"contents",utilArray[pIndex][2])
				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
			clanPower[GetHogClan(CurrentHedgehog)] = clanPower[GetHogClan(CurrentHedgehog)] - placedExpense
			placedCount = placedCount + 1
		else
			AddCaption(loc("Invalid Placement"),0xffba00ff,capgrpVolume)
			PlaySound(sndDenied)
		end

	else
	    if (clanPower[GetHogClan(CurrentHedgehog)] >= placedExpense) then
            AddCaption(loc("Invalid Placement"),0xffba00ff,capgrpVolume)
        else
            AddCaption(loc("Insufficient Power"),0xffba00ff,capgrpVolume)
        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 = {}
	placedExpense = 1

	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 = CGR
		pMode = {loc("Girder")}
	elseif cat[cIndex] == "Rubber Placement Mode" then
		pIndex = CGR
		pMode = {loc("Rubber")}
		placedExpense = 3
	elseif cat[cIndex] == "Barrel Placement Mode" then
		pMode = {60}
		placedExpense = 10
		teamLObjectMode[team] = cat[cIndex]
	elseif cat[cIndex] == "Health Crate Placement Mode" then
		pMode = {HealthCaseAmount}
		placedExpense = 5
		teamLCrateMode[team] = cat[cIndex]
	elseif cat[cIndex] == "Weapon Crate Placement Mode" then
		for i = 1, #atkArray do
			pMode[i] = GetAmmoName(atkArray[i][1])
		end
		placedExpense = atkArray[pIndex][4]
		teamLCrateMode[team] = cat[cIndex]
		pIndex = teamLWeapIndex[team]
	elseif cat[cIndex] == "Utility Crate Placement Mode" then
		for i = 1, #utilArray do
			pMode[i] = GetAmmoName(utilArray[i][1])
		end
		placedExpense = utilArray[pIndex][4]
		teamLCrateMode[team] = cat[cIndex]
		pIndex = teamLUtilIndex[team]
	elseif cat[cIndex] == "Mine Placement Mode" then
		pMode = {0,1000,2000,3000,4000,5000}
		placedExpense = 15
		teamLObjectMode[team] = cat[cIndex]
		pIndex = teamLMineIndex[team]
	elseif cat[cIndex] == "Sticky Mine Placement Mode" then
		pMode = {loc("Sticky Mine")}
		placedExpense = 20
		teamLObjectMode[team] = cat[cIndex]
	elseif cat[cIndex] == "Structure Placement Mode" then
		pMode = {
			loc("Support Station"),
			loc("Construction Station"),
			loc("Healing Station"),
			loc("Teleportation Node"),
			loc("Weapon Filter"),

			loc("Bio-Filter"),
			loc("Reflector Shield"),
			loc("Respawner"),
			loc("Generator"),
		}
		pIndex = teamLStructIndex[team]
	end

	return true
end

-- called in onGameTick()
function HandleHedgeEditor()

	HandleStructures()

	if CurrentHedgehog ~= nil then

		if wallsVisible == true then
			HandleBorderEffects()
		end

		if (TurnTimeLeft ~= TurnTime) then
			if (lastWep ~= GetCurAmmoType()) then
				checkForSpecialWeapons()
			elseif checkForSpecialWeaponsIn == 0 then
				checkForSpecialWeapons()
				checkForSpecialWeaponsIn = -1
			else
				checkForSpecialWeaponsIn = checkForSpecialWeaponsIn - 1
			end
		end

		if GameTime % 100 == 0 then

			DrawClanPowerTag()


			-- Update display selection criteria
			if (band(GetState(CurrentHedgehog), gstHHDriven) ~= 0) then
				curWep = GetCurAmmoType()

				local updated = false
				local team = GetHogTeamName(CurrentHedgehog)
				if (curWep == amGirder) then
					cIndex = 1
					RedefineSubset()
					updated = true
				elseif (curWep == amRubber) then
					cIndex = 2
					RedefineSubset()
					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 updated then
					AddCaption(loc(cat[cIndex]), 0xffba00ff, capgrpMessage)
					showModeMessage()
					wallsVisible = true
				else
					wallsVisible = false
				end
			else
				curWep = amNothing
				wallsVisible = false
			end

		end

	end

	-- some kind of target detected, tell me your story
	if cGear ~= nil then

		x,y = GetGearTarget(cGear)

		if GetGearType(cGear) == gtAirAttack then
			DeleteGear(cGear)
			PlaceObject(x, y)
		elseif GetGearType(cGear) == gtTeleport then

				CheckTeleport(cGear, x, y)
				cGear = nil
		elseif GetGearType(cGear) == gtGirder then

			CGR = GetState(cGear)

			PlaceObject(x, y)
		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

	if pMode[pIndex] == loc("Healing Station") then
		placedExpense = 50
	elseif pMode[pIndex] == loc("Weapon Filter") then
		placedExpense = 50
	elseif pMode[pIndex] == loc("Bio-Filter") then
		placedExpense = 100
	elseif pMode[pIndex] == loc("Respawner") then
		placedExpense = 300
	elseif pMode[pIndex] == loc("Teleportation Node") then
		placedExpense = 30
	elseif pMode[pIndex] == loc("Support Station") then
		placedExpense = 50
	elseif pMode[pIndex] == loc("Construction Station") then
		placedExpense = 50
	elseif pMode[pIndex] == loc("Generator") then
			placedExpense = 300
	elseif pMode[pIndex] == loc("Reflector Shield") then
			placedExpense = 200
	elseif cat[cIndex] == "Weapon Crate Placement Mode" then
		placedExpense = atkArray[pIndex][4]
	elseif cat[cIndex] == "Utility Crate Placement Mode" then
		placedExpense = utilArray[pIndex][4]
	end

	AddCaption(loc("Cost") .. ": " .. placedExpense,0xffba00ff,capgrpAmmostate)

end

function onTimer(key)

	-- Hacky workaround for object placer: Since this is based on the drill strike, it
	-- allows the 5 timer keys to be pressed, causing the announcer to show up
	-- This triggers code in 1 tick to send other message to mask the earlier one.
	checkForSpecialWeaponsIn = 1

	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

function onSwitch()
	if (curWep == amCMObjectPlacer) then
		-- [Switch]: Set mine time to 0
		pIndex = 1
		updateIndex()
	end
end

function onLeft()
	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()
	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

-- 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] == "Girder Placement Mode" then
		str = loc("Girder")
	elseif cat[cIndex] == "Rubber Placement Mode" then
		str = loc("Rubber")
	else
		str = tostring(val)
	end
	AddCaption(str,0xffba00ff,capgrpMessage2)
end

function updatePlacementDisplay(pDir)

	foundMatch = false
	while(foundMatch == false) do
		cIndex = cIndex + pDir

		if (cIndex == 1) or (cIndex == 2) then --1	--we no longer hit girder by normal means
			cIndex = #cat
		elseif cIndex > #cat then
			cIndex = 3	 -- 2 ----we no longer hit girder by normal means
		end

		if sProx[cIndex][2] == true then
			if (GetCurAmmoType() == amCMCratePlacer) then
				if (sProx[cIndex][1] == loc("Health Crate Placement Mode")) or
					(sProx[cIndex][1] == loc("Weapon Crate Placement Mode")) or
					(sProx[cIndex][1] == loc("Utility Crate Placement Mode"))
					then
						foundMatch = true
					end
			elseif (GetCurAmmoType() == amCMObjectPlacer) then
				if (sProx[cIndex][1] == loc("Mine Placement Mode")) or
					(sProx[cIndex][1] == loc("Sticky Mine Placement Mode")) or
					(sProx[cIndex][1] == loc("Barrel Placement Mode"))
					then
						foundMatch = true
					end
			elseif (GetCurAmmoType() == amCMStructurePlacer) then
				if sProx[cIndex][1] == loc("Structure Placement Mode") then
					foundMatch = true
				end
			end
		end


		if foundMatch == true then
			RedefineSubset()
			updateCost()
		end

	end

end

---------------------------------------------------------
-- Cycle through primary categories (by changing cIndex)
-- i.e 	mine, sticky mine, barrels
--		health/weapon/utility crate, placement of gears
---------------------------------------------------------
function onUp()

	if ( (curWep == amCMCratePlacer) or (curWep == amCMObjectPlacer) ) then
		if CurrentHedgehog ~= nil and band(GetState(CurrentHedgehog), gstHHDriven) ~= 0 then
			updatePlacementDisplay(-1)
		end
	end

end

function onDown()

	if ( (curWep == amCMCratePlacer) or (curWep == amCMObjectPlacer) ) then
		if CurrentHedgehog ~= nil and band(GetState(CurrentHedgehog), gstHHDriven) ~= 0 then
			updatePlacementDisplay(1)
		end
	end

end

----------------------------
-- 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

	-- for now, everyone should have this stuff
	AddAmmo(gear, amCMStructurePlacer, 100)
	AddAmmo(gear, amSwitch, 100)
	AddAmmo(gear, amSkip, 100)

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.")
				, 4, 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."))
	
	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
	end

	tMapWidth = RightX - LeftX
	tMapHeight = WaterLine - TopY
	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,margin,color)
		AddWall(LeftX+(clanInterval*slot),WaterLine-25,clanInterval,margin,color)

		--add a wall to the left and right
		AddWall(LeftX+(clanInterval*slot)+20,TopY,margin,WaterLine,color)
		AddWall(LeftX+(clanInterval*slot)+clanInterval-20,TopY,margin,WaterLine,color)

	end

	runOnHogs(initialSetup)

end


function onNewTurn()

	curWep = GetCurAmmoType()

	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

end

function onTurnEnd()
	curWep = amNothing
end

function onGameTick()
	HandleHedgeEditor()
end

function isATrackedGear(gear)
	if 	(GetGearType(gear) == gtHedgehog) or
		(GetGearType(gear) == gtTarget) or
		(GetGearType(gear) == gtCase)
	then
		return(true)
	else
		return(false)
	end
end

-- track hedgehogs and placement gears
function onGearAdd(gear)

	if GetGearType(gear) == gtHedgehog then
	elseif (GetGearType(gear) == gtAirAttack) or (GetGearType(gear) == gtTeleport) or (GetGearType(gear) == gtGirder) then
		cGear = gear

	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

		if getGearValue(gear, "tCirc") ~= nil then
			DeleteVisualGear(getGearValue(gear, "tCirc"))
		end

		trackDeletion(gear)

	end

end