-- Old Weapons by LJ Sonic; Ported to 2.2 by CobaltBW

// Todo:
// Balancing
// Fix interferences with vanilla (done?)

mobjinfo[MT_THROWNGRENADE].mass = 200

local weapondurations =
{
	15 * TICRATE, // Infinity
	45 * TICRATE, // Automatic
	45 * TICRATE, // Bounce
	45 * TICRATE, // Scatter
	45 * TICRATE, // Grenade
	45 * TICRATE, // Explosion
	45 * TICRATE  // Rail
}

local cv_manyweapons = CV_RegisterVar({"manyweapons", "On", CV_NETVAR, CV_OnOff})
local cv_oldexplosions = CV_RegisterVar({"oldexplosions", "On", CV_NETVAR, CV_OnOff})

hud.disable("weaponrings")


function A_RingExplode(mo)
	if cv_oldexplosions.value
		A_OldRingExplode(mo, MT_REDRING)
	else
		super(mo)
	end
end

/*local function railThinker(mo)
	local x, y, z = mo.x, mo.y, mo.z

	if mo.momx ~= 0 or mo.momy ~= 0
		P_XYMovement(mo)
		if not mo.valid return true end
	end

	if mo.momz ~= 0
		if not P_ZMovement(mo) return true end
		//P_CheckPosition(mobj, mo.x, mo.y)
	end

	return not mo.valid or x == mo.x and y == mo.y and z == mo.z
end*/

local function railThinker(mo)
	local x, y, z = mo.x, mo.y, mo.z

	if mo.momx ~= 0 or mo.momy ~= 0
		if not P_TryMove(mo, mo.x + mo.momx, mo.y + mo.momy, true) return true end
		if not mo.valid return true end
	end

	if mo.momz ~= 0
		mo.z = $ + mo.momz
		if mo.z < mo.floorz or mo.z + mo.height > mo.ceilingz return true end
	end

	return not mo.valid or x == mo.x and y == mo.y and z == mo.z
end

local function shootRail(mo)
	local nblockmap = not (mo.flags & MF_NOBLOCKMAP)

	for i = 0, 255
		if nblockmap
			mo.flags = $ | MF_NOBLOCKMAP
		end

		if i & 1
			P_SpawnMobj(mo.x, mo.y, mo.z, MT_SPARK)
		end

		if railThinker(mo) break end
	end

	S_StartSound(mo, sfx_rail2)
end

local function setWeaponDelay(p, delay)
	p.weapondelay = p.skin == "knuckles" and delay * 2 / 3 or delay
end

local function P_DoOldFiring(p)
	if not (p.cmd.buttons & BT_ATTACK or p.cmd.buttons & BT_FIRENORMAL)
		p.attackdown = false
		return
	end

	local pw = p.powers

	if not p.attackdown and pw[pw_shield] & SH_FIREFLOWER and not p.climbing
		p.attackdown = true
		P_SpawnPlayerMissile(p.mo, MT_FIREBALL, 0)
		S_StartSound(p.mo, sfx_mario7)
		return
	elseif not(G_RingSlingerGametype() and (not G_TagGametype() or p.pflags & PF_TAGIT)
	and p.weapondelay == 0 and not p.climbing
	and not p.attackdown)
		return
	end

	p.attackdown = true

	if not pw[pw_infinityring]
		if p.rings <= 0 return end
