// content by Luigifan

//----------- ability definition -----------

--actions
freeslot(
"S_PLAY_FLORA_HOLYFLAME",
"S_PLAY_FLORA_BLUESPLASH2D",
"S_PLAY_FLORA_FROSTSHIELD",
"S_PLAY_FLORA_ICICLEBLADES",
"S_PLAY_FLORA_BLUESPLASH3D",
"S_PLAY_FLORA_HOLYLIGHTNING",
"S_PLAY_FLORA_SHADOWTRAP",
"S_PLAY_FLORA_HOLYBARRIERWALL",
"S_PLAY_FLORA_HOLYBARRIERDOME"
)

--spell objects
freeslot(
"MT_HOLYFLAME",
"MT_HOLYFLAMECORE",
"MT_BLUESPLASHICICLE",
"MT_FROSTSHIELDOBELISK",
"MT_HOLYLIGHTNINGORB",
"MT_SHADOWTRAPORB",
"MT_DARKGUARDIANORB",
"MT_HOLYBARRIERWALL",
"MT_HOLYBARRIERDOME"
)

freeslot(
"SPR_HFLM",
"SPR_HFLC",
"SPR_BSPL",
"SPR_DESC",
"SPR_FWAL",
"SPR_HLBL",
"SPR_HBWL",
"SPR_HBDM"
)

freeslot("S_HOLYFLAME_SPAWNSTATE",
"S_HOLYFLAME_MELEESTATE",
"S_HOLYFLAME_DEATHSTATE",
"S_HOLYFLAMECORE_SPAWNSTATE",
"S_HOLYFLAMECORE_MELEESTATE",
"S_HOLYFLAMECORE_DEATHSTATE",
"S_BLUESPLASHICICLE_SPAWNSTATE",
"S_BLUESPLASHICICLE_MISSILESTATE",
"S_BLUESPLASHICICLE_MELEESTATE",
"S_BLUESPLASHICICLE_DEATHSTATE",
"S_FROSTSHIELDOBELISK_SPAWNSTATE",
"S_FROSTSHIELDOBELISK_MELEESTATE",
"S_FROSTSHIELDOBELISK_DEATHSTATE",
"S_HOLYLIGHTNINGORB_SPAWNSTATE",
"S_HOLYLIGHTNINGORB_MISSILESTATE",
"S_HOLYLIGHTNINGORB_PAINSTATE",
"S_HOLYLIGHTNINGORB_DEATHSTATE",
"S_SHADOWTRAPORB_SPAWNSTATE",
"S_SHADOWTRAPORB_MISSILESTATE",
"S_SHADOWTRAPORB_DEATHSTATE",
"S_DARKGUARDIANORB_SPAWNSTATE",
"S_DARKGUARDIANORB_MISSILESTATE",
"S_DARKGUARDIANORB_DEATHSTATE",
"S_HOLYBARRIERWALL_SPAWNSTATE",
"S_HOLYBARRIERWALL_MELEESTATE",
"S_HOLYBARRIERWALL_DEATHSTATE",
"S_HOLYBARRIERDOME_SPAWNSTATE",
"S_HOLYBARRIERDOME_MELEESTATE",
"S_HOLYBARRIERDOME_DEATHSTATE"
)

--sound effects

//Flora's passive, Small Stature, doesn't need special code of its own; it's already accounted for by her lower-than-standard height, radius, and spinheight parameters in S_SKIN.

// main thinker
addHook("ThinkFrame", function()
	for player in players.iterate do
		if player.mo.skin ~= "flora_belnades" then
			continue
		end
	end
end)

//Holy Flame (horizontal semi-short-ranged burst of flames; one of the three standard Belnades spells, as seen in Castlevania 3: Dracula's Curse, Castlevania: Dawn of Sorrow, and Castlevania: Harmony of Despair)
--Flame blast
mobjinfo[MT_HOLYFLAMECORE] = {
	spawnstate = S_HOLYFLAMECORE_SPAWNSTATE,
	meleestate = S_HOLYFLAMECORE_MELEESTATE,
	deathstate = S_HOLYFLAMECORE_DEATHSTATE,
	spawnhealth = 30,
	height = 48*FRACUNIT,
	radius = 35*FRACUNIT,
	speed = 3*FRACUNIT, //Holy Flame doesn't move after being generated
	damage = 2, //Holy Flame deals double damage at point-blank range. That's the whole reason why it's split into two objects.
	mass = DMG_FIRE, //It's a fire spell. Duh.
	flags = MF_NOGRAVITY|MF_MISSILE|MF2_EXPLOSION|MF2_LINKDRAW
}
states[S_HOLYFLAMECORE_SPAWNSTATE] = {
	sprite = SPR_HFLCA,
	frame = FF_TRANS40|FF_FULLBRIGHT|A,
	tics = 10,
	nextstate = S_HOLYFLAMECORE_MELEESTATE
}
states[S_HOLYFLAMECORE_MELEESTATE] = {
	sprite = SPR_HFLCA,
	frame = FF_TRANS20|FF_FULLBRIGHT|A,
	tics = 50,
	nextstate = S_HOLYFLAMECORE_DEATHSTATE
}
states[S_HOLYFLAMECORE_DEATHSTATE] = {
	sprite = SPR_HFLCA,
	frame = FF_TRANS60|FF_FULLBRIGHT|A,
	tics = 5
}

mobjinfo[MT_HOLYFLAME] = {
	spawnstate = S_HOLYFLAME_SPAWNSTATE,
	meleestate = S_HOLYFLAME_MELEESTATE,
	deathstate = S_HOLYFLAME_DEATHSTATE,
	spawnhealth = 30,
	height = 24*FRACUNIT,
	radius = 55*FRACUNIT, //The intention was for this to be longer but thinner than the "core", but there are no separate "length" and "width" parameters...
	speed = 6*FRACUNIT,
	damage = 1,
	mass = DMG_FIRE,
	flags = MF_NOGRAVITY|MF_MISSILE|MF2_LINKDRAW
}
states[S_HOLYFLAME_SPAWNSTATE] = {
	sprite = SPR_HFLMA,
	frame = FF_TRANS40|FF_FULLBRIGHT|A,
	tics = 10,
	nextstate = S_HOLYFLAME_MELEESTATE
}
states[S_HOLYFLAME_MELEESTATE] = {
	sprite = SPR_HFLMA,
	frame = FF_TRANS20|FF_FULLBRIGHT|A,
	tics = 50,
	nextstate = S_HOLYFLAME_DEATHSTATE
}
states[S_HOLYFLAME_DEATHSTATE] = {
	sprite = SPR_HFLMA,
	frame = FF_TRANS60|FF_FULLBRIGHT|A,
	tics = 5
}

--Activation
addHook("PlayerThink", function(player)
	if player.mo and player.mo.valid then -- check if the player object exists
    
        if player.mo.skin ~= "flora_belnades" then -- is the player NOT playing as Flora?
            return -- stop running hook for this player
        end
		
/*		if player.custom1down == nil then -- if the player does not have this variable yet
			player.custom1down = 0 -- give it a starting number
		end
		
		if player.cmd.buttons & BT_CUSTOM1 > 0 then -- if player is pressing Custom1
			player.custom1down = $1 + 1 -- increment custom1 variable
		else
			player.custom1down = 0 -- reset custom1 variable
		end*/
		
		local flamexfromplayer = cos(player.mo.angle)
		local flameyfromplayer = sin(player.mo.angle)
		
		if player.custom1down == 1 -- if custom1 was *just* pressed
		and player.custom3down == 0
		and player.mo.energy >= 8*FRACUNIT then -- and the player has energy
			P_ResetPlayer(player)
			player.mo.energy = $ - 8*FRACUNIT --energy cost
			local flamecore = P_SpawnMobjFromMobj(player.mo, 35*flamexfromplayer, 35*flameyfromplayer, 6*FRACUNIT, MT_HOLYFLAMECORE) --generate the flame explosion
			flamecore.target = player.mo --assign ownership of Holy Flame to Flora
			local flame = P_SpawnMobjFromMobj(flamecore, 55*flamexfromplayer, 55*flameyfromplayer, 12*FRACUNIT, MT_HOLYFLAME) --generate the outward blast
			flame.target = player.mo --assign ownership of Holy Flame to Flora
		end
	end
end)

--Breaking bustable walls and spikes
addHook("MobjLineCollide", function(mobj, line)
	local backfront = {line.frontsector, line.backsector}
	
	for i, sector in ipairs(backfront) do
		for rover in sector.ffloors() do
			if rover and rover.valid --check that the FOF exists
			and (mobj.z <= rover.topheight or (mobj.z + mobj.height) >= rover.bottomheight) then --height check
				if rover.master.special == 252
				or rover.master.special == 253
				or rover.master.special == 254
				or rover.master.special == 255
				or rover.master.special == 256 then
					EV_CrumbleChain(sector, rover) --Holy Flame can break bustable walls
					return true
				else
					continue
				end
			else
				continue
			end
		end
	end
end, MT_HOLYFLAMECORE)

addHook("MobjLineCollide", function(mobj, line)
	local backfront = {line.frontsector, line.backsector}
	
	for i, sector in ipairs(backfront) do
		for rover in sector.ffloors() do
			if rover and rover.valid --check that the FOF exists
			and (mobj.z <= rover.topheight or (mobj.z + mobj.height) >= rover.bottomheight) then --height check
				if rover.master.special == 252
				or rover.master.special == 253
				or rover.master.special == 254
				or rover.master.special == 255
				or rover.master.special == 256 then
					EV_CrumbleChain(sector, rover) --Holy Flame can break bustable walls
					return true
				else
					continue
				end
			else
				continue
			end
		end
	end
end, MT_HOLYFLAME)

addHook("MobjMoveCollide", function(tmthing, thing)
	if not (tmthing.z >= (thing.z - tmthing.height) and tmthing.z <= (thing.z + thing.height)) then --height check
		return false
	end
	
	if thing.type == MT_SPIKE
	or thing.type == MT_WALLSPIKE
	or thing.type == MT_WALLSPIKEBASE
	or thing.type == MT_SPIKEBALL
	or thing.type == MT_UNIBALL
	or thing.type == MT_SMALLMACE
	or thing.type == MT_BIGMACE
	or thing.type == MT_EGGMOBILE4_MACE then
		P_KillMobj(thing, tmthing, tmthing.target, tmthing.info.mass) --Holy Flame can break spikes
	end
end, MT_HOLYFLAMECORE)

