// content by Luigifan

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

--actions
freeslot(
"S_PLAY_VIXENVORTEX",
"S_PLAY_ENERGY",
"S_PLAY_HOLYBOLT",
"S_PLAY_HOLYBOLTCHARGING"
)

--objects
freeslot("MT_HOLYBOLT")

freeslot("SPR_HBLT")

freeslot(
"S_HOLYBOLT_SPAWNSTATE",
"S_HOLYBOLT_MISSILESTATE",
"S_HOLYBOLT_DEATHSTATE"
)

--sound effects
freeslot(
"sfx_hblt",
"sfx_hchrg",
"sfx_bhblt",
"sfx_vbhblt",
"sfx_ebhblt"
)

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

//Vixen Vortex (double jump)
addHook("AbilitySpecial", function(player)
	for player in players.iterate do
		if player.mo.skin ~= "cassandra_b" then
			continue
		end
		
		if player.charability == skins[player.skin].ability then --Default Vixen Vortex air action
			if not (player.pflags & PF_THOKKED) --if Vixen Vortex hasn't been used in the current jump
			and (player.pflags & PF_JUMPED) then --if the player is jumping
				P_SetObjectMomZ(player.mo, 20*FRACUNIT, false) --High double jump
/*					mobj = player.mo
					momz = 40*FRACUNIT --The planned height is 130 fracunits. Setting momz to 130*FRACUNIT took the Belnades to the ceiling of GFZ1.
					relative? = false*/
				player.pflags = $1|PF_THOKKED
				player.mo.vixenvortexed = 1
			end
		end
	end
end)

addHook("PlayerThink", function(player) --Alternative supplemental Vixen Vortex if Cassandra has another character's air action due to her Copy Bolt
	if player.mo and player.mo.valid then
	
		if player.mo.skin ~= "cassandra_b" then
			return
		end
		
		if player.charability ~= skins[player.skin].ability --If Cassandra has another character's air action
		and player.mo.copy ~= 0 --and she obtained said air action by copying them
		and player.mo.mimicry == 0 then --NOT by mimicry
			if ((player.cmd.buttons & BT_JUMP) == 1 and (player.cmd.buttons & BT_SPIN) == 1) --Vixen Vortex can be used in addition to the copied air action, but requires Jump and Spin to be pressed simultaneously
			and player.mo.vixenvortexed == 0 --if Vixen Vortex hasn't been used in the current jump
			and (player.pflags & PF_JUMPED) then --if the player is jumping
				P_SetObjectMomZ(player.mo, 20*FRACUNIT, false) --high double jump
/*					mobj = player.mo
					momz = 40*FRACUNIT --The planned height is 130 fracunits. Setting momz to 130*FRACUNIT took the Belnades to the ceiling of GFZ1.
					relative? = false*/
				player.mo.vixenvortexed = 1 --Vixen Vortex can only be used once per jump, but can be used before, after, or instead of the copied air action
			end
		end
	end
end)

addHook("PlayerThink", function(player)
	if player.mo and player.mo.valid then
	
		if player.mo.skin ~= "cassandra_b" then
			return
		end
		
		if player.mo.vixenvortexed == nil then
			player.mo.vixenvortexed = 0
		end
		
		if player.mo.momz <= 0 --This should be "when player.momz <= 0", but Lua doesn't allow that...
//		and (player.pflags & PF_THOKKED)
		and player.mo.vixenvortexed == 1 then --if PF_THOKKED was specifically turned on by Vixen Vortex
			player.pflags = $1|PF_NOJUMPDAMAGE
			player.pflags = $&~PF_SPINNING --Player can't damage enemies by colliding with them after Vixen Vortex until they touch the ground or otherwise stop descending.
			player.panim = PA_FALL
		end
	
		if not (player.pflags & PF_JUMPED) then --if the player is on the ground
			player.mo.vixenvortexed = 0
			player.pflags = $&~PF_NOJUMPDAMAGE
		end
	end
end)

--code ripped from Hinote that I don't think is working as intended
/*function A_ResetJumpFlags(actor, var1, var2)
	if actor.player and not P_IsObjectOnGround(actor)
		actor.player.pflags = $1|PF_JUMPED|PF_THOKKED
	end
end*/