-- 		p.mo.health = $ - 1
		p.rings = $ - 1
	end

	local mo

	if p.cmd.buttons & BT_FIRENORMAL
		setWeaponDelay(p, TICRATE / 4)

		if pw[pw_infinityring]
			mo = P_SpawnPlayerMissile(p.mo, MT_THROWNINFINITY, 0)
		else
			mo = P_SpawnPlayerMissile(p.mo, MT_REDRING, 0)

			if mo
				P_ColorTeamMissile(mo, p)
			end
		end

		return
	end

	local d

	local infinity = pw[pw_infinityring]
	local auto = pw[pw_automaticring]
	local bounce = pw[pw_bouncering]
	local grenade = pw[pw_grenadering]
	local bomb = pw[pw_explosionring]
	local rail = pw[pw_railring]

	if pw[pw_scatterring]
		local mt
		local mf2 = MF2_SCATTER
		local oldz = p.mo.z
		local shotangle = p.mo.angle
		local oldaiming = p.aiming

		if rail
			mf2 = $ | MF2_RAILRING | MF2_DONTDRAW
			S_StartSound(p.mo, sfx_rail1)

			if auto
				p.attackdown = false
				mf2 = $ | MF2_AUTOMATIC

				if bomb
					d = TICRATE
					mt = MT_THROWNEXPLOSION
					mf2 = $ | MF2_EXPLOSION
				else
					d = TICRATE * 2 / 3
					mt = MT_REDRING
				end
			else
				if bomb
					d = TICRATE * 2
					mt = MT_THROWNEXPLOSION
					mf2 = $ | MF2_EXPLOSION
				else
					d = TICRATE * 2
					mt = MT_REDRING
				end
			end
		else
			if auto
				p.attackdown = false
				mf2 = $ | MF2_AUTOMATIC

				if bomb
					d = TICRATE
					mt = MT_THROWNEXPLOSION
					mf2 = $ | MF2_EXPLOSION
				elseif grenade
					d = TICRATE / 4
					mt = MT_THROWNGRENADE
					mf2 = $ | MF2_EXPLOSION
				elseif bounce
					d = 6
					mt = MT_THROWNBOUNCE
					mf2 = $ | MF2_BOUNCERING
				else
					d = 6
					mt = MT_THROWNSCATTER
				end
			else
				if bomb
					d = TICRATE * 2
					mt = MT_THROWNEXPLOSION
					mf2 = $ | MF2_EXPLOSION
				elseif grenade
					d = TICRATE
					mt = MT_THROWNGRENADE
					mf2 = $ | MF2_EXPLOSION
				elseif bounce
					d = TICRATE * 2 / 3
					mt = MT_THROWNBOUNCE
					mf2 = $ | MF2_BOUNCERING
				else
					d = TICRATE * 2 / 3
					mt = MT_THROWNSCATTER
				end
			end
		end

		mo = P_SpawnPlayerMissile(p.mo, mt, mf2)
		if mo
			shotangle = mt == MT_THROWNGRENADE and p.mo.angle or R_PointToAngle2(p.mo.x, p.mo.y, mo.x, mo.y)
			if rail and mo.flags & MF_MISSILE
				shootRail(mo)
			elseif mt == MT_THROWNGRENADE
				//P_InstaThrust(mo, p.mo.angle, FixedMul(mo.info.speed, p.mo.scale))
				mo.fuse = mo.info.mass
			elseif mf2 & MF2_BOUNCERING
				mo.fuse = 3 * TICRATE
			end
		end

		mo = P_SPMAngle(p.mo, mt, shotangle - ANG2, 1, mf2)
		if rail and mo and mo.flags & MF_MISSILE
			shootRail(mo)
		elseif mt == MT_THROWNGRENADE and mo
			//P_InstaThrust(mo, p.mo.angle, FixedMul(mo.info.speed, p.mo.scale))
			mo.fuse = mo.info.mass
		elseif mf2 & MF2_BOUNCERING and mo
			mo.fuse = 3 * TICRATE
		end

		mo = P_SPMAngle(p.mo, mt, shotangle + ANG2, 1, mf2)
		if rail and mo and mo.flags & MF_MISSILE
			shootRail(mo)
		elseif mt == MT_THROWNGRENADE and mo
			//P_InstaThrust(mo, p.mo.angle, FixedMul(mo.info.speed, p.mo.scale))
			mo.fuse = mo.info.mass
		elseif mf2 & MF2_BOUNCERING and mo
			mo.fuse = 3 * TICRATE
		end

		p.mo.z = $ + FixedMul(12 * FRACUNIT, p.mo.scale)
		p.aiming = $ + ANG1
		mo = P_SPMAngle(p.mo, mt, shotangle, 1, mf2)
		if rail and mo and mo.flags & MF_MISSILE
			shootRail(mo)
		elseif mt == MT_THROWNGRENADE and mo
			//P_InstaThrust(mo, p.mo.angle, FixedMul(mo.info.speed, p.mo.scale))
			mo.fuse = mo.info.mass
		elseif mf2 & MF2_BOUNCERING and mo
			mo.fuse = 3 * TICRATE
		end

		p.mo.z = $ - FixedMul(24 * FRACUNIT, p.mo.scale)
		p.aiming = $ - ANG2
		mo = P_SPMAngle(p.mo, mt, shotangle, 1, mf2)
		if rail and mo and mo.flags & MF_MISSILE
			shootRail(mo)
		elseif mt == MT_THROWNGRENADE and mo
			//P_InstaThrust(mo, p.mo.angle, FixedMul(mo.info.speed, p.mo.scale))
			mo.fuse = mo.info.mass
		elseif mf2 & MF2_BOUNCERING and mo
			mo.fuse = 3 * TICRATE
		end

		p.mo.z = oldz
		p.aiming = oldaiming
	else
		local mt
		local mf2

		if rail
			mf2 = MF2_RAILRING | MF2_DONTDRAW
			S_StartSound(p.mo, sfx_rail1)

			if auto
				p.attackdown = false
				mf2 = $ | MF2_AUTOMATIC

				if bomb
					d = TICRATE / 2
					mt = MT_THROWNEXPLOSION
					mf2 = $ | MF2_EXPLOSION
				else
					d = TICRATE * 3 / 8
					mt = MT_REDRING
				end
			else
				if bomb
					d = TICRATE * 3 / 2
					mt = MT_THROWNEXPLOSION
					mf2 = $ | MF2_EXPLOSION
				else
					d = TICRATE * 3 / 2
					mt = MT_REDRING
				end
			end
		else
			if auto
				p.attackdown = false
				mf2 = MF2_AUTOMATIC

				if bomb
					d = TICRATE * 3 / 8
					mt = MT_THROWNEXPLOSION
					mf2 = $ | MF2_EXPLOSION
				elseif grenade
					d = 3
					mt = MT_THROWNGRENADE
					mf2 = $ | MF2_EXPLOSION
				elseif bounce
					d = 2
					mt = MT_THROWNBOUNCE
					mf2 = $ | MF2_BOUNCERING
				else
					d = 2
					mt = MT_THROWNAUTOMATIC
				end
			else
				if bomb
					d = TICRATE * 3 / 2
					mt = MT_THROWNEXPLOSION
					mf2 = MF2_EXPLOSION
				elseif grenade
					d = TICRATE / 3
					mt = MT_THROWNGRENADE
					mf2 = MF2_EXPLOSION
				elseif bounce
					d = TICRATE / 4
					mt = MT_THROWNBOUNCE
					mf2 = MF2_BOUNCERING
				else
					d = TICRATE / 4
					mt = infinity and MT_THROWNINFINITY or MT_REDRING
					mf2 = 0
				end
			end
		end

		mo = P_SpawnPlayerMissile(p.mo, mt, mf2)
		if rail and mo
			shootRail(mo)
		elseif mt == MT_THROWNGRENADE and mo
			//P_InstaThrust(mo, p.mo.angle, FixedMul(mo.info.speed, p.mo.scale))
			mo.fuse = mo.info.mass
		elseif mf2 & MF2_BOUNCERING and mo
			mo.fuse = 3 * TICRATE
		elseif mt == MT_REDRING and mo
			P_ColorTeamMissile(mo, p)
		end
	end

	setWeaponDelay(p, d)