addHook("MobjMoveCollide", function(tmthing, thing)
	if not (tmthing.z >= (thing.z - tmthing.height) and tmthing.z <= (thing.z + thing.height)) then --height check
		return false
	end
	
	if thing.type == MT_SPIKE
	or thing.type == MT_WALLSPIKE
	or thing.type == MT_WALLSPIKEBASE
	or thing.type == MT_SPIKEBALL
	or thing.type == MT_UNIBALL then
		P_KillMobj(thing, tmthing, tmthing.target, tmthing.info.mass) --Holy Flame can break spikes
	end
end, MT_HOLYFLAMECORE)

//Blue Splash (2D) (5-way icicle launcher; one of the three standard Belnades spells, as seen in Castlevania 3: Dracula's Curse, Castlevania: Dawn of Sorrow, and Castlevania: Harmony of Despair)
--Objects
mobjinfo[MT_BLUESPLASHICICLE] = {
	spawnstate = S_BLUESPLASHICICLE_SPAWNSTATE,
	meleestate = S_BLUESPLASHICICLE_MELEESTATE, --Regardless of version, the Blue Splash icicles hover around Flora for some time before they get launched.
	missilestate = S_BLUESPLASHICICLE_MISSILESTATE, --Once the icicles are launched, THEN they are treated like missiles and have missile-like behavior.
	deathstate = S_BLUESPLASHICICLE_DEATHSTATE,
	damage = 1,
	spawnhealth = 5, --The icicles aren't supposed to be destroyed if they collide with something in their melee state.
	height = 30*FRACUNIT,
	radius = 60*FRACUNIT,
	speed = 20*FRACUNIT,
	fuse = 20*TICRATE, --The icicles may move slowly, but they can still cover large distances.
	mass = DMG_WATER, --Because ice equals water, apparently.
	flags = MF_NOGRAVITY --Blue Splash icicles are NOT missiles by default; the missile flag is added while launching them.
}
states[S_BLUESPLASHICICLE_SPAWNSTATE] = {
	sprite = SPR_BSPLA,
	frame = FF_TRANS20|FF_ADD|A,
	tics = 20,
	nextstate = S_BLUESPLASHICICLE_MELEESTATE
}
states[S_BLUESPLASHICICLE_MELEESTATE] = {
	sprite = SPR_BSPLA,
	frame = FF_TRANS10|FF_ADD|A,
	tics = 1,
/*	action = A_CapeChase, --icicles follow the player until they're ready to launch
	var1 = (8*65536)+1,
	var2 = (18*65536)+18,*/
	nextstate = S_BLUESPLASHICICLE_MELEESTATE
}
states[S_BLUESPLASHICICLE_MISSILESTATE] = {
	sprite = SPR_BSPLA,
	frame = FF_TRANS10|FF_ADD|A,
	tics = 20*TICRATE,
	nextstate = S_BLUESPLASHICICLE_DEATHSTATE
}
states[S_BLUESPLASHICICLE_DEATHSTATE] = {
	sprite = SPR_BSPLA,
	frame = FF_TRANS60|FF_ADD|A,
	tics = 10,
	nextstate = S_NULL
}

--Activation
addHook("PlayerThink", function(player)
	if player.mo and player.mo.valid then --check if the player object exists
    
		if player.mo.skin ~= "flora_belnades" then --is the player NOT playing as Flora?
			return --stop running hook for this player
		end
		
/*		if player.custom2down == nil then --if the player does not have this variable yet
			player.custom2down = 0 --give it a starting number
        end

		if player.cmd.buttons & BT_CUSTOM2 > 0 then --if player is pressing Custom2
			player.custom2down = $1 + 1 --increment custom2 variable
		else
			player.custom2down = 0 --reset custom2 variable
		end*/
        
		local twodiciclexfromplayer = cos(player.mo.angle)
		local twodicicleyfromplayer = sin(player.mo.angle)
		
		if player.mo.iciclecount == nil then
			player.mo.iciclecount = 0
		end
		
		if player.custom2down == 1 --if custom2 was *just* pressed
		and player.custom3down == 0
		and (player.mo.flags2 & MF2_TWOD) > 0 --and the player is in 2D mode
		and player.mo.iciclecount == 0 --and no icicles are spawned
		and player.mo.energy >= 12*FRACUNIT then --and the player has energy,
			//P_ResetPlayer(player) --player stops moving
			player.mo.energy = $ - 12*FRACUNIT --energy cost
			local twodicicle1 = P_SpawnMobjFromMobj(player.mo, 24*twodiciclexfromplayer, 24*twodicicleyfromplayer, 18*FRACUNIT, MT_BLUESPLASHICICLE) --spawn the first icicle
			twodicicle1.target = player.mo
			player.mo.iciclecount = 1
		end
		
		if player.mo.iciclecount == 5
		and (twodicicle1 and twodicicle1.valid)
		and twodicicle1.state == S_BLUESPLASHICICLE_MELEESTATE
		and (twodicicle1 and twodicicle2.valid)
		and twodicicle2.state == S_BLUESPLASHICICLE_MELEESTATE
		and (twodicicle3 and twodicicle3.valid)
		and twodicicle3.state == S_BLUESPLASHICICLE_MELEESTATE
		and (twodicicle4 and twodicicle4.valid)
		and twodicicle4.state == S_BLUESPLASHICICLE_MELEESTATE
		and (twodicicle5 and twodicicle5.valid)
		and twodicicle5.state == S_BLUESPLASHICICLE_MELEESTATE then --if all of the icicles are ready
			twodicicle1.state = S_BLUESPLASHICICLE_MISSILESTATE --launch the icicles
			A_SetObjectFlags(twodicicle1, 32768, 2)
			twodicicle2.state = S_BLUESPLASHICICLE_MISSILESTATE
			A_SetObjectFlags(twodicicle2, 32768, 2)
			twodicicle3.state = S_BLUESPLASHICICLE_MISSILESTATE
			A_SetObjectFlags(twodicicle3, 32768, 2)
			twodicicle4.state = S_BLUESPLASHICICLE_MISSILESTATE
			A_SetObjectFlags(twodicicle4, 32768, 2)
			twodicicle5.state = S_BLUESPLASHICICLE_MISSILESTATE
			A_SetObjectFlags(twodicicle5, 32768, 2)
			player.mo.iciclecount = 0 --reset iciclecount so more icicles can be launched
		end
	end --player.mo validity check end
end)

addHook("MobjThinker", function(twodicicle1)
	local twodiciclexfromplayer = cos(twodicicle1.target.angle)
	local twodicicleyfromplayer = sin(twodicicle1.target.angle)
	
	if twodicicle1 and twodicicle1.valid then
		if twodicicle1.state == S_BLUESPLASHICICLE_SPAWNSTATE then
			A_CapeChase(twodicicle1, (18*65536)+0, (24*65536)+0) --setting the position of the first icicle
			if not (twodicicle1.flags2 & MF2_TWOD) then
				A_SetObjectFlags2(twodicicle1, 2, 2) --flag the icicle as a 2D object if it isn't already flagged as such
			end
		end
		if twodicicle1.state == S_BLUESPLASHICICLE_MELEESTATE then
			A_CapeChase(twodicicle1, (18*65536)+0, (24*65536)+0) --keeping the first icicle in position relative to the others and Flora
			if twodicicle1.target.iciclecount == 1 then
				local twodicicle2 = P_SpawnMobjFromMobj(twodicicle1.target, 12*twodiciclexfromplayer, 12*twodicicleyfromplayer, 36*FRACUNIT, MT_BLUESPLASHICICLE) --spawn the second icicle
				twodicicle2.target = twodicicle1.target
				twodicicle1.target.iciclecount = 2
			end
		end
	end
end, MT_BLUESPLASHICICLE)
addHook("MobjThinker", function(twodicicle2)
	local twodiciclexfromplayer = cos(twodicicle2.target.angle)
	local twodicicleyfromplayer = sin(twodicicle2.target.angle)
	
	if twodicicle2 and twodicicle2.valid then
		if twodicicle2.state == S_BLUESPLASHICICLE_SPAWNSTATE then
			A_CapeChase(twodicicle2, (36*65536)+0, (12*65536)+0) --setting the position of the second icicle
			if not (twodicicle2.flags2 & MF2_TWOD) then
				A_SetObjectFlags2(twodicicle2, 2, 2) --flag the icicle as a 2D object if it isn't already flagged as such
			end
		end
		if twodicicle2.state == S_BLUESPLASHICICLE_MELEESTATE then
			A_CapeChase(twodicicle2, (36*65536)+0, (12*65536)+0) --keeping the second icicle in position relative to the others and Flora
			if twodicicle2.target.iciclecount == 2 then
				local twodicicle3 = P_SpawnMobjFromMobj(twodicicle2.target, 0*twodiciclexfromplayer, 0*twodicicleyfromplayer, 54*FRACUNIT, MT_BLUESPLASHICICLE) --spawn the third icicle
				twodicicle3.target = twodicicle2.target
				twodicicle2.target.iciclecount = 3
			end
		end
	end
end, MT_BLUESPLASHICICLE)
addHook("MobjThinker", function(twodicicle3)
	local twodiciclexfromplayer = cos(twodicicle3.target.angle)
	local twodicicleyfromplayer = sin(twodicicle3.target.angle)
	
	if twodicicle3 and twodicicle3.valid then
		if twodicicle3.state == S_BLUESPLASHICICLE_SPAWNSTATE then
			A_CapeChase(twodicicle3, (54*65536)+0, (0*65536)+0) --setting the position of the third icicle
			if not (twodicicle3.flags2 & MF2_TWOD) then
				A_SetObjectFlags2(twodicicle3, 2, 2) --flag the icicle as a 2D object if it isn't already flagged as such
			end
		end
		if twodicicle3.state == S_BLUESPLASHICICLE_MELEESTATE then
			A_CapeChase(twodicicle3, (54*65536)+0, (0*65536)+0) --keeping the third icicle in position relative to the others and Flora
			if twodicicle3.target.iciclecount == 3 then
				local twodicicle4 = P_SpawnMobjFromMobj(twodicicle3.target, -12*twodiciclexfromplayer, -12*twodicicleyfromplayer, 36*FRACUNIT, MT_BLUESPLASHICICLE) --spawn the fourth icicle
				twodicicle4.target = twodicicle3.target
				twodicicle3.target.iciclecount = 4
			end
		end
	end
end, MT_BLUESPLASHICICLE)
addHook("MobjThinker", function(twodicicle4)
	local twodiciclexfromplayer = cos(twodicicle4.target.angle)
	local twodicicleyfromplayer = sin(twodicicle4.target.angle)
	
	if twodicicle4 and twodicicle4.valid then
		if twodicicle4.state == S_BLUESPLASHICICLE_SPAWNSTATE then
			A_CapeChase(twodicicle4, (36*65536)+0, (-12*65536)+0) --setting the position of the fourth icicle
			if not (twodicicle4.flags2 & MF2_TWOD) then
				A_SetObjectFlags2(twodicicle4, 2, 2) --flag the icicle as a 2D object if it isn't already flagged as such
			end
		end
		if twodicicle4.state == S_BLUESPLASHICICLE_MELEESTATE then
			A_CapeChase(twodicicle4, (36*65536)+0, (-12*65536)+0) --keeping the fourth icicle in position relative to the others and Flora
			if twodicicle4.target.iciclecount == 4 then
				local twodicicle5 = P_SpawnMobjFromMobj(twodicicle4.target, -24*twodiciclexfromplayer, -24*twodicicleyfromplayer, 18*FRACUNIT, MT_BLUESPLASHICICLE) --spawn the fifth icicle
				twodicicle5.target = twodicicle4.target
				twodicicle4.target.iciclecount = 5
			end
		end
	end
end, MT_BLUESPLASHICICLE)
addHook("MobjThinker", function(twodicicle5)
	local twodiciclexfromplayer = cos(twodicicle5.target.angle)
	local twodicicleyfromplayer = sin(twodicicle5.target.angle)
	
	if twodicicle5 and twodicicle5.valid then
		if twodicicle5.state == S_BLUESPLASHICICLE_SPAWNSTATE then
			A_CapeChase(twodicicle5, (18*65536)+0, (-24*65536)+0) --setting the position of the fifth icicle
			if not (twodicicle5.flags2 & MF2_TWOD) then
				A_SetObjectFlags2(twodicicle5, 2, 2) --flag the icicle as a 2D object if it isn't already flagged as such
			end
		end
		if twodicicle5.state == S_BLUESPLASHICICLE_MELEESTATE then
			A_CapeChase(twodicicle5, (18*65536)+0, (-24*65536)+0) --keeping the fifth icicle in position relative to the others and Flora
		end
	end
end, MT_BLUESPLASHICICLE)