//Energy meter (limitation on Holy Bolt and unique abilities)
addHook("PlayerThink", function(player)
	if player.mo and player.mo.valid then
	
		if player.mo.skin ~= "cassandra_b" then
			return --only the Belnades Sisters get this energy meter mechanic
		end
	
		player.mo.energy = max(min($,100*FRACUNIT),0) --defines player.mo.energy as a value that has a lower limit of 0 and an upper limit of 100
/*			if not (leveltime%(TICRATE*5)) then
				print("current energy = ", player.mo.energy>>FRACBITS) --will return a number between 0-100, including 0 and 100
			end*/
		if player.mo.energy == nil then
			player.mo.energy = 100*FRACUNIT --Sets the energy meter to 100 upon player.mo.energy being initially defined at game start
		end
		
		if not (leveltime%TICRATE) then --refill energy over time
			if player.firenormaldown < 2 and player.mo.copy == 0 then --default refill rate when Holy Bolt isn't charging and no powers are copied
				if player.mo.mimicry == 0
				and player.mo.copypoweruse == 0 then --energy does not refill over time if a mimicry is active or if a continuous copy ability is in use
					if player.panim == (PA_IDLE or PA_EDGE or PA_RIDE) then
						player.mo.energy = $ + 3*FRACUNIT --energy refills faster when the player isn't moving
					else
						player.mo.energy = $ + 3*FRACUNIT/2
					end
				end
			end
			if player.firenormaldown >= 2 and player.mo.copy == 0 then --slower refill rate when Holy Bolt is charging or a power is copied
				if player.mo.mimicry == 0
				and player.mo.copypoweruse == 0 then --energy does not refill over time if a mimicry is active or if a continuous copy ability is in use
					if player.panim == (PA_IDLE or PA_EDGE or PA_RIDE) then
						player.mo.energy = $ + 24*FRACUNIT/10 --energy refills faster when the player isn't moving
					else
						player.mo.energy = $ + 12*FRACUNIT/10
					end
				end
			end
			if player.firenormaldown < 2 and player.mo.copy ~= 0 then --slower refill rate when Holy Bolt is charging or a power is copied
				if player.mo.mimicry == 0
				and player.mo.copypoweruse == 0 then --energy does not refill over time if a mimicry is active or if a continuous copy ability is in use
					if player.panim == (PA_IDLE or PA_EDGE or PA_RIDE) then
						player.mo.energy = $ + 24*FRACUNIT/10 --energy refills faster when the player isn't moving
					else
						player.mo.energy = $ + 12*FRACUNIT/10
					end
				end
			end
			if player.firenormaldown >= 2 and player.mo.copy ~= 0 then --even slower refill rate when Holy Bolt is charging and a power is copied
				if player.mo.mimicry == 0
				and player.mo.copypoweruse == 0 then --energy does not refill over time if a mimicry is active or if a continuous copy ability is in use
					if player.panim == (PA_IDLE or PA_EDGE or PA_RIDE) then
						player.mo.energy = $ + 18*FRACUNIT/10 --energy refills faster when the player isn't moving
					else
						player.mo.energy = $ + 9*FRACUNIT/10
					end
				end
			end
		end
	end
end)

addHook("TouchSpecial", function(special, toucher) --code should run when the player collects a Ring
	if special and special.valid then
		if toucher.player and toucher.player.valid then
			if toucher.player.mo.skin ~= "cassandra_b" then
				return
			end
		end
		
		if toucher.player.mo.mimicry == 0 then
			toucher.player.mo.energy = $ + 15*FRACUNIT/2 --energy increases by 7.5 when a Ring is collected
		else
			toucher.player.mo.energy = $ + 5*FRACUNIT --Cassandra only gains 5 energy per Ring during mimicry
		end
	end
end, MT_RING)

