code:
/obj/effect/proc_holder/spell/targeted/charge
	name = "Charge"
	desc = "This spell can be used to recharge a variety of things in your hands, from magical artifacts to electrical components. A creative wizard can even use it to grant magical power to a fellow magic user."

	school = SCHOOL_TRANSMUTATION
	charge_max = 600
	clothes_req = FALSE
	invocation = "DIRI CEL"
	invocation_type = INVOCATION_WHISPER
	range = -1
	cooldown_min = 400 //50 deciseconds reduction per rank
	include_user = TRUE
	action_icon_state = "charge"

/obj/effect/proc_holder/spell/targeted/charge/cast(list/targets,mob/user = usr)
	for(var/mob/living/L in targets)
		var/list/hand_items = list(L.get_active_held_item(),L.get_inactive_held_item())
		var/charged_item = null
		var/burnt_out = FALSE

		if(L.pulling && isliving(L.pulling))
			var/mob/living/M = L.pulling
			if(LAZYLEN(M.mob_spell_list) || (LAZYLEN(M.mind?.spell_list)))
				for(var/obj/effect/proc_holder/spell/S in M.mob_spell_list)
					S.charge_counter = S.charge_max
				if(M.mind)
					for(var/obj/effect/proc_holder/spell/S in M.mind.spell_list)
						S.charge_counter = S.charge_max
				to_chat(M, span_notice("You feel raw magic flowing through you. It feels good!"))
			else
				to_chat(M, span_notice("You feel very strange for a moment, but then it passes."))
				burnt_out = TRUE
			charged_item = M
			break
		for(var/obj/item in hand_items)
			if(istype(item, /obj/item/spellbook))
				to_chat(L, span_danger("Glowing red letters appear on the front cover..."))
				to_chat(L, span_warning("[pick("NICE TRY BUT NO!","CLEVER BUT NOT CLEVER ENOUGH!", "SUCH FLAGRANT CHEESING IS WHY WE ACCEPTED YOUR APPLICATION!", "CUTE! VERY CUTE!", "YOU DIDN'T THINK IT'D BE THAT EASY, DID YOU?")]"))
				burnt_out = TRUE
			else if(istype(item, /obj/item/book/granter/spell))
				var/obj/item/book/granter/spell/I = item
				if(!I.oneuse)
					to_chat(L, span_notice("This book is infinite use and can't be recharged, yet the magic has improved the book somehow..."))
					burnt_out = TRUE
					I.pages_to_mastery--
					break
				if(prob(80))
					L.visible_message(span_warning("[I] catches fire!"))
					qdel(I)
				else
					I.used = FALSE
					charged_item = I
					break
			else if(istype(item, /obj/item/gun/magic))
				var/obj/item/gun/magic/I = item
				if(prob(80) && !I.can_charge)
					I.max_charges--
				if(I.max_charges <= 0)
					I.max_charges = 0
					burnt_out = TRUE
				I.charges = I.max_charges
				if(istype(item, /obj/item/gun/magic/wand) && I.max_charges != 0)
					var/obj/item/gun/magic/W = item
					W.icon_state = initial(W.icon_state)
				I.recharge_newshot()
				charged_item = I
				break
			else if(istype(item, /obj/item/stock_parts/cell))
				var/obj/item/stock_parts/cell/C = item
				if(prob(80))
					C.maxcharge -= 200
				if(C.maxcharge <= 1) //Div by 0 protection
					C.maxcharge = 1
					burnt_out = TRUE
				C.charge = C.maxcharge
				charged_item = C
				break
			else if(item.contents)
				var/obj/I = null
				for(I in item.contents)
					if(istype(I, /obj/item/stock_parts/cell/))
						var/obj/item/stock_parts/cell/C = I
						if(prob(80))
							C.maxcharge -= 200
						if(C.maxcharge <= 1) //Div by 0 protection
							C.maxcharge = 1
							burnt_out = TRUE
						C.charge = C.maxcharge
						if(istype(C.loc, /obj/item/gun))
							var/obj/item/gun/G = C.loc
							G.process_chamber()
						item.update_appearance()
						charged_item = item
						break
		if(!charged_item)
			to_chat(L, span_notice("You feel magical power surging through your hands, but the feeling rapidly fades..."))
		else if(burnt_out)
			to_chat(L, span_warning("[charged_item] doesn't seem to be reacting to the spell!"))
		else
			playsound(get_turf(L), 'sound/magic/charge.ogg', 50, TRUE)
			to_chat(L, span_notice("[charged_item] suddenly feels very warm!"))


code:
/obj/effect/proc_holder/spell/cone
	name = "Cone of Nothing"
	desc = "Does nothing in a cone! Wow!"
	school = SCHOOL_EVOCATION
	charge_max = 100
	clothes_req = FALSE
	invocation = "FUKAN NOTHAN"
	invocation_type = "shout"
	sound = 'sound/magic/forcewall.ogg'
	action_icon_state = "shield"
	range = -1
	cooldown_min = 0.5 SECONDS
	///This controls how many levels the cone has, increase this value to make a bigger cone.
	var/cone_levels = 3
	///This value determines if the cone penetrates walls.
	var/respect_density = FALSE

/obj/effect/proc_holder/spell/cone/choose_targets(mob/user = usr)
	perform(null, user=user)

///This proc creates a list of turfs that are hit by the cone
/obj/effect/proc_holder/spell/cone/proc/cone_helper(turf/starter_turf, dir_to_use, cone_levels = 3)
	var/list/turfs_to_return = list()
	var/turf/turf_to_use = starter_turf
	var/turf/left_turf
	var/turf/right_turf
	var/right_dir
	var/left_dir
	switch(dir_to_use)
		if(NORTH)
			left_dir = WEST
			right_dir = EAST
		if(SOUTH)
			left_dir = EAST
			right_dir = WEST
		if(EAST)
			left_dir = NORTH
			right_dir = SOUTH
		if(WEST)
			left_dir = SOUTH
			right_dir = NORTH

	for(var/i in 1 to cone_levels)
		var/list/level_turfs = list()
		turf_to_use = get_step(turf_to_use, dir_to_use)
		level_turfs += turf_to_use
		if(i != 1)
			left_turf = get_step(turf_to_use, left_dir)
			level_turfs += left_turf
			right_turf = get_step(turf_to_use, right_dir)
			level_turfs += right_turf
			for(var/left_i in 1 to i -calculate_cone_shape(i))
				if(left_turf.density && respect_density)
					break
				left_turf = get_step(left_turf, left_dir)
				level_turfs += left_turf
			for(var/right_i in 1 to i -calculate_cone_shape(i))
				if(right_turf.density && respect_density)
					break
				right_turf = get_step(right_turf, right_dir)
				level_turfs += right_turf
		turfs_to_return += list(level_turfs)
		if(i == cone_levels)
			continue
		if(turf_to_use.density && respect_density)
			break
	return turfs_to_return

/obj/effect/proc_holder/spell/cone/cast(list/targets,mob/user = usr)
	var/list/cone_turfs = cone_helper(get_turf(user), user.dir, cone_levels)
	for(var/list/turf_list in cone_turfs)
		do_cone_effects(turf_list)

///This proc does obj, mob and turf cone effects on all targets in a list
/obj/effect/proc_holder/spell/cone/proc/do_cone_effects(list/target_turf_list, level)
	for(var/target_turf in target_turf_list)
		if(!target_turf) //if turf is no longer there
			continue
		do_turf_cone_effect(target_turf, level)
		if(isopenturf(target_turf))
			var/turf/open/open_turf = target_turf
			for(var/movable_content in open_turf)
				if(isobj(movable_content))
					do_obj_cone_effect(movable_content, level)
				else if(isliving(movable_content))
					do_mob_cone_effect(movable_content, level)

///This proc deterimines how the spell will affect turfs.
/obj/effect/proc_holder/spell/cone/proc/do_turf_cone_effect(turf/target_turf, level)
	return

///This proc deterimines how the spell will affect objects.
/obj/effect/proc_holder/spell/cone/proc/do_obj_cone_effect(obj/target_obj, level)
	return

///This proc deterimines how the spell will affect mobs.
/obj/effect/proc_holder/spell/cone/proc/do_mob_cone_effect(mob/living/target_mob, level)
	return

///This proc adjusts the cones width depending on the level.
/obj/effect/proc_holder/spell/cone/proc/calculate_cone_shape(current_level)
	var/end_taper_start = round(cone_levels * 0.8)
	if(current_level > end_taper_start)
		return (current_level % end_taper_start) * 2 //someone more talented and probably come up with a better formula.
	else
		return 2

///This type of cone gradually affects each level of the cone instead of affecting the entire area at once.
/obj/effect/proc_holder/spell/cone/staggered

/obj/effect/proc_holder/spell/cone/staggered/cast(list/targets,mob/user = usr)
	var/level_counter = 0
	var/list/cone_turfs = cone_helper(get_turf(user), user.dir, cone_levels)
	for(var/list/turf_list in cone_turfs)
		level_counter++
		addtimer(CALLBACK(src, .proc/do_cone_effects, turf_list, level_counter), 2 * level_counter)

repo_name: AnalWerewolf/sundown

license: mit


code:
/obj/effect/proc_holder/spell/aoe_turf/conjure
	name = "Conjure"
	desc = "This spell conjures objs of the specified types in range."

	school = SCHOOL_CONJURATION

	var/list/summon_type = list() //determines what exactly will be summoned
	//should be text, like list("/mob/living/simple_animal/bot/ed209")

	var/summon_lifespan = 0 // 0=permanent, any other time in deciseconds
	var/summon_amt = 1 //amount of objects summoned
	var/summon_ignore_density = FALSE //if set to TRUE, adds dense tiles to possible spawn places
	var/summon_ignore_prev_spawn_points = TRUE //if set to TRUE, each new object is summoned on a new spawn point

	var/list/newVars = list() //vars of the summoned objects will be replaced with those where they meet
	//should have format of list("emagged" = 1,"name" = "Wizard's Justicebot"), for example

	var/cast_sound = 'sound/items/welder.ogg'

/obj/effect/proc_holder/spell/aoe_turf/conjure/cast(list/targets,mob/user = usr)
	playsound(get_turf(user), cast_sound, 50,TRUE)
	for(var/turf/T in targets)
		if(T.density && !summon_ignore_density)
			targets -= T

	for(var/i=0,i<summon_amt,i++)
		if(!targets.len)
			break
		var/summoned_object_type = pick(summon_type)
		var/spawn_place = pick(targets)
		if(summon_ignore_prev_spawn_points)
			targets -= spawn_place
		if(ispath(summoned_object_type, /turf))
			var/turf/O = spawn_place
			var/N = summoned_object_type
			O.ChangeTurf(N, flags = CHANGETURF_INHERIT_AIR)
		else
			var/atom/summoned_object = new summoned_object_type(spawn_place)

			for(var/varName in newVars)
				if(varName in newVars)
					summoned_object.vv_edit_var(varName, newVars[varName])
			summoned_object.flags_1 |= ADMIN_SPAWNED_1
			if(summon_lifespan)
				QDEL_IN(summoned_object, summon_lifespan)

			post_summon(summoned_object, user)

/obj/effect/proc_holder/spell/aoe_turf/conjure/proc/post_summon(atom/summoned_object, mob/user)
	return

/obj/effect/proc_holder/spell/aoe_turf/conjure/summon_ed_swarm //test purposes - Also a lot of fun
	name = "Dispense Wizard Justice"
	desc = "This spell dispenses wizard justice."
	summon_type = list(/mob/living/simple_animal/bot/secbot/ed209)
	summon_amt = 10
	range = 3
	newVars = list("emagged" = 2, "remote_disabled" = 1,"shoot_sound" = 'sound/weapons/laser.ogg',"projectile" = /obj/projectile/beam/laser, "declare_arrests" = 0,"name" = "Wizard's Justicebot")

/obj/effect/proc_holder/spell/aoe_turf/conjure/link_worlds
	name = "Link Worlds"
	desc = "A whole new dimension for you to play with! They won't be happy about it, though."
	invocation = "WTF"
	clothes_req = FALSE
	charge_max = 600
	cooldown_min = 200
	summon_type = list(/obj/structure/spawner/nether)
	summon_amt = 1
	range = 1
	cast_sound = 'sound/weapons/marauder.ogg'

/obj/effect/proc_holder/spell/targeted/conjure_item
	name = "Summon weapon"
	desc = "A generic spell that should not exist.  This summons an instance of a specific type of item, or if one already exists, un-summons it.  Summons into hand if possible."
	invocation_type = "none"
	include_user = TRUE
	range = -1
	clothes_req = FALSE
	var/obj/item/item
	var/item_type = /obj/item/banhammer
	school = SCHOOL_CONJURATION
	charge_max = 150
	cooldown_min = 10
	var/delete_old = TRUE //TRUE to delete the last summoned object if it's still there, FALSE for infinite item stream weeeee

/obj/effect/proc_holder/spell/targeted/conjure_item/cast(list/targets, mob/user = usr)
	if (delete_old && item && !QDELETED(item))
		QDEL_NULL(item)
	else
		for(var/mob/living/carbon/C in targets)
			if(C.dropItemToGround(C.get_active_held_item()))
				C.put_in_hands(make_item(), TRUE)

/obj/effect/proc_holder/spell/targeted/conjure_item/Destroy()
	if(item)
		qdel(item)
	return ..()

/obj/effect/proc_holder/spell/targeted/conjure_item/proc/make_item()
	item = new item_type
	return item


code:
//////////////////////////////Construct Spells/////////////////////////

/obj/effect/proc_holder/spell/aoe_turf/conjure/construct/lesser
	charge_max = 3 MINUTES
	action_background_icon_state = "bg_demon"

/obj/effect/proc_holder/spell/aoe_turf/conjure/construct/lesser/cult
	clothes_req = TRUE
	charge_max = 250 SECONDS

