//Lua to choose a slug cat based on your skincolor

local SCUG_SKIN = "slugcat"
local SCUG_InvGrandPrix = false

//Define slug cat IDs
local SCUG_DEFAULT = 0
local SCUG_INV = 1
local SCUG_MONK = 2
local SCUG_SURVIVOR = 3
local SCUG_RIVULET = 4
local SCUG_MAX = 5 //Always needs to be one above the last slug cat

//Inv's own special skincolor
freeslot("SKINCOLOR_SOFANTHIEL")
skincolors[SKINCOLOR_SOFANTHIEL] = {
	name = "Sofanthiel",
	ramp = {44,46,199,254,254,175,175,137,137,136,136,142,141,141,140,140},
	invcolor = SKINCOLOR_SLATE,
	invshade = 8, 
	chatcolor = V_SKYMAP,
	accessible = false
}

//Assign slug cats to colors
//Positive numbers are chat colors, negative colors are skincolors
local SCUG_COLORS = {
	//Inv
	[-SKINCOLOR_VOMIT] = SCUG_INV,
	[-SKINCOLOR_SOFANTHIEL] = SCUG_INV,
	
	//Monk
	[V_YELLOWMAP] = SCUG_MONK,
	[V_GOLDMAP] = SCUG_MONK,
	//[-SKINCOLOR_BANANA] = SCUG_MONK,
	[-SKINCOLOR_GARDEN] = SCUG_MONK,
	
	//Survivor
	[0] = SCUG_SURVIVOR, //V_WHITEMAP (since it doesn't exist)
	//[-SKINCOLOR_SLATE] = SCUG_SURVIVOR,
	[-SKINCOLOR_GREY] = SCUG_SURVIVOR,
	[-SKINCOLOR_PLATINUM] = SCUG_SURVIVOR,
	[-SKINCOLOR_STEEL] = SCUG_SURVIVOR,
	
	//Rivulet
	[V_SKYMAP] = SCUG_RIVULET,
	[V_BLUEMAP] = SCUG_RIVULET,
	//[-SKINCOLOR_JAWZ] = SCUG_RIVULET,
}

//Keep track of common frame translations
//Index using (mo.frame & FF_FRAMEMASK) | (mo.sprite2 << 8) | (player.slugcat << 16)
local SCUG_FRAMES = {}

//Inv bots
local SCUG_BOTNUM = 2
local SCUG_BOTS = {
	[0] = "redz",
	[1] = "zipp",
	["redz"] = SKINCOLOR_BYZANTIUM,
	["zipp"] = SKINCOLOR_RED,
}

//Half of Inv's rings are spikes...
function A_ScugAttractChase(mobj, var1, var2)
	//Need a valid non-bot player
	local mo = mobj.target
	local player = mo and mo.valid and mo.player
	if not player then return end
	
	//Is this a ring being used with the item button?
	local isboostring = mobj.extravalue2
	local ringtimer = mobj.extravalue1
	
	//Visual frame
	if ringtimer & 1
		mobj.frame = $ | 7
	else
		mobj.frame = $ | (ringtimer % 7)
	end
	
	//Get our current variables before doing the ring logic
	local ringboost = player.ringboost
	local isfinalring = mobj.cvmem
	
	//Don't do the ring logic unless it's the last frame!
	if not (ringtimer >= 20 or (ringtimer >= 15 and not isboostring))
		return
	end
	mobj.extravalue1 = $ + 1
	
	//Do the ring logic
	mobj.cvmem = (not isboostring) and 1 or $ //Hijack the cash register sound for our spike sfx
	A_AttractChase(mobj, var1, var2)
	
	//Revert cvmem variable
	if mobj and mobj.valid
		mobj.cvmem = isfinalring
		return
	end
	
	//You aren't getting anything out of these spikes!
	if player.ringboost != ringboost
		player.ringboost = ringboost
		
		//Play the appropriate sfx instead of the ring ones
		if isboostring
			if S_SoundPlaying(mo, sfx_s1b5)
				S_StopSoundByID(mo, sfx_s1b5)
				S_StartSoundAtVolume(mo, sfx_cdfm39, player.ringvolume)
			end
		elseif not isfinalring and S_SoundPlaying(mo, sfx_s1c5)
			S_StopSoundByID(mo, sfx_s1c5)
			S_StartSoundAtVolume(mo, sfx_s222, player.ringvolume)
		end
	end
end

//Inv Ring State
freeslot("S_SCUG_RING")
states[S_SCUG_RING] = {SPR_DEBT, FF_FULLBRIGHT, 1, A_ScugAttractChase, 23, 1, S_SCUG_RING}

