
----------------------
-- WALL TO WALL 0.4
----------------------
-- a shoppa minigame
-- by mikade

-- feel free to add map specific walls to LoadConfig, or post additional
-- wall suggestions on our forum at: http://www.hedgewars.org/forum

----------------
--0.1
----------------
-- concept test

----------------
--0.2
----------------
-- unhardcoded turntimeleft, now uses shoppa default of 45s
-- changed some things behind the scenes
-- fixed oooooold radar bug
-- added radar / script support for multiple crates
-- tweaked weapons tables
-- added surfing and changed crate spawn requirements a bit

----------------
--0.3
----------------
-- stuffed dirty clothes into cupboard
-- improved user feedback
-- added/improved experimental config system, input masks included :D

----------------
--0.4
----------------
-- for version 0.9.18, now detects border in correct location
-- fix 0.3 config constraint
-- remove unnecessary vars
-- oops, remove hardcoding of minesnum,explosives
-- ... and unhardcode turntime (again)... man, 30s is hard :(
-- move some initialisations around
-- numerous improvements to user feedback
-- walls disappear after being touched
-- added backwards compatibility with 0.9.17

----------------
--TO DO
----------------
-- achievements / try detect shoppa moves? :|
-- maybe add ability for the user to place zones like in Racer?
-- add more hard-coded values for specific maps

-----------------------------
-- GO PONIES, GO PONIES, GO!
-----------------------------

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

-- experimental menu stuff
local menuIndex = 1
local menu = {}
local preMenuCfg
local postMenuCfg
local roundN = 0

-- config and wall variables
local AFR = false
local allowCrazyWeps = false
local requireSurfer = true
local wX = {}
local wY = {}
local wWidth = {}
local wHeight = {}
local wTouched = {}
--local margin
local wallsLeft = 0

local hasSurfed = false
local allWallsHit = false

local gTimer = 1
local effectTimer = 1

local ropeG = nil
local crateG = nil
local allowCrate = true

-- crate radar vars
local rCirc = {}
local rAlpha = 255
local rPingTimer = 0
local m2Count = 0

local weapons = {}

--[[local unlisted = {amTardis, amLandGun,amExtraTime,amExtraDamage,
				amVampiric, amSwitch, amInvulnerable, amGirder, amJetpack,
				amPortalGun, amTeleport, amResurrector, amLaserSight, amLowGravity,
				amAirAttack, amNapalm, amMineStrike, amDrillStrike,
				amKamikaze, amSnowball, amSeduction}]]

local crazyWeps = {amWatermelon, amHellishBomb, amBallgun, amRCPlane}

local groundWeps = 	{amBee, amShotgun,amDEagle,amFirePunch, amWhip,
				amPickHammer, amBaseballBat, amCake,amBallgun,
				amRCPlane, amSniperRifle, amBirdy, amBlowTorch, amGasBomb,
				amFlamethrower, amSMine, amMortar, amHammer}

local ropeWeps = {amGrenade, amClusterBomb, amBazooka, amMine, amDynamite,
				amWatermelon, amHellishBomb, amDrill, amMolotov}

-- 0.9.18+ extra custom data for preset maps
local MapList =
	{
	--name,      						surfer, roof, 	LRwalls
	{"Atlantis Shoppa", 			    true, 	false, true},
	{"BambooPlinko", 				    true,	false, true},
	{"BrickShoppa", 				    false, 	false, true},
	{"BubbleFlow",   					true, 	false, true},
	{"Cave",       						false, 	false, true},
	{"Glass Shoppa",      				true, 	false, true},
	{"HardIce",      					false, 	false, true},
	{"Industrial",       				false,	false, true},
	{"Islands",       					true, 	false, true},
	{"Hedgelove",       				true, 	false, true},
	{"NeonStyle",       				false, 	false, true},
	{"Octorama",       					false, 	false, true},
	{"red vs blue - Castle",     		true, 	false, true},
	{"red vs blue - castle2",     		true, 	false, true},
	{"red vs blue - True Shoppa Sky",   true, 	false, true},
	{"Ropes",       					false, 	false, true},
	{"Ropes Rearranged",      			false, 	false, true},
	{"RopesRevenge Flipped",    		true, 	false, true},
	{"Ropes Three",      				false, 	false, true},
	{"RopesTwo",      					false, 	false, true},
	{"ShapeShoppa1.0",     				true, 	false, true},
	{"ShappeShoppa Darkhow",      		true, 	false, true},
	{"ShoppaCave2",      				true, 	false, true},
	{"ShoppaFun",      					true, 	false, true},
	{"ShoppaGolf",      				false, 	false,  true},
	{"ShoppaHell",      				false, 	true,  false},
	{"ShoppaKing",       				false, 	false, false},
	{"ShoppaNeon",       				false, 	false, true},
	{"ShoppaSky",       				false, 	false, true},
	{"Shoppawall",       				false, 	false, true},
	{"SkatePark",       				false, 	false, true},
	{"SloppyShoppa",      				false, 	false, true},
	{"Sticks",       					true, 	false, true},
	{"Symmetrical Ropes ",       		false, 	false, true},
	{"Tetris",       					false, 	false, true},
	{"TransRopes2",      				false, 	false, true},
	{"Wildmap",      					false, 	false, true},
	{"Winter Shoppa",      				false, 	false, true},
	{"2Cshoppa",      					true, 	false, true}
	}

function BoolToCfgTxt(p)
	if p == false then
		return("Disabled")
	else
		return("Enabled")
	end
end

function LoadConfig(p)

	margin = 20
	mapID = nil

	-- 0.9.17
	if Map == "CHANGE_ME" then
		AddCaption(loc("For improved features/stability, play 0.9.18+"))
		--AddWall(10,10,4085,margin)
		AddWall(10,10,margin,2025)
		AddWall(4085-margin,10,margin,2025)
	end

	--0.9.18+
	for i = 1, #MapList do
		if Map == MapList[i][1] then
			mapID = i
			--AddCaption(MapList[i][1] .. " found. reqSurf is " .. BoolToCfgTxt(MapList[i][2]))
		end
	end

	if (p == 1) and (mapID ~= nil) then
		requireSurfer = MapList[mapID][2]
	end

	if mapID ~= nil then

		-- add a wall to the roof
		if MapList[mapID][3] == true then
			AddWall(LeftX+10,TopY+10,RightX-LeftX-20,margin)
		end

		-- add walls on the left and right border
		if MapList[mapID][4] == true then
			AddWall(LeftX+10,TopY+10,margin,WaterLine)
			AddWall(RightX-10-margin,TopY+10,margin,WaterLine)
		end

		-- add map specific walls
		if Map == "Ropes" then
			AddWall(1092,934,54,262)
			AddWall(2822,323,33,137)
		elseif Map == "ShoppaKing" then
			AddWall(3777,1520,50,196)
			AddWall(1658,338,46,670)
		elseif Map == "ShoppaHell" then
			AddWall(2035,831,30,263)
			AddWall(3968,1668,31,383)
		elseif Map == "ShoppaNeon" then
			AddWall(980,400,20,300)
			AddWall(1940,400,20,300)
			AddWall(3088,565,26,284)
			AddWall(187,270,28,266)
		end

	-- if map is unrecognized, add two walls on the side borders
	-- also, if version of hw is not 0.9.17 or lower
	elseif Map ~= "CHANGE_ME" then
		AddWall(LeftX+10,TopY+10,margin,WaterLine)
		AddWall(RightX-10-margin,TopY+10,margin,WaterLine)
	end


end

function AddWall(zXMin,zYMin, zWidth, zHeight)

	table.insert(wX, zXMin)
	table.insert(wY, zYMin)
	table.insert(wWidth, zWidth)
	table.insert(wHeight, zHeight)
	table.insert(wTouched, false)

end

function DrawBlip(gear)
	SetVisualGearValues(getGearValue(gear,"CIRC"), getGearValue(gear,"RX"), getGearValue(gear,"RY"), 100, 255, 1, 10, 0, 40, 3, GetClanColor(GetHogClan(CurrentHedgehog))-rAlpha)
end

function TrackRadarBlip(gear)

	-- work out the distance to the target
	g1X, g1Y = GetGearPosition(CurrentHedgehog)
	g2X, g2Y = GetX(gear), GetY(gear)
	q = g1X - g2X
	w = g1Y - g2Y
	r = math.sqrt( (q*q) + (w*w) )	--alternate

	RCX = getGearValue(gear,"RX")
	RCY = getGearValue(gear,"RY")

	rCircDistance = r -- distance to circle

	opp = w
	if opp < 0 then
		opp = opp*-1
	end

	-- work out the angle (theta) to the target
	t = math.deg ( math.asin(opp / r) )

	-- based on the radius of the radar, calculate what x/y displacement should be
	NR = 150 -- radius at which to draw circs
	NX = math.cos( math.rad(t) ) * NR
	NY = math.sin( math.rad(t) ) * NR

	if rCircDistance < NR then
		RCX = g2X
	elseif q > 0 then
		RCX = g1X - NX
	else
		RCX = g1X + NX
	end

	if rCircDistance < NR then
		RCY = g2Y
	elseif w > 0 then
		RCY = g1Y - NY
	else
		RCY = g1Y + NY
	end

	setGearValue(gear, "RX", RCX)
	setGearValue(gear, "RY", RCY)

end


function HandleCircles()

	-- enable this if you want the radar to only show for a few seconds
	-- after you spawn the crate
	--[[if rAlpha ~= 255 then

		rPingTimer = rPingTimer + 1
		if rPingTimer == 100 then
			rPingTimer = 0

			rAlpha = rAlpha + 5
			if rAlpha >= 255 then
				rAlpha = 255
			end
		end

	end]]

	runOnGears(DrawBlip)

	m2Count = m2Count + 1
	if m2Count == 25 then
		m2Count = 0

		if (CurrentHedgehog ~= nil) and (rAlpha ~= 255) then
			runOnGears(TrackRadarBlip)
		end

	end

end


function CheckCrateConditions()

	crateSpawn = true

	if requireSurfer == true then
		if hasSurfed == false then
			crateSpawn = false
		end
	end

	if #wTouched > 0 then
		if allWallsHit == false then
			crateSpawn = false
		end
	end

	if crateSpawn == true then
		if allowCrate == true then
		--if (crateG == nil) and (allowCrate == true) then
			--AddCaption("")
			SpawnAmmoCrate(0, 0, weapons[1+GetRandom(#weapons)] )
			rPingTimer = 0
			rAlpha = 0
			PlaySound(sndWarp)
		end
	end

end

function onGearWaterSkip(gear)
	if gear == CurrentHedgehog then
		hasSurfed = true
		AddCaption(loc("Surfer!"),0xffba00ff,capgrpMessage2)
	end
end


function WallHit(id, zXMin,zYMin, zWidth, zHeight)

	if wTouched[id] == false then
		tempE = AddVisualGear(GetX(CurrentHedgehog), GetY(CurrentHedgehog), vgtBigExplosion, 0, false)
		PlaySound(sndExplosion)
		wallsLeft = wallsLeft - 1

		if wallsLeft == 0 then
			AddCaption(loc("All walls touched!"))
			allWallsHit = true
			if (requireSurfer == true) and (hasSurfed == false) then
				AddCaption(loc("Go surf!"),0xffba00ff,capgrpMessage2)
			end
		else
			AddCaption(loc("Walls Left") .. ": " .. wallsLeft)
		end

	end

	wTouched[id] = true
	tempE = AddVisualGear(GetX(CurrentHedgehog), GetY(CurrentHedgehog), vgtSmoke, 0, false)
	--PlaySound(sndVaporize) -- yeah, this is just annoying as shit

end

function CheckForWallCollision()

	for i = 1, #wTouched do
		if gearIsInBox(CurrentHedgehog, wX[i],wY[i],wWidth[i],wHeight[i]) then
			WallHit(i, wX[i],wY[i],wWidth[i],wHeight[i])
		end
	end

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

		effectTimer = 1

		for i = 1, #wTouched do
			if wTouched[i] == true then
				--bCol = GetClanColor(GetHogClan(CurrentHedgehog))
			else
				--bCol = 0xFFFFFFFF
				bCol = GetClanColor(GetHogClan(CurrentHedgehog))
				BorderSpark(wX[i],wY[i],wWidth[i],wHeight[i], bCol)
			end
			--BorderSpark(wX[i],wY[i],wWidth[i],wHeight[i], bCol)
		end

	end

end

function onLJump()
	if roundN < 2 then
		roundN = 100
		SetInputMask(0xFFFFFFFF)
		TurnTimeLeft = 1
		AddCaption(loc("Configuration accepted."),0xffba00ff,capgrpMessage)
		HideMission()
	end
end

function onAttack()

	if roundN < 2 then

		if menuIndex == 1 then

			if #wTouched > 0 then
				for i = 1, #wTouched do
					wTouched[i] = nil
					wX[i] = nil
					wY[i] = nil
					wWidth[i] = nil
					wHeight[i] = nil
				end
			else
				LoadConfig(2)
			end

		elseif menuIndex == 2 then
			requireSurfer = not(requireSurfer)
		elseif menuIndex == 3 then
			AFR = not(AFR)
		elseif menuIndex == 4 then
			allowCrazyWeps = not(allowCrazyWeps)
		end

		UpdateMenu()
		configureWeapons()
		HandleStartingStage()

	elseif (AFR == true) then

		if (GetCurAmmoType() ~= amRope) and
			(GetCurAmmoType() ~= amSkip) and
			(GetCurAmmoType() ~= amNothing)
		then
			AddCaption(loc("You may only attack from a rope!"),0xffba00ff,capgrpMessage2)
		end

	end

end

function onDown()
	if roundN < 2 then
		menuIndex = menuIndex +1
		if menuIndex > #menu then
			menuIndex = 1
		end
		HandleStartingStage()
	end
end

function onUp()
	if roundN < 2 then
		menuIndex = menuIndex -1
		if 	menuIndex == 0 then
			menuIndex = #menu
		end
		HandleStartingStage()
	end
end

function onGameInit()

	ClearGameFlags()
	EnableGameFlags(gfRandomOrder, gfBorder, gfSolidLand) --, gfInfAttack
	HealthCaseProb = 0
	CaseFreq = 0

end

function configureWeapons()

	-- reset wep array
	for i = 1, #weapons do
		weapons[i] = nil
	end

	-- add rope weps
	for i, w in pairs(ropeWeps) do
        table.insert(weapons, w)
	end

	-- add ground weps
	for i, w in pairs(groundWeps) do
        table.insert(weapons, w)
	end

	-- remove ground weps if attacking from rope is mandatory
	if AFR == true then
		for i = 1, #weapons do
			for w = 1, #groundWeps do
				if groundWeps[w] == weapons[i] then
					table.remove(weapons, i)
				end
			end
		end
	end

	-- remove crazy weps is crazy weps aren't allowed
	if allowCrazyWeps == false then
		for i = 1, #weapons do
			for w = 1, #crazyWeps do
				if crazyWeps[w] == weapons[i] then
					table.remove(weapons, i)
				end
			end
		end
	end

end

function onGameStart()

	LoadConfig(1)
	configureWeapons()
	UpdateMenu()
	HandleStartingStage()

end

function onNewTurn()

	wallsLeft = #wTouched

	for i = 1, #wTouched do
		wTouched[i] = false
	end

	allowCrate = true

	hasSurfed = false
	allWallsHit = false

	crateG = nil

	-- new config stuff
	roundN = roundN + 1
	if roundN < 2 then
		TurnTimeLeft = -1
		SetInputMask(0)
		allowCrate = false
		HandleStartingStage() -- new
	end

end

function UpdateMenu()

	preMenuCfg = loc("Spawn the crate, and attack!") .. "|"
	postMenuCfg = loc("Press [Enter] to accept this configuration.")

	menu = 	{
			loc("Walls Required") .. ": " .. #wTouched .. "|",
			loc("Surf Before Crate") .. ": " .. BoolToCfgTxt(requireSurfer) .. "|",
			loc("Attack From Rope") .. ": " .. BoolToCfgTxt(AFR) .. "|",
			loc("Super Weapons") .. ": " .. BoolToCfgTxt(allowCrazyWeps) .. "|"
			}
end

function HandleStartingStage()

	temp = menu[menuIndex]
	menu[menuIndex] = "--> " .. menu[menuIndex]

	missionComment = ""
	for i = 1, #menu do
		missionComment = missionComment .. menu[i]
	end

	ShowMission	(
				loc("WALL TO WALL") .. " 0.4",
				loc("a shoppa minigame"),
				preMenuCfg..
				missionComment ..
				postMenuCfg ..
				--" " .. "|" ..
				"", 4, 300000
				)

	menu[menuIndex] = temp

end

function onGameTick()

	if CurrentHedgehog ~= nil then

		--AddCaption(Map)
		--AddCaption(RightX ..";" .. GetX(CurrentHedgehog))

		gTimer = gTimer + 1
		if gTimer == 25 then
			gTimer = 1

			CheckForWallCollision()
			CheckCrateConditions()

			if (crateG == GetFollowGear()) and (crateG ~= nil) then
				FollowGear(CurrentHedgehog)
			end

			-- if attackfromrope is set, forbid firing unless using rope
			if (AFR == true) and (roundN >= 2) then
				if (GetCurAmmoType() == amRope) or
					(GetCurAmmoType() == amSkip) or
					(GetCurAmmoType() == amNothing)
				then
					SetInputMask(0xFFFFFFFF)
				elseif ropeG == nil then
					SetInputMask(bnot(gmAttack))
				end
			end

		end

		HandleBorderEffects()
		HandleCircles()

	end

end

function onGearAdd(gear)

	if GetGearType(gear) == gtRope then
		ropeG = gear
	elseif GetGearType(gear) == gtCase then

		crateG = gear
		trackGear(gear)

		table.insert(rCirc, AddVisualGear(0,0,vgtCircle,0,true) )
		setGearValue(gear,"CIRC",rCirc[#rCirc])
		setGearValue(gear,"RX",0)
		setGearValue(gear,"RY",0)
		SetVisualGearValues(rCirc[#rCirc], 0, 0, 100, 255, 1, 10, 0, 40, 3, 0xff00ffff)

		allowCrate = false

		rPingTimer = 0
		rAlpha = 0

	end

end

function onGearDelete(gear)

	if gear == ropeG then
		ropeG = nil
	elseif GetGearType(gear) == gtCase then

		if gear == crateG then
			crateG = nil
		--	rAlpha = 255
		end

		for i = 1, #rCirc do
			if rCirc[i] == getGearValue(gear,"CIRC") then
				DeleteVisualGear(rCirc[i])
				table.remove(rCirc, i)
			end
		end

		trackDeletion(gear)

	end

end

function onAmmoStoreInit()

	for i, w in pairs(ropeWeps) do
        SetAmmo(w, 0, 0, 0, 1)
    end

    for i, w in pairs(groundWeps) do
        SetAmmo(w, 0, 0, 0, 1)
    end

    for i, w in pairs(crazyWeps) do
        SetAmmo(w, 0, 0, 0, 1)
    end

	SetAmmo(amRope, 9, 0, 0, 0)
	SetAmmo(amSkip, 9, 0, 0, 0)

end