/obj/effect/proc_holder/spell/aoe_turf/area_conversion
	name = "Area Conversion"
	desc = "This spell instantly converts a small area around you."

	school = SCHOOL_TRANSMUTATION
	charge_max = 5 SECONDS
	clothes_req = FALSE
	invocation = "none"
	invocation_type = "none"
	range = 2
	action_icon = 'icons/mob/actions/actions_cult.dmi'
	action_icon_state = "areaconvert"
	action_background_icon_state = "bg_cult"

/obj/effect/proc_holder/spell/aoe_turf/area_conversion/cast(list/targets, mob/user = usr)
	playsound(get_turf(user), 'sound/items/welder.ogg', 75, TRUE)
	for(var/turf/T in targets)
		T.narsie_act(FALSE, TRUE, 100 - (get_dist(user, T) * 25))

/obj/effect/proc_holder/spell/aoe_turf/conjure/floor
	name = "Summon Cult Floor"
	desc = "This spell constructs a cult floor."

	school = SCHOOL_CONJURATION
	charge_max = 2 SECONDS
	clothes_req = FALSE
	invocation = "none"
	invocation_type = "none"
	range = 0
	summon_type = list(/turf/open/floor/engine/cult)
	action_icon = 'icons/mob/actions/actions_cult.dmi'
	action_icon_state = "floorconstruct"
	action_background_icon_state = "bg_cult"

/obj/effect/proc_holder/spell/aoe_turf/conjure/wall
	name = "Summon Cult Wall"
	desc = "This spell constructs a cult wall."

	school = SCHOOL_CONJURATION
	charge_max = 10 SECONDS
	clothes_req = FALSE
	invocation = "none"
	invocation_type = "none"
	range = 0
	action_icon = 'icons/mob/actions/actions_cult.dmi'
	action_icon_state = "lesserconstruct"
	action_background_icon_state = "bg_cult"

	summon_type = list(/turf/closed/wall/mineral/cult/artificer) //we don't want artificer-based runed metal farms

/obj/effect/proc_holder/spell/aoe_turf/conjure/wall/reinforced
	name = "Greater Construction"
	desc = "This spell constructs a reinforced metal wall."

	school = SCHOOL_CONJURATION
	charge_max = 30 SECONDS
	clothes_req = FALSE
	invocation = "none"
	invocation_type = "none"
	range = 0

	summon_type = list(/turf/closed/wall/r_wall)

/obj/effect/proc_holder/spell/aoe_turf/conjure/soulstone
	name = "Summon Soulstone"
	desc = "This spell reaches into Nar'Sie's realm, summoning one of the legendary fragments across time and space."

	school = SCHOOL_CONJURATION
	charge_max = 4 MINUTES
	clothes_req = FALSE
	invocation = "none"
	invocation_type = "none"
	range = 0
	action_icon = 'icons/mob/actions/actions_cult.dmi'
	action_icon_state = "summonsoulstone"
	action_background_icon_state = "bg_demon"

	summon_type = list(/obj/item/soulstone)

/obj/effect/proc_holder/spell/aoe_turf/conjure/soulstone/cult
	clothes_req = TRUE
	charge_max = 6 MINUTES

/obj/effect/proc_holder/spell/aoe_turf/conjure/soulstone/noncult
	summon_type = list(/obj/item/soulstone/anybody)

/obj/effect/proc_holder/spell/aoe_turf/conjure/soulstone/purified
	summon_type = list(/obj/item/soulstone/anybody/purified)

/obj/effect/proc_holder/spell/aoe_turf/conjure/soulstone/mystic
	summon_type = list(/obj/item/soulstone/mystic)

/obj/effect/proc_holder/spell/targeted/forcewall/cult
	name = "Shield"
	desc = "This spell creates a temporary forcefield to shield yourself and allies from incoming fire."
	school = SCHOOL_TRANSMUTATION
	charge_max = 40 SECONDS
	clothes_req = FALSE
	invocation = "none"
	invocation_type = "none"
	wall_type = /obj/effect/forcefield/cult
	action_icon = 'icons/mob/actions/actions_cult.dmi'
	action_icon_state = "cultforcewall"
	action_background_icon_state = "bg_demon"

/obj/effect/proc_holder/spell/targeted/ethereal_jaunt/shift
	name = "Phase Shift"
	desc = "This spell allows you to pass through walls."

	school = SCHOOL_TRANSMUTATION
	charge_max = 25 SECONDS
	clothes_req = FALSE
	invocation = "none"
	invocation_type = "none"
	jaunt_duration = 5 SECONDS
	action_icon = 'icons/mob/actions/actions_cult.dmi'
	action_icon_state = "phaseshift"
	action_background_icon_state = "bg_demon"
	jaunt_in_time = 0.6 SECONDS
	jaunt_out_time = 0.6 SECONDS
	jaunt_in_type = /obj/effect/temp_visual/dir_setting/wraith
	jaunt_out_type = /obj/effect/temp_visual/dir_setting/wraith/out

/obj/effect/proc_holder/spell/targeted/ethereal_jaunt/shift/jaunt_steam(mobloc)
	return

/obj/effect/proc_holder/spell/targeted/ethereal_jaunt/shift/angelic
	jaunt_in_type = /obj/effect/temp_visual/dir_setting/wraith/angelic
	jaunt_out_type = /obj/effect/temp_visual/dir_setting/wraith/out/angelic

/obj/effect/proc_holder/spell/targeted/ethereal_jaunt/shift/mystic
	jaunt_in_type = /obj/effect/temp_visual/dir_setting/wraith/mystic
	jaunt_out_type = /obj/effect/temp_visual/dir_setting/wraith/out/mystic

/obj/effect/proc_holder/spell/targeted/projectile/magic_missile/lesser
	name = "Lesser Magic Missile"
	desc = "This spell fires several, slow moving, magic projectiles at nearby targets."

	school = SCHOOL_EVOCATION
	charge_max = 40 SECONDS
	clothes_req = FALSE
	invocation = "none"
	invocation_type = "none"
	max_targets = 6
	action_icon_state = "magicm"
	action_background_icon_state = "bg_demon"
	proj_type = /obj/projectile/magic/spell/magic_missile/lesser

/obj/projectile/magic/spell/magic_missile/lesser
	color = "red" //Looks more culty this way
	range = 10

/obj/effect/proc_holder/spell/targeted/smoke/disable
	name = "Paralysing Smoke"
	desc = "This spell spawns a cloud of paralysing smoke."

	school = SCHOOL_CONJURATION
	charge_max = 20 SECONDS
	clothes_req = FALSE
	invocation = "none"
	invocation_type = "none"
	range = -1
	include_user = TRUE
	cooldown_min = 20 //25 deciseconds reduction per rank

	smoke_spread = 3
	smoke_amt = 4
	action_icon_state = "smoke"
	action_background_icon_state = "bg_cult"

/obj/effect/proc_holder/spell/pointed/abyssal_gaze
	name = "Abyssal Gaze"
	desc = "This spell instills a deep terror in your target, temporarily chilling and blinding it."
	charge_max = 75 SECONDS
	range = 5
	stat_allowed = FALSE
	school = SCHOOL_EVOCATION
	clothes_req = FALSE
	invocation = "none"
	invocation_type = "none"
	ranged_mousepointer = 'icons/effects/mouse_pointers/cult_target.dmi'
	action_icon = 'icons/mob/actions/actions_cult.dmi'
	action_background_icon_state = "bg_demon"
	action_icon_state = "abyssal_gaze"
	active_msg = "You prepare to instill a deep terror in a target..."

/obj/effect/proc_holder/spell/pointed/abyssal_gaze/cast(list/targets, mob/user)
	if(!LAZYLEN(targets))
		to_chat(user, span_warning("No target found in range!"))
		return FALSE
	if(!can_target(targets[1], user))
		return FALSE

	var/mob/living/carbon/target = targets[1]
	if(target.anti_magic_check(TRUE, TRUE))
		to_chat(user, span_warning("The spell had no effect!"))
		to_chat(target, span_warning("You feel a freezing darkness closing in on you, but it rapidly dissipates."))
		return FALSE

	to_chat(target, span_userdanger("A freezing darkness surrounds you..."))
	target.playsound_local(get_turf(target), 'sound/hallucinations/i_see_you1.ogg', 50, 1)
	user.playsound_local(get_turf(user), 'sound/effects/ghost2.ogg', 50, 1)
	target.become_blind(ABYSSAL_GAZE_BLIND)
	addtimer(CALLBACK(src, .proc/cure_blindness, target), 40)
	if(ishuman(targets[1]))
		var/mob/living/carbon/human/humi = targets[1]
		humi.adjust_coretemperature(-200)
	target.adjust_bodytemperature(-200)

/**
 * cure_blidness: Cures Abyssal Gaze blindness from the target
 *
 * Arguments:
 * * target The mob that is being cured of the blindness.
 */
/obj/effect/proc_holder/spell/pointed/abyssal_gaze/proc/cure_blindness(mob/target)
	if(isliving(target))
		var/mob/living/L = target
		L.cure_blind(ABYSSAL_GAZE_BLIND)

/obj/effect/proc_holder/spell/pointed/abyssal_gaze/can_target(atom/target, mob/user, silent)
	. = ..()
	if(!.)
		return FALSE
	if(!iscarbon(target))
		if(!silent)
			to_chat(user, span_warning("You can only target carbon based lifeforms!"))
		return FALSE
	return TRUE

/obj/effect/proc_holder/spell/pointed/dominate
	name = "Dominate"
	desc = "This spell dominates the mind of a lesser creature to the will of Nar'Sie, allying it only to her direct followers."
	charge_max = 1 MINUTES
	range = 7
	stat_allowed = FALSE
	school = SCHOOL_EVOCATION
	clothes_req = FALSE
	invocation = "none"
	invocation_type = "none"
	ranged_mousepointer = 'icons/effects/mouse_pointers/cult_target.dmi'
	action_icon = 'icons/mob/actions/actions_cult.dmi'
	action_background_icon_state = "bg_demon"
	action_icon_state = "dominate"
	active_msg = "You prepare to dominate the mind of a target..."

/obj/effect/proc_holder/spell/pointed/dominate/cast(list/targets, mob/user)
	if(!LAZYLEN(targets))
		to_chat(user, span_notice("No target found in range."))
		return FALSE
	if(!can_target(targets[1], user))
		return FALSE

	var/mob/living/simple_animal/S = targets[1]
	S.add_atom_colour("#990000", FIXED_COLOUR_PRIORITY)
	S.faction = list("cult")
	playsound(get_turf(S), 'sound/effects/ghost.ogg', 100, TRUE)
	new /obj/effect/temp_visual/cult/sac(get_turf(S))

/obj/effect/proc_holder/spell/pointed/dominate/can_target(atom/target, mob/user, silent)
	. = ..()
	if(!.)
		return FALSE
	if(!isanimal(target))
		if(!silent)
			to_chat(user, span_warning("Target is not a lesser creature!"))
		return FALSE

	var/mob/living/simple_animal/S = target
	if(S.mind)
		if(!silent)
			to_chat(user, span_warning("[S] is too intelligent to dominate!"))
		return FALSE
	if(S.stat)
		if(!silent)
			to_chat(user, span_warning("[S] is dead!"))
		return FALSE
	if(S.sentience_type != SENTIENCE_ORGANIC)
		if(!silent)
			to_chat(user, span_warning("[S] cannot be dominated!"))
		return FALSE
	if("cult" in S.faction)
		if(!silent)
			to_chat(user, span_warning("[S] is already serving Nar'Sie!"))
		return FALSE
	return TRUE

/obj/effect/proc_holder/spell/targeted/ethereal_jaunt/shift/golem
	charge_max = 80 SECONDS
	jaunt_in_type = /obj/effect/temp_visual/dir_setting/cult/phase
	jaunt_out_type = /obj/effect/temp_visual/dir_setting/cult/phase/out

/obj/effect/proc_holder/spell/targeted/projectile/dumbfire/juggernaut
	name = "Gauntlet Echo"
	desc = "Channels energy into your gauntlet - firing its essence forward in a slow moving, yet devastating, attack."
	proj_type = /obj/projectile/magic/spell/juggernaut
	charge_max = 35 SECONDS
	clothes_req = FALSE
	action_icon = 'icons/mob/actions/actions_cult.dmi'
	action_icon_state = "cultfist"
	action_background_icon_state = "bg_demon"
	sound = 'sound/weapons/resonator_blast.ogg'

/obj/projectile/magic/spell/juggernaut
	name = "Gauntlet Echo"
	icon_state = "cultfist"
	alpha = 180
	damage = 30
	damage_type = BRUTE
	knockdown = 50
	hitsound = 'sound/weapons/punch3.ogg'
	trigger_range = 0
	check_holy = TRUE
	ignored_factions = list("cult")
	range = 15
	speed = 7

/obj/projectile/magic/spell/juggernaut/on_hit(atom/target, blocked)
	. = ..()
	var/turf/T = get_turf(src)
	playsound(T, 'sound/weapons/resonator_blast.ogg', 100, FALSE)
	new /obj/effect/temp_visual/cult/sac(T)
	for(var/obj/O in range(src,1))
		if(O.density && !istype(O, /obj/structure/destructible/cult))
			O.take_damage(90, BRUTE, MELEE, 0)
			new /obj/effect/temp_visual/cult/turf/floor(get_turf(O))


code:
GLOBAL_VAR_INIT(curse_of_madness_triggered, FALSE)

/proc/curse_of_madness(mob/user, message)
	if(user) //in this case either someone holding a spellbook or a badmin
		to_chat(user, span_warning("You sent a curse of madness with the message \"[message]\"!"))
		message_admins("[ADMIN_LOOKUPFLW(user)] sent a curse of madness with the message \"[message]\"!")
		log_game("[key_name(user)] sent a curse of madness with the message \"[message]\"!")

	GLOB.curse_of_madness_triggered = message // So latejoiners are also afflicted.

	deadchat_broadcast("A [span_name("Curse of Madness")] has stricken the station, shattering their minds with the awful secret: \"[message]\"", message_type=DEADCHAT_ANNOUNCEMENT)

	for(var/mob/living/carbon/human/H in GLOB.player_list)
		if(H.stat == DEAD)
			continue
		var/turf/T = get_turf(H)
		if(T && !is_station_level(T.z))
			continue
		if(H.anti_magic_check(TRUE, FALSE, TRUE))
			to_chat(H, span_notice("You have a strange feeling for a moment, but then it passes."))
			continue
		give_madness(H, message)

