--Map elements
local function HyuuPurification(l,mo,s)
	if mo.player.kartstuff[k_hyudorotimer] > 0
		return
	end
	P_DamageMobj(mo,nil,nil,10000)
end

--Lua port of K_DoThunderShield as it is not exposed to lua.
local function Thundershield(player)
	local mo
	local sx
	local sy
	local an
	local THUNDERRADIUS = 320
	

	S_StartSound(player.mo, sfx_zio3)
	P_NukeEnemies(player.mo, player.mo, RING_DIST/4)

	-- spawn vertical bolt
	mo = P_SpawnMobj(player.mo.x, player.mo.y, player.mo.z, MT_THOK)
	mo.target = player.mo
	mo.state = S_LZIO11
	mo.color = SKINCOLOR_TEAL
	mo.scale = player.mo.scale*3 + (player.mo.scale/2)

	mo = P_SpawnMobj(player.mo.x, player.mo.y, player.mo.z, MT_THOK)
	mo.target = player.mo
	mo.state = S_LZIO21
	mo.color = SKINCOLOR_CYAN
	mo.scale = player.mo.scale*3 + (player.mo.scale/2)

	-- spawn horizontal bolts
	for i=0,7
		mo = P_SpawnMobj(player.mo.x, player.mo.y, player.mo.z, MT_THOK)
		mo.angle = P_RandomRange(0, 359)*ANG1
		mo.fuse = P_RandomRange(20, 50)
		mo.target = player.mo
		mo.state = S_KLIT1
	end

	-- spawn the radius thing:
	an = ANGLE_22h
	for i=0,15
		sx = player.mo.x + FixedMul((player.mo.scale*THUNDERRADIUS), cos((an*i)))
		sy = player.mo.y + FixedMul((player.mo.scale*THUNDERRADIUS), sin((an*i)))
		mo = P_SpawnMobj(sx, sy, player.mo.z, MT_THOK)
		mo.angle = an*i
		mo.extravalue1 = THUNDERRADIUS	-- Used to know whether we should teleport by radius or something.
		mo.scale = player.mo.scale*3
		mo.target = player.mo
		mo.state = S_KSPARK1
	end
end


--Autodetonate shield upon attacking the core.
local function HitAssist(l,mo,s)
	if mo.player.kartstuff[k_curshield] == 1
		Thundershield(mo.player)
		mo.player.kartstuff[k_itemamount] = $1 - 1
		mo.player.powers[pw_flashing] = 50
		K_PlayAttackTaunt(mo.player.mo)
	end
end

local function EdenThankYou (l,mo,s)
	local thanksstring = "\x82Thank you for playing Abstraction Pack! \x86It has been a long road of development. It would not have been possible without STJr, Kart Krew and the support of the fantastic community!"
	if mo.player
		S_StartSound(nil,sfx_ncitem,mo.player)
		if multiplayer
			chatprintf(mo.player,thanksstring)
		else
			CONS_Printf(mo.player,thanksstring)
		end
	end
end

addHook("LinedefExecute",EdenThankYou,"EDTHANKS")
addHook("LinedefExecute",HitAssist,"HITASST")
addHook("LinedefExecute",HyuuPurification,"HYUUPURE")


--Ascended Orbifiring actiton. This is a slight modification of A_Fireshot.
function A_AscendedOrbinaut(actor,var1,var2) 
	local z
	if not actor.target
		return
	end
	
	A_FaceTarget(actor)
	
	if (actor.eflags & MFE_VERTICALFLIP)
		z = actor.z + actor.height - FixedMul(48*FRACUNIT + var2*FRACUNIT, actor.scale)
	else
		z = actor.z + FixedMul(48*FRACUNIT + var2*FRACUNIT, actor.scale)
	end
	
	local shot = P_SpawnXYZMissile(actor, actor.target, var1, actor.x, actor.y, z)
	shot.movefactor = 50*FRACUNIT
	shot.color = SKINCOLOR_PEACH
	
	if (not(actor.flags & MF_BOSS))
		if (ultimatemode)
			actor.reactiontime = actor.info.reactiontime*TICRATE
		else
			actor.reactiontime = actor.info.reactiontime*TICRATE*2
		end
	end
end

--Pickups
freeslot(
"MT_EDEN_CORE",
"MT_ASCENDEDSOUL",
"MT_THUNDERSHIELDSPAWNER",
"S_THUNDERSHIELD_DELAY",
"S_THUNDERSHIELD_SPAWNER_RESPAWN",
"S_ASCENDEDSOULFLIGHT",
"S_ASCENDEDSOULFLIGHT1",
"S_ASCENDEDSOULFLIGHT2",
"S_ASCENDEDSOULESCAPE",
"S_ASCENDEDSOULESCAPE1",
"S_ASCENDEDSOULESCAPE2",
"S_ASCENDEDSOULESCAPE3",
"S_ASCENDEDSOULESCAPE4",
"S_ASCENDEDSOULESCAPE5"
)

states[S_ASCENDEDSOULFLIGHT] = {SPR_BBAL, A, 16, A_ZThrust, 2,(1<<16)+1 , S_ASCENDEDSOULFLIGHT1}
states[S_ASCENDEDSOULFLIGHT1] = {SPR_BBAL, A, 16, A_ZThrust, -2,(1<<16)+1 , S_ASCENDEDSOULFLIGHT2}
states[S_ASCENDEDSOULFLIGHT2] = {SPR_BBAL, A, 0, A_Repeat, 11, S_ASCENDEDSOULFLIGHT, S_ASCENDEDSOULESCAPE}

states[S_ASCENDEDSOULESCAPE] = {SPR_PITY, C, 25, A_ZThrust, 15, (1<<16)+1, S_ASCENDEDSOULESCAPE1}
states[S_ASCENDEDSOULESCAPE1] = {SPR_PITY, C, 2, A_ZThrust, 0, (1<<16)+1, S_ASCENDEDSOULESCAPE3}
--states[S_ASCENDEDSOULESCAPE2] = {SPR_PITY, C, 1, A_FindTarget, MT_EDEN_CORE, 0, S_ASCENDEDSOULESCAPE3}
states[S_ASCENDEDSOULESCAPE3] = {SPR_PITY, C, 1, A_SkullAttack, 1, 0, S_ASCENDEDSOULESCAPE4}
states[S_ASCENDEDSOULESCAPE4] = {SPR_PITY, A, 0, A_SetObjectFlags, MF_NOGRAVITY|MF_NOCLIP|MF_NOCLIPHEIGHT, 2, S_ASCENDEDSOULESCAPE5}
states[S_ASCENDEDSOULESCAPE5] = {SPR_PITY, A|FF_ANIMATE, 140, None, 5, 3, S_NULL}

--Gives 1 hyuus on touch (you can get more)
--Ideally autodetonate all shields the player has.
--itemtype 
--itemamount
addHook("TouchSpecial", function(special,toucher)
	if toucher.player.kartstuff[k_itemtype] == KITEM_HYUDORO --give more ghosts
		toucher.player.kartstuff[k_itemamount] = $1 + 1
	elseif toucher.player.kartstuff[k_itemtype] == KITEM_THUNDERSHIELD --Detonate and replace with ghosts
		Thundershield(toucher.player)
		toucher.player.kartstuff[k_itemtype] = KITEM_HYUDORO
		toucher.player.kartstuff[k_itemamount] = 1
	else
		toucher.player.kartstuff[k_itemtype] = KITEM_HYUDORO
		toucher.player.kartstuff[k_itemamount] = 1
	end
	return false
end
,MT_ASCENDEDSOUL)