end

addHook("ThinkFrame", do
	for p in players.iterate
		if not p.mo continue end

		p.pflags = $ | PF_ATTACKDOWN

		P_DoOldFiring(p)

		local pw = p.powers
		for i = pw_infinityring, pw_railring
			if pw[i]
				pw[i] = $ - 1
			end
		end
	end
end)


addHook("MapLoad", do
	hud.disable("weaponrings")
	if gametyperules&GTR_RINGSLINGER
		hud.disable("lives")
	else
		hud.enable("lives")
	end
end)

local DespawnAmmo = function(mo,thing)
	if not cv_manyweapons.value
	and not (mo.flags2 & MF2_DONTRESPAWN)
		mo.flags2 = $ | MF2_DONTRESPAWN | MF2_DONTDRAW
		P_KillMobj(mo)
	end
end

addHook("MapThingSpawn",DespawnAmmo,MT_BOUNCERING)
addHook("MapThingSpawn",DespawnAmmo,MT_AUTOMATICRING)
addHook("MapThingSpawn",DespawnAmmo,MT_SCATTERRING)
addHook("MapThingSpawn",DespawnAmmo,MT_EXPLOSIONRING)
addHook("MapThingSpawn",DespawnAmmo,MT_RAILRING)
addHook("MapThingSpawn",DespawnAmmo,MT_GRENADERING)

addHook("PlayerJoin", do
	hud.disable("weaponrings")
end)


addHook("MobjSpawn", function(mo)
	mo.state = S_BOUNCERINGAMMO
end, MT_BOUNCEPICKUP)

addHook("MobjSpawn", function(mo)
	mo.state = S_RAILRINGAMMO
end, MT_RAILPICKUP)

