local function L_ZCollide(mo1,mo2)
	if mo1.z > mo2.height+mo2.z then return false end
	if mo2.z > mo1.height+mo1.z then return false end
	return true
end

-- stuff for netvars
//TehRealSalt is sooooo cool for making e102 gamma reusable!!
//using Gamma.IsCowboyMap from definitions, modified for takis
local function isTexas(map)
	if (mapheaderinfo[map] == nil)
		return false;
	end
	
	if (string.lower(mapheaderinfo[map].lvlttl) == "arid canyon")
	and (mapheaderinfo[map].actnum ~= 1)
		TAKIS_NET.donotsunstroke = true
	end
	
	if (mapheaderinfo[map].typeoflevel & TOL_NIGHTS)
		TAKIS_NET.donotsunstroke = true
	end
	
	if (mapheaderinfo[map].takis_donotsunstroke)
		TAKIS_NET.donotsunstroke = true
	end

	if tonumber(mapheaderinfo[map].takis_shadebrightness)
		TAKIS_SHADE_BRIGHTNESS = tonumber(mapheaderinfo[map].takis_shadebrightness)
	else
		TAKIS_SHADE_BRIGHTNESS = 200
	end
	
	if (mapheaderinfo[map].takis_ishotarea)
		return true;
	end
		
	if (mapheaderinfo[map].skynum >= 13
	and mapheaderinfo[map].skynum <= 16)
		// ACZ sky textures
		return true;
	end

	if (mapheaderinfo[map].musname == "ACZ1"
	or mapheaderinfo[map].musname == "ACZ2"
	or mapheaderinfo[map].musname == "VSFANG"
	or mapheaderinfo[map].musname == "SPEC5"
	or mapheaderinfo[map].musname == "MP_DES"
	or mapheaderinfo[map].musname == "MP_GLZ"
	or mapheaderinfo[map].musname == "MP_GL2"
	//red volcano
	or mapheaderinfo[map].musname == "RVZ1"
	or mapheaderinfo[map].musname == "RVZ2")
		// ACZ or desert music
		return true;
	end

	local desertWords = {
		"arid",
		"canyon",
		"wasteland",
		"sand",
		"desert",
		"mirage",
		"saloon",
		"western",
		"cactus",
		"cacti",
		"oasis",
		"gulch",
		"badland",
		"pyramid",
		"cowboy",
		"dune",
		"tumbleweed",
		"wild west",
		"roast",
		"texas",
		"templar",
		"flame",
		"volcano",
		"vulcan",
		"molten",
		"lava",
		"eruption",
		"erupt",
		"erupting",
		
	};

	local stageName = string.lower(mapheaderinfo[map].lvlttl);
	for i = 1,#desertWords do
		if (string.find(stageName, desertWords[i]) != nil)
			-- Has a very distinctly desert word in its title
			return true;
		end
	end

	return false;

end
local function isIcy(map)
	if (mapheaderinfo[map] == nil)
		return false;
	end
	
	if (mapheaderinfo[map].typeoflevel & TOL_NIGHTS)
		TAKIS_NET.donotfreeze = true
	end

	if (mapheaderinfo[map].takis_donotfreeze)
		TAKIS_NET.donotfreeze = true
	end

	if (mapheaderinfo[map].takis_iscoldarea)
		return true;
	end
	
	// https://wiki.srb2.org/wiki/Flats_and_textures/Skies
	if (mapheaderinfo[map].skynum == 17
	or mapheaderinfo[map].skynum == 29
	or mapheaderinfo[map].skynum == 30
	or mapheaderinfo[map].skynum == 107
	or mapheaderinfo[map].skynum == 55)
		return true;
	end

	if (mapheaderinfo[map].musname == "MP_ICE"
	or mapheaderinfo[map].musname == "FHZ"
	or mapheaderinfo[map].musname == "CCZ")
		// ice music
		return true;
	end
	
	//time to bust out the thesaurus!
	local icywords = {
		"frozen",
		"christmas",
		"ice",
		"icy",
		"icicle",
		"blizzard",
		"snow",
		"snowstorm",
		"frost",
		"winter",
		"chilly",
		"frigid",
		"artic",
		"polar",
		"glacial",
		"glacier",
		"wintery",
		"subzero",
		"tundra",
		"snowcap",
		"icecap",
	};

	local stageName = string.lower(mapheaderinfo[map].lvlttl);
	for i = 1,#icywords do
		if (string.find(stageName, icywords[i]) != nil)
			-- Has a very distinctly desert word in its title
			return true;
		end
	end

	return false;