addHook("MobjDeath", function(target, inflictor, source, damagetype) --code should run when the player breaks a Super Ring Monitor
	if target and target.valid then
		if source.player and source.player.valid then
			if source.player.mo.skin ~= "cassandra_b" then
				return
			end
		end
      
		if source.player.mo.mimicry == 0 then
			source.player.mo.energy = $ + 75*FRACUNIT --energy increases by 75 when a Super Ring Monitor is broken
		else
			source.player.mo.energy = $ + 50*FRACUNIT --Cassandra only gains 5 energy per Ring during mimicry
		end
	end
end, MT_RING_BOX)

addHook("PlayerSpawn", function(player) --Fills the energy meter to maximum when the player starts a level or dies and respawns
	if player.mo and player.mo.valid then
	
		if player.mo.skin ~= "cassandra_b" then
			return
		else	
			player.mo.energy = 100*FRACUNIT
		end
	end
end)

--Devmode-exclusive console command to set energy to any valid value

//Holy Bolt (chargeable projectile)
mobjinfo[MT_HOLYBOLT] = {
	spawnstate = S_HOLYBOLT_SPAWNSTATE,
	missilestate = S_HOLYBOLT_MISSILESTATE,
	deathstate = S_HOLYBOLT_DEATHSTATE,
	damage = 0, //((1*FRACUNIT/6) * (player.mo.holyboltcharge + 1))
	speed = 75*FRACUNIT,
	height = 10*FRACUNIT,
	radius = 40*FRACUNIT, //It really should be 40 fracunits long and 10 fracunits wide, but there are no separate "length" and "width" parameters...
	spawnhealth = 1,
	fuse = 8*TICRATE,
	flags = MF_NOGRAVITY|MF_MISSILE
}
states[S_HOLYBOLT_SPAWNSTATE] = {
	sprite = SPR_HBLTA,
	frame = FF_FULLBRIGHT|FF_TRANS60|FF_PAPERSPRITE|A,
	tics = 2,
	nextstate = S_HOLYBOLT_MISSILESTATE
}
states[S_HOLYBOLT_MISSILESTATE] = {
	sprite = SPR_HBLTA,
	frame = FF_FULLBRIGHT|FF_TRANS30|FF_PAPERSPRITE|A,
	tics = -1,
	nextstate = S_HOLYBOLT_DEATHSTATE
}
states[S_HOLYBOLT_DEATHSTATE] = {
	sprite = SPR_HBLTA,
	frame = FF_FULLBRIGHT|FF_TRANS80|FF_PAPERSPRITE|A,
	tics = 1,
	nextstate = S_NULL
}
sfxinfo[sfx_hblt] = {
	singular = true,
	caption = "Holy energy shot",
	priority = 6,
	flags = SF_X2AWAYSOUND
}
sfxinfo[sfx_hchrg] = {
	singular = false,
	caption = "Holy energy accumulation",
	priority = 5,
	flags = SF_NOMULTIPLESOUND
}
sfxinfo[sfx_bhblt] = {
	singular = true,
	caption = "Holy energy shot",
	priority = 9,
	flags = SF_X4AWAYSOUND
}
sfxinfo[sfx_vbhblt] = {
	singular = true,
	caption = "Intense holy energy shot",
	priority = 10,
	flags = SF_X8AWAYSOUND
}
sfxinfo[sfx_ebhblt] = {
	singular = true,
	caption = "Intense holy energy shot",
	priority = 12,
	flags = SF_X2AWAYSOUND|SF_X8AWAYSOUND
}