//Get a slug cat ID from a skin color
local SCUG_GetSlugcatFromColor = function(color)
	return SCUG_COLORS[-color] or SCUG_COLORS[skincolors[color].chatcolor] or SCUG_DEFAULT
end

addHook("MapLoad", do
	//Give everyone their slug cat ID at the beginning of the race
	//I would do this check more often, but there's no sense when the game
	//doesn't naturally let you change your skin midrace
	for player in players.iterate
		if skins[player.skin].name == SCUG_SKIN
			player.slugcat = SCUG_GetSlugcatFromColor(player.skincolor)
		elseif skins[player.skin].flags & SF_IRONMAN
			player.slugcat = -1 //Uh oh! Ironman special case
		else
			player.slugcat = nil
		end
	end
	
	//Inv's torture chamber!
	SCUG_InvGrandPrix = not netgame and grandprixinfo.gp and consoleplayer.slugcat == SCUG_INV
	if not SCUG_InvGrandPrix then return end
	
	//Go through all the players again...
	//Change all bots to max difficulty Redz, any real players get land mines
	local foundredz = true //Loop feedback variable
	while foundredz do
		foundredz = false //We haven't gotten a new Redz yet...
		for player in players.iterate
			//Not a bot? Have a land mine!
			if not player.bot
				if not player.itemtype
					player.itemtype = KITEM_LANDMINE
					player.itemamount = 1
				end
				continue
			end
			
			//Not a Redz? Delete this bot and make a new one!
			local botskin = SCUG_BOTS[(#player - 1) % SCUG_BOTNUM] or "redz"
			if skins[player.skin].name != botskin
				K_RemoveBot(player) //Remove this bot
				K_AddBot(botskin, 13, BOT_STYLE_NORMAL) //Add max level Redz
				
				//Restart loop to account for shuffling player IDs
				foundredz = true
				break
				
			//Already a Redz? Max out the difficulty!
			else
				player.botvars.difficulty = 13 //Max out Redz's level
				player.botvars.rival = true //Force rival mode!
			end
		end
	end
	
	//Go through all the sectors and clamp their brightness down
	for sector in sectors.iterate
		/*
		if not sector.floorlightabsolute
			sector.floorlightabsolute = true
			sector.ceilinglightabsolute = true
			sector.floorlightlevel = min(sector.lightlevel, 144)
			sector.ceilinglightlevel = min(sector.lightlevel, 144)
		end
		*/
		sector.lightlevel = min($, 128)
	end
	
	//Go through all objects and fullbright them at the start
	//Just so the darkness is a little more sane, plus it looks like the game!
	for mobj in mobjs.iterate()
		if (mobj.renderflags & RF_SEMIBRIGHT) == RF_SEMIBRIGHT
			mobj.renderflags = $ &~ RF_FULLDARK
		else
			mobj.renderflags = $ | RF_FULLBRIGHT
		end
	end
	
	//It's a Rain World, and we're living in it
	P_SetupLevelSky("~031")
	if not curWeather
		P_SwitchWeather(PRECIP_RAIN)
	end
end)

//Inv Grand Prix! It's horrible
local SCUG_InvGrandPrixThinker = function()
	if not SCUG_InvGrandPrix then return end
	
	for player in players.iterate
		local mo = player.mo
		if not (mo and mo.valid) then continue end
		
		//Always be seeable, even in the dark rain
		if (mo.renderflags & RF_SEMIBRIGHT) == RF_SEMIBRIGHT
			mo.renderflags = $ &~ RF_FULLDARK
		else
			mo.renderflags = $ | RF_FULLBRIGHT
		end
		
		//Player behaviors
		if not player.bot
			//Get a land mine with every item
			if player.itemroulette and player.itemroulette.active
			and not player.backupitemtype
				//While we're at it, why not force the second item to be a sink
				if not player.itemroulette.ringbox
					if #player.itemroulette.itemlist > 1
						K_AddItemToReelByIndex(player, 2, KITEM_KITCHENSINK)
					else
						K_AddItemToReel(player, KITEM_KITCHENSINK)
					end
				end
				
				//Get the land mine!
				player.backupitemtype = KITEM_LANDMINE
				player.backupitemamount = 1
			end
			
			//Half of Inv's rings are spikes...
			if leveltime & 1 then continue end //Let's only do this every other frame
			searchBlockmap("objects", function(refmobj, mobj)
				//Needs to be a ring that belongs to us!
				if mobj.type != MT_RING then return end
				mobj.frame = $ | FF_FULLBRIGHT &~ FF_FULLDARK
				
				if not mobj.extravalue1 or mobj.target != mo
				or mobj.scugringspike != nil then return end
				
				//Is this a ring being used with the item button?
				local isboostring = mobj.extravalue2
				
				//Only every other ring being used by the player is a spike!
				if player.rings == 20 or isboostring
					mo.scugringspike = not $
					mobj.scugringspike = mo.scugringspike
					if mo.scugringspike
						//mobj.flags2 = $ | MF2_NIGHTSPULL
						mobj.state = S_SCUG_RING
					end
				else
					mobj.scugringspike = false
				end
			end, mo)
		
		//Bot behaviors
		else
			//Bots get voltage for every checkpoint
			if mo.scugcheckpoint != player.checkpointid //We passed a new checkpoint
			and player.latestlap //We're actually in the game
				player.dotrickfx = true //Give voltage
				mo.scugcheckpoint = player.checkpointid //Update checkpoint
			end
			
			//Force specific colors
			local color = SCUG_BOTS[mo.skin] or SKINCOLOR_RED
			if player.skincolor != color
				if mo.color == player.skincolor
					mo.color = color
				end
				player.skincolor = color
			end
		end
	end
end

//Slug cat thinker
local SCUG_SlugcatThinker = function() for player in players.iterate
	local mo = player.mo
	if not (mo and mo.valid) then continue end
	
	local slugcat = player.slugcat //Grab what slug cat we are
	if slugcat == nil
		continue //We aren't a slug cat? Well that's a waste
	end
	
	//Not actually a slug cat, we're in Ironman mode
	if slugcat == -1
		if mo.skin != SCUG_SKIN then continue end //Not a slug cat... yet
		slugcat = 0
	end
	
	//Get the max number of frames for a specific animation (2 for idle)
	local maxframes = 2
	if not mo.sprite2
		mo.sprite2 = SPR2_SIGL
		mo.tics = -1
		mo.frame = ($ &~ FF_FRAMEMASK) | FF_ANIMATE
	elseif mo.sprite2 == SPR2_SIGL
		mo.anim_duration = 1 
	end
	
	//Inv's special behavior in normal gameplay
	if slugcat == SCUG_INV
		//Force skincolor
		if player.skincolor != SKINCOLOR_SOFANTHIEL
			if mo.color == player.skincolor
				mo.color = SKINCOLOR_SOFANTHIEL
			end
			player.skincolor = SKINCOLOR_SOFANTHIEL
		end
		
		//Death voice clip
		if mo.state == S_KART_DEAD and mo.tics != -1
			mo.tics = -1
			S_StartSound(nil, skins[SCUG_SKIN].soundsid[SKSPLDET1 + (leveltime % 4)], player)
		end
	end
	
	//Truncate the frame to what slug cat we are
	local curframe = mo.frame & FF_FRAMEMASK //Our current frame
	local index = curframe | (mo.sprite2 << 8) | (player.slugcat << 16)
	local newframe = SCUG_FRAMES[index]
	if newframe == nil
		newframe = 0
		maxframes = skins[SCUG_SKIN].sprites[mo.sprite2].numframes / SCUG_MAX
		if maxframes
			newframe = (curframe % maxframes) + (slugcat * maxframes) //Mathz
			SCUG_FRAMES[index] = newframe
		end
	end
	
	//Apply the frame!
	mo.frame = ($ &~ FF_FRAMEMASK) | newframe
end end

//Add the above functions into a hook!
addHook("PostThinkFrame", do
	SCUG_InvGrandPrixThinker()
	SCUG_SlugcatThinker()
end)

//Sign post logic

//Keep the old signpost action in reserves
local SCUG_OldSignAction = states[S_KART_SIGN].action or A_PlaySeeSound

//Make the signpost show the correct slug cat for each player and color
function A_ScugSignpost(mobj, var1, var2)
	SCUG_OldSignAction(mobj, var1, var2) //Perform the old signpost action
	
	//We need to be a slug cat and displaying a color first
	if mobj.skin != SCUG_SKIN or not mobj.color then return end
	
	local slugcat = SCUG_GetSlugcatFromColor(mobj.color) //Get the slug cat from our color
	mobj.frame = ($ &~ FF_FRAMEMASK &~ FF_ANIMATE) | slugcat //Apply the frame
end

//Assign our new action to the signpost state
states[S_KART_SIGN].action = A_ScugSignpost