local EdenMonitor

addHook("MobjSpawn", function(mo)
	if EdenMonitor.valid
		mo.target = EdenMonitor
	end
end
,MT_ASCENDEDSOUL)


mobjinfo[MT_ASCENDEDSOUL] = {
        doomednum = -1,
        spawnstate = S_ASCENDEDSOULFLIGHT,
        spawnhealth = 1000,
        seestate = S_NULL,
        seesound = sfx_None,
        reactiontime = 8,
        attacksound = sfx_None,
        painstate = S_NULL,
        painchance = MT_THOK,
        painsound = sfx_None,
        meleestate = S_NULL,
        missilestate = S_NULL,
        deathstate = S_NULL,
        xdeathstate = S_NULL,
        deathsound = sfx_s3k9c,
        speed = 1,
        radius = 48*FRACUNIT,
        height = 128*FRACUNIT,
        dispoffset = 0,
        mass = 0,
        damage = 0,
        activesound = sfx_None,
        flags = MF_SLIDEME|MF_SPECIAL|MF_NOGRAVITY|MF_NOCLIPHEIGHT|MF_DONTENCOREMAP|MF_RUNSPAWNFUNC,
        raisestate = S_NULL
}


addHook("TouchSpecial", function(special,toucher)
		toucher.player.kartstuff[k_stealingtimer] = 0
	if toucher.player.kartstuff[k_itemtype] == KITEM_HYUDORO --auto ghost?
		S_StartSound(toucher.player.mo, sfx_s3k92)
		toucher.player.kartstuff[k_hyudorotimer] = 7*TICRATE
		toucher.player.kartstuff[k_itemtype] = KITEM_THUNDERSHIELD
		toucher.player.kartstuff[k_itemamount] = 2
			return false
	elseif (toucher.player.kartstuff[k_itemtype] == KITEM_THUNDERSHIELD and (toucher.player.kartstuff[k_itemamount] < 2)) 
	or (toucher.player.kartstuff[k_itemtype] == KITEM_NONE)--Replenish shields
		toucher.player.kartstuff[k_itemtype] = KITEM_THUNDERSHIELD
		toucher.player.kartstuff[k_itemamount] = 2
		return false
	else
		return true
	end
end
,MT_THUNDERSHIELDSPAWNER)

states[S_THUNDERSHIELD_DELAY] = {
	sprite = SPR_NULL,
	frame = A,
	var1 = 1,
	var2 = 2,
	tics = 105,
	nextstate = S_THUNDERSHIELD_SPAWNER_RESPAWN,
	action = None
}
states[S_THUNDERSHIELD_SPAWNER_RESPAWN] = {
	sprite = SPR_NULL,
	frame = A,
	var1 = 0,
	var2 = 0,
	tics = 1,
	action = A_SpawnFreshCopy,
	nextstate = S_NULL
}
mobjinfo[MT_THUNDERSHIELDSPAWNER] = {
	--$Name Thunder Shield Spawner
	--$Sprite THNSK0
	--$Category Flesh Eden
	--You may need to change the thingnum to avoid conflicts.
	doomednum = 3339,
	spawnstate = S_THUNDERSHIELD1,
	spawnhealth = 1000,
	seestate = S_NULL,
	seesound = sfx_None,
	reactiontime = 8,
	attacksound = sfx_None,
	painstate = S_NULL,
	painchance = MT_THOK,
	painsound = sfx_None,
	meleestate = S_NULL,
	missilestate = S_NULL,
	deathstate = S_THUNDERSHIELD_DELAY,
	xdeathstate = S_NULL,
	deathsound = sfx_kc2e,
	speed = 1,
	radius = 32*FRACUNIT,
	height = 32*FRACUNIT,
	dispoffset = 0,
	mass = 0,
	damage = 0,
	activesound = sfx_None,
	flags = MF_SLIDEME|MF_SPECIAL|MF_NOGRAVITY|MF_NOCLIPHEIGHT|MF_DONTENCOREMAP,
	raisestate = MT_FLOATINGITEM
}

--Eden's Ascended
freeslot(
"MT_EDENASCENDED",
"S_ASCENDEDIDLE",
"S_ASCENDEDCHASE",
"S_ASCENDEDCHASE1",
"S_ASCENDEDCHASE2",
"S_ASCENDEDCHASE3",
"S_ASCENDEDCHOICE",
"S_ASCENDEDCHOICETARGET",
"S_ASCENDEDFIRE",
"S_ASCENDEDFIREB",
"S_ASCENDEDFIREB2",
"S_ASCENDEDFIREWAIT1",
"S_ASCENDEDFIREWAIT2",
"S_ASCENDEDREPEAT",
"S_ASCENDEDCRUMBLE",
"S_ASCENDEDDEATH",
"S_ASCENDEDDEATHCHOICE",
"S_ASCENDEDDEATH1",
"S_ASCENDEDDEATH2",
"SPR_LMWZ",
"sfx_wizact",
"sfx_wizdth",
"sfx_wztel1",
"sfx_wzpain"
)

states[S_ASCENDEDIDLE] = {
	sprite = SPR_LMWZ,
	frame = A,
	var1 = (1500<<16)+1,
	var2 = 0,
	tics = 1,
	nextstate =  S_ASCENDEDIDLE,
	action = A_Look
}

states[S_ASCENDEDCHASE] = {
	sprite = SPR_LMWZ,
	frame = A,
	var1 = 3,
	var2 = 0,
	tics = 7,
	nextstate =  S_ASCENDEDCHASE1,
	action = A_Chase
}

states[S_ASCENDEDCHASE1] = {
	sprite = SPR_LMWZ,
	frame = B,
	var1 = 3,
	var2 = 0,
	tics = 7,
	nextstate =  S_ASCENDEDCHASE2,
	action = A_Chase
}

states[S_ASCENDEDCHASE2] = {
	sprite = SPR_LMWZ,
	frame = C,
	var1 = 3,
	var2 = 0,
	tics = 7,
	nextstate =  S_ASCENDEDCHASE3,
	action = A_Chase
}

states[S_ASCENDEDCHASE3] = {
	sprite = SPR_LMWZ,
	frame = D,
	var1 = 6,
	var2 = S_ASCENDEDCHASE,
	tics = 4,
	nextstate =  S_ASCENDEDCHOICETARGET,
	action = A_Repeat
}

states[S_ASCENDEDCHOICETARGET] = {
	sprite = SPR_LMWZ,
	frame = A,
	var1 = 0,
	var2 = S_ASCENDEDCHOICETARGET,
	tics = 1,
	nextstate =  S_ASCENDEDCHOICE,
	action = A_SearchForPlayers
}
states[S_ASCENDEDCHOICE] = {
	sprite = SPR_LMWZ,
	frame = E,
	var1 = (7<<16)+10,
	var2 = S_ASCENDEDFIRE,
	tics = 0,
	nextstate =  S_ASCENDEDFIREB,
	action = A_CheckRandom
}