/proc/give_madness(mob/living/carbon/human/H, message)
	H.playsound_local(H,'sound/magic/curse.ogg',40,1)
	to_chat(H, "[message]")
	to_chat(H, span_warning("Your mind shatters!"))
	switch(rand(1,10))
		if(1 to 3)
			H.gain_trauma_type(BRAIN_TRAUMA_MILD, TRAUMA_RESILIENCE_LOBOTOMY)
			H.gain_trauma_type(BRAIN_TRAUMA_MILD, TRAUMA_RESILIENCE_LOBOTOMY)
		if(4 to 6)
			H.gain_trauma_type(BRAIN_TRAUMA_SEVERE, TRAUMA_RESILIENCE_LOBOTOMY)
		if(7 to 8)
			H.gain_trauma_type(BRAIN_TRAUMA_MAGIC, TRAUMA_RESILIENCE_LOBOTOMY)
		if(9 to 10)
			H.gain_trauma_type(BRAIN_TRAUMA_SPECIAL, TRAUMA_RESILIENCE_LOBOTOMY)


code:
/obj/effect/proc_holder/spell/targeted/emplosion
	name = "Emplosion"
	desc = "This spell emplodes an area."

	school = SCHOOL_EVOCATION
	var/emp_heavy = 2
	var/emp_light = 3

	action_icon_state = "emp"
	sound = 'sound/weapons/zapbang.ogg'

/obj/effect/proc_holder/spell/targeted/emplosion/cast(list/targets,mob/user = usr)
	playsound(get_turf(user), sound, 50,TRUE)
	for(var/mob/living/target in targets)
		if(target.anti_magic_check())
			continue
		empulse(target.loc, emp_heavy, emp_light)

	return


code:
/obj/effect/proc_holder/spell/targeted/ethereal_jaunt
	name = "Ethereal Jaunt"
	desc = "This spell turns your form ethereal, temporarily making you invisible and able to pass through walls."

	school = SCHOOL_TRANSMUTATION
	charge_max = 30 SECONDS
	clothes_req = TRUE
	invocation = "none"
	invocation_type = "none"
	range = -1
	cooldown_min = 10 SECONDS
	include_user = TRUE
	nonabstract_req = TRUE
	action_icon_state = "jaunt"
	/// For how long are we jaunting?
	var/jaunt_duration = 5 SECONDS
	/// For how long we become immobilized after exiting the jaunt.
	var/jaunt_in_time = 0.5 SECONDS
	/// For how long we become immobilized when using this spell.
	var/jaunt_out_time = 0 SECONDS
	/// Visual for jaunting
	var/jaunt_in_type = /obj/effect/temp_visual/wizard
	/// Visual for exiting the jaunt
	var/jaunt_out_type = /obj/effect/temp_visual/wizard/out
	/// List of valid exit points
	var/list/exit_point_list

/obj/effect/proc_holder/spell/targeted/ethereal_jaunt/cast_check(skipcharge = 0,mob/user = usr)
	. = ..()
	if(!.)
		return FALSE
	var/area/noteleport_check = get_area(user)
	if(noteleport_check && noteleport_check.area_flags & NOTELEPORT)
		to_chat(user, span_danger("Some dull, universal force is stopping you from jaunting here."))
		return FALSE

/obj/effect/proc_holder/spell/targeted/ethereal_jaunt/cast(list/targets,mob/user = usr) //magnets, so mostly hardcoded
	play_sound("enter",user)
	for(var/mob/living/target in targets)
		INVOKE_ASYNC(src, .proc/do_jaunt, target)

/obj/effect/proc_holder/spell/targeted/ethereal_jaunt/proc/do_jaunt(mob/living/target)
	target.notransform = 1
	var/turf/mobloc = get_turf(target)
	var/obj/effect/dummy/phased_mob/spell_jaunt/holder = new /obj/effect/dummy/phased_mob/spell_jaunt(mobloc)
	new jaunt_out_type(mobloc, target.dir)
	target.extinguish_mob()
	target.forceMove(holder)
	target.reset_perspective(holder)
	target.notransform=0 //mob is safely inside holder now, no need for protection.
	jaunt_steam(mobloc)
	if(jaunt_out_time)
		ADD_TRAIT(target, TRAIT_IMMOBILIZED, type)
		sleep(jaunt_out_time)
		REMOVE_TRAIT(target, TRAIT_IMMOBILIZED, type)
	var/turf/exit_point = get_turf(holder) //Hopefully this gets updated, otherwise this is our fallback
	LAZYINITLIST(exit_point_list)
	RegisterSignal(holder, COMSIG_MOVABLE_MOVED, .proc/update_exit_point, target)
	sleep(jaunt_duration)

	UnregisterSignal(holder, COMSIG_MOVABLE_MOVED)
	if(target.loc != holder) //mob warped out of the warp
		qdel(holder)
		return

	var/found_exit = FALSE
	for(var/turf/possible_exit as anything in exit_point_list)
		if(possible_exit.is_blocked_turf_ignore_climbable())
			continue
		exit_point = possible_exit
		found_exit = TRUE
		break
	if(!found_exit)
		to_chat(target, "<span='danger'>Unable to find an unobstructed space, you find yourself ripped back to where you started.</span>")
	exit_point_list.Cut()
	holder.forceMove(exit_point)

	mobloc = get_turf(target.loc)
	jaunt_steam(mobloc)
	ADD_TRAIT(target, TRAIT_IMMOBILIZED, type)
	holder.reappearing = 1
	play_sound("exit",target)
	sleep(25 - jaunt_in_time)
	new jaunt_in_type(mobloc, holder.dir)
	target.setDir(holder.dir)
	sleep(jaunt_in_time)
	qdel(holder)
	if(!QDELETED(target))
		if(mobloc.density)
			for(var/direction in GLOB.alldirs)
				var/turf/T = get_step(mobloc, direction)
				if(T)
					if(target.Move(T))
						break
		REMOVE_TRAIT(target, TRAIT_IMMOBILIZED, type)

/**
 * Updates the exit point of the jaunt
 *
 * Called when the jaunting mob holder moves, this updates the backup exit-jaunt
 * location, in case the jaunt ends with the mob still in a wall. Five
 * spots are kept in the list, in case the last few changed since we passed
 * by (doors closing, engineers building walls, etc)
 */
/obj/effect/proc_holder/spell/targeted/ethereal_jaunt/proc/update_exit_point(mob/living/target)
	SIGNAL_HANDLER
	var/turf/location = get_turf(target)
	if(location.is_blocked_turf_ignore_climbable())
		return
	exit_point_list.Insert(1, location)
	if(length(exit_point_list) >= 5)
		exit_point_list.Cut(5)

/obj/effect/proc_holder/spell/targeted/ethereal_jaunt/proc/jaunt_steam(mobloc)
	var/datum/effect_system/steam_spread/steam = new /datum/effect_system/steam_spread()
	steam.set_up(10, 0, mobloc)
	steam.start()

/obj/effect/proc_holder/spell/targeted/ethereal_jaunt/proc/play_sound(type,mob/living/target)
	switch(type)
		if("enter")
			playsound(get_turf(target), 'sound/magic/ethereal_enter.ogg', 50, TRUE, -1)
		if("exit")
			playsound(get_turf(target), 'sound/magic/ethereal_exit.ogg', 50, TRUE, -1)

/obj/effect/dummy/phased_mob/spell_jaunt
	movespeed = 2 //quite slow.
	var/reappearing = FALSE

/obj/effect/dummy/phased_mob/spell_jaunt/phased_check(mob/living/user, direction)
	if(reappearing)
		return
	. = ..()
	if(!.)
		return
	if (locate(/obj/effect/blessing, .))
		to_chat(user, span_warning("Holy energies block your path!"))
		return null


code:
/obj/effect/proc_holder/spell/targeted/explosion
	name = "Explosion"
	desc = "This spell explodes an area."

	school = SCHOOL_EVOCATION

	/// The devastation range of the resulting explosion.
	var/ex_severe = 1
	/// The heavy impact range of the resulting explosion.
	var/ex_heavy = 2
	/// The light impact range of the resulting explosion.
	var/ex_light = 3
	/// The flash range of the resulting explosion.
	var/ex_flash = 4

/obj/effect/proc_holder/spell/targeted/explosion/cast(list/targets,mob/user = usr)
	for(var/mob/living/target in targets)
		if(target.anti_magic_check())
			continue
		explosion(target, devastation_range = ex_severe, heavy_impact_range = ex_heavy, light_impact_range = ex_light, flash_range = ex_flash, explosion_cause = src)

	return


code:
/obj/effect/proc_holder/spell/targeted/forcewall
	name = "Forcewall"
	desc = "Create a magical barrier that only you can pass through."
	school = SCHOOL_TRANSMUTATION
	charge_max = 100
	clothes_req = FALSE
	invocation = "TARCOL MINTI ZHERI"
	invocation_type = INVOCATION_SHOUT
	sound = 'sound/magic/forcewall.ogg'
	action_icon_state = "shield"
	range = -1
	include_user = TRUE
	cooldown_min = 50 //12 deciseconds reduction per rank
	var/wall_type = /obj/effect/forcefield/wizard

/obj/effect/proc_holder/spell/targeted/forcewall/cast(list/targets,mob/user = usr)
	new wall_type(get_turf(user),user)
	if(user.dir == SOUTH || user.dir == NORTH)
		new wall_type(get_step(user, EAST),user)
		new wall_type(get_step(user, WEST),user)
	else
		new wall_type(get_step(user, NORTH),user)
		new wall_type(get_step(user, SOUTH),user)

/obj/effect/forcefield/wizard
	var/mob/wizard

/obj/effect/forcefield/wizard/Initialize(mapload, mob/summoner)
	. = ..()
	wizard = summoner

/obj/effect/forcefield/wizard/CanAllowThrough(atom/movable/mover, border_dir)
	. = ..()
	if(mover == wizard)
		return TRUE
	if(isliving(mover))
		var/mob/M = mover
		if(M.anti_magic_check(chargecost = 0))
			return TRUE


code:
/obj/effect/proc_holder/spell/targeted/genetic
	name = "Genetic"
	desc = "This spell inflicts a set of mutations and disabilities upon the target."

	school = SCHOOL_TRANSMUTATION

	var/list/active_on = list()
	var/list/traits = list() //disabilities
	var/list/mutations = list() //mutation defines
	var/duration = 100 //deciseconds
	/*
		Disabilities
			1st bit - ?
			2nd bit - ?
			3rd bit - ?
			4th bit - ?
			5th bit - ?
			6th bit - ?
	*/

/obj/effect/proc_holder/spell/targeted/genetic/cast(list/targets,mob/user = usr)
	playMagSound()
	for(var/mob/living/carbon/target in targets)
		if(target.anti_magic_check())
			continue
		if(!target.dna)
			continue
		for(var/A in mutations)
			target.dna.add_mutation(A)
		for(var/A in traits)
			ADD_TRAIT(target, A, GENETICS_SPELL)
		active_on += target
		if(duration < charge_max)
			addtimer(CALLBACK(src, .proc/remove, target), duration, TIMER_OVERRIDE|TIMER_UNIQUE)

/obj/effect/proc_holder/spell/targeted/genetic/Destroy()
	. = ..()
	for(var/V in active_on)
		remove(V)

/obj/effect/proc_holder/spell/targeted/genetic/proc/remove(mob/living/carbon/target)
	active_on -= target
	if(!QDELETED(target))
		for(var/A in mutations)
			target.dna.remove_mutation(A)
		for(var/A in traits)
			REMOVE_TRAIT(target, A, GENETICS_SPELL)


code:
/obj/item/melee/touch_attack
	name = "\improper outstretched hand"
	desc = "High Five?"
	var/catchphrase = "High Five!"
	var/on_use_sound = null
	var/obj/effect/proc_holder/spell/targeted/touch/attached_spell
	icon = 'icons/obj/items_and_weapons.dmi'
	lefthand_file = 'icons/mob/inhands/misc/touchspell_lefthand.dmi'
	righthand_file = 'icons/mob/inhands/misc/touchspell_righthand.dmi'
	icon_state = "latexballon"
	inhand_icon_state = null
	item_flags = NEEDS_PERMIT | ABSTRACT | DROPDEL
	w_class = WEIGHT_CLASS_HUGE
	force = 0
	throwforce = 0
	throw_range = 0
	throw_speed = 0
	var/charges = 1

/obj/item/melee/touch_attack/Initialize(mapload)
	. = ..()
	ADD_TRAIT(src, TRAIT_NODROP, ABSTRACT_ITEM_TRAIT)

/obj/item/melee/touch_attack/attack(mob/target, mob/living/carbon/user)
	if(!iscarbon(user)) //Look ma, no hands
		return
	if(!(user.mobility_flags & MOBILITY_USE))
		to_chat(user, span_warning("You can't reach out!"))
		return
	..()

/obj/item/melee/touch_attack/afterattack(atom/target, mob/user, proximity)
	. = ..()
	if(!proximity)
		return
	if(catchphrase)
		user.say(catchphrase, forced = "spell")
	playsound(get_turf(user), on_use_sound,50,TRUE)
	charges--
	if(charges <= 0)
		qdel(src)

/obj/item/melee/touch_attack/Destroy()
	if(attached_spell)
		attached_spell.on_hand_destroy(src)
	return ..()