addHook("MobjSpawn", function(mo)
	mo.state = S_AUTOMATICRINGAMMO
end, MT_AUTOPICKUP)

addHook("MobjSpawn", function(mo)
	mo.state = S_EXPLOSIONRINGAMMO
end, MT_EXPLODEPICKUP)

addHook("MobjSpawn", function(mo)
	mo.state = S_SCATTERRINGAMMO
end, MT_SCATTERPICKUP)

addHook("MobjSpawn", function(mo)
	mo.state = S_GRENADERINGAMMO
end, MT_GRENADEPICKUP)

local function touchSpecialPanel(mo, pmo)
	local p = pmo.player

	if not P_CanPickupItem(p, true) return true end

	local pw = mo.info.mass

	if pw >= pw_infinityring and pw <= pw_railring
		p.powers[pw] = $ + weapondurations[pw - pw_infinityring + 1]
	end

	S_StartSound(pmo, mobjinfo[MT_BOUNCERING].deathsound)
	P_KillMobj(mo, nil, pmo)
	mo.state = mobjinfo[MT_BOUNCERING].deathstate

	return true
end

for mt = MT_BOUNCEPICKUP, MT_GRENADEPICKUP
	addHook("TouchSpecial", touchSpecialPanel, mt)
end


local function touchSpecialAmmo(mo, pmo)
	local p = pmo.player

	if not P_CanPickupItem(p, true) return true end

	local pw = mo.info.mass

	if pw >= pw_infinityring and pw <= pw_railring
		if mo.flags2 & MF2_DONTRESPAWN
			p.powers[pw] = $ + mo.health
		else
			p.powers[pw] = $ + weapondurations[pw - pw_infinityring + 1]
		end
	end

	S_StartSound(pmo, mo.info.deathsound)
	P_KillMobj(mo, nil, pmo)

	return true
end

for mt = MT_BOUNCERING, MT_GRENADERING
	addHook("TouchSpecial", touchSpecialAmmo, mt)
	//if mt ~= MT_INFINITYRING
		//addHook("MobjSpawn", spawnammo, mt)
	//end
end


local function ctfName(p)
	return p.ctfteam and ((p.ctfteam == 1 and "\x85" or "\x84")..p.name.."\x80") or p.name
end

local function hurtMsg(p, inflictor, source)
	if not (inflictor and inflictor.valid and source and source.valid) return end
	source = $.player
	if not (source and source.valid) return end

	local f = inflictor.flags2

	local weapon = ""
	if f & MF2_AUTOMATIC
		weapon = $..(weapon == "" and "" or "-").."automatic"
	end
	if f & MF2_SCATTER
		weapon = $..(weapon == "" and "" or "-").."scatter"
	end
	if f & MF2_EXPLOSION
		if inflictor.type == MT_THROWNEXPLOSION
			weapon = $..(weapon == "" and "" or "-").."explosion"
		else
			weapon = $..(weapon == "" and "" or "-").."grenade"
		end
	end
	if f & MF2_BOUNCERING
		weapon = $..(weapon == "" and "" or "-").."bounce"
	end
	if f & MF2_RAILRING
		weapon = $..(weapon == "" and "" or "-").."rail"
	end
	if weapon == ""
		weapon = inflictor.flags2 & MF2_DEBRIS and "explosion ring shrapnel" or "thrown ring"
	else
		weapon = $.." ring"
	end

	local deadsource = source.playerstate == PST_DEAD and source ~= p and inflictor.flags2 & MF2_BEYONDTHEGRAVE
	print((deadsource and "The late " or "")..ctfName(source).."'s "..weapon..(p.playerstate ~= PST_LIVE and " killed " or " hit ")..ctfName(p))

	return true
end

addHook("HurtMsg", hurtMsg, MT_REDRING)
for mt = MT_THROWNBOUNCE, MT_THROWNGRENADE
	if mt ~= MT_THROWNINFINITY
		addHook("HurtMsg", hurtMsg, mt)
	end
end


local function stringy(p, y)
	if splitscreen
		y = $ >> 1
		if #p == 0
			return y
		else
			return y + 100
		end
	else
		return y
	end
end