end

addHook("MapChange", function(mapid)
	TAKIS_MAX_HEARTCARDS = 6
	if (mapheaderinfo[mapid].takis_maxheartcards)
		if (tonumber(mapheaderinfo[mapid].takis_maxheartcards) > 0)
			TAKIS_MAX_HEARTCARDS = tonumber(mapheaderinfo[mapid].takis_maxheartcards)
		end
	end
		
end)

addHook("MapLoad", function(mapid)
	local t = TAKIS_NET
	t.inspecialstage = G_IsSpecialStage(mapid)
	
	t.donotsunstroke = false
	t.texasarea = isTexas(mapid)
	
	t.donotfreeze = false
	t.icyarea = isIcy(mapid)
	
	//or you can put Lua.Takis_DoNotSunstroke/Freeze in your map
	//header to activate these
	if t.inspecialstage
		t.donotsunstroke = true
		t.donotfreeze = true
	end
	
	t.livescount = 0
	t.usesheartcards = true
  	
	if (G_RingSlingerGametype())
	or (gametyperules & (GTR_DEATHPENALTY|GTR_HURTMESSAGES|GTR_POINTLIMIT|GTR_PITYSHIELD|GTR_RINGSLINGER|GTR_TIMELIMIT|GTR_SPECTATORS))
		t.usesheartcards = false
	end
	
	
	if (mapheaderinfo[mapid].takis_usesheartcards)
		if (string.lower(mapheaderinfo[mapid].takis_usesheartcards) == "false")
			t.usesheartcards = false
		elseif (string.lower(mapheaderinfo[mapid].takis_usesheartcards) == "true")
			t.usesheartcards = true
		end
	end

end)

//thinkframe for netvars
addHook("ThinkFrame", do
	if gamestate ~= GS_LEVEL
		return
	end
	
	if (gametyperules & GTR_TAG)
		return
	elseif (G_GametypeHasTeams())
		return
	else
		
		if (G_GametypeUsesLives())
			
			if ((netgame or multiplayer) and G_GametypeUsesCoopLives() and (CV_FindVar("cooplives").value == 3))
				
				local lives = 0
				
				for p in players.iterate
					if p.lives < 1
						continue
					end
					
					if (p.lives == INFLIVES)
						lives = INFLIVES
						break
					elseif lives < 99
						lives = $+p.lives
					end
					
				end
				
				TAKIS_NET.livescount = lives
			end
		end
	end
end)


//after image
addHook("MobjThinker", function(ai)
	if not ai
	or not ai.valid
		return
	end
	
	//we need a thing to follow
	if not ai.target
	or not ai.target.valid
		P_RemoveMobj(ai)
		return
	end
	

	if (leveltime % 6) > 3
		ai.frame = $|TR_TRANS70
		//ai.flags2 = $ &~MF2_DONTDRAW
	else
		ai.frame = $|TR_TRANS90
		//ai.flags2 = $|MF2_DONTDRAW
	end
	
	local p = ai.target.player
	local me = p.mo
	
	//bruh
	if not me
	or not me.valid
		P_RemoveMobj(ai)
		return	
	end
	
	ai.spritexoffset = me.spritexoffset
	ai.spriteyoffset = me.spriteyoffset
	
	ai.colorized = true
	if not ai.timealive
		ai.timealive = 1
	else
		ai.timealive = $+1
	end
	
	//no interpolation please fingers crossed???????
	//i said PLEASE
	P_SetOrigin(ai, ai.x, ai.y, ai.z)
	
	if not (camera.chase)
		ai.flags2 = $|MF2_DONTDRAW
	end
	
	local fuselimit = 5

	//because fuse doesnt wanna work
	if ai.timealive > fuselimit
		P_RemoveMobj(ai)
		return
	end
	
end, MT_TAKIS_AFTERIMAGE)

addHook("MobjThinker", function(rag)
	if not rag
	or not rag.valid
		return
	end
	
	rag.speed = abs(FixedHypot(rag.momx,rag.momy))
	rag.timealive = $+1
	if rag.timealive % 5 == 0
		local poof = P_SpawnMobjFromMobj(rag,0,0,rag.height/2,MT_SPINDUST)
		poof.scale = FixedMul(2*FRACUNIT,rag.scale)
		poof.colorized = true
		poof.destscale = rag.scale/4
		poof.scalespeed = FRACUNIT/4
		poof.fuse = 10				
	end
	rag.angle = $-ANG10
	if rag.speed == 0
	or ((P_IsObjectOnGround(rag)) and (rag.timealive > 4))
		for i = 0, 34
			A_BossScream(rag,1,MT_SONIC3KBOSSEXPLODE)
		end
		local f = P_SpawnGhostMobj(rag)
		f.flags2 = $|MF2_DONTDRAW
		f.fuse = 2*TR
		S_StartSound(f,sfx_tkapow)
		P_RemoveMobj(rag)
	end
end, MT_TAKIS_BADNIK_RAGDOLL)