/obj/item/melee/touch_attack/disintegrate
	name = "\improper smiting touch"
	desc = "This hand of mine glows with an awesome power!"
	catchphrase = "EI NATH!!"
	on_use_sound = 'sound/magic/disintegrate.ogg'
	icon_state = "disintegrate"
	inhand_icon_state = "disintegrate"

/obj/item/melee/touch_attack/disintegrate/afterattack(mob/living/target, mob/living/carbon/user, proximity)
	if(!proximity || target == user || !istype(target) || !iscarbon(user) || !(user.mobility_flags & MOBILITY_USE)) //exploding after touching yourself would be bad
		return
	if(!user.can_speak_vocal())
		to_chat(user, span_warning("You can't get the words out!"))
		return
	do_sparks(4, FALSE, target.loc)
	for(var/mob/living/L in view(src, 7))
		if(L != user)
			L.flash_act(affect_silicon = FALSE)
	var/atom/A = target.anti_magic_check()
	if(A)
		if(isitem(A))
			target.visible_message(span_warning("[target]'s [A] glows brightly as it wards off the spell!"))
		user.visible_message(span_warning("The feedback blows [user]'s arm off!"),span_userdanger("The spell bounces from [target]'s skin back into your arm!"))
		user.flash_act()
		var/obj/item/bodypart/part = user.get_holding_bodypart_of_item(src)
		if(part)
			part.dismember()
		return ..()
	var/obj/item/clothing/suit/hooded/bloated_human/suit = target.get_item_by_slot(ITEM_SLOT_OCLOTHING)
	if(istype(suit))
		target.visible_message(span_danger("[target]'s [suit] explodes off of them into a puddle of gore!"))
		target.dropItemToGround(suit)
		qdel(suit)
		new /obj/effect/gibspawner(target.loc)
		return ..()
	target.gib()
	return ..()

/obj/item/melee/touch_attack/fleshtostone
	name = "\improper petrifying touch"
	desc = "That's the bottom line, because flesh to stone said so!"
	catchphrase = "STAUN EI!!"
	on_use_sound = 'sound/magic/fleshtostone.ogg'
	icon_state = "fleshtostone"
	inhand_icon_state = "fleshtostone"

/obj/item/melee/touch_attack/fleshtostone/afterattack(atom/target, mob/living/carbon/user, proximity)
	if(!proximity || target == user || !isliving(target) || !iscarbon(user)) //getting hard after touching yourself would also be bad
		return
	if(!(user.mobility_flags & MOBILITY_USE))
		to_chat(user, span_warning("You can't reach out!"))
		return
	if(!user.can_speak_vocal())
		to_chat(user, span_warning("You can't get the words out!"))
		return
	var/mob/living/M = target
	if(M.anti_magic_check())
		to_chat(user, span_warning("The spell can't seem to affect [M]!"))
		to_chat(M, span_warning("You feel your flesh turn to stone for a moment, then revert back!"))
		..()
		return
	M.Stun(40)
	M.petrify()
	return ..()

/obj/item/melee/touch_attack/duffelbag
	name = "\improper burdening touch"
	desc = "Where is the bar from here?"
	catchphrase = "HU'SWCH H'ANS!!"
	on_use_sound = 'sound/magic/mm_hit.ogg'
	icon_state = "duffelcurse"
	inhand_icon_state = "duffelcurse"

/obj/item/melee/touch_attack/duffelbag/afterattack(atom/target, mob/living/carbon/user, proximity)
	if(!proximity || target == user || !isliving(target) || !iscarbon(user)) //Roleplay involving touching is equally as bad
		return
	if(!(user.mobility_flags & MOBILITY_USE))
		to_chat(user, span_warning("You can't reach out!"))
		return
	if(!user.can_speak_vocal())
		to_chat(user, span_warning("You can't get the words out!"))
		return
	var/mob/living/carbon/duffelvictim = target
	var/elaborate_backstory = pick("spacewar origin story", "military background", "corporate connections", "life in the colonies", "anti-government activities", "upbringing on the space farm", "fond memories with your buddy Keith")
	if(duffelvictim.anti_magic_check())
		to_chat(user, span_warning("The spell can't seem to affect [duffelvictim]!"))
		to_chat(duffelvictim, span_warning("You really don't feel like talking about your [elaborate_backstory] with complete strangers today."))
		..()
		return

	duffelvictim.flash_act()
	duffelvictim.Immobilize(5 SECONDS)
	duffelvictim.apply_damage(80, STAMINA)
	duffelvictim.Knockdown(5 SECONDS)

	if(HAS_TRAIT(target, TRAIT_DUFFEL_CURSE_PROOF))
		to_chat(user, span_warning("The burden of [duffelvictim]'s duffel bag becomes too much, shoving them to the floor!"))
		to_chat(duffelvictim, span_warning("The weight of this bag becomes overburdening!"))
		return ..()

	var/obj/item/storage/backpack/duffelbag/cursed/conjuredduffel = new get_turf(target)

	duffelvictim.visible_message(span_danger("A growling duffel bag appears on [duffelvictim]!"), \
						   span_danger("You feel something attaching itself to you, and a strong desire to discuss your [elaborate_backstory] at length!"))

	ADD_TRAIT(duffelvictim, TRAIT_DUFFEL_CURSE_PROOF, CURSED_ITEM_TRAIT(conjuredduffel.name))
	conjuredduffel.pickup(duffelvictim)
	conjuredduffel.forceMove(duffelvictim)
	if(duffelvictim.dropItemToGround(duffelvictim.back))
		duffelvictim.equip_to_slot_if_possible(conjuredduffel, ITEM_SLOT_BACK, TRUE, TRUE)
	else
		if(!duffelvictim.put_in_hands(conjuredduffel))
			duffelvictim.dropItemToGround(duffelvictim.get_inactive_held_item())
			if(!duffelvictim.put_in_hands(conjuredduffel))
				duffelvictim.dropItemToGround(duffelvictim.get_active_held_item())
				duffelvictim.put_in_hands(conjuredduffel)
			else
				return ..()
	return ..()


code:
/obj/effect/proc_holder/spell/targeted/infinite_guns
	name = "Lesser Summon Guns"
	desc = "Why reload when you have infinite guns? Summons an unending stream of bolt action rifles that deal little damage, but will knock targets down. Requires both hands free to use. Learning this spell makes you unable to learn Arcane Barrage."
	invocation_type = "none"
	include_user = TRUE
	range = -1

	school = SCHOOL_CONJURATION
	charge_max = 750
	clothes_req = TRUE
	cooldown_min = 10 //Gun wizard
	action_icon_state = "bolt_action"
	var/summon_path = /obj/item/gun/ballistic/rifle/enchanted

/obj/effect/proc_holder/spell/targeted/infinite_guns/cast(list/targets, mob/user = usr)
	for(var/mob/living/carbon/C in targets)
		C.drop_all_held_items()
		var/GUN = new summon_path
		C.put_in_hands(GUN)

/obj/effect/proc_holder/spell/targeted/infinite_guns/gun

/obj/effect/proc_holder/spell/targeted/infinite_guns/arcane_barrage
	name = "Arcane Barrage"
	desc = "Fire a torrent of arcane energy at your foes with this (powerful) spell. Deals much more damage than Lesser Summon Guns, but won't knock targets down. Requires both hands free to use. Learning this spell makes you unable to learn Lesser Summon Gun."
	action_icon_state = "arcane_barrage"
	summon_path = /obj/item/gun/ballistic/rifle/enchanted/arcane_barrage


code:
/obj/effect/proc_holder/spell/targeted/inflict_handler
	name = "Inflict Handler"
	desc = "This spell blinds and/or destroys/damages/heals and/or knockdowns/stuns the target."

	school = SCHOOL_EVOCATION

	var/amt_paralyze = 0
	var/amt_unconscious = 0
	var/amt_stun = 0

	var/inflict_status
	var/list/status_params = list()

	//set to negatives for healing
	var/amt_dam_fire = 0
	var/amt_dam_brute = 0
	var/amt_dam_oxy = 0
	var/amt_dam_tox = 0

	var/amt_eye_blind = 0
	var/amt_eye_blurry = 0

	var/destroys = "none" //can be "none", "gib" or "disintegrate"

	var/summon_type = null //this will put an obj at the target's location

	var/check_anti_magic = TRUE
	var/check_holy = FALSE

/obj/effect/proc_holder/spell/targeted/inflict_handler/cast(list/targets,mob/user = usr)
	for(var/mob/living/target in targets)
		playsound(target,sound, 50,TRUE)
		if(target.anti_magic_check(check_anti_magic, check_holy))
			return
		switch(destroys)
			if("gib")
				target.gib()
			if("disintegrate")
				target.dust()

		if(!target)
			continue
		//damage/healing
		target.adjustBruteLoss(amt_dam_brute)
		target.adjustFireLoss(amt_dam_fire)
		target.adjustToxLoss(amt_dam_tox)
		target.adjustOxyLoss(amt_dam_oxy)
		//disabling
		target.Paralyze(amt_paralyze)
		target.Unconscious(amt_unconscious)
		target.Stun(amt_stun)

		target.blind_eyes(amt_eye_blind)
		target.blur_eyes(amt_eye_blurry)
		//summoning
		if(summon_type)
			new summon_type(target.loc, target)

		if(inflict_status)
			var/list/stat_args = status_params.Copy()
			stat_args.Insert(1,inflict_status)
			target.apply_status_effect(arglist(stat_args))


code:
/obj/effect/proc_holder/spell/aoe_turf/knock
	name = "Knock"
	desc = "This spell opens nearby doors and closets."

	school = SCHOOL_TRANSMUTATION
	charge_max = 100
	clothes_req = FALSE
	invocation = "AULIE OXIN FIERA"
	invocation_type = INVOCATION_WHISPER
	range = 3
	cooldown_min = 20 //20 deciseconds reduction per rank

	action_icon_state = "knock"

/obj/effect/proc_holder/spell/aoe_turf/knock/cast(list/targets,mob/user = usr)
	SEND_SOUND(user, sound('sound/magic/knock.ogg'))
	for(var/turf/T in targets)
		for(var/obj/machinery/door/door in T.contents)
			INVOKE_ASYNC(src, .proc/open_door, door)
		for(var/obj/structure/closet/C in T.contents)
			INVOKE_ASYNC(src, .proc/open_closet, C)

/obj/effect/proc_holder/spell/aoe_turf/knock/proc/open_door(obj/machinery/door/door)
	if(istype(door, /obj/machinery/door/airlock))
		var/obj/machinery/door/airlock/A = door
		A.locked = FALSE
	door.open()

/obj/effect/proc_holder/spell/aoe_turf/knock/proc/open_closet(obj/structure/closet/C)
	C.locked = FALSE
	C.open()


code:
/obj/effect/proc_holder/spell/targeted/lichdom
	name = "Bind Soul"
	desc = "A dark necromantic pact that can forever bind your soul to an \
	item of your choosing. So long as both your body and the item remain \
	intact and on the same plane you can revive from death, though the time \
	between reincarnations grows steadily with use, along with the weakness \
	that the new skeleton body will experience upon 'birth'. Note that \
	becoming a lich destroys all internal organs except the brain."
	school = SCHOOL_NECROMANCY
	charge_max = 10
	clothes_req = FALSE
	centcom_cancast = FALSE
	invocation = "NECREM IMORTIUM!"
	invocation_type = INVOCATION_SHOUT
	range = -1
	level_max = 0 //cannot be improved
	cooldown_min = 10
	include_user = TRUE

	action_icon = 'icons/mob/actions/actions_spells.dmi'
	action_icon_state = "skeleton"

/obj/effect/proc_holder/spell/targeted/lichdom/cast(list/targets,mob/user = usr)
	for(var/mob/M in targets)
		var/list/hand_items = list()
		if(iscarbon(M))
			hand_items = list(M.get_active_held_item(),M.get_inactive_held_item())
		if(!hand_items.len)
			to_chat(M, span_warning("You must hold an item you wish to make your phylactery!"))
			return

		var/obj/item/marked_item

		for(var/obj/item/item in hand_items)
			// I ensouled the nuke disk once. But it's probably a really
			// mean tactic, so probably should discourage it.
			if((item.item_flags & ABSTRACT) || HAS_TRAIT(item, TRAIT_NODROP) || SEND_SIGNAL(item, COMSIG_ITEM_IMBUE_SOUL, user))
				continue
			marked_item = item
			to_chat(M, span_warning("You begin to focus your very being into [item]..."))
			break

		if(!marked_item)
			to_chat(M, span_warning("None of the items you hold are suitable for emplacement of your fragile soul."))
			return

		playsound(user, 'sound/effects/pope_entry.ogg', 100)

		if(!do_after(M, 5 SECONDS, target = marked_item, timed_action_flags = IGNORE_HELD_ITEM))
			to_chat(M, span_warning("Your soul snaps back to your body as you stop ensouling [marked_item]!"))
			return

		marked_item.name = "ensouled [marked_item.name]"
		marked_item.desc += "\nA terrible aura surrounds this item, its very existence is offensive to life itself..."
		marked_item.add_atom_colour("#003300", ADMIN_COLOUR_PRIORITY)
		marked_item.AddComponent(/datum/component/stationloving, FALSE, TRUE)

		new /obj/item/phylactery(marked_item, M.mind)

		to_chat(M, span_userdanger("With a hideous feeling of emptiness you watch in horrified fascination as skin sloughs off bone! Blood boils, nerves disintegrate, eyes boil in their sockets! As your organs crumble to dust in your fleshless chest you come to terms with your choice. You're a lich!"))
		M.set_species(/datum/species/skeleton)
		if(ishuman(M))
			var/mob/living/carbon/human/H = M
			H.dropItemToGround(H.w_uniform)
			H.dropItemToGround(H.wear_suit)
			H.dropItemToGround(H.head)
			H.equip_to_slot_or_del(new /obj/item/clothing/suit/wizrobe/black(H), ITEM_SLOT_OCLOTHING)
			H.equip_to_slot_or_del(new /obj/item/clothing/head/wizard/black(H), ITEM_SLOT_HEAD)
			H.equip_to_slot_or_del(new /obj/item/clothing/under/color/black(H), ITEM_SLOT_ICLOTHING)

		// you only get one phylactery.
		M.mind.RemoveSpell(src)