states[S_ASCENDEDFIREB] = {
	sprite = SPR_LMWZ,
	frame = E,
	var1 = MT_DEMONFIRE,
	var2 = 0,
	tics = 10,
	nextstate =  S_ASCENDEDFIREB2,
	action = A_FireShot
}

states[S_ASCENDEDFIREB2] = {
	sprite = SPR_LMWZ,
	frame = E,
	var1 = MT_DEMONFIRE,
	var2 = 0,
	tics = 10,
	nextstate =  S_ASCENDEDFIREWAIT2,
	action = A_FireShot
}

states[S_ASCENDEDFIRE] = {
	sprite = SPR_LMWZ,
	frame = E,
	var1 = MT_ORBINAUT,
	var2 = 24,
	tics = 0,
	nextstate =  S_ASCENDEDFIREWAIT1,
	action = A_AscendedOrbinaut
}
states[S_ASCENDEDFIREWAIT1] = {
	sprite = SPR_LMWZ,
	frame = E,
	var1 = 0,
	var2 = 0,
	tics = 6,
	nextstate =  S_ASCENDEDFIREWAIT2,
	action = None
}

states[S_ASCENDEDFIREWAIT2] = {
	sprite = SPR_LMWZ,
	frame = A,
	var1 = 50,
	var2 = 105,
	tics = 105,
	nextstate =  S_ASCENDEDREPEAT,
	action = A_SetRandomTics
}
states[S_ASCENDEDREPEAT] = {
	sprite = SPR_LMWZ,
	frame = A,
	var1 = 9,
	var2 = S_ASCENDEDCHOICETARGET,
	tics = 0,
	nextstate = S_ASCENDEDCRUMBLE,
	action = A_Repeat
}

states[S_ASCENDEDCRUMBLE] = {
	sprite = SPR_LMWZ,
	frame = G,
	var1 = 0,
	var2 = 1,
	tics = 1,
	nextstate = S_NULL,
	action = A_RemoteDamage
}

states[S_ASCENDEDDEATH] = {
	sprite = SPR_LMWZ,
	frame = FF_ANIMATE|G,
	var1 = 6,
	var2 = 6,
	tics = 36,
	nextstate =  S_ASCENDEDDEATHCHOICE,
	action = none
}

states[S_ASCENDEDDEATHCHOICE] = {
	sprite = SPR_LMWZ,
	frame = M,
	var1 = (2<<16)+4,
	var2 = S_ASCENDEDDEATH1,
	tics = 1,
	nextstate =  S_ASCENDEDDEATH2,
	action = A_CheckRandom
}

states[S_ASCENDEDDEATH1] = {
	sprite = SPR_LMWZ,
	frame = M,
	var1 = 0,
	var2 = (16<<16)+MT_ASCENDEDSOUL,
	tics = 105,
	nextstate =  S_NULL,
	action = A_SpawnObjectRelative
}

states[S_ASCENDEDDEATH2] = {
	sprite = SPR_LMWZ,
	frame = M,
	var1 = 0,
	var2 = 0,
	tics = 105,
	nextstate =  S_NULL,
	action = none
}

mobjinfo[MT_EDENASCENDED] = {
	doomednum = -1,
	spawnstate = S_ASCENDEDIDLE,
	spawnhealth = 1,
	seestate = S_ASCENDEDCHASE,
	seesound = sfx_wizact,
	reactiontime = 0,
	attacksound = sfx_wztel1,
	painstate = S_NULL,
	painchance = 5000,
	painsound = sfx_wzpain,
	meleestate = S_NULL,
	missilestate = S_ASCENDEDFIRE,
	deathstate = S_ASCENDEDDEATH,
	xdeathstate = S_NULL,
	deathsound = sfx_wizdth,
	speed = 10,
	radius = 24*FRACUNIT,
	height = 64*FRACUNIT,
	dispoffset = 0,
	mass = 1,
	damage = 1000,
	activesound = sfx_None,
	flags = MF_RUNSPAWNFUNC|MF_SLIDEME|MF_SPECIAL|MF_SHOOTABLE|MF_PAIN,
	raisestate = MT_ORBINAUT
}
--Eden Missile
freeslot(
"MT_EDEN_MISSILE",
"S_EDEN_MISSILE_FLIGHT",
"S_EDEN_MISSILE_FLIGHT1",
"S_EDEN_MISSILE_CRASHDOWN",
"S_EDEN_MISSILE_CRDN1",
"S_EDEN_MISSILE_CRASHDOWN2",
"S_EDEN_MISSILE_CRASHDOWN3",
"S_EDEN_MISSILE_CRASHDOWN4",
"S_EDEN_MISSILE_BURST",
"S_EDEN_MISSILE_BURST1",
"S_EDEN_MISSILE_BURST2",
"S_EDEN_ASCENDED_RAISE",
"S_EDEN_ASCENDED_RAISE1"
)

states[S_EDEN_MISSILE_FLIGHT] = {
	sprite = SPR_ARMA,
	frame = FF_FULLBRIGHT|FF_ANIMATE|A,
	var1 = 10,
	var2 = 1,
	tics = 30,
	nextstate = S_EDEN_MISSILE_FLIGHT1,
	action = none
}

states[S_EDEN_MISSILE_FLIGHT1] = {
	sprite = SPR_ARMA,
	frame = FF_FULLBRIGHT|FF_ANIMATE|A,
	var1 = 10,
	var2 = 1,
	tics = 20,
	nextstate = S_EDEN_MISSILE_CRASHDOWN,
	action = none
}

states[S_EDEN_MISSILE_CRASHDOWN] = {
	sprite = SPR_DBAL,
	frame = FF_FULLBRIGHT|A,
	var1 = S_EDEN_MISSILE_CRDN1,
	var2 = S_EDEN_MISSILE_FLIGHT1,
	tics = 0,
	nextstate = S_NULL,
	action = A_RandomState
}

states[S_EDEN_MISSILE_CRDN1] = {
	sprite = SPR_ARMA,
	frame = A,
	var1 = 0,
	var2 = (1<<16)+1,
	tics = 1,
	nextstate = S_EDEN_MISSILE_CRASHDOWN2,
	action = A_ZThrust
}

states[S_EDEN_MISSILE_CRASHDOWN2] = {
	sprite = SPR_ARMA,
	frame = FF_FULLBRIGHT|A,
	var1 = FRACUNIT*3,
	var2 = 1 ,
	tics = 75,
	nextstate = S_EDEN_MISSILE_CRASHDOWN3,
	action = A_SetScale
}

states[S_EDEN_MISSILE_CRASHDOWN3] = {
	sprite = SPR_ARMA,
	frame = A,
	var1 = -32,
	var2 = (1<<16)+1,
	tics = 1,
	nextstate = S_EDEN_MISSILE_CRASHDOWN4,
	action = A_ZThrust,
}

states[S_EDEN_MISSILE_CRASHDOWN4] = {
	sprite = SPR_ARMA,
	frame = B,
	var1 = -32,
	var2 = (1<<16)+1,
	tics = 1,
	nextstate = S_EDEN_MISSILE_CRASHDOWN3,
	action = A_ZThrust
}