addHook("MobjCollide",function(t,tm)
	if not L_ZCollide(tm,t)
		return
	end

	if t.alreadydidthisbefore
		return
	else
		t.alreadydidthisbefore = true
	end
	
	if not tm.health
		return
	end
	
	if not t.health
		return
	end
	
//	if t == tm.parent2
//		return
//	end
	
	if (t.flags & (MF_ENEMY|MF_MONITOR))
	
		if not (t.flags & MF_BOSS)

			local ragdoll = P_SpawnMobjFromMobj(t,0,0,0,MT_TAKIS_BADNIK_RAGDOLL)
			t.tics = -1
			ragdoll.sprite = t.sprite
			ragdoll.color = t.color
			ragdoll.angle = R_PointToAngle2(t.x,t.y, tm.x,tm.y)
			ragdoll.frame = t.frame
			ragdoll.height = t.height
			ragdoll.radius = t.radius
			ragdoll.scale = t.scale
			ragdoll.timealive = 1
			ragdoll.angle = t.angle+tm.speed
			ragdoll.parent2 = tm.parent2
			
			P_SetObjectMomZ(ragdoll,7*t.scale)
			P_Thrust(ragdoll,ragdoll.angle,(-63*tm.scale)-tm.speed)
			
			if P_RandomChance(FRACUNIT/13)
				S_StartSound(ragdoll,sfx_takoww)
			end

			//P_KillMobj(t,tm,tm.tracer)
		else
			
			//crit
			S_StartSound(tm,sfx_tacrit)
			local ghost = P_SpawnGhostMobj(t)
			ghost.color = t.color
			ghost.colorized = true
			ghost.scale = t.scale*7/5
			ghost.destscale = ghost.scale*3/2
			ghost.frame = $|TR_TRANS80
			ghost.blendmode = AST_ADD

			P_DamageMobj(t,tm,tm.tracer,2)
		
		end
	/*
	elseif t.type == MT_PLAYER
		if CanPlayerHurtPlayer(tm.tracer.player,t.player)
			P_DamageMobj(t,tm,tm.tracer)
		end
	*/
	end
end,MT_TAKIS_BADNIK_RAGDOLL)

//starposts refill combo bar
addHook("MobjSpawn", function(post)
	post.activators = {}
end, MT_STARPOST)

addHook("TouchSpecial", function(post,touch)
	if not L_ZCollide(post,touch)
		return
	end
	
	if not post.activators
		post.activators = {}
	end
	
	//thanks amperbee
	if not post.activators[touch]
		
		if ((post.activators[touch] == false) or (post.activators[touch] == nil))
			post.activators[touch] = true
		
			if touch.player.takistable.combo.time
			
				
				TakisGiveCombo(touch.player,touch.player.takistable,false,true)
				
			end

			//also heal!
			TakisHealPlayer(touch.player,touch,touch.player.takistable,2)
			touch.player.takistable.HUD.statusface.happyfacetic = 3*TR/2
			
		end
	end
end, MT_STARPOST)

addHook("MobjDeath",function(t,i,s)
	if s
	and s.skin == TAKIS_SKIN
	and s.player
	
		if s.player.takistable.combo.time
			TakisGiveCombo(s.player,s.player.takistable,false,true)
		end
		
		if s.player.powers[pw_shield] & SH_FIREFLOWER
			TakisHealPlayer(s.player,s,s.player.takistable,1,1)
		end
	end
end,MT_FIREFLOWER)

addHook("MobjDeath", function(target,inflict,source)
	if source
	and source.skin == TAKIS_SKIN
	and source.player
		for p in players.iterate
			p.takistable.HUD.statusface.happyfacetic = 3*TR/2
		end
	end
end, MT_TOKEN)