addHook("MobjMoveCollide", function(tmthing, thing)
	if not (tmthing.z >= (thing.z - tmthing.height) and tmthing.z <= (thing.z + thing.height)) then --height check
		return false
	end

	if tmthing.state == S_BLUESPLASHICICLE_MELEESTATE
	or tmthing.state == S_BLUESPLASHICICLE_MISSILESTATE then
		if (thing.flags & MF_SHOOTABLE) then
			P_DamageMobj(thing, tmthing, tmthing.target, tmthing.damage, tmthing.info.mass) --Blue Splash icicles can damage enemies while hovering around Flora --tmthing.info.mass == DMG_WATER
		end
	end
end, MT_BLUESPLASHICICLE)

//3D Blue Splash (3-stage reinterpretation of Blue Splash for a 3D environment, hailing from Castlevania Judgment)
--Objects
mobjinfo[MT_FROSTSHIELDOBELISK] = {
	spawnstate = S_FROSTSHIELDOBELISK_SPAWNSTATE,
	meleestate = S_FROSTSHIELDOBELISK_MELEESTATE,
	deathstate = S_FROSTSHIELDOBELISK_DEATHSTATE,
	height = 40*FRACUNIT,
	radius = 40*FRACUNIT,
	fuse = 10*TICRATE, --The frost obelisks are intended to only last for 8 seconds, but they can briefly stick around after their duration has technically expired if Flora transitions into Icicle Blades.
	spawnhealth = 1,
	flags = MF_NOCLIP
}
states[S_FROSTSHIELDOBELISK_SPAWNSTATE] = {
	sprite = SPR_DESCA, //SPR_FWALA
	frame = FF_TRANS20|A,
	tics = 4,
	nextstate = S_FROSTSHIELDOBELISK_MELEESTATE
}
states[S_FROSTSHIELDOBELISK_MELEESTATE] = {
	sprite = SPR_DESCA,
	frame = FF_TRANS10|A,
	tics = 1, //8*TICRATE
/*	action = A_CapeChase,
	var1 = (3*65536)+1,
	var2 = (12*65536)+12,*/
	nextstate = S_FROSTSHIELDOBELISK_MELEESTATE --death state should kick in upon one of the P_KillMobj functions that's called when Frost Shield is expended or expires; melee state is repeated to repeat A_CapeChase
}
states[S_FROSTSHIELDOBELISK_DEATHSTATE] = {
	sprite = SPR_DESCA,
	frame = FF_TRANS60|A,
	tics = 7,
	nextstate = S_NULL
}