states[S_EDEN_MISSILE_BURST] = {
	sprite = SPR_NULL,
	frame = A,
	var1 = FRACUNIT,
	var2 = 0,
	tics = 2,
	nextstate =  S_EDEN_MISSILE_BURST1,
	action = A_SetScale
}
states[S_EDEN_MISSILE_BURST1] = {
	sprite = SPR_NULL,
	frame = A,
	var1 = (2<<16)+4,
	var2 = S_EDEN_ASCENDED_RAISE,
	tics = 1,
	nextstate = S_EDEN_MISSILE_BURST2,
	action = A_CheckRandom
}

states[S_EDEN_MISSILE_BURST2] = {
	sprite = SPR_NULL,
	frame = A,
	var1 = (MT_DEMONFIRE<<16)+6,
	var2 = -20,
	tics = 2,
	nextstate = S_CYBRAKDEMONMISSILE_EXPLODE1,
	action = A_MultiShot
}

states[S_EDEN_ASCENDED_RAISE] = {
	sprite = SPR_NULL,
	frame = A,
	var1 = S_EDEN_ASCENDED_RAISE1,
	var2 = S_EDEN_MISSILE_BURST2,
	tics = 2,
	nextstate = S_EDEN_ASCENDED_RAISE1,
	action = none
}

states[S_EDEN_ASCENDED_RAISE1] = {
	sprite = SPR_NULL,
	frame = A,
	var1 = 0,
	var2 = MT_EDENASCENDED,
	tics = 2,
	nextstate = S_NULL,
	action = A_SpawnObjectRelative
}

mobjinfo[MT_EDEN_MISSILE] = {
	doomednum = -1,
	spawnstate = S_EDEN_MISSILE_FLIGHT,
	spawnhealth = 1000,
	seestate = S_NULL,
	seesound = sfx_s3kc2s,
	reactiontime = 8,
	attacksound = sfx_None,
	painstate = S_NULL,
	painchance = MT_THOK,
	painsound = sfx_None,
	meleestate = S_NULL,
	missilestate = S_NULL,
	deathstate = S_EDEN_MISSILE_BURST,
	xdeathstate = S_NULL,
	deathsound = sfx_bexpld,
	speed = 12*FRACUNIT,
	radius = 24*FRACUNIT,
	height = 24*FRACUNIT,
	dispoffset = 0,
	mass = 1,
	damage = 1000,
	activesound = sfx_None,
	flags = MF_MISSILE|MF_NOBLOCKMAP|MF_NOGRAVITY,
	raisestate = S_NULL
}

--Flesh Eden
freeslot(
"S_EDEN_CORE",
"S_EDEN_CORE2",
"S_EDEN_CORE3",
"S_EDEN_CORE_SPAWN",
"S_EDEN_RAIN",
"S_EDEN_RAIN1",
"S_EDEN_RAIN2",
"S_EDEN_RAIN3",
"S_EDEN_WAIT_CHECK",
"S_EDEN_PAIN",
"S_EDEN_PAIN1",
"S_EDEN_PAIN2",
"S_EDEN_DEATH",
"S_EDEN_SCREAM",
"S_EDEN_DREPEAT",
"S_EDEN_FALL",
"S_EDEN_FALL1"
)

states[S_EDEN_CORE_SPAWN] = {
	sprite = SPR_SPBM,
	frame = A,
	var1 = FRACUNIT*2,
	var2 = 0,
	tics = 301,
	nextstate = S_EDEN_RAIN1,
	action = none
}

states[S_EDEN_WAIT_CHECK] = {
	sprite = SPR_SPBM,
	frame = A,
	var1 = 0,
	var2 = 0,
	tics = 1,
	nextstate = S_EDEN_CORE,
	action = none
}

states[S_EDEN_CORE] = {
	sprite = SPR_SPBM,
	frame = FF_ANIMATE|FF_FULLBRIGHT|A,
	var1 = 8,
	var2 = 1,
	tics = 25*TICRATE,
	nextstate = S_EDEN_CORE2,
	action = none
}

states[S_EDEN_CORE2] = {
	sprite = SPR_SPBM,
	frame = FF_FULLBRIGHT|A,
	var1 = sfx_s3k80,
	var2 = 0,
	tics = 0,
	nextstate = S_EDEN_CORE3,
	action = A_PlaySound
}

states[S_EDEN_CORE3] = {
	sprite = SPR_SPBM,
	frame = FF_ANIMATE|FF_FULLBRIGHT|A,
	var1 = 8,
	var2 = 1,
	tics = 5*TICRATE,
	nextstate = S_EDEN_RAIN,
	action = none
}

states[S_EDEN_RAIN] = {
	sprite = SPR_SPBM,
	frame = A,
	var1 = MT_PLAYER,
	var2 = 0,
	tics = 2,
	nextstate = S_EDEN_RAIN1,
	action = A_SearchForPlayers
}

states[S_EDEN_RAIN1] = {
	sprite = SPR_SPBM,
	frame = A,
	var1 = (MT_EDEN_MISSILE<<16)+8,
	var2 = 0,
	tics = 40,
	nextstate = S_EDEN_RAIN2,
	action = A_MultiShot
}

states[S_EDEN_RAIN2] = {
	sprite = SPR_SPBM,
	frame = A,
	var1 = 8,
	var2 = S_EDEN_RAIN,
	tics = 1,
	nextstate = S_EDEN_RAIN3,
	action = A_Repeat
}

states[S_EDEN_RAIN3] = { 
	sprite = SPR_SPBM,
	frame = A,
	var1 = sfx_wind1,
	var2 = 0,
	tics = 2,
	nextstate = S_EDEN_WAIT_CHECK,
	action = A_PlaySound
}
states[S_EDEN_PAIN] = {
	sprite = SPR_SPBM,
	frame = A,
	var1 = 908,
	var2 = 0,
	tics = 0,
	nextstate = S_EDEN_PAIN1,
	action = A_LinedefExecute
}
states[S_EDEN_PAIN1] = {
	sprite = SPR_SPBM,
	frame = E,
	var1 = 0,
	var2 = 0,
	tics = 140,
	nextstate = S_EDEN_PAIN2,
	action = A_Pain
}
states[S_EDEN_PAIN2] = {
	sprite = SPR_SPBM,
	frame = E,
	var1 = MF2_FRET,
	var2 = 1,
	tics = 0,
	nextstate = S_EDEN_RAIN,
	action = A_SetObjectFlags2
}
states[S_EDEN_DEATH] = {
	sprite = SPR_SPBM,
	frame = FF_FULLBRIGHT|A,
	var1 = 909,
	var2 = 0,
	tics = 1,
	nextstate = S_EDEN_SCREAM,
	action = A_LinedefExecute
}
states[S_EDEN_SCREAM] = {
	sprite = SPR_SPBM,
	frame = FF_FULLBRIGHT|A,
	var1 = 1,
	var2 = MT_BOSSEXPLODE,
	tics = 4,
	nextstate = S_EDEN_DREPEAT,
	action = A_BossScream
}