/obj/item/phylactery
	name = "phylactery"
	desc = "Stores souls. Revives liches. Also repels mosquitos."
	icon = 'icons/obj/guns/projectiles.dmi'
	icon_state = "bluespace"
	color = COLOR_VERY_DARK_LIME_GREEN
	light_system = MOVABLE_LIGHT
	light_range = 3
	light_color = COLOR_VERY_DARK_LIME_GREEN
	var/resurrections = 0
	var/datum/mind/mind
	var/respawn_time = 1800

	var/static/active_phylacteries = 0

/obj/item/phylactery/Initialize(mapload, datum/mind/newmind)
	. = ..()
	if(!mind)
		stack_trace("A phylactery was created with no target mind")
		return INITIALIZE_HINT_QDEL
	mind = newmind
	name = "phylactery of [mind.name]"

	active_phylacteries++
	SSpoints_of_interest.make_point_of_interest(src)
	START_PROCESSING(SSobj, src)

/obj/item/phylactery/Destroy(force=FALSE)
	STOP_PROCESSING(SSobj, src)
	active_phylacteries--
	. = ..()

/obj/item/phylactery/process()
	if(QDELETED(mind))
		qdel(src)
		return

	if(!mind.current || (mind.current && mind.current.stat == DEAD))
		addtimer(CALLBACK(src, .proc/rise), respawn_time, TIMER_UNIQUE)

/obj/item/phylactery/proc/rise()
	if(mind.current && mind.current.stat != DEAD)
		return "[mind] already has a living body: [mind.current]"

	var/turf/item_turf = get_turf(src)
	if(!item_turf)
		return "[src] is not at a turf? NULLSPACE!?"

	var/mob/living/old_body = mind.current
	var/mob/living/carbon/human/lich = new(item_turf)

	lich.equip_to_slot_or_del(new /obj/item/clothing/shoes/sandal/magic(lich), ITEM_SLOT_FEET)
	lich.equip_to_slot_or_del(new /obj/item/clothing/under/color/black(lich), ITEM_SLOT_ICLOTHING)
	lich.equip_to_slot_or_del(new /obj/item/clothing/suit/wizrobe/black(lich), ITEM_SLOT_OCLOTHING)
	lich.equip_to_slot_or_del(new /obj/item/clothing/head/wizard/black(lich), ITEM_SLOT_HEAD)

	lich.real_name = mind.name
	mind.transfer_to(lich)
	mind.grab_ghost(force=TRUE)
	lich.hardset_dna(null,null,null,lich.real_name,null, new /datum/species/skeleton)
	to_chat(lich, span_warning("Your bones clatter and shudder as you are pulled back into this world!"))
	var/turf/body_turf = get_turf(old_body)
	lich.Paralyze(200 + 200*resurrections)
	resurrections++
	if(old_body?.loc)
		if(iscarbon(old_body))
			var/mob/living/carbon/C = old_body
			for(var/obj/item/W in C)
				C.dropItemToGround(W)
			for(var/X in C.internal_organs)
				var/obj/item/organ/I = X
				I.Remove(C)
				I.forceMove(body_turf)
		var/wheres_wizdo = dir2text(get_dir(body_turf, item_turf))
		if(wheres_wizdo)
			old_body.visible_message(span_warning("Suddenly [old_body.name]'s corpse falls to pieces! You see a strange energy rise from the remains, and speed off towards the [wheres_wizdo]!"))
			body_turf.Beam(item_turf,icon_state="lichbeam", time = 10 + 10 * resurrections)
		old_body.dust()

	return "Respawn of [mind] successful."


code:
/obj/effect/proc_holder/spell/targeted/tesla
	name = "Tesla Blast"
	desc = "Charge up a tesla arc and release it at a random nearby target! You can move freely while it charges. The arc jumps between targets and can knock them down."
	charge_type = "recharge"
	charge_max = 300
	clothes_req = TRUE
	invocation = "UN'LTD P'WAH!"
	invocation_type = INVOCATION_SHOUT
	school = SCHOOL_EVOCATION
	range = 7
	cooldown_min = 30
	selection_type = "view"
	random_target = TRUE
	var/ready = FALSE
	var/static/mutable_appearance/halo
	var/sound/Snd // so far only way i can think of to stop a sound, thank MSO for the idea.

	action_icon_state = "lightning"

/obj/effect/proc_holder/spell/targeted/tesla/Click()
	if(!ready && cast_check())
		StartChargeup()
	return TRUE

/obj/effect/proc_holder/spell/targeted/tesla/proc/StartChargeup(mob/user = usr)
	ready = TRUE
	to_chat(user, span_notice("You start gathering the power."))
	Snd = new/sound('sound/magic/lightning_chargeup.ogg',channel = 7)
	halo = halo || mutable_appearance('icons/effects/effects.dmi', "electricity", EFFECTS_LAYER)
	user.add_overlay(halo)
	playsound(get_turf(user), Snd, 50, FALSE)
	if(do_after(user, 10 SECONDS, timed_action_flags = (IGNORE_USER_LOC_CHANGE|IGNORE_HELD_ITEM)))
		if(ready && cast_check(skipcharge=1))
			choose_targets()
		else
			revert_cast(user, 0)
	else
		revert_cast(user, 0)

/obj/effect/proc_holder/spell/targeted/tesla/proc/Reset(mob/user = usr)
	ready = FALSE
	user.cut_overlay(halo)

/obj/effect/proc_holder/spell/targeted/tesla/revert_cast(mob/user = usr, message = 1)
	if(message)
		to_chat(user, span_notice("No target found in range."))
	Reset(user)
	..()

/obj/effect/proc_holder/spell/targeted/tesla/cast(list/targets, mob/user = usr)
	ready = FALSE
	var/mob/living/carbon/target = targets[1]
	Snd=sound(null, repeat = 0, wait = 1, channel = Snd.channel) //byond, why you suck?
	playsound(get_turf(user),Snd,50,FALSE)// Sorry MrPerson, but the other ways just didn't do it the way i needed to work, this is the only way.
	if(get_dist(user,target)>range)
		to_chat(user, span_warning("[target.p_theyre(TRUE)] too far away!"))
		Reset(user)
		return

	playsound(get_turf(user), 'sound/magic/lightningbolt.ogg', 50, TRUE)
	user.Beam(target,icon_state="lightning[rand(1,12)]", time = 5)

	Bolt(user,target,30,5,user)
	Reset(user)

/obj/effect/proc_holder/spell/targeted/tesla/proc/Bolt(mob/origin,mob/target,bolt_energy,bounces,mob/user = usr)
	origin.Beam(target,icon_state="lightning[rand(1,12)]", time = 5)
	var/mob/living/carbon/current = target
	if(current.anti_magic_check())
		playsound(get_turf(current), 'sound/magic/lightningshock.ogg', 50, TRUE, -1)
		current.visible_message(span_warning("[current] absorbs the spell, remaining unharmed!"), span_userdanger("You absorb the spell, remaining unharmed!"))
	else if(bounces < 1)
		current.electrocute_act(bolt_energy,"Lightning Bolt",flags = SHOCK_NOGLOVES)
		playsound(get_turf(current), 'sound/magic/lightningshock.ogg', 50, TRUE, -1)
	else
		current.electrocute_act(bolt_energy,"Lightning Bolt",flags = SHOCK_NOGLOVES)
		playsound(get_turf(current), 'sound/magic/lightningshock.ogg', 50, TRUE, -1)
		var/list/possible_targets = new
		for(var/mob/living/M in view(range,target))
			if(user == M || target == M && los_check(current,M)) // || origin == M ? Not sure double shockings is good or not
				continue
			possible_targets += M
		if(!possible_targets.len)
			return
		var/mob/living/next = pick(possible_targets)
		if(next)
			Bolt(current,next,max((bolt_energy-5),5),bounces-1,user)


code:
/obj/effect/proc_holder/spell/aoe_turf/conjure/mime_wall
	name = "Invisible Wall"
	desc = "The mime's performance transmutates a wall into physical reality."
	school = SCHOOL_MIME
	panel = "Mime"
	summon_type = list(/obj/effect/forcefield/mime)
	invocation_type = INVOCATION_EMOTE
	invocation_emote_self = "You form a wall in front of yourself."
	summon_lifespan = 300
	charge_max = 300
	clothes_req = FALSE
	antimagic_allowed = TRUE
	range = 0
	cast_sound = null
	human_req = TRUE

	action_icon = 'icons/mob/actions/actions_mime.dmi'
	action_icon_state = "invisible_wall"
	action_background_icon_state = "bg_mime"

/obj/effect/proc_holder/spell/aoe_turf/conjure/mime_wall/Click()
	if(usr?.mind)
		if(!usr.mind.miming)
			to_chat(usr, span_warning("You must dedicate yourself to silence first!"))
			return
		invocation = "[usr.real_name] looks as if a wall is in front of [usr.p_them()]."
	else
		invocation_type ="none"
	..()

/obj/effect/proc_holder/spell/aoe_turf/conjure/mime_chair
	name = "Invisible Chair"
	desc = "The mime's performance transmutates a chair into physical reality."
	school = SCHOOL_MIME
	panel = "Mime"
	summon_type = list(/obj/structure/chair/mime)
	invocation_type = INVOCATION_EMOTE
	invocation_emote_self = "You conjure an invisible chair and sit down."
	summon_lifespan = 250
	charge_max = 300
	clothes_req = FALSE
	antimagic_allowed = TRUE
	range = 0
	cast_sound = null
	human_req = TRUE

	action_icon = 'icons/mob/actions/actions_mime.dmi'
	action_icon_state = "invisible_chair"
	action_background_icon_state = "bg_mime"

/obj/effect/proc_holder/spell/aoe_turf/conjure/mime_chair/Click()
	if(usr?.mind)
		if(!usr.mind.miming)
			to_chat(usr, span_warning("You must dedicate yourself to silence first!"))
			return
		invocation = "[usr.real_name] pulls out an invisible chair and sits down."
	else
		invocation_type ="none"
	..()

/obj/effect/proc_holder/spell/aoe_turf/conjure/mime_chair/cast(list/targets,mob/user = usr)
	..()
	var/turf/T = user.loc
	for (var/obj/structure/chair/A in T)
		if (is_type_in_list(A, summon_type))
			A.setDir(user.dir)
			A.buckle_mob(user)

/obj/effect/proc_holder/spell/aoe_turf/conjure/mime_box
	name = "Invisible Box"
	desc = "The mime's performance transmutates a box into physical reality."
	school = SCHOOL_MIME
	panel = "Mime"
	summon_type = list(/obj/item/storage/box/mime)
	invocation_type = INVOCATION_EMOTE
	invocation_emote_self = "You conjure up an invisible box, large enough to store a few things."
	summon_lifespan = 500
	charge_max = 300
	clothes_req = FALSE
	antimagic_allowed = TRUE
	range = 0
	cast_sound = null
	human_req = TRUE

	action_icon = 'icons/mob/actions/actions_mime.dmi'
	action_icon_state = "invisible_box"
	action_background_icon_state = "bg_mime"

/obj/effect/proc_holder/spell/aoe_turf/conjure/mime_box/cast(list/targets,mob/user = usr)
	..()
	var/turf/T = user.loc
	for (var/obj/item/storage/box/mime/B in T)
		user.put_in_hands(B)
		B.alpha = 255
		addtimer(CALLBACK(B, /obj/item/storage/box/mime/.proc/emptyStorage, FALSE), (summon_lifespan - 1))

/obj/effect/proc_holder/spell/aoe_turf/conjure/mime_box/Click()
	if(usr?.mind)
		if(!usr.mind.miming)
			to_chat(usr, span_warning("You must dedicate yourself to silence first!"))
			return
		invocation = "[usr.real_name] moves [usr.p_their()] hands in the shape of a cube, pressing a box out of the air."
	else
		invocation_type ="none"
	..()

/obj/effect/proc_holder/spell/targeted/mime/speak
	name = "Speech"
	desc = "Make or break a vow of silence."
	school = SCHOOL_MIME
	panel = "Mime"
	clothes_req = FALSE
	human_req = TRUE
	antimagic_allowed = TRUE
	charge_max = 3000
	range = -1
	include_user = TRUE

	action_icon = 'icons/mob/actions/actions_mime.dmi'
	action_icon_state = "mime_speech"
	action_background_icon_state = "bg_mime"

/obj/effect/proc_holder/spell/targeted/mime/speak/Click()
	if(!usr)
		return
	if(!ishuman(usr))
		return
	var/mob/living/carbon/human/H = usr
	if(H.mind.miming)
		still_recharging_msg = span_warning("You can't break your vow of silence that fast!")
	else
		still_recharging_msg = span_warning("You'll have to wait before you can give your vow of silence again!")
	..()

/obj/effect/proc_holder/spell/targeted/mime/speak/cast(list/targets,mob/user = usr)
	for(var/mob/living/carbon/human/H in targets)
		H.mind.miming=!H.mind.miming
		if(H.mind.miming)
			to_chat(H, span_notice("You make a vow of silence."))
			SEND_SIGNAL(H, COMSIG_CLEAR_MOOD_EVENT, "vow")
		else
			SEND_SIGNAL(H, COMSIG_ADD_MOOD_EVENT, "vow", /datum/mood_event/broken_vow)
			to_chat(H, span_notice("You break your vow of silence."))

// These spells can only be gotten from the "Guide for Advanced Mimery series" for Mime Traitors.