--Activation
addHook("PlayerThink", function(player)
	if player.mo and player.mo.valid then

		if player.mo.skin ~= "flora_belnades"
			return
		end
		
/*		if player.custom2down == nil then
			player.custom2down = 0
		end
		
		if player.cmd.buttons & BT_CUSTOM2 > 0 then
			player.custom2down = $1 + 1
		else
			player.custom2down = 0
		end*/
		
		//Frost Shield (8 obelisks of ice that protect the caster from harm and can be used to generate icicles; stage 1 of the Castlevania Judgment reinterpretation of Blue Splash)
		
		if player.mo.frostshieldactive == nil then
			player.mo.frostshieldactive = 0
		end
		
		if player.mo.frostshieldactive > 0 then
			if (leveltime%TICRATE) then
				player.mo.frostshieldactive = $ - 1 --Frost Shield timer
			end
		end
		
		local obeliskxfromplayer = cos(player.mo.angle)
		local obeliskyfromplayer = sin(player.mo.angle)
		
		if player.custom2down == 3 --should be player.custom2down == 1, but until I can assign a player state and check against that to prevent the same C2 press from activating Frost Shield AND Icicle Blades, there will have to be a tiny delay
		and player.custom3down == 0
		and (player.mo.flags2 & MF2_TWOD) == 0
		and player.mo.frostshieldactive == 0
		and player.mo.iciclebladesactive == 0
		and player.mo.energy >= 10*FRACUNIT then
			player.mo.energy = $ - 10*FRACUNIT --energy cost
			local obelisk1 = P_SpawnMobjFromMobj(player.mo, 0, 20*obeliskyfromplayer, 0, MT_FROSTSHIELDOBELISK)
			obelisk1.tracer = player.mo
			obelisk1.angle = FixedAngle(AngleFixed(player.mo.angle))
			local obelisk2 = P_SpawnMobjFromMobj(player.mo, 20*obeliskxfromplayer, 20*obeliskyfromplayer, 0, MT_FROSTSHIELDOBELISK)
			obelisk2.tracer = player.mo
			obelisk2.angle = FixedAngle(AngleFixed(player.mo.angle) + 45*FRACUNIT)
			local obelisk3 = P_SpawnMobjFromMobj(player.mo, 20*obeliskxfromplayer, 0, 0, MT_FROSTSHIELDOBELISK)
			obelisk3.tracer = player.mo
			obelisk3.angle = FixedAngle(AngleFixed(player.mo.angle) + 90*FRACUNIT)
			local obelisk4 = P_SpawnMobjFromMobj(player.mo, 20*obeliskxfromplayer, -20*obeliskyfromplayer, 0, MT_FROSTSHIELDOBELISK)
			obelisk4.tracer = player.mo
			obelisk4.angle = FixedAngle(AngleFixed(player.mo.angle) + 135*FRACUNIT)
			local obelisk5 = P_SpawnMobjFromMobj(player.mo, 0, -20*obeliskyfromplayer, 0, MT_FROSTSHIELDOBELISK)
			obelisk5.tracer = player.mo
			obelisk5.angle = FixedAngle(AngleFixed(player.mo.angle) + 180*FRACUNIT)
			local obelisk6 = P_SpawnMobjFromMobj(player.mo, -20*obeliskxfromplayer, -20*obeliskyfromplayer, 0, MT_FROSTSHIELDOBELISK)
			obelisk6.tracer = player.mo
			obelisk6.angle = FixedAngle(AngleFixed(player.mo.angle) + 225*FRACUNIT)
			local obelisk7 = P_SpawnMobjFromMobj(player.mo, -20*obeliskxfromplayer, 0, 0, MT_FROSTSHIELDOBELISK)
			obelisk7.tracer = player.mo
			obelisk7.angle = FixedAngle(AngleFixed(player.mo.angle) + 270*FRACUNIT)
			local obelisk8 = P_SpawnMobjFromMobj(player.mo, -20*obeliskxfromplayer, 20*obeliskyfromplayer, 0, MT_FROSTSHIELDOBELISK)
			obelisk8.tracer = player.mo
			obelisk8.angle = FixedAngle(AngleFixed(player.mo.angle) + 315*FRACUNIT)
			player.mo.frostshieldactive = 8*TICRATE --Activate Frost Shield for 8 seconds
		end
		
		if player.mo.frostshieldactive == 0 --if Frost Shield has expired
		and player.mo.iciclebladesactive == 0 then --if the obelisks do not have icicles attached
			if obelisk1 and obelisk1.valid then --make sure that Frost Shield actually was active
				P_KillMobj(obelisk1, nil, nil) --remove the obelisks
			end
			if obelisk2 and obelisk2.valid then
				P_KillMobj(obelisk2, nil, nil)
			end
			if obelisk3 and obelisk3.valid then
				P_KillMobj(obelisk3, nil, nil)
			end
			if obelisk4 and obelisk4.valid then
				P_KillMobj(obelisk4, nil, nil)
			end
			if obelisk5 and obelisk5.valid then
				P_KillMobj(obelisk5, nil, nil)
			end
			if obelisk6 and obelisk6.valid then
				P_KillMobj(obelisk6, nil, nil)
			end
			if obelisk7 and obelisk7.valid then
				P_KillMobj(obelisk7, nil, nil)
			end
			if obelisk8 and obelisk8.valid then
				P_KillMobj(obelisk8, nil, nil)
			end
		end
		
		//Icicle Blades (icicles emerge from Frost Shield obelisks to attack nearby enemies, with a longer range than Holy Flame; stage 2 of the Castlevania Judgment reinterpretation of Blue Splash)
		
		if player.mo.iciclebladesactive == nil then
			player.mo.iciclebladesactive = 0
		end
		
		if player.mo.iciclebladesactive > 0 then
			if (leveltime%TICRATE) then
				player.mo.iciclebladesactive = $ - 1 --Icicle Blades timer
			end
		end
		
		local threediciclexfromplayer = cos(player.mo.angle)
		local threedicicleyfromplayer = sin(player.mo.angle)
		
		if player.custom2down == 2 --should be player.custom2down == 1, but until I can assign a player state and check against that to prevent the same C2 press from activating Frost Shield AND 3D Blue Splash, there will have to be a tiny delay
		and player.custom3down == 0
		and (player.mo.flags2 & MF2_TWOD) == 0
		and player.mo.frostshieldactive > 0
		and player.mo.iciclebladesactive == 0
		and player.mo.energy >= 4*FRACUNIT then
			player.mo.energy = $ - 4*FRACUNIT --energy cost
			if obelisk1 and obelisk1.valid then
				local threedicicle1 = P_SpawnMobjFromMobj(obelisk1, 0, 6*threedicicleyfromplayer, 0, MT_BLUESPLASHICICLE)
				threedicicle1.tracer = player.mo
				threedicicle1.target = player.mo
				threedicicle1.angle = obelisk1.angle
			end
			if obelisk2 and obelisk2.valid then
				local threedicicle2 = P_SpawnMobjFromMobj(obelisk2, 6*threediciclexfromplayer, 6*threedicicleyfromplayer, 0, MT_BLUESPLASHICICLE)
				threedicicle2.tracer = player.mo
				threedicicle2.target = player.mo
				threedicicle2.angle = obelisk2.angle
			end
			if obelisk3 and obelisk3.valid then
				local threedicicle3 = P_SpawnMobjFromMobj(obelisk3, 6*threediciclexfromplayer, 0, 0, MT_BLUESPLASHICICLE)
				threedicicle3.tracer = player.mo
				threedicicle3.target = player.mo
				threedicicle3.angle = obelisk3.angle
			end
			if obelisk4 and obelisk4.valid then
				local threedicicle4 = P_SpawnMobjFromMobj(obelisk4, 6*threediciclexfromplayer, -6*threedicicleyfromplayer, 0, MT_BLUESPLASHICICLE)
				threedicicle4.tracer = player.mo
				threedicicle4.target = player.mo
				threedicicle4.angle = obelisk4.angle
			end
			if obelisk5 and obelisk5.valid then
				local threedicicle5 = P_SpawnMobjFromMobj(obelisk5, 0, -6*threedicicleyfromplayer, 0, MT_BLUESPLASHICICLE)
				threedicicle5.tracer = player.mo
				threedicicle5.target = player.mo
				threedicicle5.angle = obelisk5.angle
			end
			if obelisk6 and obelisk6.valid then
				local threedicicle6 = P_SpawnMobjFromMobj(obelisk6, -6*threediciclexfromplayer, 0, 0, MT_BLUESPLASHICICLE)
				threedicicle6.tracer = player.mo
				threedicicle6.target = player.mo
				threedicicle6.angle = obelisk6.angle
			end
			if obelisk7 and obelisk7.valid then
				local threedicicle7 = P_SpawnMobjFromMobj(obelisk7, -6*threediciclexfromplayer, -6*threedicicleyfromplayer, 0, MT_BLUESPLASHICICLE)
				threedicicle7.tracer = player.mo
				threedicicle7.target = player.mo
				threedidicle7.angle = obelisk7.angle
			end
			if obelisk8 and obelisk8.valid then
				local threedicicle8 = P_SpawnMobjFromMobj(obelisk8, -6*threediciclexfromplayer, 6*threedicicleyfromplayer, 0, MT_BLUESPLASHICICLE)
				threedicicle8.tracer = player.mo
				threedicicle8.target = player.mo
				threedicicle8.angle = obelisk8.angle
			end
			player.mo.iciclebladesactive = 3*TICRATE/2 --Activate Icicle Blades for 1.5 seconds
			player.mo.frostshieldactive = 12 --Deactivate Frost Shield, but give the icicles time to form so the obelisks don't self-destruct until the icicles self-destruct or get launched
		end
		
		if player.mo.frostshieldactive <= 12
		and player.mo.iciclebladesactive == 0 then
			if (threedicicle1 and threedicicle1.valid) and not (threedicicle1.flags & MF_MISSILE) then --if Icicle Blades expired without launching the icicles (and the icicles actually exist)
				P_KillMobj(threedicicle1, nil, nil) --kill the icicles
			end
			if (threedicicle2 and threedicicle2.valid) and not (threedicicle2.flags & MF_MISSILE) then
				P_KillMobj(threedicicle2, nil, nil)
			end
			if (threedicicle3 and threedicicle3.valid) and not (threedicicle3.flags & MF_MISSILE) then
				P_KillMobj(threedicicle3, nil, nil)
			end
			if (threedicicle4 and threedicicle4.valid) and not (threedicicle4.flags & MF_MISSILE) then
				P_KillMobj(threedicicle4, nil, nil)
			end
			if (threedicicle5 and threedicicle5.valid) and not (threedicicle5.flags & MF_MISSILE) then
				P_KillMobj(threedicicle5, nil, nil)
			end
			if (threedicicle6 and threedicicle6.valid) and not (threedicicle6.flags & MF_MISSILE) then
				P_KillMobj(threedicicle6, nil, nil)
			end
			if (threedicicle7 and threedicicle7.valid) and not (threedicicle7.flags & MF_MISSILE) then
				P_KillMobj(threedicicle7, nil, nil)
			end
			if (threedicicle8 and threedicicle8.valid) and not (threedicicle8.flags & MF_MISSILE) then
				P_KillMobj(threedicicle8, nil, nil)
			end
		end
		
		//Blue Splash (3D) (8-way icicle launcher following Icicle Blades; re-introduces the projectile element to Castlevania Judgment's version of Blue Splash)
		
		if player.custom2down == 1 --if custom2 has been tapped
		and player.custom3down == 0
		and (player.mo.flags2 & MF2_TWOD) == 0 --and the player is in 3D
		and player.mo.frostshieldactive <= 12 --double-checking that Frost Shield is deactivated
		and player.mo.iciclebladesactive > 0 --if icicles are attached to the obelisks
		and player.mo.energy >= 2*FRACUNIT then --if the player has energy
			player.mo.energy = $ - 2*FRACUNIT --energy cost
			player.mo.iciclebladesactive = 12 --end Icicle Blades timer, but give the icicles time to become independent missiles so they don't immediately self-destruct
			if threedicicle1 and threedicicle1.valid
			and threedicicle1.state == S_BLUESPLASHICICLE_MELEESTATE then
				threedicicle1.state = S_BLUESPLASHICICLE_MISSILESTATE
				A_SetObjectFlags(threedicicle1, 32768, 2) --launch icicles (assign MF_MISSILE flag)
			end
			if threedicicle2 and threedicicle2.valid
			and threedicicle2.state == S_BLUESPLASHICICLE_MELEESTATE then
				threedicicle2.state = S_BLUESPLASHICICLE_MISSILESTATE
				A_SetObjectFlags(threedicicle2, 32768, 2)
			end
			if threedicicle3 and threedicicle3.valid
			and threedicicle3.state == S_BLUESPLASHICICLE_MELEESTATE then
				threedicicle3.state = S_BLUESPLASHICICLE_MISSILESTATE
				A_SetObjectFlags(threedicicle3, 32768, 2)
			end
			if threedicicle4 and threedicicle4.valid
			and threedicicle4.state == S_BLUESPLASHICICLE_MELEESTATE then
				threedicicle4.state = S_BLUESPLASHICICLE_MISSILESTATE
				A_SetObjectFlags(threedicicle4, 32768, 2)
			end
			if threedicicle5 and threedicicle5.valid
			and threedicicle5.state == S_BLUESPLASHICICLE_MELEESTATE then
				threedicicle5.state = S_BLUESPLASHICICLE_MISSILESTATE
				A_SetObjectFlags(threedicicle5, 32768, 2)
			end
			if threedicicle6 and threedicicle6.valid
			and threedicicle6.state == S_BLUESPLASHICICLE_MELEESTATE then
				threedicicle6.state = S_BLUESPLASHICICLE_MISSILESTATE
				A_SetObjectFlags(threedicicle6, 32768, 2)
			end
			if threedicicle7 and threedicicle7.valid
			and threedicicle7.state == S_BLUESPLASHICICLE_MELEESTATE then
				threedicicle7.state = S_BLUESPLASHICICLE_MISSILESTATE
				A_SetObjectFlags(threedicicle7, 32768, 2)
			end
			if threedicicle8 and threedicicle8.valid
			and threedicicle8.state == S_BLUESPLASHICICLE_MELEESTATE then
				threedicicle8.state = S_BLUESPLASHICICLE_MISSILESTATE
				A_SetObjectFlags(threedicicle8, 32768, 2)
			end
		end
	end
end)