addHook("PlayerThink", function(player)
	if player.mo and player.mo.valid then
	
		if player.mo.skin ~= "cassandra_b" then
			return
		end
		
/*		if player.firenormaldown == nil then
			player.firenormaldown = 0
		end
		
		if player.cmd.buttons & BT_FIRENORMAL > 0 then
			player.firenormaldown = $1 + 1
		else
			player.firenormaldown = 0
		end*/
		
		if player.mo.holyboltcooldown > 0 then
			if (leveltime%TICRATE) then
				player.mo.holyboltcooldown = $ - 1
			end
		end
		
		if player.firenormaldown == 1 --if FireNormal has been tapped
		and player.mo.holyboltcooldown == 0 --a cooldown is required to avoid making this a machine gun and/or draining the entire energy meter in seconds flat
		and player.mo.energy >= 1*FRACUNIT then --Holy Bolt costs 1 energy (plus 1 per 3 seconds of charging)
			player.mo.energy = $ - 1*FRACUNIT --energy cost
			local bolt = P_SpawnPlayerMissile(player.mo, MT_HOLYBOLT, 0) --Fire Holy Bolt and assign ownership of it to the player
//			print(bolt.valid) --Did the bolt actually fire?
			S_StartSoundAtVolume(player.mo, sfx_hblt, 50, nil)
			bolt.holyboltcharge = player.mo.holyboltcharge --transfer charge to Holy Bolt
			player.mo.holyboltcooldown = 1*TICRATE --1-second cooldown
			player.mo.holyboltcharge = 0 --cleanup of errant charge
		end
		
		if player.firenormaldown > 1 then --if FireNormal is being held
			if not (leveltime%TICRATE) then
				player.mo.holyboltcharge = $ + 1 --Charge up Holy Bolt
				S_StartSoundAtVolume(player.mo, sfx_hchrg, 40, nil)
			end
		end
		
		if player.mo.holyboltcharge > 300 then
			player.mo.holyboltcharge = 300 --I didn't want to have a hard cap, but if holyboltcharge rises any higher than this, it can't be fired at all
		end
		
		if player.firenormaldown == 0 --If FireNormal isn't being held
		and player.mo.holyboltcooldown == 0
		and player.mo.holyboltcharge ~= 0 then --and the player has charged Holy Bolt
			S_StopSoundByID(player.mo, sfx_hchrg)
			if player.mo.energy >= (1*FRACUNIT + (player.mo.holyboltcharge*FRACUNIT/3)) then --if the player has enough energy
				player.mo.energy = $ - (1*FRACUNIT + (player.mo.holyboltcharge*FRACUNIT/3)) --energy cost
				local bolt = P_SpawnPlayerMissile(player.mo, MT_HOLYBOLT, 0) --Fire Holy Bolt and assign ownership of it to the player
//				print(bolt.valid) --Did the bolt actually fire?
				if player.mo.holyboltcharge == 1 then --scaling Holy Bolt volume with charge
					S_StartSoundAtVolume(player.mo, sfx_hblt, 55, nil)
				end
				if player.mo.holyboltcharge == 2 then
					S_StartSoundAtVolume(player.mo, sfx_hblt, 60, nil)
				end
				if player.mo.holyboltcharge == 3 then
					S_StartSoundAtVolume(player.mo, sfx_hblt, 65, nil)
				end
				if player.mo.holyboltcharge == 4 then
					S_StartSoundAtVolume(player.mo, sfx_hblt, 70, nil)
				end
				if player.mo.holyboltcharge == 5 then
					S_StartSoundAtVolume(player.mo, sfx_hblt, 75, nil)
				end
				if player.mo.holyboltcharge == 6 then
					S_StartSoundAtVolume(player.mo, sfx_bhblt, 80, nil)
				end
				if player.mo.holyboltcharge == 7 then
					S_StartSoundAtVolume(player.mo, sfx_bhblt, 85, nil)
				end
				if player.mo.holyboltcharge == 8 then
					S_StartSoundAtVolume(player.mo, sfx_bhblt, 90, nil)
				end
				if player.mo.holyboltcharge == 9 then
					S_StartSoundAtVolume(player.mo, sfx_bhblt, 95, nil)
				end
				if player.mo.holyboltcharge == 10 then
					S_StartSoundAtVolume(player.mo, sfx_bhblt, 100, nil)
				end
				if player.mo.holyboltcharge == 11 then
					S_StartSoundAtVolume(player.mo, sfx_bhblt, 105, nil)
				end
				if player.mo.holyboltcharge == 12 then
					S_StartSoundAtVolume(player.mo, sfx_vbhblt, 110, nil)
				end
				if player.mo.holyboltcharge == 13 then
					S_StartSoundAtVolume(player.mo, sfx_vbhblt, 115, nil)
				end
				if player.mo.holyboltcharge == 14 then
					S_StartSoundAtVolume(player.mo, sfx_vbhblt, 120, nil)
				end
				if player.mo.holyboltcharge == 15 then
					S_StartSoundAtVolume(player.mo, sfx_vbhblt, 125, nil)
				end
				if player.mo.holyboltcharge == 16 then
					S_StartSoundAtVolume(player.mo, sfx_vbhblt, 130, nil)
				end
				if player.mo.holyboltcharge == 17 then
					S_StartSoundAtVolume(player.mo, sfx_vbhblt, 135, nil)
				end
				if player.mo.holyboltcharge == 18 then
					S_StartSoundAtVolume(player.mo, sfx_ebhblt, 140, nil)
				end
				if player.mo.holyboltcharge == 19 then
					S_StartSoundAtVolume(player.mo, sfx_ebhblt, 145, nil)
				end
				if player.mo.holyboltcharge == 20 then
					S_StartSoundAtVolume(player.mo, sfx_ebhblt, 150, nil)
				end
				if player.mo.holyboltcharge == 21 then
					S_StartSoundAtVolume(player.mo, sfx_ebhblt, 155, nil)
				end
				if player.mo.holyboltcharge == 22 then
					S_StartSoundAtVolume(player.mo, sfx_ebhblt, 160, nil)
				end
				if player.mo.holyboltcharge == 23 then
					S_StartSoundAtVolume(player.mo, sfx_ebhblt, 165, nil)
				end
				if player.mo.holyboltcharge >= 24 then
					S_StartSoundAtVolume(player.mo, sfx_ebhblt, 170, nil)
				end
				bolt.holyboltcharge = player.mo.holyboltcharge --transfer charge to Holy Bolt
				player.mo.holyboltcooldown = 1*TICRATE --1-second cooldown
				player.mo.holyboltcharge = 0 --reset Holy Bolt charge
			else
				player.mo.holyboltcharge = 0 --Can't fire without enough energy, but the charge still has to reset so that it doesn't accumulate to the point where firing is impossible
			end
		end
	end
end)