states[S_EDEN_DREPEAT] = {
	sprite = SPR_SPBM,
	frame = FF_FULLBRIGHT|A,
	var1 = 70,
	var2 = S_EDEN_SCREAM,
	tics = 0,
	nextstate = S_EDEN_FALL,
	action = A_Repeat
}
states[S_EDEN_FALL] = {
	sprite = SPR_SPBM,
	frame = FF_FULLBRIGHT|A,
	var1 = sfx_kc57,
	var2 = 0,
	tics = 1,
	nextstate = S_EDEN_FALL1,
	action = A_PlaySound
}
states[S_EDEN_FALL1] = {
	sprite = SPR_SPBM,
	frame = A,
	var1 = 0,
	var2 = 0,
	tics = 1,
	nextstate = S_XPLD1,
	action = A_BossDeath
}
mobjinfo[MT_EDEN_CORE] = {
	--$Name Eden Core
	--$Sprite SPBMA1
	--$Category Flesh Eden
	doomednum = 3340,
	spawnstate = S_EDEN_CORE_SPAWN,
	spawnhealth = 4,
	seestate = S_NULL,
	seesound = sfx_none,
	reactiontime = 8,
	attacksound = sfx_none,
	painstate = S_EDEN_PAIN,
	painchance = MT_THOK,
	painsound = sfx_dmpain,
	meleestate = S_NULL,
	missilestate = S_NULL,
	deathstate = S_EDEN_DEATH,
	xdeathstate = S_NULL,
	deathsound = sfx_kc2e,
	speed = 1,
	radius = 48*FRACUNIT,
	height = 96*FRACUNIT,
	dispoffset = 0,
	mass = 0,
	damage = 0,
	activesound = sfx_none,
	flags = MF_SPECIAL|MF_SHOOTABLE|MF_NOGRAVITY|MF_RUNSPAWNFUNC|MF_BOSS,
	raisestate = S_NULL
}

addHook("MobjThinker",function(mo)
	local executetable = {904,903,902,901}
	--[[for i = 1, 4
		executetable[i] = 905 - i
	end]]
	if (mo.state == S_EDEN_WAIT_CHECK)
		P_LinedefExecute(executetable[mo.health])
	end
end
,MT_EDEN_CORE)

addHook("MobjSpawn", function(mo)
	EdenMonitor = mo
	mo.color = SKINCOLOR_LEMONADE
	mo.colorized = true
	mo.scale = 2*FRACUNIT
end
,MT_EDEN_CORE)

--Hud magic

local edendeathtime = (270*TICRATE)
local vulnticker = 0*TICRATE
local vulnratio =0
local vulncharge = 0 
local chargeratio = 0

local pipstationaryincrement = 75
local pipshimmerincrement = 1
local pipwaveincrement = 2
local piptotincrement = pipstationaryincrement + 3 * (pipwaveincrement + pipshimmerincrement)

addHook("MobjThinker",function(mo)
	if mo == EdenMonitor
		if mo.state == S_EDEN_CORE or mo.state == S_EDEN_CORE2 or mo.state == S_EDEN_CORE3 or mo.state == S_EDEN_RAIN3
			vulncharge = 0
			vulnticker = $1 + 1
			vulnratio = (vulnticker*FRACUNIT)/(30*TICRATE)
		else 
			if vulnticker != 0
				vulnticker = 0
			end
		end
		if mo.state == S_EDEN_RAIN or mo.state == S_EDEN_RAIN1 or mo.state == S_EDEN_RAIN2 
			vulncharge = $1 + 1
			vulnratio = (vulncharge*FRACUNIT)/(344)
		else
			if vulncharge != 0
				vulncharge = 0
			end
		end
		if leveltime >= (edendeathtime+(6*TICRATE + (3*TICRATE/4))) and mo.fuse == 0
			mo.fuse = 280
		end
	end
end
,MT_EDEN_CORE)

local function getPipFrame(edenpip, i)
	if (edenpip[i] > pipstationaryincrement) and (edenpip[i] <= (pipstationaryincrement + pipwaveincrement))
		return 2
	elseif (edenpip[i] > (pipstationaryincrement + pipwaveincrement + pipshimmerincrement)) and (edenpip[i] <= (pipstationaryincrement + 2*pipwaveincrement + pipshimmerincrement)) 
		return 3
	elseif (edenpip[i] > (pipstationaryincrement + 2*pipwaveincrement + pipshimmerincrement)) and (edenpip[i] <= (pipstationaryincrement + 3*pipwaveincrement + 2*pipshimmerincrement)) 
		return 4
	else 
		return 1
	end
end

local prevleveltime
local edenpip = {0,0,0,0}
local hudrestore = false

local function EdenBossBar(v, player, cam)
	if not(mapheaderinfo[gamemap].edenboss)
		if hudrestore
			hud.enable("gametypeinfo")
			hud.enable("freeplay")
			hudrestore = false 
		end
		return
	end
	local edenbar = v.cachePatch("EDENBAR")
	local pip = {}
	for i = 1, 4
		pip[i] = v.cachePatch("SPBPIP"..i)
	end
	local edeninit = {5,25,45,65}
	if not (leveltime == prevleveltime)
		for i = 1, #edenpip
			if edenpip[i] > piptotincrement
				edenpip[i] = edeninit[i]
			end
			edenpip[i] = $1+1
		end
		prevleveltime = leveltime
	end
	local slice = v.cachePatch("EDENSLI")	
	local basex = 13
	local basey = 159
	if splitscreen 
		basex = 81
		basey = 80
	end
	
	if leveltime < (6*TICRATE + (3*TICRATE/4)) or player.awayviewtics > 0 or player.spectator == true
		return
	end
	v.draw(basex, basey, edenbar,V_HUDTRANS)
	
	if EdenMonitor.valid
		for i = 1, EdenMonitor.health
			v.draw(basex + 76 - (23*(i-1)), basey + 14,pip[getPipFrame(edenpip,i)],V_HUDTRANS)
		end
		local timedifference = (leveltime*FRACUNIT)/edendeathtime
		if EdenMonitor.health >= 1
			if leveltime < edendeathtime
				for i = 0, FixedInt(timedifference *36)
					v.draw(basex + 103 + i, basey + 31,slice,V_HUDTRANS,v.getColormap(0,SKINCOLOR_BLACK))
				end
			end
			--Bar increase while attacking.
			if EdenMonitor.state == S_EDEN_RAIN or EdenMonitor.state == S_EDEN_RAIN1 or EdenMonitor.state == S_EDEN_RAIN2
				for i = 0, FixedInt(vulnratio *36)
					v.draw(basex + 103 + i, basey + 2,slice,V_HUDTRANS,v.getColormap(0,SKINCOLOR_MAUVE))
				end
			end
			--Bar decrease while waiting.
			if EdenMonitor.state == S_EDEN_CORE or EdenMonitor.state == S_EDEN_CORE2 or EdenMonitor.state == S_EDEN_CORE3 or EdenMonitor.state == S_EDEN_RAIN3
				for i = 0,(36 - FixedInt(vulnratio *36))
					if vulnticker >= 25*TICRATE 
						v.draw(basex + 103 + i, basey + 2,slice,V_HUDTRANS,v.getColormap(0,SKINCOLOR_JET))
					else
						v.draw(basex + 103 + i, basey + 2,slice,V_HUDTRANS,v.getColormap(0,SKINCOLOR_NOVA))
					end
				end
			end
		end
		if leveltime >= edendeathtime
			for i = 0, 36
				v.draw(basex + 103 + i, basey + 31,slice,V_HUDTRANS,v.getColormap(0,SKINCOLOR_BLACK))
			end
		end
	end