--MobjThinker hooks for Frost Shield obelisks
addHook("MobjThinker", function(obelisk1)
	if obelisk1 and obelisk1.valid then
		A_CapeChase(obelisk1, (0*65536)+1, (0*65536)+(20*FRACUNIT))
	end
end, MT_FROSTSHIELDOBELISK)
addHook("MobjThinker", function(obelisk2)
	if obelisk2 and obelisk2.valid then
		A_CapeChase(obelisk2, (0*65536)+1, ((20*FRACUNIT)*65536)+(20*FRACUNIT))
	end
end, MT_FROSTSHIELDOBELISK)
addHook("MobjThinker", function(obelisk3)
	if obelisk3 and obelisk3.valid then
		A_CapeChase(obelisk3, (0*65536)+1, ((20*FRACUNIT)*65536)+0)
	end
end, MT_FROSTSHIELDOBELISK)
addHook("MobjThinker", function(obelisk4)
	if obelisk4 and obelisk4.valid then
		A_CapeChase(obelisk4, (0*65536)+1, ((-20*FRACUNIT)*65536)+(20*FRACUNIT))
	end
end, MT_FROSTSHIELDOBELISK)
addHook("MobjThinker", function(obelisk5)
	if obelisk5 and obelisk5.valid then
		A_CapeChase(obelisk5, (0*65536)+1, ((-20*FRACUNIT)*65536)+0)
	end
end, MT_FROSTSHIELDOBELISK)
addHook("MobjThinker", function(obelisk6)
	if obelisk6 and obelisk6.valid then
		A_CapeChase(obelisk6, (0*65536)+1, ((-20*FRACUNIT)*65536)+(-20*FRACUNIT))
	end
end, MT_FROSTSHIELDOBELISK)
addHook("MobjThinker", function(obelisk7)
	if obelisk7 and obelisk7.valid then
		A_CapeChase(obelisk7, (0*65536)+1, (0*65536)+(-20*FRACUNIT))
	end
end, MT_FROSTSHIELDOBELISK)
addHook("MobjThinker", function(obelisk8)
	if obelisk8 and obelisk8.valid then
		A_CapeChase(obelisk8, (0*65536)+1, ((20*FRACUNIT)*65536)+(-20*FRACUNIT))
	end
end, MT_FROSTSHIELDOBELISK)

--If Frost Shield is up, it can take a hit and protect Flora's shield, Rings, and/or life, but will be deactivated immediately without allowing a transition to Icicle Blades
addHook("ShouldDamage", function(target, inflictor, source, damage, damagetype)
	if target.player and target.player.valid then
	
		if target.player.mo.skin ~= "flora_belnades" then
			return
		end
		
		if damagetype ~= DMG_CRUSHED --Frost Shield is essentially a temporary extra Pity Shield, so it can't protect from things that shields can't protect from
		and damagetype ~= DMG_DROWNED
		and damagetype ~= DMG_SPACEDROWN
		and damagetype ~= DMG_INSTAKILL
		and damagetype ~= DMG_DEATHPIT
		and target.player.mo.frostshieldactive > 0 then
			P_DoPlayerPain(target.player, source, inflictor) --player still takes knockback and enters flashing state
			target.player.losstime = $ + 10*TICRATE
			target.player.timeshit = $ + 1 --hit still counts against the player for relevant things like guard bonus
			target.player.mo.frostshieldactive = 0 --Frost Shield only protects from one hit
			return false
		end
	end
end, MT_PLAYER)

--MobjThinker hooks for icicles
addHook("MobjThinker", function(threedicicle1)
	if threedicicle1 and threedicicle1.valid then
		if threedicicle1.state == S_BLUESPLASHICICLE_SPAWNSTATE
		or threedicicle1.state == S_BLUESPLASHICICLE_MELEESTATE then
			A_CapeChase(threedicicle1, (0*65536)+1, (0*65536)+(30*FRACUNIT))
		end
	end
end, MT_BLUESPLASHICICLE)
addHook("MobjThinker", function(threedicicle2)
	if threedicicle2 and threedicicle2.valid then
		if threedicicle2.state == S_BLUESPLASHICICLE_SPAWNSTATE
		or threedicicle2.state == S_BLUESPLASHICICLE_MELEESTATE then
			A_CapeChase(threedicicle2, (0*65536)+1, ((30*FRACUNIT)*65536)+(30*FRACUNIT))
		end
	end
end, MT_BLUESPLASHICICLE)
addHook("MobjThinker", function(threedicicle3)
	if threedicicle3 and threedicicle3.valid then
		if threedicicle3.state == S_BLUESPLASHICICLE_SPAWNSTATE
		or threedicicle3.state == S_BLUESPLASHICICLE_MELEESTATE then
			A_CapeChase(threedicicle3, (0*65536)+1, ((30*FRACUNIT)*65536)+0)
		end
	end
end, MT_BLUESPLASHICICLE)
addHook("MobjThinker", function(threedicicle4)
	if threedicicle4 and threedicicle4.valid then
		if threedicicle4.state == S_BLUESPLASHICICLE_SPAWNSTATE
		or threedicicle4.state == S_BLUESPLASHICICLE_MELEESTATE then
			A_CapeChase(threedicicle4, (0*65536)+1, ((-30*FRACUNIT)*65536)+(30*FRACUNIT))
		end
	end
end, MT_BLUESPLASHICICLE)
addHook("MobjThinker", function(threedicicle5)
	if threedicicle5 and threedicicle5.valid then
		if threedicicle5.state == S_BLUESPLASHICICLE_SPAWNSTATE
		or threedicicle5.state == S_BLUESPLASHICICLE_MELEESTATE then
			A_CapeChase(threedicicle5, (0*65536)+1, ((-30*FRACUNIT)*65536)+0)
		end
	end
end, MT_BLUESPLASHICICLE)
addHook("MobjThinker", function(threedicicle6)
	if threedicicle6 and threedicicle6.valid then
		if threedicicle6.state == S_BLUESPLASHICICLE_SPAWNSTATE
		or threedicicle6.state == S_BLUESPLASHICICLE_MELEESTATE then
			A_CapeChase(threedicicle6, (0*65536)+1, ((-30*FRACUNIT)*65536)+(-30*FRACUNIT))
		end
	end
end, MT_BLUESPLASHICICLE)
addHook("MobjThinker", function(threedicicle7)
	if threedicicle7 and threedicicle7.valid then
		if threedicicle7.state == S_BLUESPLASHICICLE_SPAWNSTATE
		or threedicicle7.state == S_BLUESPLASHICICLE_MELEESTATE then
			A_CapeChase(threedicicle7, (0*65536)+1, (0*65536)+(-30*FRACUNIT))
		end
	end
end, MT_BLUESPLASHICICLE)
addHook("MobjThinker", function(threedicicle8)
	if threedicicle8 and threedicicle8.valid then
		if threedicicle8.state == S_BLUESPLASHICICLE_SPAWNSTATE
		or threedicicle8.state == S_BLUESPLASHICICLE_MELEESTATE then
			A_CapeChase(threedicicle8, (0*65536)+1, ((30*FRACUNIT)*65536)+(-30*FRACUNIT))
		end
	end
end, MT_BLUESPLASHICICLE)

//Holy Lightning (3 orbs of electricity home in on enemies and monitors; one of the three standard Belnades spells, as seen in Castlevania 3: Dracula's Curse, Castlevania: Dawn of Sorrow, and Castlevania: Harmony of Despair)
--Objects
mobjinfo[MT_HOLYLIGHTNINGORB] = {
	spawnstate = S_HOLYLIGHTNINGORB_SPAWNSTATE,
	missilestate = S_HOLYLIGHTNINGORB_MISSILESTATE,
	painstate = S_HOLYLIGHTNINGORB_PAINSTATE,
	deathstate = S_HOLYLIGHTNINGORB_DEATHSTATE,
	spawnhealth = 2, --A single Holy Lightning orb can hit things up to 2 times.
	damage = 1,
	height = 15*FRACUNIT,
	radius = 15*FRACUNIT,
	speed = 18*FRACUNIT,
	fuse = 7*TICRATE,
	mass = DMG_ELECTRIC, --It's an electricity spell.
	flags = MF_NOGRAVITY|MF_MISSILE
}
states[S_HOLYLIGHTNINGORB_SPAWNSTATE] = {
	sprite = SPR_HLBLA,
	frame = FF_TRANS60|FF_FULLBRIGHT|A,
	tics = 10,
	nextstate = S_HOLYLIGHTNINGORB_MISSILESTATE
}
states[S_HOLYLIGHTNINGORB_MISSILESTATE] = {
	sprite = SPR_HLBLA,
	frame = FF_TRANS10|FF_FULLBRIGHT|A,
	tics = 5, //7*TICRATE
	action = A_HomingChase,
	var1 = 18*FRACUNIT,
	var2 = 1,
	nextstate = S_HOLYLIGHTNINGORB_MISSILESTATE --missile state repeats to repeat A_HomingChase; death state should kick in when health or fuse reach 0
}
states[S_HOLYLIGHTNINGORB_PAINSTATE] = {
	sprite = SPR_HLBLA,
	frame = FF_TRANS30|FF_MODULATE|A,
	tics = 40,
	nextstate = S_HOLYLIGHTNINGORB_MISSILESTATE
}
states[S_HOLYLIGHTNINGORB_DEATHSTATE] = {
	sprite = SPR_HLBLA,
	frame = FF_TRANS60|FF_FULLBRIGHT|A,
	tics = 10,
	nextstate = S_NULL
}