addHook("MobjMoveCollide", function(bolt, thing) --tmthing == bolt
	if not (bolt.z >= (thing.z - bolt.height) and bolt.z <= (thing.z + thing.height)) then --height check
		return false
	end
	
	if (thing.flags & MF_SHOOTABLE)
	and not ((thing.flags & MF_MONITOR) or thing.type == MT_PLAYER or (thing.flags & MF_ENEMY) or (thing.flags & MF_BOSS)) then --if the shot object can be interacted with by projectiles, but is not a monitor, player, enemy, or boss
		P_DamageMobj(thing, bolt, bolt.target, ((bolt.holyboltcharge/3) + 1)) --Holy Bolt damages/triggers the object --bolt.target == player according to P_SpawnPlayerMissile
		P_KillMobj(bolt, nil, nil) --Holy Bolt stops moving
	end
	
	if (thing.flags & MF_MONITOR) then
		P_DamageMobj(thing, bolt, bolt.target, 1) --Holy Bolt breaks the monitor and grants its effects to the player
		P_KillMobj(bolt, nil, nil) --Holy Bolt stops moving
	end
	
	if thing.type == MT_PLAYER then
		if G_CoopGametype() == true
		or (G_GametypeHasTeams == true and thing.player.ctfteam == bolt.target.ctfteam) then
			return --don't harm friendly players
		else
			P_DamageMobj(thing, bolt, bolt.target, ((bolt.holyboltcharge/3) + 1)) --damage opposing players in competitive modes
			P_KillMobj(bolt, nil, nil)
		end
	end
	
	if (thing.flags & MF_ENEMY) or (thing.flags & MF_BOSS) then
		//local healthonhit = thing.health --record how much HP the target had when it was hit before doing any damage
		if bolt.holyboltcharge >= 3 then
			P_DamageMobj(thing, bolt, bolt.target, (bolt.holyboltcharge/3)) --+1 real damage for every 3 seconds of charge
			if thing.health >= 1 then
				print("Target hit! "..thing.type.."'s current health: "..thing.health.." full HP, "..thing.holyboltblock.." sub-HP.") --check to make sure that Holy Bolt actually connected, particularly in the absence of pain state
			end
		end
		if bolt.holyboltcharge == 0 then
			if thing.holyboltblock == nil then
				thing.holyboltblock = 5 --establish the sub-health meter used to govern Holy Bolt damage
				print("Target hit! "..thing.type.."'s current health: "..thing.health.." full HP, "..thing.holyboltblock.." sub-HP.") --check to make sure that Holy Bolt actually connected, particularly in the absence of pain state
				if thing.healthonhit == thing.health then --if Holy Bolt wasn't charged enough to lower the target's actual health and induce a pain state or death
					thing.flags = $&~MF_SHOOTABLE --temporarily remove MF_SHOOTABLE to prevent consecutive hits
					thing.holyboltrecovery = (1*TICRATE)+1 --set timer before returning MF_SHOOTABLE
				end
			else
				thing.holyboltblock = $ - 1 --uncharged Holy Bolt deals 1/6 damage
				print("Target hit! "..thing.type.."'s current health: "..thing.health.." full HP, "..thing.holyboltblock.." sub-HP.") --check to make sure that Holy Bolt actually connected, particularly in the absence of pain state
				if thing.healthonhit == thing.health and thing.holyboltblock > 0 then --if Holy Bolt removed no "real" HP and thus didn't induce a pain state or kill the target
					thing.flags = $&~MF_SHOOTABLE --temporarily remove MF_SHOOTABLE to prevent consecutive hits
					thing.holyboltrecovery = (1*TICRATE)+1 --set timer before returning MF_SHOOTABLE
				end
			end
		end
		if (bolt.holyboltcharge%3) == 1 then --if Holy Bolt has been charged for 1, 4, 7, etc. seconds
			if thing.holyboltblock == nil then
				thing.holyboltblock = 4 --establish the sub-health meter used to govern Holy Bolt damage
				print("Target hit! "..thing.type.."'s current health: "..thing.health.." full HP, "..thing.holyboltblock.." sub-HP.") --check to make sure that Holy Bolt actually connected, particularly in the absence of pain state
				if thing.healthonhit == thing.health then --if Holy Bolt wasn't charged enough to lower the target's actual health and induce a pain state or death
					thing.flags = $&~MF_SHOOTABLE --temporarily remove MF_SHOOTABLE to prevent consecutive hits
					thing.holyboltrecovery = (1*TICRATE)+1 --set timer before returning MF_SHOOTABLE
				end
			else
				thing.holyboltblock = $ - 2 --1 second of charging = 1/3 damage
				print("Target hit! "..thing.type.."'s current health: "..thing.health.." full HP, "..thing.holyboltblock.." sub-HP.") --check to make sure that Holy Bolt actually connected, particularly in the absence of pain state
				if thing.healthonhit == thing.health and thing.holyboltblock > 0 then --if Holy Bolt removed no "real" HP and thus didn't induce a pain state or kill the target
					thing.flags = $&~MF_SHOOTABLE --temporarily remove MF_SHOOTABLE to prevent consecutive hits
					thing.holyboltrecovery = (1*TICRATE)+1 --set timer before returning MF_SHOOTABLE
				end
			end
		end
		if (bolt.holyboltcharge%3) == 2 then --if Holy Bolt has been charged for 2, 5, 8, etc. seconds
			if thing.holyboltblock == nil then
				thing.holyboltblock = 2 --establish the sub-health meter used to govern Holy Bolt damage
				print("Target hit! "..thing.type.."'s current health: "..thing.health.." full HP, "..thing.holyboltblock.." sub-HP.") --check to make sure that Holy Bolt actually connected, particularly in the absence of pain state
				if thing.healthonhit == thing.health then --if Holy Bolt wasn't charged enough to lower the target's actual health and induce a pain state or death
					thing.flags = $&~MF_SHOOTABLE --temporarily remove MF_SHOOTABLE to prevent consecutive hits
					thing.holyboltrecovery = (1*TICRATE)+1 --set timer before returning MF_SHOOTABLE
				end
			else
				thing.holyboltblock = $ - 4 --2 seconds of charging = 2/3 damage
				print("Target hit! "..thing.type.."'s current health: "..thing.health.." full HP, "..thing.holyboltblock.." sub-HP.") --check to make sure that Holy Bolt actually connected, particularly in the absence of pain state
				if thing.healthonhit == thing.health and thing.holyboltblock > 0 then --if Holy Bolt removed no "real" HP and thus didn't induce a pain state or kill the target
					thing.flags = $&~MF_SHOOTABLE --temporarily remove MF_SHOOTABLE to prevent consecutive hits
					thing.holyboltrecovery = (1*TICRATE)+1 --set timer before returning MF_SHOOTABLE
				end
			end
		end
		if thing.holyboltblock <= 0 then
			P_DamageMobj(thing, bolt, bolt.target, 1) --if a total of 6 sub-damage has been dealt, the target takes 1 real damage
			if thing.health >= 1 then
				thing.holyboltblock = $ + 6 --if the target isn't dead, add 6 sub-health (prior sub-damage can carry over)
				print("Target hit! "..thing.type.."'s current health: "..thing.health.." full HP, "..thing.holyboltblock.." sub-HP.") --check to make sure that Holy Bolt actually connected, particularly in the absence of pain state
			end
		end
		P_KillMobj(bolt, nil, nil)
	end
	
	if thing.type == MT_BOMBSPHERE then
		P_KillMobj(thing, bolt, bolt.tracer) --Allow Holy Bolt to disarm Bomb Spheres
		P_KillMobj(bolt, nil, nil)
	end
end, MT_HOLYBOLT)