/obj/effect/proc_holder/spell/targeted/forcewall/mime
	name = "Invisible Blockade"
	desc = "Form an invisible three tile wide blockade."
	school = SCHOOL_MIME
	panel = "Mime"
	wall_type = /obj/effect/forcefield/mime/advanced
	invocation_type = INVOCATION_EMOTE
	invocation_emote_self = "You form a blockade in front of yourself."
	charge_max = 600
	sound =  null
	clothes_req = FALSE
	antimagic_allowed = TRUE
	range = -1
	include_user = TRUE

	action_icon = 'icons/mob/actions/actions_mime.dmi'
	action_icon_state = "invisible_blockade"
	action_background_icon_state = "bg_mime"

/obj/effect/proc_holder/spell/targeted/forcewall/mime/Click()
	if(usr?.mind)
		if(!usr.mind.miming)
			to_chat(usr, span_warning("You must dedicate yourself to silence first!"))
			return
		invocation = "[usr.real_name] looks as if a blockade is in front of [usr.p_them()]."
	else
		invocation_type ="none"
	..()

/obj/effect/proc_holder/spell/aimed/finger_guns
	name = "Finger Guns"
	desc = "Shoot a mimed bullet from your fingers that stuns and does some damage."
	school = SCHOOL_MIME
	panel = "Mime"
	charge_max = 300
	clothes_req = FALSE
	antimagic_allowed = TRUE
	invocation_type = INVOCATION_EMOTE
	invocation_emote_self = "You fire your finger gun!"
	range = 20
	projectile_type = /obj/projectile/bullet/mime
	projectile_amount = 3
	sound = null
	active_msg = "You draw your fingers!"
	deactive_msg = "You put your fingers at ease. Another time."
	active = FALSE

	action_icon = 'icons/mob/actions/actions_mime.dmi'
	action_icon_state = "finger_guns0"
	action_background_icon_state = "bg_mime"
	base_icon_state = "finger_guns"

/obj/effect/proc_holder/spell/aimed/finger_guns/Click()
	var/mob/living/carbon/human/owner = usr
	if(owner.incapacitated())
		to_chat(owner, span_warning("You can't properly point your fingers while incapacitated."))
		return
	if(usr?.mind)
		if(!usr.mind.miming)
			to_chat(usr, span_warning("You must dedicate yourself to silence first!"))
			return
		invocation = "[usr.real_name] fires [usr.p_their()] finger gun!"
	else
		invocation_type ="none"
	..()

/obj/effect/proc_holder/spell/aimed/finger_guns/InterceptClickOn(mob/living/caller, params, atom/target)
	if(caller.incapacitated())
		to_chat(caller, span_warning("You can't properly point your fingers while incapacitated."))
		if(charge_type == "recharge")
			var/refund_percent = current_amount/projectile_amount
			charge_counter = charge_max * refund_percent
			start_recharge()
		remove_ranged_ability()
		on_deactivation(caller)
	..()

/obj/item/book/granter/spell/mimery_blockade
	spell = /obj/effect/proc_holder/spell/targeted/forcewall/mime
	spellname = "Invisible Blockade"
	name = "Guide to Advanced Mimery Vol 1"
	desc = "The pages don't make any sound when turned."
	icon_state ="bookmime"
	remarks = list("...")

/obj/item/book/granter/spell/mimery_blockade/attack_self(mob/user)
	. = ..()
	if(!.)
		return
	if(!locate(/obj/effect/proc_holder/spell/targeted/mime/speak) in user.mind.spell_list)
		user.mind.AddSpell(new /obj/effect/proc_holder/spell/targeted/mime/speak)

/obj/item/book/granter/spell/mimery_guns
	spell = /obj/effect/proc_holder/spell/aimed/finger_guns
	spellname = "Finger Guns"
	name = "Guide to Advanced Mimery Vol 2"
	desc = "There aren't any words written..."
	icon_state ="bookmime"
	remarks = list("...")

/obj/item/book/granter/spell/mimery_guns/attack_self(mob/user)
	. = ..()
	if(!.)
		return
	if(!locate(/obj/effect/proc_holder/spell/targeted/mime/speak) in user.mind.spell_list)
		user.mind.AddSpell(new /obj/effect/proc_holder/spell/targeted/mime/speak)


code:
/obj/effect/proc_holder/spell/targeted/personality_commune
	name = "Personality Commune"
	desc = "Sends thoughts to your alternate consciousness."
	charge_max = 0
	clothes_req = FALSE
	range = -1
	include_user = TRUE
	action_icon_state = "telepathy"
	action_background_icon_state = "bg_spell"
	var/datum/brain_trauma/severe/split_personality/trauma
	var/flufftext = "You hear an echoing voice in the back of your head..."

/obj/effect/proc_holder/spell/targeted/personality_commune/New(datum/brain_trauma/severe/split_personality/T)
	. = ..()
	trauma = T

/obj/effect/proc_holder/spell/targeted/personality_commune/Destroy()
	trauma = null
	return ..()

// Pillaged and adapted from telepathy code
/obj/effect/proc_holder/spell/targeted/personality_commune/cast(list/targets, mob/user)
	if(!istype(trauma))
		to_chat(user, span_warning("Something is wrong; Either due a bug or admemes, you are trying to cast this spell without a split personality!"))
		return
	var/msg = stripped_input(usr, "What would you like to tell your other self?", null , "")
	if(!msg)
		charge_counter = charge_max
		return
	to_chat(user, span_boldnotice("You concentrate and send thoughts to your other self: [msg]"))
	to_chat(trauma.owner, span_boldnotice("[flufftext] [msg]"))
	log_directed_talk(user, trauma.owner, msg, LOG_SAY ,"[name]")
	for(var/ded in GLOB.dead_mob_list)
		if(!isobserver(ded))
			continue
		to_chat(ded, "[FOLLOW_LINK(ded, user)] [span_boldnotice("[user] [name]:")] [span_notice("\"[msg]\" to")] [span_name("[trauma]")]")


code:
/obj/effect/proc_holder/spell/pointed/barnyardcurse
	name = "Curse of the Barnyard"
	desc = "This spell dooms an unlucky soul to possess the speech and facial attributes of a barnyard animal."
	school = SCHOOL_TRANSMUTATION
	charge_type = "recharge"
	charge_max = 150
	charge_counter = 0
	clothes_req = FALSE
	stat_allowed = FALSE
	invocation = "KN'A FTAGHU, PUCK 'BTHNK!"
	invocation_type = INVOCATION_SHOUT
	range = 7
	cooldown_min = 30
	ranged_mousepointer = 'icons/effects/mouse_pointers/barn_target.dmi'
	action_icon_state = "barn"
	active_msg = "You prepare to curse a target..."
	deactive_msg = "You dispel the curse..."
	/// List of mobs which are allowed to be a target of the spell
	var/static/list/compatible_mobs_typecache = typecacheof(list(/mob/living/carbon/human))

/obj/effect/proc_holder/spell/pointed/barnyardcurse/cast(list/targets, mob/user)
	if(!targets.len)
		to_chat(user, span_warning("No target found in range!"))
		return FALSE
	if(!can_target(targets[1], user))
		return FALSE

	var/mob/living/carbon/target = targets[1]
	if(target.anti_magic_check())
		to_chat(user, span_warning("The spell had no effect!"))
		target.visible_message(span_danger("[target]'s face bursts into flames, which instantly burst outward, leaving [target] unharmed!"), \
						span_danger("Your face starts burning up, but the flames are repulsed by your anti-magic protection!"))
		return FALSE

	var/choice = pick(GLOB.cursed_animal_masks)
	var/obj/item/clothing/mask/magichead = new choice(get_turf(target))

	target.visible_message(span_danger("[target]'s face bursts into flames, and a barnyard animal's head takes its place!"), \
						   span_danger("Your face burns up, and shortly after the fire you realise you have the face of a barnyard animal!"))
	if(!target.dropItemToGround(target.wear_mask))
		qdel(target.wear_mask)
	target.equip_to_slot_if_possible(magichead, ITEM_SLOT_MASK, 1, 1)
	target.flash_act()

/obj/effect/proc_holder/spell/pointed/barnyardcurse/can_target(atom/target, mob/user, silent)
	. = ..()
	if(!.)
		return FALSE
	if(!is_type_in_typecache(target, compatible_mobs_typecache))
		if(!silent)
			to_chat(user, span_warning("You are unable to curse [target]!"))
		return FALSE
	return TRUE


code:
/obj/effect/proc_holder/spell/pointed/trigger/blind
	name = "Blind"
	desc = "This spell temporarily blinds a single target."
	school = SCHOOL_TRANSMUTATION
	charge_max = 300
	clothes_req = FALSE
	invocation = "STI KALY"
	invocation_type = INVOCATION_WHISPER
	message = "Your eyes cry out in pain!"
	cooldown_min = 50 //12 deciseconds reduction per rank
	starting_spells = list("/obj/effect/proc_holder/spell/targeted/inflict_handler/blind", "/obj/effect/proc_holder/spell/targeted/genetic/blind")
	ranged_mousepointer = 'icons/effects/mouse_pointers/blind_target.dmi'
	action_icon_state = "blind"
	active_msg = "You prepare to blind a target..."

/obj/effect/proc_holder/spell/targeted/inflict_handler/blind
	amt_eye_blind = 10
	amt_eye_blurry = 20
	sound = 'sound/magic/blind.ogg'

/obj/effect/proc_holder/spell/targeted/genetic/blind
	mutations = list(BLINDMUT)
	duration = 300
	charge_max = 400 // needs to be higher than the duration or it'll be permanent
	sound = 'sound/magic/blind.ogg'

/obj/effect/proc_holder/spell/pointed/trigger/blind/can_target(atom/target, mob/user, silent)
	. = ..()
	if(!.)
		return FALSE
	if(!isliving(target))
		if(!silent)
			to_chat(user, span_warning("You can only blind living beings!"))
		return FALSE
	return TRUE


code:
/obj/effect/proc_holder/spell/pointed/mind_transfer
	name = "Mind Transfer"
	desc = "This spell allows the user to switch bodies with a target next to him."
	school = SCHOOL_TRANSMUTATION
	charge_max = 600
	clothes_req = FALSE
	invocation = "GIN'YU CAPAN"
	invocation_type = INVOCATION_WHISPER
	range = 1
	cooldown_min = 200 //100 deciseconds reduction per rank
	ranged_mousepointer = 'icons/effects/mouse_pointers/mindswap_target.dmi'
	action_icon_state = "mindswap"
	active_msg = "You prepare to swap minds with a target..."
	/// For how long is the caster stunned for after the spell
	var/unconscious_amount_caster = 40 SECONDS
	/// For how long is the victim stunned for after the spell
	var/unconscious_amount_victim = 40 SECONDS

/obj/effect/proc_holder/spell/pointed/mind_transfer/cast(list/targets, mob/living/user, silent = FALSE)
	if(!targets.len)
		if(!silent)
			to_chat(user, span_warning("No mind found!"))
		return FALSE
	if(targets.len > 1)
		if(!silent)
			to_chat(user, span_warning("Too many minds! You're not a hive damnit!"))
		return FALSE
	if(!can_target(targets[1], user, silent))
		return FALSE

	var/mob/living/victim = targets[1] //The target of the spell whos body will be transferred to.
	if(istype(victim, /mob/living/simple_animal/hostile/guardian))
		var/mob/living/simple_animal/hostile/guardian/stand = victim
		if(stand.summoner)
			victim = stand.summoner
	var/datum/mind/VM = victim.mind
	if(victim.anti_magic_check(TRUE, FALSE) || VM.has_antag_datum(/datum/antagonist/wizard) || VM.has_antag_datum(/datum/antagonist/cult) || VM.has_antag_datum(/datum/antagonist/changeling) || VM.has_antag_datum(/datum/antagonist/rev) || victim.key[1] == "@")
		if(!silent)
			to_chat(user, span_warning("[victim.p_their(TRUE)] mind is resisting your spell!"))
		return FALSE

	//You should not be able to enter one of the most powerful side-antags as a fucking wizard.
	if(istype(victim,/mob/living/simple_animal/hostile/imp/slaughter))
		to_chat(user, span_warning("The devilish contract doesn't include the 'mind swappable' package, please try again another lifetime."))
		return

	//MIND TRANSFER BEGIN
	var/mob/dead/observer/ghost = victim.ghostize()
	user.mind.transfer_to(victim)

	ghost.mind.transfer_to(user)
	if(ghost.key)
		user.key = ghost.key //have to transfer the key since the mind was not active
	qdel(ghost)
	//MIND TRANSFER END

	//Here we knock both mobs out for a time.
	user.Unconscious(unconscious_amount_caster)
	victim.Unconscious(unconscious_amount_victim)
	SEND_SOUND(user, sound('sound/magic/mandswap.ogg'))
	SEND_SOUND(victim, sound('sound/magic/mandswap.ogg')) // only the caster and victim hear the sounds, that way no one knows for sure if the swap happened
	return TRUE

/obj/effect/proc_holder/spell/pointed/mind_transfer/can_target(atom/target, mob/user, silent)
	. = ..()
	if(!.)
		return FALSE
	if(!isliving(target))
		if(!silent)
			to_chat(user, span_warning("You can only swap minds with living beings!"))
		return FALSE
	if(user == target)
		if(!silent)
			to_chat(user, span_warning("You can't swap minds with yourself!"))
		return FALSE

	var/mob/living/victim = target
	var/t_He = victim.p_they(TRUE)

	if(ismegafauna(victim))
		if(!silent)
			to_chat(user, span_warning("This creature is too powerful to control!"))
		return FALSE
	if(victim.stat == DEAD)
		if(!silent)
			to_chat(user, span_warning("You don't particularly want to be dead!"))
		return FALSE
	if(!victim.key || !victim.mind)
		if(!silent)
			to_chat(user, span_warning("[t_He] appear[victim.p_s()] to be catatonic! Not even magic can affect [victim.p_their()] vacant mind."))
		return FALSE
	if(user.suiciding)
		if(!silent)
			to_chat(user, span_warning("You're killing yourself! You can't concentrate enough to do this!"))
		return FALSE
	if(istype(victim, /mob/living/simple_animal/hostile/guardian))
		var/mob/living/simple_animal/hostile/guardian/stand = victim
		if(stand.summoner)
			if(stand.summoner == user)
				if(!silent)
					to_chat(user, span_warning("Swapping minds with your own guardian would just put you back into your own head!"))
				return FALSE
	return TRUE