--Activation
addHook("PlayerThink", function(player)
	if player.mo and player.mo.valid then
	
		if player.mo.skin ~= "flora_belnades" then
			return
		end
	
/*		if player.custom3down == nil then
			player.custom3down = 0
		end
		
		if player.cmd.buttons & BT_CUSTOM3 > 0 then
			player.custom3down = $1 + 1
		else
			player.custom3down = 0
		end*/
		
		local lightningxfromplayer = cos(player.mo.angle)
		local lightningyfromplayer = sin(player.mo.angle)
		
		if player.custom3down == 1
		and player.custom1down == 0
		and player.tossflagdown == 0
		and player.mo.energy >= 24*FRACUNIT then
			player.mo.energy = $ - 24*FRACUNIT --energy cost
			local orb1 = P_SpawnMobjFromMobj(player.mo, -45*lightningxfromplayer, -60*lightningyfromplayer, 80*FRACUNIT, MT_HOLYLIGHTNINGORB) --spawn the lightning orb
			orb1.target = player.mo --assigning ownership of the orb to Flora so it doesn't hurt her
			orb1.tracer = P_LookForEnemies(player, true, true)
			local orb2 = P_SpawnMobjFromMobj(player.mo, 1*lightningxfromplayer, 1*lightningyfromplayer, 120*FRACUNIT, MT_HOLYLIGHTNINGORB)
			orb2.target = player.mo
			orb2.tracer = P_LookForEnemies(player, true, true)
			local orb3 = P_SpawnMobjFromMobj(player.mo, 45*lightningxfromplayer, 60*lightningyfromplayer, 80*FRACUNIT, MT_HOLYLIGHTNINGORB)
			orb3.target = player.mo
			orb3.tracer = P_LookForEnemies(player, true, true)
		end
	end
end)

addHook("MobjThinker", function(orb1)
	if orb1 and orb1.valid then
		A_FindTracer(orb1, ((MF_SHOOTABLE)), 0) --look for the closest enemy (including hostile players) or monitor to the orb, then set that mobj to be the tracer
	end
end, MT_HOLYLIGHTNINGORB)
addHook("MobjThinker", function(orb2)
	if orb2 and orb2.valid then
		A_FindTracer(orb2, ((MF_SHOOTABLE)), 0) --look for the closest enemy (including hostile players) or monitor to the orb, then set that mobj to be the tracer
	end
end, MT_HOLYLIGHTNINGORB)
addHook("MobjThinker", function(orb3)
	if orb3 and orb3.valid then
		A_FindTracer(orb3, ((MF_SHOOTABLE)), 0) --look for the closest enemy (including hostile players) or monitor to the orb, then set that mobj to be the tracer
	end
end, MT_HOLYLIGHTNINGORB)

addHook("MobjMoveCollide", function(orb1, thing)
	if orb1 and orb1.valid then
		if not (orb1.z >= (thing.z - orb1.height) and orb1.z <= (thing.z + thing.height)) then --height check
			return false
		end
		
		if (thing.flags & MF_SHOOTABLE) then
			if thing.type == MT_PLAYER then
				if G_CoopGametype() == true
				or (G_GametypeHasTeams == true and thing.player.ctfteam == orb1.target.ctfteam) then
					return --don't harm friendly players
				else
					P_DamageMobj(thing, orb1, orb1.target, orb1.damage, orb1.info.mass) --orb1.info.mass == DMG_ELECTRIC
					P_DamageMobj(orb1, nil, nil, 1) --send orb into pain state and reduce its health by 1 when it contacts a mobj it can damage (so that the first such contact damages the orb and temporarily shuts off its homing without outright killing it)
				end
			else
				P_DamageMobj(thing, orb1, orb1.target, orb1.damage, orb1.info.mass)
				P_DamageMobj(orb1, nil, nil, 1) --send orb into pain state and reduce its health by 1 when it contacts a mobj it can damage (so that the first such contact damages the orb and temporarily shuts off its homing without outright killing it)
			end
		end
	end
end, MT_HOLYLIGHTNINGORB)

addHook("MobjMoveCollide", function(orb2, thing)
	if orb2 and orb2.valid then
		if not (orb2.z >= (thing.z - orb2.height) and orb2.z <= (thing.z + thing.height)) then --height check
			return false
		end
		
		if (thing.flags & MF_SHOOTABLE) then
			if thing.type == MT_PLAYER then
				if G_CoopGametype() == true
				or (G_GametypeHasTeams == true and thing.player.ctfteam == orb2.target.ctfteam) then
					return --don't harm friendly players
				else
					P_DamageMobj(thing, orb2, orb2.target, orb2.damage, orb2.info.mass) --orb2.info.mass == DMG_ELECTRIC
					P_DamageMobj(orb2, nil, nil, 1) --send orb into pain state and reduce its health by 1 when it contacts a mobj it can damage (so that the first such contact damages the orb and temporarily shuts off its homing without outright killing it)
				end
			else
				P_DamageMobj(thing, orb2, orb2.target, orb2.damage, orb2.info.mass)
				P_DamageMobj(orb2, nil, nil, 1) --send orb into pain state and reduce its health by 1 when it contacts a mobj it can damage (so that the first such contact damages the orb and temporarily shuts off its homing without outright killing it)
			end
		end
	end
end, MT_HOLYLIGHTNINGORB)

addHook("MobjMoveCollide", function(orb3, thing)
	if orb3 and orb3.valid then
		if not (orb3.z >= (thing.z - orb3.height) and orb3.z <= (thing.z + thing.height)) then --height check
			return false
		end
		
		if (thing.flags & MF_SHOOTABLE) then
			if thing.type == MT_PLAYER then
				if G_CoopGametype() == true
				or (G_GametypeHasTeams == true and thing.player.ctfteam == orb3.target.ctfteam) then
					return --don't harm friendly players
				else
					P_DamageMobj(thing, orb3, orb3.target, orb3.damage, orb3.info.mass) --orb3.info.mass == DMG_ELECTRIC
					P_DamageMobj(orb3, nil, nil, 1) --send orb into pain state and reduce its health by 1 when it contacts a mobj it can damage (so that the first such contact damages the orb and temporarily shuts off its homing without outright killing it)
				end
			else
				P_DamageMobj(thing, orb3, orb3.target, orb3.damage, orb3.info.mass)
				P_DamageMobj(orb3, nil, nil, 1) --send orb into pain state and reduce its health by 1 when it contacts a mobj it can damage (so that the first such contact damages the orb and temporarily shuts off its homing without outright killing it)
			end
		end
	end
end, MT_HOLYLIGHTNINGORB)

//Shadow Trap (Easter egg alpha/bugged version of Holy Lightning that stays in place and hurts enemies that blunder into it (this is how Holy Lightning worked before I added the "tracer = P_LookForEnemies" code, but I liked its potential for setting up traps too much to completely remove it when I got Holy Lightning working closer to how I had intended it))
--objects
mobjinfo[MT_SHADOWTRAPORB] = {
	spawnstate = S_SHADOWTRAPORB_SPAWNSTATE,
	missilestate = S_SHADOWTRAPORB_MISSILESTATE,
	deathstate = S_SHADOWTRAPORB_DEATHSTATE,
	spawnhealth = 2,
	damage = 1,
	height = 15*FRACUNIT,
	radius = 15*FRACUNIT,
	speed = 2*FRACUNIT,
	fuse = 30*TICRATE,
	mass = DMG_ELECTRIC, --It's an electricity spell.
	flags = MF_NOGRAVITY|MF_MISSILE
}
states[S_SHADOWTRAPORB_SPAWNSTATE] = {
	sprite = SPR_HLBLA,
	frame = FF_TRANS60|FF_FULLBRIGHT|FF_MODULATE|A,
	tics = 10,
	nextstate = S_SHADOWTRAPORB_MISSILESTATE
}
states[S_SHADOWTRAPORB_MISSILESTATE] = {
	sprite = SPR_HLBLA,
	frame = FF_TRANS10|FF_FULLBRIGHT|FF_MODULATE|A,
	tics = 30*TICRATE,
/*	action = A_HomingChase,
	var1 = 2*FRACUNIT,
	var2 = 1,*/
	nextstate = S_SHADOWTRAPORB_DEATHSTATE
}
states[S_SHADOWTRAPORB_DEATHSTATE] = {
	sprite = SPR_HLBLA,
	frame = FF_TRANS60|FF_FULLBRIGHT|FF_MODULATE|A,
	tics = 10,
	nextstate = S_NULL
}

--Activation
addHook("PlayerThink", function(player)
	if player.mo and player.mo.valid then
	
		if player.mo.skin ~= "flora_belnades" then
			return
		end
	
/*		if player.custom3down == nil then
			player.custom3down = 0
		end
		
		if player.cmd.buttons & BT_CUSTOM3 > 0 then
			player.custom3down = $1 + 1
		else
			player.custom3down = 0
		end*/
		
		local trapxfromplayer = cos(player.mo.angle)
		local trapyfromplayer = sin(player.mo.angle)
		
		if player.custom3down == 25
		and player.custom1down >= 8
		and player.custom3down > player.custom1down
		and player.tossflagdown == 0
		and player.mo.energy >= 16*FRACUNIT
		and not ((player.ctfteam == 1 and player.mo.subsector.sector.special == 12288) or (player.ctfteam == 2 and player.mo.subsector.sector.special == 16384)) then --no, you can't put a trap orb on top of your flag in CTF, you dingus
			player.mo.energy = $ - 16*FRACUNIT --energy cost
			local trap = P_SpawnMobjFromMobj(player.mo, 1*trapxfromplayer, 1*trapyfromplayer, 8*FRACUNIT, MT_SHADOWTRAPORB) --spawn the trap orb
			trap.target = player.mo --assigning ownership of the trap orb to Flora so it doesn't hurt her
		end
	end
end)

//Dark Guardian (Easter egg deliberately bugged version of Holy Lightning that follows Flora around instead of enemies)
--objects
mobjinfo[MT_DARKGUARDIANORB] = {
	spawnstate = S_DARKGUARDIANORB_SPAWNSTATE,
	missilestate = S_DARKGUARDIANORB_MISSILESTATE,
	deathstate = S_DARKGUARDIANORB_DEATHSTATE,
	spawnhealth = 4,
	damage = 1,
	height = 60*FRACUNIT,
	radius = 60*FRACUNIT,
	speed = 36*FRACUNIT,
	fuse = 10*TICRATE,
	mass = DMG_ELECTRIC, --It's an electricity spell.
	flags = MF_NOGRAVITY|MF_MISSILE
}
states[S_DARKGUARDIANORB_SPAWNSTATE] = {
	sprite = SPR_HLBLA,
	frame = FF_TRANS60|FF_FULLBRIGHT|FF_MODULATE|A,
	tics = 10,
	nextstate = S_DARKGUARDIANORB_MISSILESTATE
}
states[S_DARKGUARDIANORB_MISSILESTATE] = {
	sprite = SPR_HLBLA,
	frame = FF_TRANS10|FF_FULLBRIGHT|FF_MODULATE|A,
	tics = 10*TICRATE,
	action = A_HomingChase,
	var1 = 36*FRACUNIT,
	var2 = 0,
	nextstate = S_DARKGUARDIANORB_DEATHSTATE
}
states[S_DARKGUARDIANORB_DEATHSTATE] = {
	sprite = SPR_HLBLA,
	frame = FF_TRANS60|FF_FULLBRIGHT|FF_MODULATE|A,
	tics = 10,
	nextstate = S_NULL
}