end

hud.add(EdenBossBar, "game")

addHook("MapLoad", function(n)
	if mapheaderinfo[gamemap].edenboss
		hud.disable("gametypeinfo")
		hud.disable("freeplay")
		hudrestore = true
	end
end)

local neweden = false --Boss dependent toggle for meat mode.
local meatmaps = 1 --Maps to meat mode after the boss.
local function edenvars(net)
	neweden = net($)
	meatmaps = net($)
end

addHook("MobjFuse",function(mo)
	if (mo.health > 0)
		if not CV_FindVar("paradiseillusion") or not modeattacking
			if not (CV_FindVar("paradiseillusion").value == 3)
				neweden = true
				meatmaps = 1
			end
		end
		G_ExitLevel()
	end
	return true
end
,MT_EDEN_CORE)

--Replaces strings with numerical indices for texture swapping
local function TextureNameNumSwap(table)
	for i =1  , #table
		table[i] = R_TextureNumForName(table[i])
	end
end

local function blacklistcheck(val, bl)
	for i = 1, #bl
		if val == bl[i]
			return true
		end
	end
	return false
end

local cominit = false --So the message will not pop up when load Abstraction Pack.
local oldvalue = 0 --Prevents redundant prints
--Flesh paradise flat and texture swapping. This will occur on the next non flesh
--map on failure of Flesh Eden or if infiniteparadise is enabled.
local infiniteparadise = CV_RegisterVar({
	name = "infiniteparadise",
	defaultvalue = "Off",
	flags = CV_NETVAR|CV_CALL|CV_NOSHOWHELP,
	possiblevalue = CV_OnOff,
	func = function(v)
		if  cominit == false
			cominit = true
			return 
		end
		if gamestate == GS_LEVEL and (v.value != oldvalue)
			if v.value == 1 
				print("\130INFINITE FLESH PARADISE ENABLED:\128 You are filled with visions of an undying world.")
				S_StartSound(nil,sfx_menu1, p)
				G_SetCustomExitVars(gamemap,1)
				G_ExitLevel()
			elseif v.value == 0
				print("\130INFINITE FLESH PARADISE DISABLED:\128 The madness subsides.")
				S_StartSound(nil,sfx_menu1, p)
				G_SetCustomExitVars(gamemap,1)
				G_ExitLevel()
			else
			end
			oldvalue = v.value
		end
		end
})


--Tables that all unique textures are added to
local texturetable = {}
local flattable = {}

--Flat Pools
local fmeattable = {"NTFLAT10","NTFLAT9","OFLSHB02","OFLSHF01",
"VISNAKF3","VSNAKF41","VSNAKF42","OHELLA02","DCZFLR09","OHELLA03"}
--,"OLAVAD01"

local ffoliagetable = {"FLPDFLWR","FLPDGRS","FLPDLCBF","FLPDWDF"}

local fcastletable = {"ADEL_J15", "DEM2_6", "OBRCKM04", "OFADEA04", "OFNCYA23", "OFNCYA32",
					"OHEXAK03", "OMBLRA44", "OMRBLD01", "OMRBLG33", "OMRBLH01", "OMRBLL01",
					"OMRBLL44", "PG_ROAD3"}

--Texture pools
local tmeattable = {"OFLSHB01","OFLSHC01","OFLSHE01","OFLSHF01","OFLSHG01",
					"SCYPFWL2","SKIN2","SKINFLE1","SKINFLE2","VISNAKE3",
					"VSNAKE41","VSNAKE42","DCWHITEW"}
--"SKINRAIL"

local tfoliagetable = {"FLPDGRSW", "FLPDLCBW", "FLPDWD"}

local tcastletable = {"GSTONE1",
"OMRBLB19","OMRBLB30","OMRBLD39","OMRBLD50","OMRBLD59",
"OMRBLE43","OMRBLF18","OMRBLG22","OMRBLP90","OPALCA01",
"OPALCA02","OPALCA40","OPALCC23","OPALCE23","SP_HOT1"}

--Meta pools
local fswappool = {fmeattable, ffoliagetable, fmeattable}

--Flat force pools
local grasstable = {
	"JNGGRS01",
	"JNGGRS02",
	"JNGGRS03",
	"JNGGRS04",
	"JNGGRS05",
	"JNGGRS06",
	"JNGGRS07",
	"JNGGRS08",
	"GFZFLR02",
	"CEZFLR03",
	"CEZFLR05",
	"CEZFLR13",
	"GRASS1",
	"GRASS3",
	"GRASS7",
	"GRASSY",
	"GRASZY",
	"PG_GRAS1",
	"PG_GRAS2"
	
}

local flowertable = {
	"JNGGRS09",
	"JNGGRS10",
	"JNGGRS11",
	"JNGGRS12",
	"CEZFLR02",
	"CEZFLR12",
	"GRASS2",
	"GRASS2L",
	"GRASZP",
	"GRAS3F",
	"GRASS2F",
	"GFZFLR10",
	"PG_GRAS3"
}
local cherryblossom = {
	"JNGFLR09",
	"JNGFLR10",
	"JNGFLR11",
	"JNGFLR12",
	"DEM1_2",
	"DKLEAFLR",
	"EC_VINES",
	"SFZLEAF",
	"SCZLEAF1",
	"SCZLEAF2"
}
local woodtable = {
	"JNGWDF5",
	"JNGWDF6",
	"JNGWDF7",
	"JNGWDF8",
	"JNGWDF9",
	"JNGWDFA",
	"JNGWDFB",
	"JNGWDFC",
	"GFZFLR11",
	"WOODFLR",
	"WOODFLR2",
	"WOODFLR3",
	"WOODFLR4"
}
--Texture force pools
local grasswalltable = {
	"JNGGRW1",
	"JNGGRW2",
	"JNGGRW3",
	"JNGGRW4",
	"CEZGRSW",
	"GFZGRSW"
}

local grassedgetable = {
	"JNGGRW5",
	"JNGGRW6",
	"JNGGRW7",
	"JNGGRW8",
	"JNGGRW5S",
	"JNGGRW6S",
	"JNGGRW7S",
	"JNGGRW8S",
	"GRSEDG1",
	"GRSEDG2",
	"GRSEDG3",
	"GRSEDG4",
	"GRSWALL",
	"GRSWALL2",
	"GRSWALL3",
	"GRSWALL4",
	"GFZGRASS",
	"WEEDWALL",
	"PG_GRASW"
}

local cherrywalltable = {
	"JNGWL09",
	"JNGWL10",
	"JNGWL11",
	"JNGWL12",
	"ECVINESW",
	"SCZLEFW1",
	"SCZLEFW2",
}

local woodwalltable = {
	"JNGWD1",
	"JNGWD2",
	"JNGWD3",
	"JNGWD4",
	"JNGWD5",
	"JNGWD6",
	"JNGWD7",
	"JNGWD8",
	"WOODWALL",
	"WOODWLL2",
	"WOODWLL3",
	"WOODWLL4",
	"OWOODW"
}