code:
/obj/effect/proc_holder/spell/pointed
	name = "pointed spell"
	ranged_mousepointer = 'icons/effects/mouse_pointers/throw_target.dmi'
	action_icon_state = "projectile"
	/// Message showing to the spell owner upon deactivating pointed spell.
	var/deactive_msg = "You dispel the magic..."
	/// Message showing to the spell owner upon activating pointed spell.
	var/active_msg = "You prepare to use the spell on a target..."
	/// Variable dictating if the user is allowed to cast a spell on himself.
	var/self_castable = FALSE
	/// Variable dictating if the spell will use turf based aim assist
	var/aim_assist = TRUE

/obj/effect/proc_holder/spell/pointed/Click()
	var/mob/living/user = usr
	if(!istype(user))
		return
	var/msg
	if(!can_cast(user))
		msg = span_warning("You can no longer cast [name]!")
		remove_ranged_ability(msg)
		return
	if(active)
		msg = span_notice("[deactive_msg]")
		remove_ranged_ability(msg)
	else
		msg = span_notice("[active_msg] <B>Left-click to activate spell on a target!</B>")
		add_ranged_ability(user, msg, TRUE)

/obj/effect/proc_holder/spell/pointed/on_lose(mob/living/user)
	remove_ranged_ability()

/obj/effect/proc_holder/spell/pointed/remove_ranged_ability(msg)
	. = ..()
	on_deactivation(ranged_ability_user)

/obj/effect/proc_holder/spell/pointed/add_ranged_ability(mob/living/user, msg, forced)
	. = ..()
	on_activation(user)

/**
 * on_activation: What happens upon pointed spell activation.
 *
 * Arguments:
 * * user The mob interacting owning the spell.
 */
/obj/effect/proc_holder/spell/pointed/proc/on_activation(mob/user)
	return

/**
 * on_activation: What happens upon pointed spell deactivation.
 *
 * Arguments:
 * * user The mob interacting owning the spell.
 */
/obj/effect/proc_holder/spell/pointed/proc/on_deactivation(mob/user)
	return

/obj/effect/proc_holder/spell/pointed/update_icon()
	if(!action)
		return

	. = ..()
	action.button_icon_state = "[action_icon_state][active ? 1 : null]"
	action.UpdateButtonIcon()

/obj/effect/proc_holder/spell/pointed/InterceptClickOn(mob/living/caller, params, atom/target)
	if(..())
		return TRUE
	if(aim_assist && isturf(target))
		var/list/possible_targets = list()
		for(var/A in target)
			if(intercept_check(caller, A, TRUE))
				possible_targets += A
		if(possible_targets.len == 1)
			target = possible_targets[1]
	if(!intercept_check(caller, target))
		return TRUE
	if(!cast_check(FALSE, caller))
		return TRUE
	perform(list(target), user = caller)
	remove_ranged_ability()
	return TRUE // Do not do any underlying actions after the spell cast

/**
 * intercept_check: Specific spell checks for InterceptClickOn() targets.
 *
 * Arguments:
 * * user The mob using the ranged spell via intercept.
 * * target The atom that is being targeted by the spell via intercept.
 * * silent If the checks should produce not any feedback messages for the user.
 */
/obj/effect/proc_holder/spell/pointed/proc/intercept_check(mob/user, atom/target, silent = FALSE)
	if(!self_castable && target == user)
		if(!silent)
			to_chat(user, span_warning("You cannot cast the spell on yourself!"))
		return FALSE
	if(!(target in view_or_range(range, user, selection_type)))
		if(!silent)
			to_chat(user, span_warning("[target.p_theyre(TRUE)] too far away!"))
		return FALSE
	if(!can_target(target, user, silent))
		return FALSE
	return TRUE


code:
/obj/projectile/magic/spell
	name = "custom spell projectile"
	var/list/ignored_factions //Do not hit these
	var/check_holy = FALSE
	var/check_antimagic = FALSE
	var/trigger_range = 0 //How far we do we need to be to hit
	var/linger = FALSE //Can't hit anything but the intended target

	var/trail = FALSE //if it leaves a trail
	var/trail_lifespan = 0 //deciseconds
	var/trail_icon = 'icons/obj/wizard.dmi'
	var/trail_icon_state = "trail"

//todo unify this and magic/aoe under common path
/obj/projectile/magic/spell/Range()
	if(trigger_range > 1)
		for(var/mob/living/L in range(trigger_range, get_turf(src)))
			if(can_hit_target(L, ignore_loc = TRUE))
				return Bump(L)
	. = ..()

/obj/projectile/magic/spell/Moved(atom/OldLoc, Dir)
	. = ..()
	if(trail)
		create_trail()

/obj/projectile/magic/spell/proc/create_trail()
	if(!trajectory)
		return
	var/datum/point/vector/previous = trajectory.return_vector_after_increments(1,-1)
	var/obj/effect/overlay/trail = new /obj/effect/overlay(previous.return_turf())
	trail.pixel_x = previous.return_px()
	trail.pixel_y = previous.return_py()
	trail.icon = trail_icon
	trail.icon_state = trail_icon_state
	//might be changed to temp overlay
	trail.set_density(FALSE)
	trail.mouse_opacity = MOUSE_OPACITY_TRANSPARENT
	QDEL_IN(trail, trail_lifespan)

/obj/projectile/magic/spell/can_hit_target(atom/target, list/passthrough, direct_target = FALSE, ignore_loc = FALSE)
	. = ..()
	if(linger && target != original)
		return FALSE
	if(ismob(target) && !direct_target) //Unsure about the direct target, i guess it could always skip these.
		var/mob/M = target
		if(M.anti_magic_check(check_antimagic, check_holy))
			return FALSE
		if(ignored_factions?.len && faction_check(M.faction,ignored_factions))
			return FALSE

//NEEDS MAJOR CODE CLEANUP.

/obj/effect/proc_holder/spell/targeted/projectile
	name = "Projectile"
	desc = "This spell summons projectiles which try to hit the targets."

	var/proj_type =  /obj/projectile/magic/spell //IMPORTANT use only subtypes of this

	var/update_projectile = FALSE //So you want to admin abuse magic bullets ? This is for you
	//Below only apply if update_projectile is true
	var/proj_icon = 'icons/obj/guns/projectiles.dmi'
	var/proj_icon_state = "spell"
	var/proj_name = "a spell projectile"
	var/proj_trail = FALSE //if it leaves a trail
	var/proj_trail_lifespan = 0 //deciseconds
	var/proj_trail_icon = 'icons/obj/wizard.dmi'
	var/proj_trail_icon_state = "trail"
	var/proj_lingering = FALSE //if it lingers or disappears upon hitting an obstacle
	var/proj_homing = TRUE //if it follows the target
	var/proj_insubstantial = FALSE //if it can pass through dense objects or not
	var/proj_trigger_range = 0 //the range from target at which the projectile triggers cast(target)
	var/proj_lifespan = 15 //in deciseconds * proj_step_delay
	var/proj_step_delay = 1 //lower = faster
	var/list/ignore_factions = list() //Faction types that will be ignored
	var/check_antimagic = TRUE
	var/check_holy = FALSE

/obj/effect/proc_holder/spell/targeted/projectile/proc/fire_projectile(atom/target, mob/user)
	var/obj/projectile/magic/spell/projectile = new proj_type()

	if(update_projectile)
		//Generally these should already be set on the projectile, this is mostly here for varedited spells.
		projectile.icon = proj_icon
		projectile.icon_state = proj_icon_state
		projectile.name = proj_name
		if(proj_insubstantial)
			projectile.movement_type |= PHASING
		if(proj_homing)
			projectile.homing = TRUE
			projectile.homing_turn_speed = 360 //Perfect tracking
		if(proj_lingering)
			projectile.linger = TRUE
		projectile.trigger_range = proj_trigger_range
		projectile.ignored_factions = ignore_factions
		projectile.range = proj_lifespan
		projectile.speed = proj_step_delay
		projectile.trail = proj_trail
		projectile.trail_lifespan = proj_trail_lifespan
		projectile.trail_icon = proj_trail_icon
		projectile.trail_icon_state = proj_trail_icon_state

	projectile.preparePixelProjectile(target,user)
	if(projectile.homing)
		projectile.set_homing_target(target)
	projectile.fire()

/obj/effect/proc_holder/spell/targeted/projectile/cast(list/targets, mob/user = usr)
	playMagSound()
	for(var/atom/target in targets)
		fire_projectile(target, user)

//This one just pops one projectile in direction user is facing, irrelevant of max_targets etc
/obj/effect/proc_holder/spell/targeted/projectile/dumbfire
	name = "Dumbfire projectile"

/obj/effect/proc_holder/spell/targeted/projectile/dumbfire/choose_targets(mob/user = usr)
	var/turf/T = get_turf(user)
	for(var/i = 1; i < range; i++)
		var/turf/new_turf = get_step(T, user.dir)
		if(new_turf.density)
			break
		T = new_turf
	perform(list(T),user = user)


code:
//In this file: Summon Magic/Summon Guns/Summon Events
//and corresponding datum controller for them

GLOBAL_DATUM(summon_guns, /datum/summon_guns_controller)
GLOBAL_DATUM(summon_magic, /datum/summon_magic_controller)

// 1 in 50 chance of getting something really special.
#define SPECIALIST_MAGIC_PROB 2

GLOBAL_LIST_INIT(summoned_guns, list(
	/obj/item/gun/energy/disabler,
	/obj/item/gun/energy/e_gun,
	/obj/item/gun/energy/e_gun/advtaser,
	/obj/item/gun/energy/laser,
	/obj/item/gun/ballistic/revolver,
	/obj/item/gun/ballistic/revolver/detective,
	/obj/item/gun/ballistic/automatic/pistol/deagle/camo,
	/obj/item/gun/ballistic/automatic/gyropistol,
	/obj/item/gun/energy/pulse,
	/obj/item/gun/ballistic/automatic/pistol/suppressed,
	/obj/item/gun/ballistic/shotgun/doublebarrel,
	/obj/item/gun/ballistic/shotgun,
	/obj/item/gun/ballistic/shotgun/automatic/combat,
	/obj/item/gun/ballistic/automatic/ar,
	/obj/item/gun/ballistic/revolver/mateba,
	/obj/item/gun/ballistic/rifle/boltaction,
	/obj/item/gun/ballistic/rifle/boltaction/harpoon,
	/obj/item/gun/ballistic/automatic/mini_uzi,
	/obj/item/gun/energy/lasercannon,
	/obj/item/gun/energy/kinetic_accelerator/crossbow/large,
	/obj/item/gun/energy/e_gun/nuclear,
	/obj/item/gun/ballistic/automatic/proto,
	/obj/item/gun/ballistic/automatic/c20r,
	/obj/item/gun/ballistic/automatic/l6_saw,
	/obj/item/gun/ballistic/automatic/m90,
	/obj/item/gun/energy/alien,
	/obj/item/gun/energy/e_gun/dragnet,
	/obj/item/gun/energy/e_gun/turret,
	/obj/item/gun/energy/pulse/carbine,
	/obj/item/gun/energy/decloner,
	/obj/item/gun/energy/mindflayer,
	/obj/item/gun/energy/kinetic_accelerator,
	/obj/item/gun/energy/plasmacutter/adv,
	/obj/item/gun/energy/wormhole_projector,
	/obj/item/gun/ballistic/automatic/wt550,
	/obj/item/gun/ballistic/shotgun/bulldog,
	/obj/item/gun/ballistic/revolver/grenadelauncher,
	/obj/item/gun/ballistic/revolver/golden,
	/obj/item/gun/ballistic/automatic/sniper_rifle,
	/obj/item/gun/ballistic/rocketlauncher,
	/obj/item/gun/medbeam,
	/obj/item/gun/energy/laser/scatter,
	/obj/item/gun/energy/gravity_gun))

//if you add anything that isn't covered by the typepaths below, add it to summon_magic_objective_types
GLOBAL_LIST_INIT(summoned_magic, list(
	/obj/item/book/granter/spell/fireball,
	/obj/item/book/granter/spell/smoke,
	/obj/item/book/granter/spell/blind,
	/obj/item/book/granter/spell/mindswap,
	/obj/item/book/granter/spell/forcewall,
	/obj/item/book/granter/spell/knock,
	/obj/item/book/granter/spell/barnyard,
	/obj/item/book/granter/spell/charge,
	/obj/item/book/granter/spell/summonitem,
	/obj/item/gun/magic/wand/nothing,
	/obj/item/gun/magic/wand/death,
	/obj/item/gun/magic/wand/resurrection,
	/obj/item/gun/magic/wand/polymorph,
	/obj/item/gun/magic/wand/teleport,
	/obj/item/gun/magic/wand/door,
	/obj/item/gun/magic/wand/fireball,
	/obj/item/gun/magic/staff/healing,
	/obj/item/gun/magic/staff/door,
	/obj/item/scrying,
	/obj/item/warpwhistle,
	/obj/item/clothing/suit/space/hardsuit/shielded/wizard,
	/obj/item/immortality_talisman,
	/obj/item/melee/ghost_sword))

GLOBAL_LIST_INIT(summoned_special_magic, list(
	/obj/item/gun/magic/staff/change,
	/obj/item/gun/magic/staff/animate,
	/obj/item/storage/belt/wands/full,
	/obj/item/antag_spawner/contract,
	/obj/item/gun/magic/staff/chaos,
	/obj/item/necromantic_stone))