--Activation
addHook("PlayerThink", function(player)
	if player.mo and player.mo.valid then
	
		if player.mo.skin ~= "flora_belnades" then
			return
		end
	
/*		if player.custom3down == nil then
			player.custom3down = 0
		end
		
		if player.cmd.buttons & BT_CUSTOM3 > 0 then
			player.custom3down = $1 + 1
		else
			player.custom3down = 0
		end*/
		
		local guardxfromplayer = cos(player.mo.angle)
		local guardyfromplayer = sin(player.mo.angle)
		
		if player.custom3down == 35
		and player.custom2down >= 10
		and player.custom3down > player.custom2down
		and player.tossflagdown == 0
		and player.mo.energy >= 32*FRACUNIT
			player.mo.energy = $ - 32*FRACUNIT --energy cost
			local guard = P_SpawnMobjFromMobj(player.mo, 1*guardxfromplayer, 1*guardyfromplayer, 8*FRACUNIT, MT_DARKGUARDIANORB) --spawn the guardian orb
			guard.target = player.mo --assigning ownership of the guardian orb to Flora so it doesn't hurt her
		end
			
		if guard and guard.valid then --if a guardian orb exists
			if not (leveltime%TICRATE) then
				player.mo.energy = $ - 2*FRACUNIT --guardian orb nullifies passive energy regeneration or drains energy while it lives
				if player.mo.energy < 2*FRACUNIT then
					P_KillMobj(guard, player.mo, player.mo)
				end
			end
		end
	end
end)

addHook("MobjThinker", function(guard)
	if guard and guard.valid then
		A_HomingChase(guard, 36*FRACUNIT, 0)
	end
end, MT_DARKGUARDIANORB)

addHook("MobjMoveCollide", function(guard, thing)
	if guard and guard.valid
	and thing and thing.valid then
		if thing == guard.target then
			return false --don't let Flora's guardian orb make contact with her and self-destruct
		end
	end
end, MT_DARKGUARDIANORB)

//Holy Barrier - Wall (moveable barricade of light that blocks enemy movement and projectiles (think Reinhardt from Overwatch and you should have the general idea))
--Objects
mobjinfo[MT_HOLYBARRIERWALL] = {
	spawnstate = S_HOLYBARRIERWALL_SPAWNSTATE,
	meleestate = S_HOLYBARRIERWALL_MELEESTATE,
	deathstate = S_HOLYBARRIERWALL_DEATHSTATE,
	spawnhealth = 100, --This should be player.mo.energy (the idea being that the player's energy meter is the wall's health), but mobjinfo tables don't like variables.
	radius = 600*FRACUNIT,
	height = 300*FRACUNIT,
	flags = MF_SHOOTABLE
}
states[S_HOLYBARRIERWALL_SPAWNSTATE] = {
	sprite = SPR_HBWLA,
	frame = FF_TRANS50|FF_FULLBRIGHT|A,
	tics = 5,
	nextstate = S_HOLYBARRIERWALL_MELEESTATE
}
states[S_HOLYBARRIERWALL_MELEESTATE] = {
	sprite = SPR_HBWLA,
	frame = FF_TRANS30|FF_FULLBRIGHT|A,
	tics = 1,
	action = A_CapeChase,
	var1 = (8*65536)+1,
	var2 = (90*65536)+0,
	nextstate = S_HOLYBARRIERWALL_MELEESTATE
}
states[S_HOLYBARRIERWALL_DEATHSTATE] = {
	sprite = SPR_HBWLA,
	frame = FF_TRANS50|FF_FULLBRIGHT|A,
	tics = 5,
	nextstate = S_NULL
}

//Holy Barrier - Dome (immobile spherical barricade of light that blocks enemy movement and projectiles (more like Winston, if he had to stay inside his barrier and couldn't do anything while it was up))
--Objects
mobjinfo[MT_HOLYBARRIERDOME] = {
	spawnstate = S_HOLYBARRIERDOME_SPAWNSTATE,
	meleestate = S_HOLYBARRIERDOME_MELEESTATE,
	deathstate = S_HOLYBARRIERDOME_DEATHSTATE,
	spawnhealth = 100,
	radius = 800*FRACUNIT,
	height = 400*FRACUNIT,
	flags = MF_SHOOTABLE
}
states[S_HOLYBARRIERDOME_SPAWNSTATE] = {
	sprite = SPR_HBDMA,
	frame = FF_TRANS50|FF_FULLBRIGHT|A,
	tics = 5,
	nextstate = S_HOLYBARRIERDOME_MELEESTATE
}
states[S_HOLYBARRIERDOME_MELEESTATE] = {
	sprite = SPR_HBDMA,
	frame = FF_TRANS30|FF_FULLBRIGHT|A,
	tics = 1,
	action = A_CapeChase,
	var1 = (8*65536)+1,
	var2 = (0*65536)+0,
	nextstate = S_HOLYBARRIERDOME_MELEESTATE
}
states[S_HOLYBARRIERDOME_DEATHSTATE] = {
	sprite = SPR_HBDMA,
	frame = FF_TRANS50|FF_FULLBRIGHT|A,
	tics = 5,
	nextstate = S_NULL
}