--Linedef special blacklist tables; Credit to Yoshimo
--define the texture blacklists per linedef type
local lineTypeFrontTopBlacklistArray = {
    4,   --Speed Pad
    9,   --Chain Parameters
    14,  --Bustable Block Parameters
    15,  --Fan Particle Spawner Parameters
    102, --Translucent Solid FOF
    121, --Translucent Water FOF
    123, --Sideless Translucent Water FOF
    124, --Translucent Goo Water FOF
    125, --Sideless Translucent Goo Water FOF
    141, --Intangible-Bottomed Translucent FOF
    142, --Intangible-Bottomed Sideless Translucent FOF
    144, --Intangible-Topped Translucent FOF
    145, --Intangible-Topped Sideless Translucent FOF
    174, --Crumbling Respawning Intangible-Bottomed Translucent FOF
    175, --Crumbling Respawnless Intangible-Bottomed Translucent FOF
    192, --Translucent Solid Rising Platform FOF
    195, --Intangible-Bottomed Translucent Rising Platform FOF
    221, --Intangible Translucent FOF
    253, --Translucent Shatter Block FOF
    256, --Translucent Spin-Bustable Block FOF
    331, --Continuous Player Skin Executor Trigger
    332, --Each-Time Player Skin Executor Trigger
    333, --Once Player Skin Executor Trigger
    334, --Continuous Object Dye Executor Trigger
    335, --Each-Time Object Dye Executor Trigger
    336, --Once Object Dye Executor Trigger
    413, --Change Music
    414, --Play Sound Effect
    425, --Change Object State
    434, --Award Power-Up
    442, --Change Object Type State
    443, --Call Lua Function
    447, --Change Tagged Sector's Colormap
    455, --Fade Tagged Sector's Colormap
    461, --Spawn Object
    463, --Dye Object
    606  --Colormap
}
local lineTypeFrontBottomBlacklistArray = {9, 14, 15, 331, 332, 333, 413, 425, 434, 442, 443, 447,
    455, 461, 606}
	
local lineTypeFrontMidBlacklistArray = {9, 14, 15, 331, 332, 333, 413, 425, 434, 442, 443, 447, 455,
    461, 606}
local lineTypeBackMidBlacklistArray = {9, 442}

local lineTypeBackTopBlacklistArray = {
    9,
    259, --Custom FOF
    442
}
local lineTypeBackBottomBlacklistArray = {9, 442}


local lineTypeFrontBlacklistArray = {lineTypeFrontTopBlacklistArray,lineTypeFrontBottomBlacklistArray}
local lineTypeMidBlacklistArray = {lineTypeFrontMidBlacklistArray, lineTypeBackMidBlacklistArray}
local lineTypeBackBlacklistArray = {lineTypeBackTopBlacklistArray,lineTypeBackBottomBlacklistArray}

--Duplicates of the above which change value on level load..
local grasswalltable2 = {}
local grassedgetable2 = {}
local cherrywalltable2 = {}
local woodwalltable2 = {}

local function tablelookup(search,table)
	for k,v in ipairs(table)
		if search == v
			return true
		end
	end
	return false
end
local Flatpool = {swap = "GFZFLR01"}

function Flatpool:new (o,swap)
	local o = o or {}
	local self = setmetatable(o, Flatpool)
	self.swap = swap or "GFZFLR01"
	return self
end