//everything above except for single use spellbooks, because they are counted separately (and are for basic bitches anyways)
GLOBAL_LIST_INIT(summoned_magic_objectives, list(
	/obj/item/antag_spawner/contract,
	/obj/item/clothing/suit/space/hardsuit/shielded/wizard,
	/obj/item/gun/magic,
	/obj/item/immortality_talisman,
	/obj/item/melee/ghost_sword,
	/obj/item/necromantic_stone,
	/obj/item/scrying,
	/obj/item/spellbook,
	/obj/item/storage/belt/wands/full,
	/obj/item/warpwhistle))

/proc/give_guns(mob/living/carbon/human/H)
	if(H.stat == DEAD || !(H.client))
		return
	if(H.mind)
		if(IS_WIZARD(H) || H.mind.has_antag_datum(/datum/antagonist/survivalist/guns))
			return
	var/datum/summon_guns_controller/controller = GLOB.summon_guns
	if(prob(controller.survivor_probability) && !(H.mind.has_antag_datum(/datum/antagonist)))
		H.mind.add_antag_datum(/datum/antagonist/survivalist/guns)
		H.log_message("was made into a survivalist, and trusts no one!", LOG_ATTACK, color="red")

	var/gun_type = pick(GLOB.summoned_guns)
	var/obj/item/gun/G = new gun_type(get_turf(H))
	if (istype(G)) // The list may contain some non-gun type guns which do not have this proc
		G.unlock()
	playsound(get_turf(H),'sound/magic/summon_guns.ogg', 50, TRUE)

	var/in_hand = H.put_in_hands(G) // not always successful

	to_chat(H, span_warning("\A [G] appears [in_hand ? "in your hand" : "at your feet"]!"))

/proc/give_magic(mob/living/carbon/human/H)
	if(H.stat == DEAD || !(H.client))
		return
	if(H.mind)
		if(IS_WIZARD(H) || H.mind.has_antag_datum(/datum/antagonist/survivalist/magic))
			return
	if(!GLOB.summon_magic)
		return
	var/datum/summon_magic_controller/controller = GLOB.summon_magic
	if(prob(controller.survivor_probability) && !(H.mind.has_antag_datum(/datum/antagonist)))
		H.mind.add_antag_datum(/datum/antagonist/survivalist/magic)
		H.log_message("was made into a survivalist, and trusts no one!</font>", LOG_ATTACK, color="red")

	var/magic_type = pick(GLOB.summoned_magic)
	var/lucky = FALSE
	if(prob(SPECIALIST_MAGIC_PROB))
		magic_type = pick(GLOB.summoned_special_magic)
		lucky = TRUE

	var/obj/item/M = new magic_type(get_turf(H))
	playsound(get_turf(H),'sound/magic/summon_magic.ogg', 50, TRUE)

	var/in_hand = H.put_in_hands(M)

	to_chat(H, span_warning("\A [M] appears [in_hand ? "in your hand" : "at your feet"]!"))
	if(lucky)
		to_chat(H, span_notice("You feel incredibly lucky."))

/proc/rightandwrong(summon_type, mob/user, survivor_probability)
	if(user) //in this case either someone holding a spellbook or a badmin
		to_chat(user, span_warning("You summoned [summon_type]!"))
		message_admins("[ADMIN_LOOKUPFLW(user)] summoned [summon_type]!")
		log_game("[key_name(user)] summoned [summon_type]!")

	if(summon_type == SUMMON_MAGIC)
		GLOB.summon_magic = new /datum/summon_magic_controller(survivor_probability)
	else if(summon_type == SUMMON_GUNS)
		GLOB.summon_guns = new /datum/summon_guns_controller(survivor_probability)
	else
		CRASH("Bad summon_type given: [summon_type]")

/proc/summonevents()
	if(!SSevents.wizardmode)
		SSevents.frequency_lower = 600 //1 minute lower bound
		SSevents.frequency_upper = 3000 //5 minutes upper bound
		SSevents.toggleWizardmode()
		SSevents.reschedule()

	else //Speed it up
		SSevents.frequency_upper -= 600 //The upper bound falls a minute each time, making the AVERAGE time between events lessen
		if(SSevents.frequency_upper < SSevents.frequency_lower) //Sanity
			SSevents.frequency_upper = SSevents.frequency_lower

		SSevents.reschedule()
		message_admins("Summon Events intensifies, events will now occur every [SSevents.frequency_lower / 600] to [SSevents.frequency_upper / 600] minutes.")
		log_game("Summon Events was increased!")

#undef SPECIALIST_MAGIC_PROB

/**
 * The magic controller handles the summon magic event.
 * It is first created when summon magic event is triggered, and it can be referenced from GLOB.summon_magic
 */
/datum/summon_magic_controller
	///chances someone who is given magic will be an antagonist
	var/survivor_probability = 0

/datum/summon_magic_controller/New(survivor_probability)
	. = ..()
	src.survivor_probability = survivor_probability
	RegisterSignal(SSdcs, COMSIG_GLOB_CREWMEMBER_JOINED, .proc/magic_up_new_crew)

	for(var/mob/living/carbon/human/unarmed_human in GLOB.player_list)
		var/turf/turf_check = get_turf(unarmed_human)
		if(turf_check && is_away_level(turf_check.z))
			continue
		give_magic(unarmed_human)

/datum/summon_magic_controller/Destroy(force, ...)
	. = ..()
	UnregisterSignal(SSdcs, COMSIG_GLOB_CREWMEMBER_JOINED)

///signal proc to give magic to new crewmembers
/datum/summon_magic_controller/proc/magic_up_new_crew(datum/source, mob/living/new_crewmember, rank)
	SIGNAL_HANDLER
	if(ishuman(new_crewmember))
		INVOKE_ASYNC(GLOB.summon_magic, .proc/give_magic, new_crewmember)

/**
 * The guns controller handles the summon guns event.
 * It is first created when summon guns event is triggered, and it can be referenced from GLOB.summon_guns
 */
/datum/summon_guns_controller
	///chances someone who is given guns will be an antagonist
	var/survivor_probability = 0

/datum/summon_guns_controller/New(survivor_probability)
	. = ..()
	src.survivor_probability = survivor_probability
	RegisterSignal(SSdcs, COMSIG_GLOB_CREWMEMBER_JOINED, .proc/arm_up_new_crew)

	for(var/mob/living/carbon/human/unarmed_human in GLOB.player_list)
		var/turf/turf_check = get_turf(unarmed_human)
		if(turf_check && is_away_level(turf_check.z))
			continue
		give_guns(unarmed_human)

/datum/summon_guns_controller/Destroy(force, ...)
	. = ..()
	UnregisterSignal(SSdcs, COMSIG_GLOB_CREWMEMBER_JOINED)

///signal proc to give guns to new crewmembers
/datum/summon_guns_controller/proc/arm_up_new_crew(datum/source, mob/living/new_crewmember, rank)
	SIGNAL_HANDLER
	if(ishuman(new_crewmember))
		INVOKE_ASYNC(GLOB.summon_guns, .proc/give_guns, new_crewmember)


code:
/obj/effect/proc_holder/spell/targeted/rod_form
	name = "Rod Form"
	desc = "Take on the form of an immovable rod, destroying all in your path. Purchasing this spell multiple times will also increase the rod's damage and travel range."
	clothes_req = TRUE
	human_req = FALSE
	charge_max = 250
	cooldown_min = 100
	range = -1
	school = SCHOOL_TRANSMUTATION
	include_user = TRUE
	invocation = "CLANG!"
	invocation_type = INVOCATION_SHOUT
	action_icon_state = "immrod"

/obj/effect/proc_holder/spell/targeted/rod_form/cast(list/targets,mob/user = usr)
	var/area/A = get_area(user)
	if(istype(A, /area/wizard_station))
		to_chat(user, span_warning("You know better than to trash Wizard Federation property. Best wait until you leave to use [src]."))
		return
	for(var/mob/living/M in targets)
		var/turf/start = get_turf(M)
		var/obj/effect/immovablerod/wizard/W = new(start, get_ranged_target_turf(start, M.dir, (15 + spell_level * 3)))
		W.wizard = M
		W.max_distance += spell_level * 3 //You travel farther when you upgrade the spell
		W.damage_bonus += spell_level * 20 //You do more damage when you upgrade the spell
		W.start_turf = start
		M.forceMove(W)
		M.notransform = TRUE
		M.status_flags |= GODMODE

//Wizard Version of the Immovable Rod

/obj/effect/immovablerod/wizard
	var/max_distance = 13
	var/damage_bonus = 0
	var/turf/start_turf
	notify = FALSE
	dnd_style_level_up = FALSE

/obj/effect/immovablerod/wizard/Move()
	if(get_dist(start_turf, get_turf(src)) >= max_distance)
		qdel(src)
	..()

/obj/effect/immovablerod/wizard/Destroy()
	if(wizard)
		wizard.status_flags &= ~GODMODE
		wizard.notransform = FALSE
		wizard.forceMove(get_turf(src))
	return ..()

/obj/effect/immovablerod/wizard/penetrate(mob/living/L)
	if(L.anti_magic_check())
		L.visible_message(span_danger("[src] hits [L], but it bounces back, then vanishes!") , span_userdanger("[src] hits you... but it bounces back, then vanishes!") , span_danger("You hear a weak, sad, CLANG."))
		qdel(src)
		return
	L.visible_message(span_danger("[L] is penetrated by an immovable rod!") , span_userdanger("The rod penetrates you!") , span_danger("You hear a CLANG!"))
	L.adjustBruteLoss(70 + damage_bonus)


code:
//Santa spells!
/obj/effect/proc_holder/spell/aoe_turf/conjure/presents
	name = "Conjure Presents!"
	desc = "This spell lets you reach into S-space and retrieve presents! Yay!"
	school = SCHOOL_CONJURATION
	charge_max = 600
	clothes_req = FALSE
	antimagic_allowed = TRUE
	invocation = "HO HO HO"
	invocation_type = INVOCATION_SHOUT
	range = 3
	cooldown_min = 50

	summon_type = list("/obj/item/a_gift")
	summon_lifespan = 0
	summon_amt = 5


code:
#define SHADOW_REGEN_RATE 1.5

/obj/effect/proc_holder/spell/targeted/shadowwalk
	name = "Shadow Walk"
	desc = "Grants unlimited movement in darkness."
	charge_max = 0
	clothes_req = FALSE
	antimagic_allowed = TRUE
	phase_allowed = TRUE
	selection_type = "range"
	range = -1
	include_user = TRUE
	cooldown_min = 0
	overlay = null
	action_icon = 'icons/mob/actions/actions_minor_antag.dmi'
	action_icon_state = "ninja_cloak"
	action_background_icon_state = "bg_alien"

/obj/effect/proc_holder/spell/targeted/shadowwalk/cast_check(skipcharge = 0,mob/user = usr)
	. = ..()
	if(!.)
		return FALSE
	var/area/noteleport_check = get_area(user)
	if(noteleport_check && noteleport_check.area_flags & NOTELEPORT)
		to_chat(user, span_danger("Some dull, universal force is stopping you from melting into the shadows here."))
		return FALSE

/obj/effect/proc_holder/spell/targeted/shadowwalk/cast(list/targets,mob/living/user = usr)
	var/L = user.loc
	if(istype(user.loc, /obj/effect/dummy/phased_mob/shadow))
		var/obj/effect/dummy/phased_mob/shadow/S = L
		S.end_jaunt(FALSE)
		return
	else
		var/turf/T = get_turf(user)
		var/light_amount = T.get_lumcount()
		if(light_amount < SHADOW_SPECIES_LIGHT_THRESHOLD)
			playsound(get_turf(user), 'sound/magic/ethereal_enter.ogg', 50, TRUE, -1)
			visible_message(span_boldwarning("[user] melts into the shadows!"))
			user.SetAllImmobility(0)
			user.setStaminaLoss(0, 0)
			var/obj/effect/dummy/phased_mob/shadow/S2 = new(get_turf(user.loc))
			user.forceMove(S2)
			S2.jaunter = user
		else
			to_chat(user, span_warning("It isn't dark enough here!"))

/obj/effect/dummy/phased_mob/shadow
	var/mob/living/jaunter

/obj/effect/dummy/phased_mob/shadow/Initialize(mapload)
	. = ..()
	START_PROCESSING(SSobj, src)

/obj/effect/dummy/phased_mob/shadow/Destroy()
	jaunter = null
	STOP_PROCESSING(SSobj, src)
	. = ..()

/obj/effect/dummy/phased_mob/shadow/process(delta_time)
	var/turf/T = get_turf(src)
	var/light_amount = T.get_lumcount()
	if(!jaunter || jaunter.loc != src)
		qdel(src)
	if (light_amount < 0.2 && (!QDELETED(jaunter))) //heal in the dark
		jaunter.heal_overall_damage((SHADOW_REGEN_RATE * delta_time), (SHADOW_REGEN_RATE * delta_time), 0, BODYPART_ORGANIC)
	check_light_level()

/obj/effect/dummy/phased_mob/shadow/relaymove(mob/living/user, direction)
	var/turf/oldloc = loc
	. = ..()
	if(loc != oldloc)
		check_light_level()

/obj/effect/dummy/phased_mob/shadow/phased_check(mob/living/user, direction)
	. = ..()
	if(. && isspaceturf(.))
		to_chat(user, span_warning("It really would not be wise to go into space."))
		return FALSE

/obj/effect/dummy/phased_mob/shadow/proc/check_light_level()
	var/turf/T = get_turf(src)
	var/light_amount = T.get_lumcount()
	if(light_amount > 0.2) // jaunt ends
		end_jaunt(TRUE)

/obj/effect/dummy/phased_mob/shadow/proc/end_jaunt(forced = FALSE)
	if(jaunter)
		if(forced)
			visible_message(span_boldwarning("[jaunter] is revealed by the light!"))
		else
			visible_message(span_boldwarning("[jaunter] emerges from the darkness!"))
		playsound(loc, 'sound/magic/ethereal_exit.ogg', 50, TRUE, -1)
	qdel(src)

#undef SHADOW_REGEN_RATE