--Holy Barrier - Activation (the wall and dome versions need to be in a single hook because they constantly reference each other)
addHook("PlayerThink", function(player)
	if player.mo and player.mo.valid then
	
		if player.mo.skin ~= "flora_belnades" then
			return
		end
	
/*		if player.tossflagdown == nil then
			player.tossflagdown = 0
		end
		
		if player.cmd.buttons & BT_TOSSFLAG > 0 then
			player.tossflagdown = $1 + 1
		else
			player.tossflagdown = 0
		end*/
		
		local wallxfromplayer = cos(player.mo.angle)
		local wallyfromplayer = sin(player.mo.angle)
		
		if player.tossflagdown == 1 --if tossflag has just been pressed
		and player.gotflag == 0 -- and Flora is not holding the flag
		and player.custom3down == 0 --and custom3 is not being pressed
		and player.mo.energy >= 3*FRACUNIT then --don't spawn a new wall every tic, that's just stupid
			player.mo.energy = $ - 3*FRACUNIT
			local wall = P_SpawnMobjFromMobj(player.mo, 90*wallxfromplayer, 90*wallyfromplayer, 8*FRACUNIT, MT_HOLYBARRIERWALL) --generate a wall in front of Flora
			wall.tracer = player.mo --attach the wall to Flora
		end
		
		if player.tossflagdown > 1 --if tossflag is currently being pressed
		and player.gotflag == 0 --and Flora is not holding the flag
		and player.custom3down == 1 --and custom3 has just been pressed
		and player.tossflagdown > player.custom3down --and custom3 was pressed *after* tossflag
		and (wall and wall.valid) then --if a wall is up
			P_KillMobj(wall, player.mo, player.mo) --remove the wall
/*				target = "MT_HOLYBARRIERWALL"
				inflictor = player.mo
				source = player.mo*/
			local dome = P_SpawnMobjFromMobj(player.mo, 0, 0, 0, MT_HOLYBARRIERDOME) --generate a dome around Flora (but not on every tic, that's just stupid)
			dome.tracer = player.mo --attach the dome to Flora
			player.pflags = $1|PF_FULLSTASIS
		end
		
		if player.tossflagdown > 1 --if tossflag is currently being pressed
//		and not (dome and dome.valid)
		and (wall and wall.valid) --and a wall exists
		and player.custom3down == 0 --and custom3 is not being held
		and player.mo.energy >= 3*FRACUNIT then
			if not (leveltime%TICRATE) then
				player.mo.energy = $ - 3*FRACUNIT
			end
			player.mo.holybarrieractive = 1 --disable Vixen Vortex while the wall is held (but not shield actions)
			player.normalspeed = 20*FRACUNIT --having the wall up slows Flora down, but does NOT outright immoblize her
			player.thrustfactor = 3*FRACUNIT
			player.accelstart = 64*FRACUNIT
			player.acceleration = 26*FRACUNIT
			player.actionspd = 60*FRACUNIT
			player.jumpfactor = 7*FRACUNIT/10
			/*if (leveltime%TICRATE) then
				player.pflags = $1|PF_THOKKED --disable Vixen Vortex while the wall is held
			end*/
		end
		
		if player.tossflagdown > 1 --if tossflag is currently being pressed
		and player.gotflag == 0 --and Flora is not holding the flag
		and player.custom3down > 1 --and custom3 is also currently being pressed
		and player.tossflagdown > player.custom3down --and custom3 was pressed *after* tossflag
		and player.mo.energy >= 3*FRACUNIT
//		and not (wall and wall.valid)
		and (dome and dome.valid) then --if a dome is up
			if not (leveltime%TICRATE) then
				player.mo.energy = $ - 3*FRACUNIT
			end
			player.mo.holybarrieractive = 1 --this is redundant with PF_FULLSTASIS, but I might as well include it in case I use player.mo.holybarrieractive for anything other than disabling Vixen Vortex
			player.pflags = $1|PF_FULLSTASIS
		end
		
		if player.tossflagdown > 1
		and player.gotflag == 0
		and player.custom3down == 0
		and player.mo.energy >= 3*FRACUNIT
		and (dome and dome.valid) then --transition from dome to wall
			P_KillMobj(dome, player.mo, player.mo) --remove the dome
/*				target = "MT_HOLYBARRIERDOME"
				inflictor = player.mo
				source = player.mo*/
			local wall = P_SpawnMobjFromMobj(player.mo, 90*wallxfromplayer, 90*wallyfromplayer, 8*FRACUNIT, MT_HOLYBARRIERWALL) --re-generate the wall
			wall.tracer = player.mo --attach the wall to Flora
		end
		
		if player.tossflagdown == 0 or player.mo.energy < 3*FRACUNIT or player.gotflag ~= 0 then
			if (wall and wall.valid) then --don't run P_KillMobj if the wall is already dead
				P_KillMobj(wall, player.mo, player.mo) --lower the barrier when tossflag is released, energy runs out, or the flag is picked up
/*					target = "MT_HOLYBARRIERWALL"
					inflictor = player.mo
					source = player.mo*/
			end
			if (dome and dome.valid) then --don't run P_KillMobj if the dome is already dead
				P_KillMobj(dome, player.mo, player.mo)
/*					target = "MT_HOLYBARRIERDOME"
					inflictor = player.mo
					source = player.mo*/
			end
		end
		
		if not (wall and wall.valid) then --if the wall is gone (regardless of whether or not it was removed by the prior P_KillMobj; this is a separate check as a failsafe against the wall being destroyed while the initial conditions (player.tossflagdown == 0, player.mo.energy < 3*FRACUNIT, or player.gotflag ~= 0) are all false)
			if not (dome and dome.valid) then --if the wall wasn't replaced with a dome
				player.mo.holybarrieractive = 0 --re-enable Vixen Vortex
			end
			player.normalspeed = skins[player.skin].normalspeed --restore original parameters when the barrier is gone (even if the prior P_KillMobj was somehow skipped)
			player.thrustfactor = skins[player.skin].thrustfactor
			player.accelstart = skins[player.skin].accelstart
			player.acceleration = skins[player.skin].acceleration
			player.actionspd = skins[player.skin].actionspd
			player.jumpfactor = skins[player.skin].jumpfactor
		end
		
		if not (dome and dome.valid)
		and not (wall and wall.valid) then
			player.mo.holybarrieractive = 0 --make sure Vixen Vortex is re-enabled if Holy Barrier is deactivated
		end
	end
end)

addHook("ShouldDamage", function(wall, inflictor, source, damage, damagetype) --draining the player's energy as the wall absorbs hits
	if wall and wall.valid
	and inflictor ~= wall.tracer --wall.tracer == player (Flora) (prevents this hook from running if the wall self-destructs)
	and not ((G_GametypeHasTeams() == true and source.ctfteam == wall.tracer.ctfteam) or (G_CoopGametype() == true and source.type == MT_PLAYER)) then --Allies can shoot and move through the wall
		wall.tracer.mo.energy = $ - damage*FRACUNIT --player loses energy equal to the damage dealt to the wall
		if (inflictor.flags & MF_MISSILE) == true then 
			P_KillMobj(inflictor, wall, wall.tracer) --destroy projectiles that collide with the wall
		end
		if inflictor.type == MT_PLAYER then
			P_DoPlayerPain(inflictor) --throw back enemy players who contact the wall, but don't hurt them
		end
		if (inflictor.flags & MF_ENEMY) == true then
			//local healthonhit = inflictor.health --recording the HP of an enemy that walks into the barrier before any health is subtracted
			if inflictor.holyboltblock == nil then
				inflictor.holyboltblock = 5 --deal minor damage to enemies that contact the wall
				if inflictor.healthonhit == inflictor.health then --making sure that Holy Barrier didn't somehow deal real damage on an initial hit
					inflictor.holyboltrecovery = (1*TICRATE)+1 --prevent consecutive damage
					inflictor.flags = $&~MF_SHOOTABLE
				end
			else
				inflictor.holyboltblock = $ - 1
				if inflictor.healthonhit == inflictor.health and inflictor.holyboltblock > 0 then --if Holy Barrier did not deal "real" damage and thus induce a pain state or death
					inflictor.holyboltrecovery = (1*TICRATE)+1 --prevent consecutive damage
					inflictor.flags = $&~MF_SHOOTABLE
				end
			end
			A_KnockBack(wall, 0) --knock back basic enemies that contact the wall
			if inflictor.holyboltblock <= 0 then
				P_DamageMobj(inflictor, wall, wall.tracer, 1) --if a total of 6 sub-damage has been dealt, the target takes 1 real damage
				if inflictor.health >= 1 then
					inflictor.holyboltblock = $ + 6 --if the target isn't dead, add 6 sub-health (prior sub-damage can carry over)
				end
			end
		end
		if (inflictor.flags & MF_BOSS) == true then
			//local healthonhit = inflictor.health --recording the HP of an enemy that walks into the barrier before any health is subtracted
			if inflictor.holyboltblock == nil then
				inflictor.holyboltblock = 5 --deal minor damage to enemies that contact the wall
				if inflictor.healthonhit == inflictor.health then --making sure that Holy Barrier didn't somehow deal real damage on an initial hit
					inflictor.holyboltrecovery = (1*TICRATE)+1 --prevent consecutive damage
					inflictor.flags = $&~MF_SHOOTABLE
				end
			else
				inflictor.holyboltblock = $ - 1
				if inflictor.healthonhit == inflictor.health and inflictor.holyboltblock > 0 then --if Holy Barrier did not deal "real" damage and thus induce a pain state or death
					inflictor.holyboltrecovery = (1*TICRATE)+1 --prevent consecutive damage
					inflictor.flags = $&~MF_SHOOTABLE
				end
			end --bosses do NOT get knocked back, in order to avoid messing with bosses that rely on axes or waypoints to move
			if inflictor.holyboltblock <= 0 then
				P_DamageMobj(inflictor, wall, wall.tracer, 1) --if a total of 6 sub-damage has been dealt, the target takes 1 real damage
				if inflictor.health >= 1 then
					inflictor.holyboltblock = $ + 6 --if the target isn't dead, add 6 sub-health (prior sub-damage can carry over)
				end
			end
		end
		return //true
	end
	if source.ctfteam == wall.tracer.ctfteam or (G_CoopGametype() == true and source.type == MT_PLAYER) == true then
		return false --Allies cannot damage the wall
	end
end, MT_HOLYBARRIERWALL)

addHook("ShouldDamage", function(dome, inflictor, source, damage, damagetype) --draining the player's energy as the dome absorbs hits
	if dome and dome.valid
	and inflictor ~= dome.tracer --dome.tracer == player (Flora) (prevents this hook from running if the dome self-destructs)
	and not ((G_GametypeHasTeams() == true and source.ctfteam == dome.tracer.ctfteam) or (G_CoopGametype() == true and source.type == MT_PLAYER)) then --Allies can shoot and move through the dome
		dome.tracer.mo.energy = $ - damage*FRACUNIT --player loses energy equal to the damage dealt to the dome
		if (inflictor.flags & MF_MISSILE) == true then 
			P_KillMobj(inflictor, dome, dome.tracer) --destroy projectiles that collide with the dome
		end
		if inflictor.type == MT_PLAYER then
			P_DoPlayerPain(inflictor) --throw back enemy players who contact the dome, but don't hurt them
		end
		if (inflictor.flags & MF_ENEMY) == true then
			//local healthonhit = inflictor.health --recording the HP of an enemy that walks into the barrier before any health is subtracted
			if inflictor.holyboltblock == nil then
				inflictor.holyboltblock = 5 --deal minor damage to enemies that contact the dome
				if inflictor.healthonhit == inflictor.health then --making sure that Holy Barrier didn't somehow deal real damage on an initial hit
					inflictor.holyboltrecovery = (1*TICRATE)+1 --prevent consecutive damage
					inflictor.flags = $&~MF_SHOOTABLE
				end
			else
				inflictor.holyboltblock = $ - 1
				if inflictor.healthonhit == inflictor.health and inflictor.holyboltblock > 0 then --if Holy Barrier did not deal "real" damage and thus induce a pain state or death
					inflictor.holyboltrecovery = (1*TICRATE)+1 --prevent consecutive damage
					inflictor.flags = $&~MF_SHOOTABLE
				end
			end
			A_KnockBack(dome, 0) --knock back basic enemies that contact the dome
			if inflictor.holyboltblock <= 0 then
				P_DamageMobj(inflictor, dome, dome.tracer, 1) --if a total of 6 sub-damage has been dealt, the target takes 1 real damage
				if inflictor.health >= 1 then
					inflictor.holyboltblock = $ + 6 --if the target isn't dead, add 6 sub-health (prior sub-damage can carry over)
				end
			end
		end
		if (inflictor.flags & MF_BOSS) == true then
			//local healthonhit = inflictor.health --recording the HP of an enemy that walks into the barrier before any health is subtracted
			if inflictor.holyboltblock == nil then
				inflictor.holyboltblock = 5 --deal minor damage to enemies that contact the dome
				if inflictor.healthonhit == inflictor.health then --making sure that Holy Barrier didn't somehow deal real damage on an initial hit
					inflictor.holyboltrecovery = (1*TICRATE)+1 --prevent consecutive damage
					inflictor.flags = $&~MF_SHOOTABLE
				end
			else
				inflictor.holyboltblock = $ - 1
				if inflictor.healthonhit == inflictor.health and inflictor.holyboltblock > 0 then --if Holy Barrier did not deal "real" damage and thus induce a pain state or death
					inflictor.holyboltrecovery = (1*TICRATE)+1 --prevent consecutive damage
					inflictor.flags = $&~MF_SHOOTABLE
				end
			end --bosses do NOT get knocked back, in order to avoid messing with bosses that rely on axes or waypoints to move
			if inflictor.holyboltblock <= 0 then
				P_DamageMobj(inflictor, dome, dome.tracer, 1) --if a total of 6 sub-damage has been dealt, the target takes 1 real damage
				if inflictor.health >= 1 then
					inflictor.holyboltblock = $ + 6 --if the target isn't dead, add 6 sub-health (prior sub-damage can carry over)
				end
			end
		end
		return //true
	end
	if source.ctfteam == dome.tracer.ctfteam or (G_CoopGametype() == true and source.type == MT_PLAYER) == true then
		return false --Allies cannot damage the dome
	end
end, MT_HOLYBARRIERDOME)