local function flatswapinit(table,flat,pool)
	if flat == "F_SKY1" 
	or flat == R_TextureNumForName("ROZLITW")
	or flat == 0
	or R_TextureNumForName(flat) == 0 
		return flat
	end
	
		
	local swapset = P_RandomRange(1,#pool)
	local randomtx = P_RandomRange(1,#pool[swapset])
	if not table[flat]
		--Special cases
		if tablelookup(flat,grasstable)
			table[flat] = Flatpool:new(nil,"FLPDGRS")
		elseif tablelookup(flat,flowertable)
			table[flat] = Flatpool:new(nil,"FLPDFLWR")
		elseif tablelookup(flat,cherryblossom)
			table[flat] = Flatpool:new(nil,"FLPDLCBF")
		elseif tablelookup(flat,woodtable)
			table[flat] = Flatpool:new(nil,"FLPDWDF")
		elseif tablelookup(flat,grasswalltable2)
			table[flat] = Flatpool:new(nil, R_TextureNumForName("FLPDGRSW"))
		elseif tablelookup(flat,grassedgetable2)
			table[flat] = Flatpool:new(nil, R_TextureNumForName("FLPDGRW"))
		elseif tablelookup(flat,cherrywalltable2)
			table[flat] = Flatpool:new(nil, R_TextureNumForName("FLPDLCBW"))
		elseif tablelookup(flat,woodwalltable2)
			table[flat] = Flatpool:new(nil, R_TextureNumForName("FLPDWD"))
		else
			table[flat] = Flatpool:new(nil,pool[swapset][randomtx])
		end
	end
	return table[flat].swap
end

local function tabledupe(new, base)
	for k,v in ipairs(base)
		new[k] = v
	end
end

--Poolcheck tests if a water sector is completely submerged in water.
--This avoids odd replacements if the texture was never to be seen.
local function poolcheck(l)
	local visiblesec = 0
	for s in sectors.iterate
		if not (s.tag == l.tag) 
			continue 
		end
		for i = 0, #s.lines -1
			local line = s.lines[i]
			if line.backside == nil continue end --This is the only sector.
			if #line.frontsector == #s and (#line.backsector != l.tag)
				if line.backsector.floorheight >= l.frontsector.ceilingheight 
					continue 
				else
					for rover in line.backsector.ffloors()
						if (rover.valid == false) visiblesec = $1 + 1 end
						--Check for visibility
						if not ((rover.flags&FF_RENDERALL) or (rover.flags&FF_RENDERSIDES) 
						or (rover.flags&FF_RENDERPLANES)) continue end
						if rover.sector.ceilingheight < l.frontsector.ceilingheight
							visiblesec = $1+1
						end
					end
				end
			else
			if (#line.backsector != l.tag)
				if line.frontsector.floorheight >= l.frontsector.ceilingheight 
					continue 
				else
					for rover in line.frontsector.ffloors()
						if (rover.valid == false) visiblesec = $1 + 1 end
						--Check for visibility
						if not ((rover.flags&FF_RENDERALL) or (rover.flags&FF_RENDERSIDES) 
						or (rover.flags&FF_RENDERPLANES)) continue end
						if rover.sector.ceilingheight < l.frontsector.ceilingheight
							visiblesec = $1+1
						end
					end
				end
			end
		end
		end
	end
	return (visiblesec > 0)
end

--waterfallcheck determines if a water block's ceiling is important for
--replacement.

local function waterfallcheck(l) 
	for s in sectors.iterate
			if not (s.tag == l.tag) 
				continue 
			end
			if s.ceilingheight < l.frontsector.ceilingheight
				return true
			end
	end
	return false
end

local infstring = "\xA5*You are blessed with a vision of the new world.*\xA6 Complete or exit the stage to free yourself of it."
--Makes the next level that is not Flesh Eden/Paradise 
--get a texture/music swap to look like Paradise on failure of Eden.
--This is disabled in Record attack or if Paradiseillusion is enabled.
addHook("ThinkFrame", function()
	if (neweden == true or (infiniteparadise.value == 1)) and
	(not mapheaderinfo[gamemap].nonewflp == true) and not modeattacking
	
	if (leveltime == 1 and infiniteparadise.value == 1) or (leveltime ==  6 * TICRATE + (3 * TICRATE / 4) and neweden == true)
		if neweden == true
			meatmaps = $1 - 1
			if meatmaps <= -1
				neweden = false
				return 
			else
				for p in players.iterate
					S_StartSound(nil,sfx_menu1,p)
					if multiplayer
						chatprintf(p,infstring)
					else
						CONS_Printf(p,infstring)
					end
				end
			end
		else
			if meatmaps != -1
				meatmaps = -1
			end
		end
		local tmeattable2 = {}
		tabledupe(tmeattable2,tmeattable)
		local tfoliagetable2 = {}
		tabledupe(tfoliagetable2,tfoliagetable)
		local tcastletable2 = {}
		tabledupe(tcastletable2,tcastletable)
		
		TextureNameNumSwap(tmeattable2)
		TextureNameNumSwap(tfoliagetable2)
		TextureNameNumSwap(tcastletable2)
		local tswappool = {tmeattable2, tfoliagetable2, tmeattable2}
		
		tabledupe(grasswalltable2,grasswalltable)
		TextureNameNumSwap(grasswalltable2)

		tabledupe(grassedgetable2,grassedgetable)
		TextureNameNumSwap(grassedgetable2)

		tabledupe(cherrywalltable2,cherrywalltable)
		TextureNameNumSwap(cherrywalltable2)

		tabledupe(woodwalltable2,woodwalltable)
		TextureNameNumSwap(woodwalltable2)
		
		local sectorblacklist = {}

		P_SetupLevelSky(867, true)
		P_SetSkyboxMobj(nil,nil,nil)
		local unique_flats = {}
		local unique_textures = {}
		local waterfalltable = {}
		for l in lines.iterate  --Water is replaced in paradise.
			if not(l.special == 120 or l.special == 121 or l.special == 122 or l.special == 123 
			or l.special == 124 or l.special == 125) continue end
				if not (l.special == 122 or l.special == 123 or l.special == 125)
					if not unique_textures[l.frontside.midtexture] and poolcheck(l)
							unique_textures[l.frontside.midtexture] = Flatpool:new(nil,R_TextureNumForName("OFALLM01"))
							table.insert(waterfalltable,l.frontside.midtexture)
					end
				end
				if not waterfallcheck(l)
					if not unique_flats[l.frontside.sector.ceilingpic]
						unique_flats[l.frontside.sector.ceilingpic] = Flatpool:new(nil,"OLAVAD01")
					end
				end
				l.frontside.sector.lightlevel = 303 
		end
		for l in lines.iterate
			if l.special == 253 or l.special == 252 continue end--Ignore Shatter Blocks
			if (l.special == 102 or l.special == 141 or l.special == 142 or l.special == 144
			or l.special == 145 or l.special == 174 or l.special == 192 or l.special == 195 or
			l.special == 221 or l.special == 256) and (l.frontside.toptexture == 256)  --Ignore opaque translucent FoFs
				table.insert(sectorblacklist,l.frontsector)
				continue
			end
			if l.special == 423 --preserve the sky.
				l.frontside.textureoffset = 867 * FRACUNIT
				continue
			end
			for i = 0,1
				if (sides[l.sidenum[i]] == nil) or (sides[l.sidenum[i]].valid == false)
					continue
				end
				if not (sides[l.sidenum[i]].toptexture == 0) and not tablelookup(l.special,lineTypeFrontBlacklistArray[i+1])
					sides[l.sidenum[i]].toptexture = flatswapinit(unique_textures,sides[l.sidenum[i]].toptexture,tswappool)
				end
				if not (sides[l.sidenum[i]].midtexture == 0)
				and not  tablelookup(l.special,lineTypeMidBlacklistArray[i+1])
				and not !(l.flags&ML_DONTPEGTOP) 
				and not !(l.flags&ML_DONTPEGBOTTOM) 
				and not !(l.flags&ML_EFFECT3)
				or (l.flags&ML_IMPASSIBLE and (l.backside == nil))
					sides[l.sidenum[i]].midtexture = flatswapinit(unique_textures,sides[l.sidenum[i]].midtexture,tswappool)
				else
					if not (sides[l.sidenum[i]].midtexture == 0) and (tablelookup(sides[l.sidenum[i]].midtexture,grasswalltable2) or
					tablelookup(sides[l.sidenum[i]].midtexture,grassedgetable2) or 
					tablelookup(sides[l.sidenum[i]].midtexture,cherrywalltable2) or
					tablelookup(sides[l.sidenum[i]].midtexture,woodwalltable2) or
					tablelookup(sides[l.sidenum[i]].midtexture,waterfalltable))
					and not  tablelookup(l.special,lineTypeMidBlacklistArray[i+1])
						sides[l.sidenum[i]].midtexture = flatswapinit(unique_textures,sides[l.sidenum[i]].midtexture,tswappool)
					end
				end
				if not (sides[l.sidenum[i]].bottomtexture == 0) and not tablelookup(l.special,lineTypeBackBlacklistArray[i+1])
					sides[l.sidenum[i]].bottomtexture = flatswapinit(unique_textures,sides[l.sidenum[i]].bottomtexture,tswappool)
				end
			end
		end
		
		for s in sectors.iterate
			if (s.lightlevel - 48 > 144)
				s.lightlevel = $1-48
			elseif (s.lightlevel - 48  < 144) and (s.lightlevel > 144) 
				s.lightlevel = 144
			else
			end
			if (GetSecSpecial(s.special, 4) == 4) or (GetSecSpecial(s.special, 4) == 6)
			or (GetSecSpecial(s.special, 3) == 3) or (GetSecSpecial(s.special, 3) == 1)
			or (GetSecSpecial(s.special, 3) == 5) or tablelookup(s,sectorblacklist)
				continue
			end
			s.floorpic = flatswapinit(unique_flats,s.floorpic,fswappool)
			s.ceilingpic = flatswapinit(unique_flats,s.ceilingpic,fswappool)
		end
	end
	
	if leveltime == (6*TICRATE + (3*TICRATE/4))
		for p in players.iterate
			COM_BufInsertText(p, "tunes NEWFLP")
		end
	end
	else
		return
	end
end
)

local function mysterywater(mo)
	--Mystery water sounds.
	if (neweden == true or (infiniteparadise.value == 1)) and
	(not mapheaderinfo[gamemap].nonewflp == true) 
		if S_SoundPlaying(mo,sfx_wslap) or S_SoundPlaying(mo,sfx_splish)
			S_StopSoundByID(mo, sfx_wslap)
			S_StopSoundByID(mo, sfx_splish)
			S_StartSound(mo, sfx_ghit)
		end
	end
end

addHook("MobjThinker",mysterywater,MT_PLAYER)
addHook("MobjThinker",mysterywater,MT_SPLISH)