local function drawWeaponRing(v, p, weapon, rwflag, wepflag, xoffs, pat)
	local txtflags = 0, 0

	if p.powers[weapon]
		v.drawScaled((8 + xoffs) << FRACBITS, stringy(p, 162) << FRACBITS, FRACUNIT, pat, V_SNAPTOLEFT | V_TRANSLUCENT)

		local n = p.powers[weapon] / TICRATE
		if n > 99
			v.drawString(9 + xoffs, stringy(p, 162), n, V_SNAPTOLEFT | V_TRANSLUCENT, "thin")
		else
			v.drawString(8 + xoffs, stringy(p, 162), n, V_SNAPTOLEFT | V_TRANSLUCENT)
		end
	end
end

hud.add(function(v, p)
	if not G_RingSlingerGametype() or G_TagGametype() and not (p.pflags & PF_TAGIT) return end

	if splitscreen
		drawWeaponRing(v, p, pw_infinityring, 0, 0, 90, v.cachePatch("INFNIND"))
		drawWeaponRing(v, p, pw_automaticring, RW_AUTO, WEP_AUTO, 116, v.cachePatch("AUTOIND"))
		drawWeaponRing(v, p, pw_bouncering, RW_BOUNCE, WEP_BOUNCE, 136, v.cachePatch("BNCEIND"))
		drawWeaponRing(v, p, pw_scatterring, RW_SCATTER, WEP_SCATTER, 156, v.cachePatch("SCATIND"))
		drawWeaponRing(v, p, pw_grenadering, RW_GRENADE, WEP_GRENADE, 176, v.cachePatch("GRENIND"))
		drawWeaponRing(v, p, pw_explosionring, RW_EXPLODE, WEP_EXPLODE, 196, v.cachePatch("BOMBIND"))
		drawWeaponRing(v, p, pw_railring, RW_RAIL, WEP_RAIL, 216, v.cachePatch("RAILIND"))
	else
		local splity = splitscreen and 24 or 0
		local f = V_SNAPTOLEFT | V_TRANSLUCENT
		local pw = p.powers

		if pw[pw_infinityring] > 5 * TICRATE or pw[pw_infinityring] and leveltime & 1
			v.draw(8, stringy(p, 56 - splity), v.cachePatch("INFNIND"), f)
			v.drawString(32, stringy(p, 56 - splity + 4), pw[pw_infinityring] / TICRATE, f)
		end

		if pw[pw_automaticring] > 5 * TICRATE or pw[pw_automaticring] and leveltime & 1
			v.draw(8, stringy(p, 76 - splity), v.cachePatch("AUTOIND"), f)
			v.drawString(32, stringy(p, 76 - splity + 4), pw[pw_automaticring] / TICRATE, f)
		end

		if pw[pw_bouncering] > 5 * TICRATE or pw[pw_bouncering] and leveltime & 1
			v.draw(8, stringy(p, 96 - splity), v.cachePatch("BNCEIND"), f)
			v.drawString(32, stringy(p, 96 - splity + 4), pw[pw_bouncering] / TICRATE, f)
		end

		if pw[pw_scatterring] > 5 * TICRATE or pw[pw_scatterring] and leveltime & 1
			v.draw(8, stringy(p, 116 - splity), v.cachePatch("SCATIND"), f)
			v.drawString(32, stringy(p, 116 - splity + 4), pw[pw_scatterring] / TICRATE, f)
		end

		if pw[pw_grenadering] > 5 * TICRATE or pw[pw_grenadering] and leveltime & 1
			v.draw(8, stringy(p, 136 - splity), v.cachePatch("GRENIND"), f)
			v.drawString(32, stringy(p, 136 - splity + 4), pw[pw_grenadering] / TICRATE, f)
		end

		if pw[pw_explosionring] > 5 * TICRATE or pw[pw_explosionring] and leveltime & 1
			v.draw(8, stringy(p, 156 - splity), v.cachePatch("BOMBIND"), f)
			v.drawString(32, stringy(p, 156 - splity + 4), pw[pw_explosionring] / TICRATE, f)
		end

		if pw[pw_railring] > 5 * TICRATE or pw[pw_railring] and leveltime & 1
			v.draw(8, stringy(p, 176 - splity), v.cachePatch("RAILIND"), f)
			v.drawString(32, stringy(p, 176 - splity + 4), pw[pw_railring] / TICRATE, f)
		end
	end
end)




/*COM_AddCommand("t", function(p, ...)
	for p in players.iterate
		local mo = p.mo
		if not mo continue end

		mo.health = 10000
		p.health = mo.health
		for _, wp in pairs({...})
			p.powers[pw_infinityring + wp - 1] = 45 * TICRATE
		end
	end
end, 1)*/