addHook("MobjThinker", function(sweat)
	if not sweat
	or not sweat.valid
		return
	end
	
	if not sweat.tracer
	or not sweat.tracer.valid
		P_RemoveMobj(sweat)
		return
	end
	
	if not (camera.chase)
		sweat.flags2 = $|MF2_DONTDRAW
	else
		sweat.flags2 = $ &~MF2_DONTDRAW
	end
	
	if sweat.tracer.skin ~= TAKIS_SKIN
		sweat.flags2 = $|MF2_DONTDRAW
	end
	
	if sweat.tracer.eflags & MFE_VERTICALFLIP
		sweat.eflags = $|MFE_VERTICALFLIP
		P_MoveOrigin(sweat, sweat.tracer.x, sweat.tracer.y, (sweat.tracer.z + sweat.tracer.height - sweat.height)-sweat.tracer.height+(45*sweat.scale))
	else
		P_MoveOrigin(sweat, sweat.tracer.x, sweat.tracer.y, (sweat.tracer.z+sweat.tracer.height)-(45*sweat.scale))
	end	
	sweat.scale = sweat.tracer.scale
end,MT_TAKIS_SWEAT)

addHook("MobjThinker", function(bolt)
	if not bolt
	or not bolt.valid
		return
	end
	
	if not bolt.tracer
	or not bolt.tracer.valid
		P_RemoveMobj(bolt)
		return
	end
	
	if not (camera.chase)
		bolt.flags2 = $|MF2_DONTDRAW
	else
		bolt.flags2 = $ &~MF2_DONTDRAW
	end
	
end,MT_SOAP_SUPERTAUNT_FLYINGBOLT)

//eject from carts
addHook("MobjThinker",function(cart)
	if not cart
	or not cart.valid
	or not cart.target
		return
	end
	
	if ((cart.target) and (cart.target.valid))
	and cart.target.skin == TAKIS_SKIN
		
		local p = cart.target.player
		local takis = p.takistable
		
		if (p.cmd.buttons & BT_CUSTOM1)
		and (p.powers[pw_carry] == CR_MINECART)
			p.powers[pw_carry] = CR_NONE
			
			p.mo.momx,p.mo.momy = cart.momx,cart.momy
			
			p.pflags = $|PF_JUMPED &~PF_THOKKED
			takis.thokked = false
			takis.dived = false

			p.mo.momz = (8*p.mo.scale)*P_MobjFlip(p.mo)
			P_DoJump(p,true)
			
			TakisGiveCombo(p,takis,true)
			cart.target = nil
			return
			
		end
		
	end
	
	
end,MT_MINECART)

addHook("MobjDeath",function(mo,i,s)
	S_StartSound(mo,sfx_mspogo)

	for i = 0,16
		local debris = P_SpawnMobjFromMobj(mo,
			(P_RandomRange(-10,10)*mo.scale),
			(P_RandomRange(-10,10)*mo.scale),
			(P_RandomRange(-10,10)*mo.scale),
			MT_THOK
		)
		debris.fuse = 3*TR
		debris.sprite = USPK
		debris.frame = P_RandomRange(E,F)
	end
	
end,MT_SPIKEBALL)

//this is stupid
addHook("ThinkFrame", function()
	for p in players.iterate
		if not p
		or not p.valid
			continue
		end
		
		if not p.takistable
			continue
		end
		
		if ((p.mo) and (p.mo.valid))
			if p.mo.skin ~= TAKIS_SKIN
				continue
			end
			
			if p.pflags & PF_SLIDING
				p.takistable.inwaterslide = true
			else
				p.takistable.inwaterslide = false
			end
		end
	end
end)

local function happyhourmus(oldname, newname)
	if splitscreen
		return
	end
	
	if not (consoleplayer and consoleplayer.valid)
		return
	end
	
	if (gametype ~= GT_PIZZATIMEJISK)
		return
	end
	
	if not (consoleplayer.takistable)
		return
	end
	
	if (consoleplayer.takistable.io.nohappyhour == 1)
		return
	end
	
	
	if (skins[consoleplayer.skin].name ~= TAKIS_SKIN)
		return
	end
	
	//stop any lap music
	if newname == "PIZTIM" or newname == "piztim"
	or newname == "DEAOLI" or newname == "deaoli"
	or newname == "LAP3LO" or newname == "lap3lo"
	or newname == "GLUWAY" or newname == "gluway"
		if oldname ~= "HPYHRE"
			if oldname ~= "HAPYHR"
				S_ChangeMusic("HAPYHR", true, consoleplayer)
			end
		else
			S_ChangeMusic("HPYHRE", false, consoleplayer)
		end
		
		return true
	end
end
addHook("MusicChange", happyhourmus)