addHook("MobjThinker", function(mobj)
	if mobj and mobj.valid then
	
		if (mobj.flags & MF_ENEMY) or (mobj.flags & MF_BOSS) then
			if mobj.holyboltrecovery == nil then
				mobj.holyboltrecovery = 0 --set up the Holy Bolt recovery timer
			end
			
			if mobj.healthonhit == nil
			or mobj.health == mobj.spawnhealth then --just in case the following MobjSpawn hook doesn't work
				mobj.healthonhit = mobj.health --setting up the healthonhit variable
			end
			
			if mobj.holyboltrecovery > 0 then
				if (leveltime%TICRATE) then
					mobj.holyboltrecovery = $ - 1 --countdown
				end
			end
			
			if mobj.healthsynchronize == nil then
				mobj.healthsynchronize = 0
			end
			
			//if mobj.holyboltrecovery == 1 then --if holyboltrecovery has run down (but is not yet inactive)
			if mobj.holyboltrecovery > 0 and mobj.holyboltrecovery <5 then --let's make sure this can run properly regardless of whether or not loading multiple Belnades Sisters makes this hook run multiple times per tic
				if not (mobj.flags & MF_SHOOTABLE) then --let's make sure Holy Bolt actually took the MF_SHOOTABLE flag
					mobj.flags = $1|MF_SHOOTABLE --make the target susceptible to damage again
				end
			end
			
			if mobj.healthonhit ~= mobj.health then --if a mobj's health changes due to damage or healing
				//mobj.healthsynchronize = 3 --setting up a delay before changing the value of healthonhit so that hooks that compare healthonhit to health can function
				mobj.healthsynchronize = 24 --setting healthsynchronize to the smallest value that's divisible by 1, 2, 3, or 4
			end
			
			if mobj.healthsynchronize > 0 then
				if (leveltime%TICRATE) then
					mobj.healthsynchronize = $ - 1
				end
			end
			
			if mobj.healthsynchronize == 1 --setting healthonhit to health after comparison hooks have run
			or mobj.healthsynchronize == 2
			or mobj.healthsynchronize == 3
			or mobj.healthsynchronize == 4 then
				mobj.healthonhit = mobj.health
			end
		end
	end
end, MT_NULL) --run this hook for all enemies

addHook("MobjSpawn", function(mobj)
	if (mobj.flags & MF_ENEMY) or (mobj.flags & MF_BOSS) then
		mobj.healthonhit = mobj.health
	end
end, MT_NULL) --run this hook for all enemies