diff --git a/code/__DEFINES/dcs/signals.dm b/code/__DEFINES/dcs/signals.dm
index 42afde1f494..09c713f9201 100644
--- a/code/__DEFINES/dcs/signals.dm
+++ b/code/__DEFINES/dcs/signals.dm
@@ -455,9 +455,9 @@
#define COMSIG_ITEM_PICKUP "item_pickup"
///from base of mob/living/carbon/attacked_by(): (mob/living/carbon/target, mob/living/user, hit_zone)
#define COMSIG_ITEM_ATTACK_ZONE "item_attack_zone"
-///return a truthy value to prevent ensouling, checked in /obj/effect/proc_holder/spell/targeted/lichdom/cast(): (mob/user)
+///return a truthy value to prevent ensouling, checked in /obj/effect/proc_holder/spell/lichdom/cast(): (mob/user)
#define COMSIG_ITEM_IMBUE_SOUL "item_imbue_soul"
-///called before marking an object for retrieval, checked in /obj/effect/proc_holder/spell/targeted/summonitem/cast() : (mob/user)
+///called before marking an object for retrieval, checked in /obj/effect/proc_holder/spell/summonitem/cast() : (mob/user)
#define COMSIG_ITEM_MARK_RETRIEVAL "item_mark_retrieval"
#define COMPONENT_BLOCK_MARK_RETRIEVAL (1<<0)
///from base of obj/item/hit_reaction(): (list/args)
diff --git a/code/__DEFINES/spell.dm b/code/__DEFINES/spell.dm
new file mode 100644
index 00000000000..6babcaad31a
--- /dev/null
+++ b/code/__DEFINES/spell.dm
@@ -0,0 +1,5 @@
+#define SPELL_TARGET_CLOSEST 1
+#define SPELL_TARGET_RANDOM 2
+
+#define SPELL_SELECTION_RANGE "range"
+#define SPELL_SELECTION_VIEW "view"
diff --git a/code/__HELPERS/lists.dm b/code/__HELPERS/lists.dm
index f1c2d3a10a9..3eaf5356dd5 100644
--- a/code/__HELPERS/lists.dm
+++ b/code/__HELPERS/lists.dm
@@ -251,6 +251,23 @@
return picked
return null
+/**
+ * Picks multiple unique elements from the suplied list.
+ * If the given list has a length less than the amount given then it will return a list with an equal amount
+ *
+ * Arguments:
+ * * listfrom - The list where to pick from
+ * * amount - The amount of elements it tries to pick.
+ */
+/proc/pick_multiple_unique(list/listfrom, amount)
+ var/list/result = list()
+ var/list/copy = listfrom.Copy() // Ensure the original ain't modified
+ while(length(copy) && length(result) < amount)
+ var/picked = pick(copy)
+ result += picked
+ copy -= picked
+ return result
+
//Returns the top(last) element from the list and removes it from the list (typical stack function)
/proc/pop(list/L)
if(L.len)
diff --git a/code/datums/spell.dm b/code/datums/spell.dm
index 21527e1dc7f..f4733f64349 100644
--- a/code/datums/spell.dm
+++ b/code/datums/spell.dm
@@ -1,6 +1,3 @@
-#define TARGET_CLOSEST 1
-#define TARGET_RANDOM 2
-
/obj/effect/proc_holder
var/panel = "Debug"//What panel the proc holder needs to go on.
var/active = FALSE //Used by toggle based abilities.
@@ -76,7 +73,7 @@ GLOBAL_LIST_INIT(spells, typesof(/obj/effect/proc_holder/spell))
update_icon()
/obj/effect/proc_holder/spell
- name = "Spell"
+ name = "Spell" // Only rename this if the spell you're making is not abstract
desc = "A wizard spell"
panel = "Spells"//What panel the proc holder needs to go on.
density = 0
@@ -89,6 +86,7 @@ GLOBAL_LIST_INIT(spells, typesof(/obj/effect/proc_holder/spell))
var/charge_max = 100 //recharge time in deciseconds if charge_type = "recharge" or starting charges if charge_type = "charges"
var/starts_charged = TRUE //Does this spell start ready to go?
var/charge_counter = 0 //can only cast spells if it equals recharge, ++ each decisecond if charge_type = "recharge" or -- each cast if charge_type = "charges"
+ var/should_recharge_after_cast = TRUE
var/still_recharging_msg = "The spell is still recharging."
var/holder_var_type = "bruteloss" //only used if charge_type equals to "holder_var"
@@ -102,9 +100,7 @@ GLOBAL_LIST_INIT(spells, typesof(/obj/effect/proc_holder/spell))
var/invocation = "HURP DURP" //what is uttered when the wizard casts the spell
var/invocation_emote_self = null
var/invocation_type = "none" //can be none, whisper and shout
- var/range = 7 //the range of the spell; outer radius for aoe spells
var/message = "" //whatever it says to the guy affected by it
- var/selection_type = "view" //can be "range" or "view"
var/spell_level = 0 //if a spell can be taken multiple times, this raises
var/level_max = 4 //The max possible level_max is 4
var/cooldown_min = 0 //This defines what spell quickened four timeshas as a cooldown. Make sure to set this for every spell
@@ -131,11 +127,28 @@ GLOBAL_LIST_INIT(spells, typesof(/obj/effect/proc_holder/spell))
var/special_availability_check = 0//Whether the spell needs to bypass the action button's IsAvailable()
var/sound = null //The sound the spell makes when it is cast
- /// If the ability is for vampires
- var/vampire_ability = FALSE
- var/required_blood = 0
var/gain_desc = null
- var/deduct_blood_on_cast = TRUE
+
+ /// The message displayed when a click based spell gets activated
+ var/selection_activated_message = "Click on a target to cast the spell."
+ /// The message displayed when a click based spell gets deactivated
+ var/selection_deactivated_message = "You choose to not cast this spell."
+
+ /// does this spell generate attack logs?
+ var/create_attack_logs = TRUE
+
+ /// If this spell creates custom logs using the write_custom_logs() proc. Will ignore create_attack_logs
+ var/create_custom_logs = FALSE
+
+ /// Which targeting system is used. Set this in create_new_targeting
+ var/datum/spell_targeting/targeting
+ /// List with the targeting datums per spell type. Key = src.type, value = the targeting datum created by create_new_targeting()
+ var/static/list/targeting_datums = list()
+
+ /// Which spell_handler is used in addition to the normal spells behaviour, can be null. Set this in create_new_handler if needed
+ var/datum/spell_handler/custom_handler
+ /// List with the handler datums per spell type. Key = src.type, value = the handler datum created by create_new_handler()
+ var/static/list/spell_handlers = list()
/* Checks if the user can cast the spell
* @param charge_check If the proc should do the cooldown check
@@ -143,6 +156,7 @@ GLOBAL_LIST_INIT(spells, typesof(/obj/effect/proc_holder/spell))
* @param user The caster of the spell
*/
/obj/effect/proc_holder/spell/proc/cast_check(charge_check = TRUE, start_recharge = TRUE, mob/user = usr) //checks if the spell can be cast based on its settings; skipcharge is used when an additional cast_check is called inside the spell
+ // SHOULD_NOT_OVERRIDE(TRUE) Todo for another refactor
if(!can_cast(user, charge_check, TRUE))
return FALSE
@@ -154,17 +168,40 @@ GLOBAL_LIST_INIT(spells, typesof(/obj/effect/proc_holder/spell))
return 0
if(start_recharge)
- switch(charge_type)
- if("recharge")
- charge_counter = 0 //doesn't start recharging until the targets selecting ends
- if("charges")
- charge_counter-- //returns the charge if the targets selecting fails
- if("holdervar")
- adjust_var(user, holder_var_type, holder_var_amount)
+ spend_spell_cost(user)
+
+ return 1
+
+/**
+ * Allows for spell specific target validation. Will be used by the spell_targeting datums
+ *
+ * Arguments:
+ * * target - Who is being considered
+ * * user - Who is the user of this spell
+ */
+/obj/effect/proc_holder/spell/proc/valid_target(target, user)
+ return TRUE
+
+/**
+ * Will spend the cost of using this spell once. Will update the action button's icon if there is any
+ *
+ * Arguments:
+ * * user - Who used this spell?
+ */
+/obj/effect/proc_holder/spell/proc/spend_spell_cost(mob/user)
+ SHOULD_CALL_PARENT(TRUE)
+ switch(charge_type)
+ if("recharge")
+ charge_counter = 0 //doesn't start recharging until the targets selecting ends
+ if("charges")
+ charge_counter-- //returns the charge if the targets selecting fails
+ if("holdervar")
+ adjust_var(user, holder_var_type, holder_var_amount)
+
+ custom_handler?.spend_spell_cost(user, src)
if(action)
action.UpdateButtonIcon()
- return 1
/obj/effect/proc_holder/spell/proc/invocation(mob/user = usr) //spelling the spell out and setting it on recharge/reducing charges amount
switch(invocation_type)
@@ -198,17 +235,89 @@ GLOBAL_LIST_INIT(spells, typesof(/obj/effect/proc_holder/spell))
if(!gain_desc)
gain_desc = "You can now use [src]."
+ if(!targeting_datums[type])
+ targeting_datums[type] = create_new_targeting()
+ if(!targeting_datums[type])
+ stack_trace("Spell of type [type] did not implement create_new_targeting")
+ if(isnull(spell_handlers[type]))
+ spell_handlers[type] = create_new_handler()
+
+ if(spell_handlers[type] != NONE)
+ custom_handler = spell_handlers[type]
+ targeting = targeting_datums[type]
+
/obj/effect/proc_holder/spell/Destroy()
QDEL_NULL(action)
return ..()
+/**
+ * Creates and returns the targeting datum for this spell type. Override this!
+ * Should return a value of type [/datum/spell_targeting]
+ */
+/obj/effect/proc_holder/spell/proc/create_new_targeting()
+ RETURN_TYPE(/datum/spell_targeting)
+ return
+
+/**
+ * Creates and returns the handler datum for this spell type.
+ * Override this if you want a custom spell handler.
+ * Should return a value of type [/datum/spell_handler] or NONE
+ */
+/obj/effect/proc_holder/spell/proc/create_new_handler()
+ RETURN_TYPE(/datum/spell_handler)
+ return NONE
+
/obj/effect/proc_holder/spell/Click()
- if(cast_check())
- choose_targets()
+ if(cast_check(TRUE, FALSE, usr))
+ choose_targets(usr)
return 1
-/obj/effect/proc_holder/spell/proc/choose_targets(mob/user = usr) //depends on subtype - /targeted or /aoe_turf
- return
+/obj/effect/proc_holder/spell/InterceptClickOn(mob/user, params, atom/A)
+ . = ..()
+ if(.)
+ return
+ targeting.InterceptClickOn(user, params, A, src)
+
+/**
+ * Will try to choose targets using the targeting variable and perform the spell if it can
+ * Do not override this! Override create_new_targeting instead
+ *
+ * Arguments:
+ * * user - The caster of the spell
+ */
+/obj/effect/proc_holder/spell/proc/choose_targets(mob/user)
+ SHOULD_NOT_OVERRIDE(TRUE)
+ if(targeting.use_intercept_click)
+ if(active)
+ remove_ranged_ability(user, selection_deactivated_message)
+ return
+
+ if(targeting.try_auto_target && targeting.attempt_auto_target(user, src))
+ return
+
+ add_ranged_ability(user, selection_activated_message)
+ else
+ var/list/targets = targeting.choose_targets(user, src)
+ try_perform(targets, user)
+
+/**
+ * Will try and perform the spell using the given targets and user. Will spend one charge of the spell
+ *
+ * Arguments:
+ * * targets - The targets the spell is being performed on
+ * * user - The caster of the spell
+ */
+/obj/effect/proc_holder/spell/proc/try_perform(list/targets, mob/user)
+ SHOULD_NOT_OVERRIDE(TRUE)
+ if(!length(targets))
+ to_chat(user, "No suitable target found.")
+ return FALSE
+
+ remove_ranged_ability(user) // Targeting succeeded. So remove the click interceptor if there is one. Even if the cast didn't succeed afterwards
+ if(!cast_check(TRUE, TRUE, user))
+ return
+
+ perform(targets, should_recharge_after_cast, user)
/obj/effect/proc_holder/spell/proc/start_recharge()
if(action)
@@ -224,11 +333,23 @@ GLOBAL_LIST_INIT(spells, typesof(/obj/effect/proc_holder/spell))
STOP_PROCESSING(SSfastprocess, src)
charge_counter = charge_max
-/obj/effect/proc_holder/spell/proc/perform(list/targets, recharge = 1, mob/user = usr, make_attack_logs = TRUE) //if recharge is started is important for the trigger spells
+/**
+ * Handles all the code for performing a spell once the targets are known
+ *
+ * Arguments:
+ * * targets - The list of targets the spell is being cast on. Will not be empty or null
+ * * recharge - Whether or not the spell should go recharge
+ * * user - The caster of the spell
+ */
+/obj/effect/proc_holder/spell/proc/perform(list/targets, recharge = TRUE, mob/user = usr) //if recharge is started is important for the trigger spells
+ SHOULD_NOT_OVERRIDE(TRUE)
before_cast(targets, user)
invocation()
- if(user && user.ckey && make_attack_logs)
- add_attack_logs(user, targets, "cast the spell [name]", ATKLOG_ALL)
+ if(user && user.ckey)
+ if(create_custom_logs)
+ write_custom_logs(targets, user)
+ if(create_attack_logs)
+ add_attack_logs(user, targets, "cast the spell [name]", ATKLOG_ALL)
spawn(0)
if(charge_type == "recharge" && recharge)
start_recharge()
@@ -240,14 +361,23 @@ GLOBAL_LIST_INIT(spells, typesof(/obj/effect/proc_holder/spell))
critfail(targets)
else
cast(targets, user = user)
- after_cast(targets)
+ after_cast(targets, user)
if(action)
action.UpdateButtonIcon()
+/**
+ * Will write additional logs if create_custom_logs is TRUE and the caster has a ckey. Override this
+ *
+ * Arguments:
+ * * targets - The targets being targeted by the spell
+ * * user - The user of the spell
+ */
+/obj/effect/proc_holder/spell/proc/write_custom_logs(list/targets, mob/user)
+ return
+
+
/obj/effect/proc_holder/spell/proc/before_cast(list/targets, mob/user)
- if(vampire_ability)
- if(!before_cast_vampire(targets))
- return
+ SHOULD_CALL_PARENT(TRUE)
if(overlay)
for(var/atom/target in targets)
var/location
@@ -263,7 +393,10 @@ GLOBAL_LIST_INIT(spells, typesof(/obj/effect/proc_holder/spell))
spawn(overlay_lifespan)
qdel(spell)
-/obj/effect/proc_holder/spell/proc/after_cast(list/targets)
+ custom_handler?.before_cast(targets, user, src)
+
+/obj/effect/proc_holder/spell/proc/after_cast(list/targets, mob/user)
+ SHOULD_CALL_PARENT(TRUE)
for(var/atom/target in targets)
var/location
if(istype(target,/mob/living))
@@ -288,6 +421,15 @@ GLOBAL_LIST_INIT(spells, typesof(/obj/effect/proc_holder/spell))
smoke.set_up(smoke_amt, 0, location) // same here
smoke.start()
+ custom_handler?.after_cast(targets, user, src)
+
+/**
+ * The proc where the actual spell gets cast.
+ *
+ * Arguments:
+ * * targets - The targets being targeted by the spell
+ * * user - The caster of the spell
+ */
/obj/effect/proc_holder/spell/proc/cast(list/targets, mob/user = usr)
return
@@ -302,6 +444,9 @@ GLOBAL_LIST_INIT(spells, typesof(/obj/effect/proc_holder/spell))
charge_counter++
if("holdervar")
adjust_var(user, holder_var_type, -holder_var_amount)
+
+ custom_handler?.revert_cast(user, src)
+
if(action)
action.UpdateButtonIcon()
@@ -344,215 +489,17 @@ GLOBAL_LIST_INIT(spells, typesof(/obj/effect/proc_holder/spell))
if("holdervar")
return 1
-/obj/effect/proc_holder/spell/targeted //can mean aoe for mobs (limited/unlimited number) or one target mob
- var/max_targets = 1 //leave 0 for unlimited targets in range, 1 for one selectable target in range, more for limited number of casts (can all target one guy, depends on target_ignore_prev) in range
- var/target_ignore_prev = 1 //only important if max_targets > 1, affects if the spell can be cast multiple times at one person from one cast
- var/include_user = 0 //if it includes usr in the target list
- var/random_target = 0 // chooses random viable target instead of asking the caster
- var/random_target_priority = TARGET_CLOSEST // if random_target is enabled how it will pick the target
- var/humans_only = 0 //for avoiding simple animals and only doing "human" mobs, 0 = all mobs, 1 = humans only
-/obj/effect/proc_holder/spell/aoe_turf //affects all turfs in view or range (depends)
- var/inner_radius = -1 //for all your ring spell needs
-
-/obj/effect/proc_holder/spell/targeted/choose_targets(mob/user = usr)
- var/list/targets = list()
-
- switch(max_targets)
- if(0) //unlimited
-
- if(!humans_only)
- for(var/mob/living/target in view_or_range(range, user, selection_type))
- targets += target
- else
- for(var/mob/living/carbon/human/target in view_or_range(range, user, selection_type))
- targets += target
-
- if(1) //single target can be picked
- if(range < 0)
- targets += user
- else
- var/possible_targets = list()
-
- if(!humans_only)
- for(var/mob/living/M in view_or_range(range, user, selection_type))
- if(!include_user && user == M)
- continue
- possible_targets += M
- else
- for(var/mob/living/carbon/human/M in view_or_range(range, user, selection_type))
- if(!include_user && user == M)
- continue
- possible_targets += M
-
- //targets += input("Choose the target for the spell.", "Targeting") as mob in possible_targets
- //Adds a safety check post-input to make sure those targets are actually in range.
- var/mob/M
- if(!random_target)
- M = input("Choose the target for the spell.", "Targeting") as mob in possible_targets
- else
- switch(random_target_priority)
- if(TARGET_RANDOM)
- M = pick(possible_targets)
- if(TARGET_CLOSEST)
- for(var/mob/living/L in possible_targets)
- if(M)
- if(get_dist(user,L) < get_dist(user,M))
- if(los_check(user,L))
- M = L
- else
- if(los_check(user,L))
- M = L
- if(M in view_or_range(range, user, selection_type)) targets += M
-
- else
- var/list/possible_targets = list()
- if(!humans_only)
- for(var/mob/living/target in view_or_range(range, user, selection_type))
- possible_targets += target
- else
- for(var/mob/living/carbon/human/target in view_or_range(range, user, selection_type))
- possible_targets += target
- for(var/i=1,i<=max_targets,i++)
- if(!possible_targets.len)
- break
- if(target_ignore_prev)
- var/target = pick(possible_targets)
- possible_targets -= target
- targets += target
- else
- targets += pick(possible_targets)
-
- if(!include_user && (user in targets))
- targets -= user
-
- if(!targets.len) //doesn't waste the spell
- revert_cast(user)
- return
-
- perform(targets, user=user)
-
- return
-
-/obj/effect/proc_holder/spell/targeted/click
- var/click_radius = 1 // How big the radius around the clicked atom is to find a suitable target. -1 is only the selected atom is considered
- var/selection_activated_message = "Click on a target to cast the spell."
- var/selection_deactivated_message = "You choose to not cast this spell."
- var/allowed_type = /mob/living // Which type the targets have to be
- var/auto_target_single = TRUE // If the spell should auto select a target if only one is found
- /// does this spell generate attack logs?
- var/create_logs = TRUE
-
-/obj/effect/proc_holder/spell/targeted/click/Click()
- // biased goddamn variable types assuming that we're alive. eat shit.
- var/mob/user = usr
- if(!istype(user))
- return
-
- if(active)
- remove_ranged_ability(user, selection_deactivated_message)
- else
- if(cast_check(TRUE, FALSE, user))
- if(auto_target_single && attempt_auto_target(user))
- return
-
- add_ranged_ability(user, selection_activated_message)
- else
- to_chat(user, "[src] is not ready to be used yet.")
-
-/obj/effect/proc_holder/spell/targeted/click/proc/attempt_auto_target(mob/user)
- var/atom/target
- for(var/atom/A in view_or_range(range, user, selection_type))
- if(valid_target(A, user))
- if(target)
- return FALSE // Two targets found. ABORT
- target = A
-
- if(target && cast_check(TRUE, TRUE, user)) // Singular target found. Cast it instantly
- to_chat(user, "Only one target found. Casting [src] on [target]!")
- perform(list(target), user = user, make_attack_logs = create_logs)
- return TRUE
- return FALSE
-
-/obj/effect/proc_holder/spell/targeted/click/InterceptClickOn(mob/living/user, params, atom/A)
- if(..() || !cast_check(TRUE, TRUE, user))
- remove_ranged_ability(user)
- revert_cast(user)
- return TRUE
-
- var/list/targets = list()
- if(valid_target(A, user))
- targets.Add(A)
-
- if((!max_targets || max_targets > targets.len) && click_radius >= 0)
- var/list/found_others = list()
- for(var/atom/target in range(click_radius, A))
- if(valid_target(target, user))
- found_others |= target
- if(!max_targets)
- targets.Add(found_others)
- else
- if(max_targets <= found_others.len + targets.len)
- targets.Add(found_others)
- else
- switch(random_target_priority) //Add in the rest
- if(TARGET_RANDOM)
- while(targets.len < max_targets && found_others.len) // Add the others
- targets.Add(pick_n_take(found_others))
- if(TARGET_CLOSEST)
- var/list/distances = list()
- for(var/target in found_others)
- distances[target] = get_dist(user, target)
- sortTim(distances, /proc/cmp_numeric_asc, TRUE) // Sort on distance
- for(var/target in distances)
- targets.Add(target)
- if(targets.len >= max_targets)
- break
-
-
- if(!targets.len)
- to_chat(user, "No suitable target found.")
- revert_cast(user)
- return FALSE
-
- remove_ranged_ability(user)
- perform(targets, user = user, make_attack_logs = create_logs)
- return TRUE
-
-/* Checks if a target is valid
- * Should not include to_chats or other types of messages since this is used often on tons of targets.
- * @param target The target to check
- * @param user The user of the spell
-*/
-/obj/effect/proc_holder/spell/targeted/click/proc/valid_target(target, user)
- return istype(target, allowed_type) && (include_user || target != user) && \
- (target in view_or_range(range, user, selection_type))
-
-/obj/effect/proc_holder/spell/targeted/click/choose_targets(mob/user, atom/A) // Not used
- return
-
-/obj/effect/proc_holder/spell/aoe_turf/choose_targets(mob/user = usr)
- var/list/targets = list()
-
- for(var/turf/target in view_or_range(range,user,selection_type))
- if(!(target in view_or_range(inner_radius,user,selection_type)))
- targets += target
-
- if(!targets.len) //doesn't waste the spell
- revert_cast()
- return
-
- perform(targets, user=user)
-
- return
+/obj/effect/proc_holder/spell/aoe_turf
+ create_attack_logs = FALSE
+ create_custom_logs = TRUE
// Normally, AoE spells will generate an attack log for every turf they loop over, while searching for targets.
// With this override, all /aoe_turf type spells will only generate 1 log, saying that the user has cast the spell.
-/obj/effect/proc_holder/spell/aoe_turf/perform(list/targets, recharge, mob/user, make_attack_logs)
+/obj/effect/proc_holder/spell/aoe_turf/write_custom_logs(list/targets, mob/user)
add_attack_logs(user, null, "Cast the AoE spell [name]", ATKLOG_ALL)
- return ..(targets, recharge, user, FALSE)
-/obj/effect/proc_holder/spell/targeted/proc/los_check(mob/A,mob/B)
+/obj/effect/proc_holder/spell/proc/los_check(mob/A,mob/B)
//Checks for obstacles from A to B
var/obj/dummy = new(A.loc)
dummy.pass_flags |= PASSTABLE
@@ -604,7 +551,7 @@ GLOBAL_LIST_INIT(spells, typesof(/obj/effect/proc_holder/spell))
var/mob/living/carbon/human/H = user
var/clothcheck = locate(/obj/effect/proc_holder/spell/noclothes) in user.mob_spell_list
var/clothcheck2 = user.mind && (locate(/obj/effect/proc_holder/spell/noclothes) in user.mind.spell_list)
- if(clothes_req && !clothcheck && !clothcheck2 && !vampire_ability) //clothes check
+ if(clothes_req && !clothcheck && !clothcheck2) //clothes check
var/obj/item/clothing/robe = H.wear_suit
var/obj/item/clothing/hat = H.head
var/obj/item/clothing/shoes = H.shoes
@@ -617,7 +564,7 @@ GLOBAL_LIST_INIT(spells, typesof(/obj/effect/proc_holder/spell))
to_chat(user, "Your outfit isn't magical enough, you should put on your robe and wizard hat, as well as your sandals.")
return FALSE
else
- if(clothes_req || human_req || vampire_ability)
+ if(clothes_req || human_req)
if(show_message)
to_chat(user, "This spell can only be cast by humans!")
return FALSE
@@ -626,33 +573,8 @@ GLOBAL_LIST_INIT(spells, typesof(/obj/effect/proc_holder/spell))
to_chat(user, "This spell can only be cast by physical beings!")
return FALSE
- if(vampire_ability)
-
- var/datum/vampire/vampire = user.mind.vampire
-
- if(!vampire)
- return FALSE
-
- var/fullpower = vampire.get_ability(/datum/vampire_passive/full)
-
- if(user.stat >= DEAD)
- if(show_message)
- to_chat(user, "Not while you're dead!")
- return FALSE
-
- if(vampire.nullified >= VAMPIRE_COMPLETE_NULLIFICATION && !fullpower) // above 100 nullification vampire powers are useless
- if(show_message)
- to_chat(user, "Something is blocking your powers!")
- return FALSE
- if(vampire.bloodusable < required_blood)
- if(show_message)
- to_chat(user, "You require at least [required_blood] units of usable blood to do that!")
- return FALSE
- //chapel check
- if(istype(get_area(user), /area/chapel) && !fullpower)
- if(show_message)
- to_chat(user, "Your powers are useless on this holy ground.")
- return FALSE
+ if(custom_handler && !custom_handler.can_cast(user, charge_check, show_message, src))
+ return FALSE
return TRUE
diff --git a/code/datums/spell_handler/morph.dm b/code/datums/spell_handler/morph.dm
new file mode 100644
index 00000000000..688c2a62e0d
--- /dev/null
+++ b/code/datums/spell_handler/morph.dm
@@ -0,0 +1,27 @@
+/datum/spell_handler/morph
+ /// How much food it costs the morph to use this
+ var/hunger_cost = 0
+
+/datum/spell_handler/morph/can_cast(mob/living/simple_animal/hostile/morph/user, charge_check, show_message, obj/effect/proc_holder/spell/spell)
+ if(!istype(user))
+ if(show_message)
+ to_chat(user, "You should not be able to use this abilty! Report this as a bug on github please.")
+ return FALSE
+
+ if(user.gathered_food < hunger_cost)
+ if(show_message)
+ to_chat(user, "You require at least [hunger_cost] stored food to use this ability!")
+ return FALSE
+
+ return TRUE
+
+/datum/spell_handler/morph/spend_spell_cost(mob/living/simple_animal/hostile/morph/user, obj/effect/proc_holder/spell/spell)
+ user.use_food(hunger_cost)
+
+/datum/spell_handler/morph/before_cast(list/targets, mob/living/simple_animal/hostile/morph/user, obj/effect/proc_holder/spell/spell)
+ if(hunger_cost)
+ to_chat(user, "You have [user.gathered_food] left to use.")
+
+/datum/spell_handler/morph/revert_cast(mob/living/simple_animal/hostile/morph/user, obj/effect/proc_holder/spell/spell)
+ user.add_food(hunger_cost)
+ to_chat(user, "You have [user.gathered_food] left to use.")
diff --git a/code/datums/spell_handler/spell_handler.dm b/code/datums/spell_handler/spell_handler.dm
new file mode 100644
index 00000000000..e11aa76f9fd
--- /dev/null
+++ b/code/datums/spell_handler/spell_handler.dm
@@ -0,0 +1,22 @@
+/**
+ * The base class for the handler systems spells use.
+ * Subtypes of this class can be added to spells to modify their behaviour and change their can_cast.
+ * Thus allowing for a more modular behaviour system. For example a vampire spell that jaunts can just add the vampire spell_handler to the jaunt spell
+ */
+
+/datum/spell_handler
+
+/datum/spell_handler/proc/can_cast(mob/user, charge_check, show_message, obj/effect/proc_holder/spell/spell)
+ return TRUE
+
+/datum/spell_handler/proc/spend_spell_cost(mob/user, obj/effect/proc_holder/spell/spell)
+ return
+
+/datum/spell_handler/proc/revert_cast(mob/user, obj/effect/proc_holder/spell/spell)
+ return
+
+/datum/spell_handler/proc/before_cast(list/targets, mob/user, obj/effect/proc_holder/spell/spell)
+ return
+
+/datum/spell_handler/proc/after_cast(list/targets, mob/user, obj/effect/proc_holder/spell/spell)
+ return
diff --git a/code/datums/spell_handler/vampire.dm b/code/datums/spell_handler/vampire.dm
new file mode 100644
index 00000000000..76f7c908393
--- /dev/null
+++ b/code/datums/spell_handler/vampire.dm
@@ -0,0 +1,53 @@
+/datum/spell_handler/vampire
+ var/required_blood
+ /// If the blood cost should be handled by this handler. Or if the spell will handle it itself
+ var/deduct_blood_on_cast = TRUE
+
+/datum/spell_handler/vampire/can_cast(mob/user, charge_check, show_message, obj/effect/proc_holder/spell/spell)
+ var/datum/vampire/vampire = user.mind.vampire
+
+ if(!vampire)
+ return FALSE
+
+ var/fullpower = vampire.get_ability(/datum/vampire_passive/full)
+
+ if(user.stat >= DEAD) // TODO check if needed
+ if(show_message)
+ to_chat(user, "Not while you're dead!")
+ return FALSE
+
+ if(vampire.nullified >= VAMPIRE_COMPLETE_NULLIFICATION && !fullpower) // above 100 nullification vampire powers are useless
+ if(show_message)
+ to_chat(user, "Something is blocking your powers!")
+ return FALSE
+ if(vampire.bloodusable < required_blood)
+ if(show_message)
+ to_chat(user, "You require at least [required_blood] units of usable blood to do that!")
+ return FALSE
+ //chapel check
+ if(istype(get_area(user), /area/chapel) && !fullpower)
+ if(show_message)
+ to_chat(user, "Your powers are useless on this holy ground.")
+ return FALSE
+ return TRUE
+
+/datum/spell_handler/vampire/spend_spell_cost(mob/user, obj/effect/proc_holder/spell/spell)
+ if(!required_blood || !deduct_blood_on_cast) //don't take the blood yet if this is false!
+ return
+
+ var/datum/vampire/vampire = user.mind.vampire
+
+ vampire.bloodusable -= calculate_blood_cost(vampire)
+
+/datum/spell_handler/vampire/proc/calculate_blood_cost(datum/vampire/vampire)
+ var/blood_cost_modifier = 1 + vampire.nullified / 100
+ var/blood_cost = round(required_blood * blood_cost_modifier)
+ return blood_cost
+
+/datum/spell_handler/vampire/after_cast(list/targets, mob/user, obj/effect/proc_holder/spell/spell)
+ if(!required_blood)
+ return
+ var/datum/vampire/vampire = user.mind.vampire
+ to_chat(user, "You have [vampire.bloodusable] left to use.")
+ SSblackbox.record_feedback("tally", "vampire_powers_used", 1, "[spell]") // Only log abilities which require blood
+
diff --git a/code/datums/spell_targeting/alive_mobs.dm b/code/datums/spell_targeting/alive_mobs.dm
new file mode 100644
index 00000000000..5acd1db7f02
--- /dev/null
+++ b/code/datums/spell_targeting/alive_mobs.dm
@@ -0,0 +1,15 @@
+/**
+ * Will find targets in the GLOB.alive_mob_list. The result will be in a random order
+ */
+/datum/spell_targeting/alive_mob_list
+ allowed_type = /mob/living
+
+/datum/spell_targeting/alive_mob_list/choose_targets(mob/user, obj/effect/proc_holder/spell/spell, params, atom/clicked_atom)
+ var/list/possible_targets = list()
+ for(var/mob/living/possible_target as anything in GLOB.alive_mob_list)
+ if(valid_target(possible_target, user, spell))
+ possible_targets += possible_target
+
+ var/list/targets = pick_multiple_unique(possible_targets, max_targets)
+
+ return targets
diff --git a/code/datums/spell_targeting/aoe.dm b/code/datums/spell_targeting/aoe.dm
new file mode 100644
index 00000000000..6b8f18fe2b2
--- /dev/null
+++ b/code/datums/spell_targeting/aoe.dm
@@ -0,0 +1,20 @@
+/**
+ * An area of effect based spell targeting system. Will return all targets in the given range
+ */
+/datum/spell_targeting/aoe
+ max_targets = INFINITY
+ /// The radius of turfs not being affected. -1 is inactive
+ var/inner_radius = -1
+
+/datum/spell_targeting/aoe/choose_targets(mob/user, obj/effect/proc_holder/spell/spell, params, atom/clicked_atom)
+ var/list/targets = list()
+
+ for(var/atom/target in view_or_range(range, user, selection_type))
+ if(valid_target(target, user, spell))
+ targets += target
+ if(inner_radius >= 0)
+ targets -= view_or_range(inner_radius, user, selection_type) // remove the inner ring
+ return targets
+
+/datum/spell_targeting/aoe/turf
+ allowed_type = /turf
diff --git a/code/datums/spell_targeting/click.dm b/code/datums/spell_targeting/click.dm
new file mode 100644
index 00000000000..5d8ffcb74e8
--- /dev/null
+++ b/code/datums/spell_targeting/click.dm
@@ -0,0 +1,37 @@
+/**
+ * A click based spell targeting system. The clicked atom will be used to determine who/what to target
+ */
+/datum/spell_targeting/click
+ use_intercept_click = TRUE
+ try_auto_target = TRUE
+ /// How big the radius around the clicked atom is to find clicked_atom suitable target. -1 is only the selected atom is considered
+ var/click_radius = 1
+ var/random_target_priority = SPELL_TARGET_CLOSEST
+
+
+/datum/spell_targeting/click/choose_targets(mob/user, obj/effect/proc_holder/spell/spell, params, atom/clicked_atom)
+ var/list/targets = list()
+ if(valid_target(clicked_atom, user, spell))
+ targets.Add(clicked_atom)
+
+ if(length(targets) >= max_targets || click_radius < 0)
+ return targets
+
+ var/list/found_others = list()
+ for(var/atom/target in range(click_radius, clicked_atom) - clicked_atom)
+ if(valid_target(target, user, spell))
+ found_others += target
+
+ if(max_targets >= length(found_others) + length(targets))
+ targets.Add(found_others)
+ else
+ switch(random_target_priority) //Add in the rest
+ if(SPELL_TARGET_RANDOM)
+ while(length(targets) < max_targets && length(found_others)) // Add the others
+ targets.Add(pick_n_take(found_others))
+ if(SPELL_TARGET_CLOSEST)
+ // Take the first X. Byond's view/range procs already keep distance in mind. Will have a bias towards the left targets due to this
+ targets += found_others.Copy(1, max_targets - length(targets) + 1)
+
+ return targets
+
diff --git a/code/datums/spell_targeting/clicked_atom.dm b/code/datums/spell_targeting/clicked_atom.dm
new file mode 100644
index 00000000000..279d28e1cde
--- /dev/null
+++ b/code/datums/spell_targeting/clicked_atom.dm
@@ -0,0 +1,12 @@
+/**
+ * A simple spell targeting system. Will return the clicked atom as a target. Only works for 1 target max and is basically a dumbed down [/datum/spell_targeting/click]
+ */
+/datum/spell_targeting/clicked_atom
+ use_intercept_click = TRUE
+
+/datum/spell_targeting/clicked_atom/choose_targets(mob/user, obj/effect/proc_holder/spell/spell, params, atom/clicked_atom)
+ if(clicked_atom)
+ return list(clicked_atom)
+ else
+ return null
+
diff --git a/code/datums/spell_targeting/matter_eater_targeting.dm b/code/datums/spell_targeting/matter_eater_targeting.dm
new file mode 100644
index 00000000000..4af727d7b73
--- /dev/null
+++ b/code/datums/spell_targeting/matter_eater_targeting.dm
@@ -0,0 +1,46 @@
+/**
+ * A spell targeting system especially made for the matter eater gene
+ */
+/datum/spell_targeting/matter_eater
+ range = 1
+ var/list/types_allowed = list(
+ /obj/item,
+ /mob/living/simple_animal/pet,
+ /mob/living/simple_animal/hostile,
+ /mob/living/simple_animal/parrot,
+ /mob/living/simple_animal/crab,
+ /mob/living/simple_animal/mouse,
+ /mob/living/carbon/human,
+ /mob/living/simple_animal/slime,
+ /mob/living/carbon/alien/larva,
+ /mob/living/simple_animal/slime,
+ /mob/living/simple_animal/chick,
+ /mob/living/simple_animal/chicken,
+ /mob/living/simple_animal/lizard,
+ /mob/living/simple_animal/cow,
+ /mob/living/simple_animal/spiderbot
+ )
+ var/list/own_blacklist = list(
+ /obj/item/organ,
+ /obj/item/implant
+ )
+
+/datum/spell_targeting/matter_eater/choose_targets(mob/user, obj/effect/proc_holder/spell/spell, params, atom/clicked_atom)
+ var/list/possible_targets = list()
+
+ for(var/atom/movable/O in view_or_range(range, user, selection_type))
+ if((O in user) && is_type_in_list(O, own_blacklist))
+ continue
+ if(is_type_in_list(O, types_allowed))
+ if(isanimal(O))
+ var/mob/living/simple_animal/SA = O
+ if(!SA.gold_core_spawnable)
+ continue
+ possible_targets += O
+
+ var/atom/movable/target = input("Choose the target of your hunger.", "Targeting") as null|anything in possible_targets
+
+ if(QDELETED(target))
+ return
+
+ return list(target)
diff --git a/code/datums/spell_targeting/reachable_turfs.dm b/code/datums/spell_targeting/reachable_turfs.dm
new file mode 100644
index 00000000000..3233ec807e4
--- /dev/null
+++ b/code/datums/spell_targeting/reachable_turfs.dm
@@ -0,0 +1,18 @@
+/**
+ * A spell targeting system which will return nearby turfs which are reachable from the users location. Will pad the targets with the user's location if needed
+ */
+/datum/spell_targeting/reachable_turfs
+
+/datum/spell_targeting/reachable_turfs/choose_targets(mob/user, obj/effect/proc_holder/spell/spell, params, atom/clicked_atom)
+ var/list/turf/locs = list()
+ for(var/direction in GLOB.alldirs)
+ if(length(locs) == max_targets) //we found 2 locations and thats all we need
+ break
+ var/turf/T = get_step(user, direction) //getting a loc in that direction
+ if(AStar(user, T, /turf/proc/Distance, 1, simulated_only = FALSE)) // if a path exists, so no dense objects in the way its valid salid
+ locs += T
+
+ // pad with player location
+ for(var/i = length(locs) + 1 to max_targets)
+ locs += user.loc
+ return locs
diff --git a/code/datums/spell_targeting/remoteview_targeting.dm b/code/datums/spell_targeting/remoteview_targeting.dm
new file mode 100644
index 00000000000..f089ba28585
--- /dev/null
+++ b/code/datums/spell_targeting/remoteview_targeting.dm
@@ -0,0 +1,24 @@
+/**
+ * A spell targeting system which will return one user picked target from all alive mobs who have the remoteview block but do not have the psyresist block active.
+ */
+/datum/spell_targeting/remoteview
+
+/datum/spell_targeting/remoteview/choose_targets(mob/user, obj/effect/proc_holder/spell/spell, params, atom/clicked_atom)
+ var/list/remoteviewers = list()
+ for(var/mob/M in GLOB.alive_mob_list)
+ if(M == user)
+ continue
+ if(M.dna?.GetSEState(GLOB.psyresistblock))
+ continue
+ if(M.dna?.GetSEState(GLOB.remoteviewblock))
+ remoteviewers += M
+
+ if(!length(remoteviewers))
+ return
+
+ var/mob/target = input("Choose the target to spy on.", "Targeting") as null|anything in remoteviewers
+
+ if(QDELETED(target))
+ return
+
+ return list(target)
diff --git a/code/datums/spell_targeting/self.dm b/code/datums/spell_targeting/self.dm
new file mode 100644
index 00000000000..a1facb7462f
--- /dev/null
+++ b/code/datums/spell_targeting/self.dm
@@ -0,0 +1,7 @@
+/**
+ * A spell targeting system which will return the caster as target
+ */
+/datum/spell_targeting/self
+
+/datum/spell_targeting/self/choose_targets(mob/user, obj/effect/proc_holder/spell/spell, params, atom/clicked_atom)
+ return list(user) // That's how simple it is
diff --git a/code/datums/spell_targeting/spell_targeting.dm b/code/datums/spell_targeting/spell_targeting.dm
new file mode 100644
index 00000000000..0560c04e0ff
--- /dev/null
+++ b/code/datums/spell_targeting/spell_targeting.dm
@@ -0,0 +1,80 @@
+/**
+ * The base class for the targeting systems spells use.
+ *
+ * To create a new targeting datum you just inherit from this base type and override the [/datum/spell_targeting/proc/choose_targets] proc.
+ * Override the [/datum/spell_targeting/proc/valid_target] proc for more complex validations.
+ * More complex behaviour like [auto targeting][/datum/spell_targeting/proc/attempt_auto_target] and [click based][/datum/spell_targeting/proc/InterceptClickOn] activation is possible.
+ */
+/datum/spell_targeting
+ /// The range of the spell; outer radius for aoe spells
+ var/range = 7
+ /// Can be SPELL_SELECTION_RANGE or SPELL_SELECTION_VIEW
+ var/selection_type = SPELL_SELECTION_VIEW
+ /// How many targets are allowed. INFINITY is used to target unlimited targets
+ var/max_targets = 1
+ /// Which type the targets have to be
+ var/allowed_type = /mob/living/carbon/human
+ /// If it includes user. Not always used in all spell_targeting objects
+ var/include_user = FALSE
+ /// Whether or not the targeting is done by intercepting a click or not
+ var/use_intercept_click = FALSE
+ /// Whether or not the spell will try to auto target first before setting up the intercept click
+ var/try_auto_target = FALSE
+ /// Whether or not the spell should use the turf of the user as starting point
+ var/use_turf_of_user = FALSE
+
+/**
+ * Called when choosing the targets for the parent spell
+ *
+ * Arguments:
+ * * user - the one who casts the spell
+ * * spell - The spell being cast
+ * * params - Params given by the intercept click. Only available if use_intercept_click is TRUE
+ * * clicked_atom - The atom clicked on. Only available if use_intercept_click is TRUE
+ */
+/datum/spell_targeting/proc/choose_targets(mob/user, obj/effect/proc_holder/spell/spell, params, atom/clicked_atom)
+ RETURN_TYPE(/list)
+ return
+
+/**
+ * Will attempt to auto target the spell. Only works with 1 target currently
+ */
+/datum/spell_targeting/proc/attempt_auto_target(mob/user, obj/effect/proc_holder/spell/spell)
+ var/atom/target
+ for(var/atom/A in view_or_range(range, use_turf_of_user ? get_turf(user) : user, selection_type))
+ if(valid_target(A, user, spell))
+ if(target)
+ return FALSE // Two targets found. ABORT
+ target = A
+
+ if(target)
+ to_chat(user, "Only one target found. Casting [spell] on [target]!")
+ spell.try_perform(list(target), user)
+ return TRUE
+ return FALSE
+
+/**
+ * Called when the parent spell intercepts the click
+ *
+ * Arguments:
+ * * user - Who clicks with the spell targeting active?
+ * * params - Additional parameters from the click
+ * * A - Atom the user clicked on
+ * * spell - The spell being cast
+ */
+/datum/spell_targeting/proc/InterceptClickOn(mob/user, params, atom/A, obj/effect/proc_holder/spell/spell)
+ var/list/targets = choose_targets(user, spell, params, A)
+ spell.try_perform(targets, user)
+
+/**
+ * Checks whether or not the given target is valid. Calls spell.valid_target as well
+ *
+ * Arguments:
+ * * target - The one who is being considered as a target
+ * * user - Who is casting the spell
+ * * spell - The spell being cast
+ */
+/datum/spell_targeting/proc/valid_target(target, user, obj/effect/proc_holder/spell/spell)
+ SHOULD_CALL_PARENT(TRUE)
+ return istype(target, allowed_type) && (include_user || target != user) && \
+ spell.valid_target(target, user) && (target in view_or_range(range, use_turf_of_user ? get_turf(user) : user, selection_type))
diff --git a/code/datums/spell_targeting/targeted.dm b/code/datums/spell_targeting/targeted.dm
new file mode 100644
index 00000000000..a80a7ee70d4
--- /dev/null
+++ b/code/datums/spell_targeting/targeted.dm
@@ -0,0 +1,54 @@
+/**
+ * A spell targeting system which is able to select 1 to many targets in range/view of the caster. Has a random mode, distance from user based mode or a user input mode.
+ */
+/datum/spell_targeting/targeted
+ /// Only important if max_targets > 1, affects if the spell can be cast multiple times at one person from one cast
+ var/can_hit_target_more_than_once = FALSE
+ /// Chooses random viable target instead of asking the caster
+ var/random_target = FALSE
+ /// Who to target when too many targets are found. Only matters when max_targets = 1
+ var/target_priority = SPELL_TARGET_CLOSEST
+
+/datum/spell_targeting/targeted/choose_targets(mob/user, obj/effect/proc_holder/spell/spell, params, atom/clicked_atom)
+ var/list/targets = list()
+ var/list/possible_targets = list()
+ var/atom/spell_location = use_turf_of_user ? get_turf(user) : user
+ for(var/atom/target in view_or_range(range, spell_location, selection_type))
+ if(valid_target(target, user, spell))
+ possible_targets += target
+
+ if(!length(possible_targets))
+ return null
+
+ if(max_targets == INFINITY) // Unlimited
+ targets = possible_targets
+ else if(max_targets == 1) // Only one target
+ var/atom/target
+ if(!random_target)
+ target = input("Choose the target for the spell.", "Targeting") as anything in possible_targets
+ //Adds a safety check post-input to make sure those targets are actually in range.
+ if(target in view_or_range(range, spell_location, selection_type))
+ targets += target
+ else
+ switch(target_priority)
+ if(SPELL_TARGET_RANDOM)
+ target = pick(possible_targets)
+ if(SPELL_TARGET_CLOSEST)
+ for(var/atom/A as anything in possible_targets)
+ if(target)
+ if(get_dist(spell_location, A) < get_dist(spell_location, target))
+ if(spell.los_check(user, A))
+ target = A
+ else
+ if(spell.los_check(user, A))
+ target = A
+ targets += target
+ else if(max_targets > 1)
+ do
+ if(can_hit_target_more_than_once)
+ targets += pick(possible_targets)
+ else
+ targets += pick_n_take(possible_targets)
+ while(length(possible_targets) && length(targets) < max_targets)
+
+ return targets
diff --git a/code/datums/spell_targeting/telepathic.dm b/code/datums/spell_targeting/telepathic.dm
new file mode 100644
index 00000000000..618f9da80ca
--- /dev/null
+++ b/code/datums/spell_targeting/telepathic.dm
@@ -0,0 +1,37 @@
+/**
+ * A spell targeting system which will allow the user to select a target from nearby living mobs. The name will be "Unknown entity" if the user can not see them
+ */
+/datum/spell_targeting/telepathic
+
+/datum/spell_targeting/telepathic/choose_targets(mob/user, obj/effect/proc_holder/spell/spell, params, atom/clicked_atom)
+ var/list/valid_targets = list()
+ var/turf/T = get_turf(user)
+ var/list/mobs_in_view = user.get_visible_mobs()
+
+ for(var/mob/living/M in range(14, T))
+ if(M && M.mind)
+ if(M == user)
+ continue
+ var/mob_name
+ if(M in mobs_in_view)
+ mob_name = M.name
+ else
+ mob_name = "Unknown entity"
+ var/i = 0
+ var/result_name
+ do
+ result_name = mob_name
+ if(i++)
+ result_name += " ([i])" // Avoid dupes
+ while(valid_targets[result_name])
+ valid_targets[result_name] = M
+ if(!length(valid_targets))
+ return
+
+ var/target_name = input("Choose the target to listen to.", "Targeting") as null|anything in valid_targets
+
+ var/mob/living/target = valid_targets[target_name]
+ if(QDELETED(target))
+ return
+
+ return list(target)
diff --git a/code/datums/spells/area_teleport.dm b/code/datums/spells/area_teleport.dm
index dfb40218816..4f84629fcec 100644
--- a/code/datums/spells/area_teleport.dm
+++ b/code/datums/spells/area_teleport.dm
@@ -1,6 +1,4 @@
-/obj/effect/proc_holder/spell/targeted/area_teleport
- name = "Area teleport"
- desc = "This spell teleports you to a type of area of your selection."
+/obj/effect/proc_holder/spell/area_teleport
nonabstract_req = 1
var/randomise_selection = 0 //if it lets the usr choose the teleport loc or picks it from the list
@@ -8,21 +6,12 @@
var/sound1 = 'sound/weapons/zapbang.ogg'
var/sound2 = 'sound/weapons/zapbang.ogg'
+ var/area/selected_area
-/obj/effect/proc_holder/spell/targeted/area_teleport/perform(list/targets, recharge = 1, mob/living/user = usr)
- var/thearea = before_cast(targets, user)
- if(!thearea || !cast_check(FALSE, FALSE, user))
- revert_cast()
- return
- invocation(thearea)
- spawn(0)
- if(charge_type == "recharge" && recharge)
- start_recharge()
- cast(targets,thearea)
- after_cast(targets)
-
-/obj/effect/proc_holder/spell/targeted/area_teleport/before_cast(list/targets, mob/user)
- var/A = null
+/obj/effect/proc_holder/spell/area_teleport/before_cast(list/targets, mob/user)
+ ..()
+ selected_area = null // Reset it
+ var/A
if(!randomise_selection)
A = input("Area to teleport to", "Teleport", A) as null|anything in SSmapping.teleportlocs
@@ -38,13 +27,17 @@
to_chat(user, "A mysterious force disrupts your arcane spell matrix, and you remain where you are.")
return
- return thearea
+ selected_area = thearea
+
+/obj/effect/proc_holder/spell/area_teleport/cast(list/targets, mob/living/user)
+ if(!selected_area)
+ revert_cast(user)
+ return
-/obj/effect/proc_holder/spell/targeted/area_teleport/cast(list/targets,area/thearea,mob/living/user = usr)
playsound(get_turf(user), sound1, 50,1)
for(var/mob/living/target in targets)
var/list/L = list()
- for(var/turf/T in get_area_turfs(thearea.type))
+ for(var/turf/T in get_area_turfs(selected_area.type))
if(!T.density)
var/clear = 1
for(var/obj/O in T)
@@ -83,7 +76,7 @@
return
-/obj/effect/proc_holder/spell/targeted/area_teleport/invocation(area/chosenarea = null)
+/obj/effect/proc_holder/spell/area_teleport/invocation(area/chosenarea = null)
if(!invocation_area || !chosenarea)
..()
else
diff --git a/code/datums/spells/banana_touch.dm b/code/datums/spells/banana_touch.dm
index ae2d1d69161..3beeb3ccf06 100644
--- a/code/datums/spells/banana_touch.dm
+++ b/code/datums/spells/banana_touch.dm
@@ -1,4 +1,4 @@
-/obj/effect/proc_holder/spell/targeted/touch/banana
+/obj/effect/proc_holder/spell/touch/banana
name = "Banana Touch"
desc = "A spell popular at wizard birthday parties, this spell will put on a clown costume on the target, \
stun them with a loud HONK, and mutate them to make them more entertaining! \
diff --git a/code/datums/spells/bloodcrawl.dm b/code/datums/spells/bloodcrawl.dm
index 0b23b12b9f2..afbf2e79c88 100644
--- a/code/datums/spells/bloodcrawl.dm
+++ b/code/datums/spells/bloodcrawl.dm
@@ -3,32 +3,39 @@
desc = "Use pools of blood to phase out of existence."
charge_max = 0
clothes_req = 0
- selection_type = "range"
- range = 1
cooldown_min = 0
+ should_recharge_after_cast = FALSE
overlay = null
action_icon_state = "bloodcrawl"
action_background_icon_state = "bg_demon"
panel = "Demon"
var/phased = 0
-/obj/effect/proc_holder/spell/bloodcrawl/choose_targets(mob/user = usr)
- for(var/obj/effect/decal/cleanable/target in range(range, get_turf(user)))
- if(target.can_bloodcrawl_in())
- perform(target, user = user)
- return
- revert_cast()
- to_chat(user, "There must be a nearby source of blood!")
+/obj/effect/proc_holder/spell/bloodcrawl/create_new_targeting()
+ var/datum/spell_targeting/targeted/T = new()
+ T.selection_type = SPELL_SELECTION_RANGE
+ T.allowed_type = /obj/effect/decal/cleanable
+ T.random_target = TRUE
+ T.range = 1
+ T.use_turf_of_user = TRUE
+ return T
-/obj/effect/proc_holder/spell/bloodcrawl/perform(obj/effect/decal/cleanable/target, recharge = 1, mob/living/user = usr)
- if(istype(user))
- if(phased)
- if(user.phasein(target))
- phased = 0
- else
- if(user.phaseout(target))
- phased = 1
- start_recharge()
+/obj/effect/proc_holder/spell/bloodcrawl/valid_target(obj/effect/decal/cleanable/target, user)
+ return target.can_bloodcrawl_in()
+
+/obj/effect/proc_holder/spell/bloodcrawl/can_cast(mob/living/user, charge_check, show_message)
+ . = ..()
+ if(!.)
return
- revert_cast()
- to_chat(user, "You are unable to blood crawl!")
+ if(!isliving(user))
+ return FALSE
+
+/obj/effect/proc_holder/spell/bloodcrawl/cast(list/targets, mob/living/user)
+ var/obj/effect/decal/cleanable/target = targets[1] // TODO Test this spell
+ if(phased)
+ if(user.phasein(target))
+ phased = 0
+ else
+ if(user.phaseout(target))
+ phased = 1
+ start_recharge()
diff --git a/code/datums/spells/chaplain.dm b/code/datums/spells/chaplain.dm
index f16a2a3fbac..5454e51ce42 100644
--- a/code/datums/spells/chaplain.dm
+++ b/code/datums/spells/chaplain.dm
@@ -1,5 +1,5 @@
-/obj/effect/proc_holder/spell/targeted/click/chaplain_bless
+/obj/effect/proc_holder/spell/chaplain_bless
name = "Bless"
desc = "Blesses a single person."
@@ -9,23 +9,21 @@
invocation = "none"
invocation_type = "none"
- max_targets = 1
- include_user = FALSE
- allowed_type = /mob/living/carbon/human
selection_activated_message = "You prepare a blessing. Click on a target to start blessing."
selection_deactivated_message = "The crew will be blessed another time."
- range = 1
- click_radius = -1 // Only precision clicking
cooldown_min = 20
action_icon_state = "shield"
-/obj/effect/proc_holder/spell/targeted/click/chaplain_bless/valid_target(mob/living/carbon/human/target, user)
- if(!..())
- return FALSE
+/obj/effect/proc_holder/spell/chaplain_bless/create_new_targeting()
+ var/datum/spell_targeting/click/T = new()
+ T.range = 1
+ T.click_radius = -1
+ return T
+/obj/effect/proc_holder/spell/chaplain_bless/valid_target(mob/living/carbon/human/target, mob/user)
return target.mind && target.ckey && !target.stat
-/obj/effect/proc_holder/spell/targeted/click/chaplain_bless/cast(list/targets, mob/living/user = usr)
+/obj/effect/proc_holder/spell/chaplain_bless/cast(list/targets, mob/living/user = usr)
if(!istype(user))
to_chat(user, "Somehow, you are not a living mob. This should never happen. Report this bug.")
revert_cast()
diff --git a/code/datums/spells/charge.dm b/code/datums/spells/charge.dm
index 78d5d41c793..9e58a8445f8 100644
--- a/code/datums/spells/charge.dm
+++ b/code/datums/spells/charge.dm
@@ -1,4 +1,4 @@
-/obj/effect/proc_holder/spell/targeted/charge
+/obj/effect/proc_holder/spell/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 = "transmutation"
@@ -6,12 +6,13 @@
clothes_req = 0
invocation = "DIRI CEL"
invocation_type = "whisper"
- range = -1
cooldown_min = 400 //50 deciseconds reduction per rank
- include_user = 1
action_icon_state = "charge"
-/obj/effect/proc_holder/spell/targeted/charge/cast(list/targets, mob/user = usr)
+/obj/effect/proc_holder/spell/charge/create_new_targeting()
+ return new /datum/spell_targeting/self
+
+/obj/effect/proc_holder/spell/charge/cast(list/targets, mob/user = usr)
for(var/mob/living/L in targets)
var/list/hand_items = list(L.get_active_hand(),L.get_inactive_hand())
var/charged_item = null
diff --git a/code/datums/spells/cluwne.dm b/code/datums/spells/cluwne.dm
index 5a3b7b5da58..ed398df0b15 100644
--- a/code/datums/spells/cluwne.dm
+++ b/code/datums/spells/cluwne.dm
@@ -1,4 +1,4 @@
-/obj/effect/proc_holder/spell/targeted/touch/cluwne
+/obj/effect/proc_holder/spell/touch/cluwne
name = "Curse of the Cluwne"
desc = "Turns the target into a fat and cursed monstrosity of a clown."
hand_path = /obj/item/melee/touch_attack/cluwne
diff --git a/code/datums/spells/conjure.dm b/code/datums/spells/conjure.dm
index be716536aff..17a5b53d0a1 100644
--- a/code/datums/spells/conjure.dm
+++ b/code/datums/spells/conjure.dm
@@ -1,5 +1,4 @@
/obj/effect/proc_holder/spell/aoe_turf/conjure
- name = "Conjure"
desc = "This spell conjures objs of the specified types in range."
var/list/summon_type = list() //determines what exactly will be summoned
@@ -61,5 +60,9 @@
summon_type = list(/mob/living/simple_animal/bot/ed209)
summon_amt = 10
- range = 3
newVars = list("emagged" = 1,"name" = "Wizard's Justicebot")
+
+/obj/effect/proc_holder/spell/aoe_turf/conjure/summonEdSwarm/create_new_targeting()
+ var/datum/spell_targeting/aoe/turf/T = new()
+ T.range = 3
+ return T
diff --git a/code/datums/spells/conjure_item.dm b/code/datums/spells/conjure_item.dm
index e7d530c1c61..ec11796eeef 100644
--- a/code/datums/spells/conjure_item.dm
+++ b/code/datums/spells/conjure_item.dm
@@ -1,9 +1,7 @@
-/obj/effect/proc_holder/spell/targeted/conjure_item
+/obj/effect/proc_holder/spell/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."
invocation_type = "none"
- include_user = 1
- range = -1
clothes_req = FALSE
var/obj/item/item
var/item_type = /obj/item/banhammer
@@ -11,7 +9,10 @@
charge_max = 150
cooldown_min = 10
-/obj/effect/proc_holder/spell/targeted/conjure_item/cast(list/targets, mob/user = usr)
+/obj/effect/proc_holder/spell/conjure_item/create_new_targeting()
+ return new /datum/spell_targeting/self
+
+/obj/effect/proc_holder/spell/conjure_item/cast(list/targets, mob/user = usr)
if(item)
QDEL_NULL(item)
else
@@ -20,6 +21,6 @@
item = new item_type
C.put_in_hands(item)
-/obj/effect/proc_holder/spell/targeted/conjure_item/Destroy()
+/obj/effect/proc_holder/spell/conjure_item/Destroy()
QDEL_NULL(item)
return ..()
diff --git a/code/datums/spells/construct_spells.dm b/code/datums/spells/construct_spells.dm
index 071a8125b10..f51bf72e8e6 100644
--- a/code/datums/spells/construct_spells.dm
+++ b/code/datums/spells/construct_spells.dm
@@ -5,7 +5,13 @@
action_icon_state = "artificer"
action_background_icon_state = "bg_cult"
-/obj/effect/proc_holder/spell/aoe_turf/conjure/floor
+/obj/effect/proc_holder/spell/aoe_turf/conjure/build/create_new_targeting()
+ var/datum/spell_targeting/aoe/turf/T = new()
+ T.range = 0
+ return T
+
+
+/obj/effect/proc_holder/spell/aoe_turf/conjure/build/floor
name = "Summon Cult Floor"
desc = "This spell constructs a cult floor"
action_icon_state = "floorconstruct"
@@ -15,12 +21,11 @@
clothes_req = FALSE
invocation = "none"
invocation_type = "none"
- range = 0
summon_type = list(/turf/simulated/floor/engine/cult)
centcom_cancast = FALSE //Stop crashing the server by spawning turfs on transit tiles
holy_area_cancast = FALSE //Stops cult magic from working on holy ground eg: chapel
-/obj/effect/proc_holder/spell/aoe_turf/conjure/wall
+/obj/effect/proc_holder/spell/aoe_turf/conjure/build/wall
name = "Summon Cult Wall"
desc = "This spell constructs a cult wall"
action_icon_state = "cultforcewall"
@@ -30,12 +35,11 @@
clothes_req = FALSE
invocation = "none"
invocation_type = "none"
- range = 0
summon_type = list(/turf/simulated/wall/cult/artificer) //we don't want artificer-based runed metal farms
centcom_cancast = FALSE //Stop crashing the server by spawning turfs on transit tiles
holy_area_cancast = FALSE //Stops cult magic from working on holy ground eg: chapel
-/obj/effect/proc_holder/spell/aoe_turf/conjure/wall/reinforced
+/obj/effect/proc_holder/spell/aoe_turf/conjure/build/wall/reinforced
name = "Greater Construction"
desc = "This spell constructs a reinforced metal wall"
school = "conjuration"
@@ -43,14 +47,13 @@
clothes_req = FALSE
invocation = "none"
invocation_type = "none"
- range = 0
centcom_cancast = FALSE //Stop crashing the server by spawning turfs on transit tiles
holy_area_cancast = FALSE //Stops cult magic from working on holy ground eg: chapel
delay = 50
summon_type = list(/turf/simulated/wall/r_wall)
-/obj/effect/proc_holder/spell/aoe_turf/conjure/soulstone
+/obj/effect/proc_holder/spell/aoe_turf/conjure/build/soulstone
name = "Summon Soulstone"
desc = "This spell reaches into Redspace, summoning one of the legendary fragments across time and space"
action_icon_state = "summonsoulstone"
@@ -60,17 +63,16 @@
clothes_req = FALSE
invocation = "none"
invocation_type = "none"
- range = 0
holy_area_cancast = FALSE //Stops cult magic from working on holy ground eg: chapel
summon_type = list(/obj/item/soulstone)
-/obj/effect/proc_holder/spell/aoe_turf/conjure/soulstone/holy
+/obj/effect/proc_holder/spell/aoe_turf/conjure/build/soulstone/holy
action_icon_state = "summonsoulstone_holy"
summon_type = list(/obj/item/soulstone/anybody/purified)
-/obj/effect/proc_holder/spell/aoe_turf/conjure/pylon
+/obj/effect/proc_holder/spell/aoe_turf/conjure/build/pylon
name = "Cult Pylon"
desc = "This spell conjures a fragile crystal from Redspace. Makes for a convenient light source."
action_icon_state = "pylon"
@@ -80,13 +82,12 @@
clothes_req = FALSE
invocation = "none"
invocation_type = "none"
- range = 0
holy_area_cancast = FALSE //Stops cult magic from working on holy ground eg: chapel
summon_type = list(/obj/structure/cult/functional/pylon)
-/obj/effect/proc_holder/spell/aoe_turf/conjure/lesserforcewall
+/obj/effect/proc_holder/spell/aoe_turf/conjure/build/lesserforcewall
name = "Shield"
desc = "This spell creates a temporary forcefield to shield yourself and allies from incoming fire"
action_icon_state = "cultforcewall"
@@ -96,7 +97,6 @@
clothes_req = FALSE
invocation = "none"
invocation_type = "none"
- range = 0
holy_area_cancast = FALSE //Stops cult magic from working on holy ground eg: chapel
summon_type = list(/obj/effect/forcefield/cult)
summon_lifespan = 200
@@ -108,7 +108,7 @@
icon_state = "m_shield_cult"
light_color = LIGHT_COLOR_PURE_RED
-/obj/effect/proc_holder/spell/targeted/ethereal_jaunt/shift
+/obj/effect/proc_holder/spell/ethereal_jaunt/shift
name = "Phase Shift"
desc = "This spell allows you to pass through walls"
action_icon_state = "phaseshift"
@@ -122,7 +122,7 @@
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/do_jaunt(mob/living/target)
+/obj/effect/proc_holder/spell/ethereal_jaunt/shift/do_jaunt(mob/living/target)
target.set_light(0)
..()
if(isconstruct(target))
@@ -132,10 +132,10 @@
else
C.set_light(2, 3, l_color = SSticker.cultdat ? SSticker.cultdat.construct_glow : LIGHT_COLOR_BLOOD_MAGIC)
-/obj/effect/proc_holder/spell/targeted/ethereal_jaunt/shift/jaunt_steam(mobloc)
+/obj/effect/proc_holder/spell/ethereal_jaunt/shift/jaunt_steam(mobloc)
return
-/obj/effect/proc_holder/spell/targeted/projectile/magic_missile/lesser
+/obj/effect/proc_holder/spell/projectile/magic_missile/lesser
name = "Lesser Magic Missile"
desc = "This spell fires several, slow moving, magic projectiles at nearby targets."
action_background_icon_state = "bg_cult"
@@ -146,9 +146,15 @@
invocation_type = "none"
holy_area_cancast = FALSE //Stops cult magic from working on holy ground eg: chapel
proj_lifespan = 10
- max_targets = 6
-/obj/effect/proc_holder/spell/targeted/smoke/disable
+/obj/effect/proc_holder/spell/projectile/magic_missile/lesser/create_new_targeting()
+ var/datum/spell_targeting/targeted/T = new()
+ T.allowed_type = /mob/living
+ T.random_target = TRUE
+ T.max_targets = 6
+ return T
+
+/obj/effect/proc_holder/spell/smoke/disable
name = "Paralysing Smoke"
desc = "This spell spawns a cloud of paralysing smoke."
action_icon_state = "parasmoke"
@@ -159,8 +165,6 @@
invocation = "none"
invocation_type = "none"
holy_area_cancast = FALSE //Stops cult magic from working on holy ground eg: chapel
- range = -1
- include_user = 1
cooldown_min = 20 //25 deciseconds reduction per rank
smoke_spread = 3
diff --git a/code/datums/spells/dumbfire.dm b/code/datums/spells/dumbfire.dm
deleted file mode 100644
index 9efb93a0e7b..00000000000
--- a/code/datums/spells/dumbfire.dm
+++ /dev/null
@@ -1,84 +0,0 @@
-/obj/effect/proc_holder/spell/dumbfire
-
- var/projectile_type = ""
- var/activate_on_collision = 1
-
- var/proj_icon = 'icons/obj/projectiles.dmi'
- var/proj_icon_state = "spell"
- var/proj_name = "a spell projectile"
-
- var/proj_trail = 0 //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_type = /obj/effect/proc_holder/spell //IMPORTANT use only subtypes of this
-
- var/proj_insubstantial = 0 //if it can pass through dense objects or not
- var/proj_trigger_range = 1 //the range from target at which the projectile triggers cast(target)
-
- var/proj_lifespan = 100 //in deciseconds * proj_step_delay
- var/proj_step_delay = 1 //lower = faster
-
-/obj/effect/proc_holder/spell/dumbfire/choose_targets(mob/user = usr)
-
- var/turf/T = get_turf(usr)
- for(var/i = 1; i < range; i++)
- var/turf/new_turf = get_step(T, usr.dir)
- if(new_turf.density)
- break
- T = new_turf
- perform(list(T), user = user)
-
-/obj/effect/proc_holder/spell/dumbfire/cast(list/targets, mob/user = usr)
-
- for(var/turf/target in targets)
- spawn(0)
- var/obj/effect/proc_holder/spell/targeted/projectile
- projectile = new proj_type(user)
- projectile.icon = proj_icon
- projectile.icon_state = proj_icon_state
- projectile.dir = get_dir(projectile, target)
- projectile.name = proj_name
-
- var/current_loc = user.loc
-
- projectile.loc = current_loc
-
- for(var/i = 0,i < proj_lifespan,i++)
- if(!projectile)
- break
-
- if(proj_insubstantial)
- projectile.loc = get_step(projectile, projectile.dir)
- else
- step(projectile, projectile.dir)
-
- if(projectile.loc == current_loc || i == proj_lifespan)
- projectile.cast(current_loc)
- break
-
- var/mob/living/L = locate(/mob/living) in range(projectile, proj_trigger_range) - user
- if(L && L.stat != DEAD)
- projectile.cast(L.loc)
- break
-
- if(proj_trail && projectile)
- spawn(0)
- if(projectile)
- var/obj/effect/overlay/trail = new /obj/effect/overlay(projectile.loc)
- trail.icon = proj_trail_icon
- trail.icon_state = proj_trail_icon_state
- trail.density = 0
- spawn(proj_trail_lifespan)
- qdel(trail)
-
- current_loc = projectile.loc
- var/matrix/M = new
- M.Turn(dir2angle(projectile.dir))
- projectile.transform = M
-
- sleep(proj_step_delay)
-
- if(projectile)
- qdel(projectile)
diff --git a/code/datums/spells/emplosion.dm b/code/datums/spells/emplosion.dm
index cd84432aba8..4eba6b127bd 100644
--- a/code/datums/spells/emplosion.dm
+++ b/code/datums/spells/emplosion.dm
@@ -1,4 +1,4 @@
-/obj/effect/proc_holder/spell/targeted/emplosion
+/obj/effect/proc_holder/spell/emplosion
name = "Emplosion"
desc = "This spell emplodes an area."
@@ -7,7 +7,10 @@
action_icon_state = "emp"
-/obj/effect/proc_holder/spell/targeted/emplosion/cast(list/targets, mob/user = usr)
+/obj/effect/proc_holder/spell/emplosion/create_new_targeting()
+ return new /datum/spell_targeting/self
+
+/obj/effect/proc_holder/spell/emplosion/cast(list/targets, mob/user = usr)
for(var/mob/living/target in targets)
empulse(target.loc, emp_heavy, emp_light, 1)
diff --git a/code/datums/spells/ethereal_jaunt.dm b/code/datums/spells/ethereal_jaunt.dm
index 12b258fca64..c25d3e5f315 100644
--- a/code/datums/spells/ethereal_jaunt.dm
+++ b/code/datums/spells/ethereal_jaunt.dm
@@ -1,4 +1,4 @@
-/obj/effect/proc_holder/spell/targeted/ethereal_jaunt
+/obj/effect/proc_holder/spell/ethereal_jaunt
name = "Ethereal Jaunt"
desc = "This spell creates your ethereal form, temporarily making you invisible and able to pass through walls."
@@ -7,9 +7,7 @@
clothes_req = 1
invocation = "none"
invocation_type = "none"
- range = -1
cooldown_min = 100 //50 deciseconds reduction per rank
- include_user = 1
nonabstract_req = 1
centcom_cancast = 0 //Prevent people from getting to centcom
var/sound1 = 'sound/magic/ethereal_enter.ogg'
@@ -22,7 +20,10 @@
action_icon_state = "jaunt"
-/obj/effect/proc_holder/spell/targeted/ethereal_jaunt/cast(list/targets, mob/user = usr) //magnets, so mostly hardcoded
+/obj/effect/proc_holder/spell/ethereal_jaunt/create_new_targeting()
+ return new /datum/spell_targeting/self
+
+/obj/effect/proc_holder/spell/ethereal_jaunt/cast(list/targets, mob/user = usr) //magnets, so mostly hardcoded
playsound(get_turf(user), sound1, 50, 1, -1)
for(var/mob/living/target in targets)
if(!target.can_safely_leave_loc()) // No more brainmobs hopping out of their brains
@@ -30,7 +31,7 @@
continue
INVOKE_ASYNC(src, .proc/do_jaunt, target)
-/obj/effect/proc_holder/spell/targeted/ethereal_jaunt/proc/do_jaunt(mob/living/target)
+/obj/effect/proc_holder/spell/ethereal_jaunt/proc/do_jaunt(mob/living/target)
target.notransform = 1
var/turf/mobloc = get_turf(target)
var/obj/effect/dummy/spell_jaunt/holder = new jaunt_type_path(mobloc)
@@ -71,7 +72,7 @@
break
target.remove_CC()
-/obj/effect/proc_holder/spell/targeted/ethereal_jaunt/proc/jaunt_steam(mobloc)
+/obj/effect/proc_holder/spell/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()
diff --git a/code/datums/spells/explosion.dm b/code/datums/spells/explosion.dm
deleted file mode 100644
index 22580d9a896..00000000000
--- a/code/datums/spells/explosion.dm
+++ /dev/null
@@ -1,15 +0,0 @@
-/obj/effect/proc_holder/spell/targeted/explosion
- name = "Explosion"
- desc = "This spell explodes an area."
-
- var/ex_severe = 1
- var/ex_heavy = 2
- var/ex_light = 3
- var/ex_flash = 4
-
-/obj/effect/proc_holder/spell/targeted/explosion/cast(list/targets, mob/user = usr)
-
- for(var/mob/living/target in targets)
- explosion(target.loc,ex_severe,ex_heavy,ex_light,ex_flash)
-
- return
diff --git a/code/datums/spells/fake_gib.dm b/code/datums/spells/fake_gib.dm
index dc187576496..ac1074ac3d4 100644
--- a/code/datums/spells/fake_gib.dm
+++ b/code/datums/spells/fake_gib.dm
@@ -1,4 +1,4 @@
-/obj/effect/proc_holder/spell/targeted/touch/fake_disintegrate
+/obj/effect/proc_holder/spell/touch/fake_disintegrate
name = "Disintegrate"
desc = "This spell charges your hand with vile energy that can be used to violently explode victims."
hand_path = "/obj/item/melee/touch_attack/fake_disintegrate"
diff --git a/code/datums/spells/genetic.dm b/code/datums/spells/genetic.dm
index dce6966512a..4a03f2c5a6c 100644
--- a/code/datums/spells/genetic.dm
+++ b/code/datums/spells/genetic.dm
@@ -1,5 +1,4 @@
-/obj/effect/proc_holder/spell/targeted/genetic
- name = "Genetic"
+/obj/effect/proc_holder/spell/genetic
desc = "This spell inflicts a set of mutations and disabilities upon the target."
var/list/active_on = list()
@@ -7,7 +6,7 @@
var/list/mutations = list() // mutation defines. Set these in Initialize. Refactor this nonsense one day
var/duration = 100 // deciseconds
-/obj/effect/proc_holder/spell/targeted/genetic/cast(list/targets, mob/user = usr)
+/obj/effect/proc_holder/spell/genetic/cast(list/targets, mob/user = usr)
for(var/mob/living/target in targets)
if(!target.dna)
continue
@@ -21,12 +20,12 @@
if(duration < charge_max)
addtimer(CALLBACK(src, .proc/remove, target), duration, TIMER_OVERRIDE|TIMER_UNIQUE)
-/obj/effect/proc_holder/spell/targeted/genetic/Destroy()
+/obj/effect/proc_holder/spell/genetic/Destroy()
for(var/V in active_on)
remove(V)
return ..()
-/obj/effect/proc_holder/spell/targeted/genetic/proc/remove(mob/living/carbon/target)
+/obj/effect/proc_holder/spell/genetic/proc/remove(mob/living/carbon/target)
active_on -= target
if(!QDELETED(target))
for(var/A in mutations)
diff --git a/code/datums/spells/horsemask.dm b/code/datums/spells/horsemask.dm
index f22689067d8..ed6bf30354c 100644
--- a/code/datums/spells/horsemask.dm
+++ b/code/datums/spells/horsemask.dm
@@ -1,4 +1,4 @@
-/obj/effect/proc_holder/spell/targeted/click/horsemask
+/obj/effect/proc_holder/spell/horsemask
name = "Curse of the Horseman"
desc = "This spell triggers a curse on a target, causing them to wield an unremovable horse head mask. They will speak like a horse! Any masks they are wearing will be disintegrated. This spell does not require robes."
school = "transmutation"
@@ -9,18 +9,21 @@
stat_allowed = FALSE
invocation = "KN'A FTAGHU, PUCK 'BTHNK!"
invocation_type = "shout"
- range = 7
cooldown_min = 30 //30 deciseconds reduction per rank
- selection_type = "range"
selection_activated_message = "You start to quietly neigh an incantation. Click on or near a target to cast the spell."
selection_deactivated_message = "You stop neighing to yourself."
- allowed_type = /mob/living/carbon/human
action_icon_state = "barn"
sound = 'sound/magic/HorseHead_curse.ogg'
-/obj/effect/proc_holder/spell/targeted/click/horsemask/cast(list/targets, mob/user = usr)
+/obj/effect/proc_holder/spell/horsemask/create_new_targeting()
+ var/datum/spell_targeting/click/T = new()
+ T.selection_type = SPELL_SELECTION_RANGE
+ return T
+
+
+/obj/effect/proc_holder/spell/horsemask/cast(list/targets, mob/user = usr)
if(!targets.len)
to_chat(user, "No target found in range.")
return
diff --git a/code/datums/spells/infinite_guns.dm b/code/datums/spells/infinite_guns.dm
index bb6e30f1bf8..6e2cd66de94 100644
--- a/code/datums/spells/infinite_guns.dm
+++ b/code/datums/spells/infinite_guns.dm
@@ -1,9 +1,7 @@
-/obj/effect/proc_holder/spell/targeted/infinite_guns
+/obj/effect/proc_holder/spell/infinite_guns
name = "Lesser Summon Guns"
desc = "Why reload when you have infinite guns? Summons an unending stream of bolt action rifles. Requires both hands free to use."
invocation_type = "none"
- include_user = 1
- range = -1
school = "conjuration"
charge_max = 600
@@ -11,7 +9,10 @@
cooldown_min = 10 //Gun wizard
action_icon_state = "bolt_action"
-/obj/effect/proc_holder/spell/targeted/infinite_guns/cast(list/targets, mob/user = usr)
+/obj/effect/proc_holder/spell/infinite_guns/create_new_targeting()
+ return new /datum/spell_targeting/self
+
+/obj/effect/proc_holder/spell/infinite_guns/cast(list/targets, mob/user = usr)
for(var/mob/living/carbon/C in targets)
C.drop_item()
C.swap_hand()
diff --git a/code/datums/spells/inflict_handler.dm b/code/datums/spells/inflict_handler.dm
index 7615a37cfff..476f8540ee5 100644
--- a/code/datums/spells/inflict_handler.dm
+++ b/code/datums/spells/inflict_handler.dm
@@ -1,4 +1,4 @@
-/obj/effect/proc_holder/spell/targeted/inflict_handler
+/obj/effect/proc_holder/spell/inflict_handler
name = "Inflict Handler"
desc = "This spell blinds and/or destroys/damages/heals and/or weakens/stuns the target."
@@ -19,7 +19,10 @@
var/summon_type = null //this will put an obj at the target's location
-/obj/effect/proc_holder/spell/targeted/inflict_handler/cast(list/targets, mob/user = usr)
+/obj/effect/proc_holder/spell/inflict_handler/create_new_targeting()
+ return new /datum/spell_targeting/self // Dummy value since it is never used for this spell... why is this even a spell
+
+/obj/effect/proc_holder/spell/inflict_handler/cast(list/targets, mob/user = usr)
for(var/mob/living/target in targets)
switch(destroys)
diff --git a/code/datums/spells/knock.dm b/code/datums/spells/knock.dm
index 072bbf244e2..1e221cf2bab 100644
--- a/code/datums/spells/knock.dm
+++ b/code/datums/spells/knock.dm
@@ -7,12 +7,16 @@
clothes_req = 0
invocation = "AULIE OXIN FIERA"
invocation_type = "whisper"
- range = 3
cooldown_min = 20 //20 deciseconds reduction per rank
action_icon_state = "knock"
sound = 'sound/magic/knock.ogg'
+/obj/effect/proc_holder/spell/aoe_turf/knock/create_new_targeting()
+ var/datum/spell_targeting/aoe/turf/T = new()
+ T.range = 3
+ return T
+
/obj/effect/proc_holder/spell/aoe_turf/knock/cast(list/targets, mob/user = usr)
for(var/turf/T in targets)
for(var/obj/machinery/door/door in T.contents)
@@ -41,11 +45,14 @@
charge_max = 200
invocation = "MAIOR OXIN FIERA"
invocation_type = "shout"
- range = 7
level_max = 0 //Cannot be improved, quality of life since can't be refunded
cooldown_min = 200
var/used = FALSE
+/obj/effect/proc_holder/spell/aoe_turf/knock/greater/create_new_targeting()
+ var/datum/spell_targeting/aoe/turf/T = new()
+ return T
+
/obj/effect/proc_holder/spell/aoe_turf/knock/greater/cast(list/targets, mob/user = usr)
if(!used)
used = TRUE
diff --git a/code/datums/spells/lichdom.dm b/code/datums/spells/lichdom.dm
index b863738c4a0..625a16e885f 100644
--- a/code/datums/spells/lichdom.dm
+++ b/code/datums/spells/lichdom.dm
@@ -1,4 +1,4 @@
-/obj/effect/proc_holder/spell/targeted/lichdom
+/obj/effect/proc_holder/spell/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."
school = "necromancy"
@@ -7,10 +7,8 @@
centcom_cancast = 0
invocation = "NECREM IMORTIUM!"
invocation_type = "shout"
- range = -1
level_max = 0 //cannot be improved
cooldown_min = 10
- include_user = 1
var/obj/marked_item
var/mob/living/current_body
@@ -19,16 +17,19 @@
action_icon_state = "skeleton"
-/obj/effect/proc_holder/spell/targeted/lichdom/Destroy()
+/obj/effect/proc_holder/spell/lichdom/create_new_targeting()
+ return new /datum/spell_targeting/self
+
+/obj/effect/proc_holder/spell/lichdom/Destroy()
for(var/datum/mind/M in SSticker.mode.wizards) //Make sure no other bones are about
for(var/obj/effect/proc_holder/spell/S in M.spell_list)
- if(istype(S,/obj/effect/proc_holder/spell/targeted/lichdom) && S != src)
+ if(istype(S,/obj/effect/proc_holder/spell/lichdom) && S != src)
return ..()
if(existence_stops_round_end)
GLOB.configuration.gamemode.disable_certain_round_early_end = FALSE
return ..()
-/obj/effect/proc_holder/spell/targeted/lichdom/cast(list/targets, mob/user = usr)
+/obj/effect/proc_holder/spell/lichdom/cast(list/targets, mob/user = usr)
if(!GLOB.configuration.gamemode.disable_certain_round_early_end)
existence_stops_round_end = TRUE
GLOB.configuration.gamemode.disable_certain_round_early_end = TRUE
@@ -126,7 +127,7 @@
H.unEquip(H.head)
equip_lich(H)
-/obj/effect/proc_holder/spell/targeted/lichdom/proc/equip_lich(mob/living/carbon/human/H)
+/obj/effect/proc_holder/spell/lichdom/proc/equip_lich(mob/living/carbon/human/H)
H.equip_to_slot_or_del(new /obj/item/clothing/suit/wizrobe/black(H), slot_wear_suit)
H.equip_to_slot_or_del(new /obj/item/clothing/head/wizard/black(H), slot_head)
H.equip_to_slot_or_del(new /obj/item/clothing/shoes/sandal(H), slot_shoes)
diff --git a/code/datums/spells/lightning.dm b/code/datums/spells/lightning.dm
index 639ba34766f..08ad49803d4 100644
--- a/code/datums/spells/lightning.dm
+++ b/code/datums/spells/lightning.dm
@@ -1,4 +1,4 @@
-/obj/effect/proc_holder/spell/targeted/lightning
+/obj/effect/proc_holder/spell/lightning
name = "Lightning Bolt"
desc = "Throws a lightning bolt at the nearby enemy. Classic."
charge_type = "recharge"
@@ -6,10 +6,7 @@
clothes_req = 1
invocation = "UN'LTD P'WAH!"
invocation_type = "shout"
- range = 7
cooldown_min = 30
- selection_type = "view"
- random_target = 1
special_availability_check = 1
var/start_time = 0
var/ready = 0
@@ -18,21 +15,27 @@
var/sound/Snd // so far only way i can think of to stop a sound, thank MSO for the idea.
var/damaging = TRUE
-/obj/effect/proc_holder/spell/targeted/lightning/lightnian
+/obj/effect/proc_holder/spell/lightning/create_new_targeting()
+ var/datum/spell_targeting/targeted/T = new()
+ T.allowed_type = /mob/living
+ T.random_target = TRUE
+ return T
+
+/obj/effect/proc_holder/spell/lightning/lightnian
clothes_req = 0
invocation_type = "none"
damaging = 0
-/obj/effect/proc_holder/spell/targeted/lightning/Click()
+/obj/effect/proc_holder/spell/lightning/Click()
if(!ready && start_time == 0)
if(cast_check(TRUE, FALSE, usr))
StartChargeup()
else
- if(ready && cast_check(TRUE, TRUE, usr))
+ if(ready && cast_check(TRUE, FALSE, usr))
choose_targets()
return 1
-/obj/effect/proc_holder/spell/targeted/lightning/proc/StartChargeup(mob/user = usr)
+/obj/effect/proc_holder/spell/lightning/proc/StartChargeup(mob/user = usr)
ready = 1
to_chat(user, "You start gathering the power.")
Snd = new/sound('sound/magic/lightning_chargeup.ogg', channel = 7)
@@ -44,33 +47,29 @@
if(ready)
Discharge()
-/obj/effect/proc_holder/spell/targeted/lightning/proc/Reset(mob/user = usr)
+/obj/effect/proc_holder/spell/lightning/proc/Reset(mob/user = usr)
ready = 0
start_time = 0
if(halo)
user.overlays.Remove(halo)
-/obj/effect/proc_holder/spell/targeted/lightning/revert_cast(mob/user = usr)
+/obj/effect/proc_holder/spell/lightning/revert_cast(mob/user = usr)
to_chat(user, "No target found in range.")
Reset(user)
..()
-/obj/effect/proc_holder/spell/targeted/lightning/proc/Discharge(mob/user = usr)
+/obj/effect/proc_holder/spell/lightning/proc/Discharge(mob/user = usr)
var/mob/living/M = user
to_chat(M, "You lose control over the spell.")
Reset(user)
start_recharge()
-/obj/effect/proc_holder/spell/targeted/lightning/cast(list/targets, mob/user = usr)
+/obj/effect/proc_holder/spell/lightning/cast(list/targets, mob/user = usr)
ready = 0
var/mob/living/target = targets[1]
Snd = sound(null, repeat = 0, wait = 1, channel = Snd.channel) //byond, why you suck?
playsound(get_turf(user), Snd, 50, 0)// 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, "They are too far away!")
- Reset(user)
- return
playsound(get_turf(user), 'sound/magic/lightningbolt.ogg', 50, 1)
user.Beam(target,icon_state="lightning[rand(1,12)]",icon='icons/effects/effects.dmi',time=5)
@@ -83,7 +82,7 @@
Bolt(user,target,0,bounces,user)
Reset(user)
-/obj/effect/proc_holder/spell/targeted/lightning/proc/Bolt(mob/origin, mob/living/target, bolt_energy, bounces, mob/user = usr)
+/obj/effect/proc_holder/spell/lightning/proc/Bolt(mob/origin, mob/living/target, bolt_energy, bounces, mob/user = usr)
origin.Beam(target,icon_state="lightning[rand(1,12)]", icon='icons/effects/effects.dmi', time=5)
var/mob/living/current = target
if(bounces < 1)
@@ -109,7 +108,7 @@
current.AdjustJitter(-1000, bound_lower = 10) //Still jittery, but vastly less
playsound(get_turf(current), 'sound/magic/lightningshock.ogg', 50, 1, -1)
var/list/possible_targets = new
- for(var/mob/living/M in view_or_range(range,target,"view"))
+ for(var/mob/living/M in view_or_range(targeting.range, target, "view"))
if(user == M || target == M && los_check(current,M)) // || origin == M ? Not sure double shockings is good or not
continue
possible_targets += M
diff --git a/code/datums/spells/magnet.dm b/code/datums/spells/magnet.dm
index 155a3cb0b45..21bf77d35b3 100644
--- a/code/datums/spells/magnet.dm
+++ b/code/datums/spells/magnet.dm
@@ -1,4 +1,5 @@
-/obj/effect/proc_holder/spell/targeted/magnet
+// Disclaimer. This ain't working. Probably never worked
+/obj/effect/proc_holder/spell/magnet
name = "Magnetic Pull"
desc = "Pulls metalic objects from enemies hands with the power of MAGNETS."
charge_type = "recharge"
@@ -6,10 +7,7 @@
clothes_req = 0
invocation = "UN'LTD P'WAH!"
invocation_type = "none"
- range = 7
cooldown_min = 30
- selection_type = "view"
- random_target = 1
var/energy = 0
var/ready = 0
var/start_time = 0
@@ -17,17 +15,22 @@
var/sound/Snd // so far only way i can think of to stop a sound, thank MSO for the idea.
action_icon_state = "tech"
+/obj/effect/proc_holder/spell/magnet/create_new_targeting()
+ var/datum/spell_targeting/targeted/T = new()
+ T.random_target = TRUE
+ T.allowed_type = /mob/living
+ return T
-/obj/effect/proc_holder/spell/targeted/magnet/Click()
+/obj/effect/proc_holder/spell/magnet/Click()
if(!ready && start_time == 0)
if(cast_check(TRUE, FALSE, usr))
StartChargeup()
else
- if(ready && cast_check(TRUE, TRUE, usr))
- choose_targets()
+ if(ready && cast_check(TRUE, FALSE, usr))
+ choose_targets(usr)
return 1
-/obj/effect/proc_holder/spell/targeted/magnet/proc/StartChargeup(mob/user = usr)
+/obj/effect/proc_holder/spell/magnet/proc/StartChargeup(mob/user = usr)
ready = 1
to_chat(user, "You start gathering the power.")
Snd = new/sound('sound/magic/lightning_chargeup.ogg', channel = 7)
@@ -39,34 +42,30 @@
if(ready)
Discharge()
-/obj/effect/proc_holder/spell/targeted/magnet/proc/Reset(mob/user = usr)
+/obj/effect/proc_holder/spell/magnet/proc/Reset(mob/user = usr)
ready = 0
energy = 0
start_time = 0
if(halo)
user.overlays.Remove(halo)
-/obj/effect/proc_holder/spell/targeted/magnet/revert_cast(mob/user = usr)
+/obj/effect/proc_holder/spell/magnet/revert_cast(mob/user = usr)
to_chat(user, "No target found in range.")
Reset(user)
..()
-/obj/effect/proc_holder/spell/targeted/magnet/proc/Discharge(mob/user = usr)
+/obj/effect/proc_holder/spell/magnet/proc/Discharge(mob/user = usr)
var/mob/living/M = user
to_chat(M, "You lose control over the power.")
Reset(user)
start_recharge()
-/obj/effect/proc_holder/spell/targeted/magnet/cast(list/targets, mob/user = usr)
+/obj/effect/proc_holder/spell/magnet/cast(list/targets, mob/user = usr)
ready = 0
var/mob/living/target = targets[1]
Snd = sound(null, repeat = 0, wait = 1, channel = Snd.channel) //byond, why you suck?
playsound(get_turf(user), Snd, 50, 0)// 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, "They are too far away!")
- Reset(user)
- return
user.Beam(target,icon_state="lightning",icon='icons/effects/effects.dmi',time=5)
@@ -94,7 +93,7 @@
Bolt(user,target,energy,5,user)
Reset(user)
-/obj/effect/proc_holder/spell/targeted/magnet/proc/Bolt(mob/origin,mob/target,bolt_energy,bounces, mob/user = usr)
+/obj/effect/proc_holder/spell/magnet/proc/Bolt(mob/origin,mob/target,bolt_energy,bounces, mob/user = usr)
origin.Beam(target, icon_state="lightning", icon='icons/effects/effects.dmi', time=5)
var/mob/living/carbon/current = target
if(bounces < 1)
@@ -114,7 +113,7 @@
I.throw_at(user, I.throw_range, 4, target)
playsound(get_turf(current), 'sound/machines/defib_zap.ogg', 50, 1, -1)
var/list/possible_targets = new
- for(var/mob/living/M in view_or_range(range,target,"view"))
+ for(var/mob/living/M in view_or_range(targeting.range, target, "view"))
if(user == M || target == M && los_check(current,M)) // || origin == M ? Not sure double shockings is good or not
continue
possible_targets += M
diff --git a/code/datums/spells/mime.dm b/code/datums/spells/mime.dm
index 985af15f349..00bcce176d9 100644
--- a/code/datums/spells/mime.dm
+++ b/code/datums/spells/mime.dm
@@ -1,4 +1,4 @@
-/obj/effect/proc_holder/spell/aoe_turf/conjure/mime_wall
+/obj/effect/proc_holder/spell/aoe_turf/conjure/build/mime_wall
name = "Invisible Wall"
desc = "The mime's performance transmutates into physical reality."
school = "mime"
@@ -9,14 +9,13 @@
summon_lifespan = 300
charge_max = 300
clothes_req = 0
- range = 0
cast_sound = null
human_req = 1
action_icon_state = "mime"
action_background_icon_state = "bg_mime"
-/obj/effect/proc_holder/spell/aoe_turf/conjure/mime_wall/Click()
+/obj/effect/proc_holder/spell/aoe_turf/conjure/build/mime_wall/Click()
if(usr && usr.mind)
if(!usr.mind.miming)
to_chat(usr, "You must dedicate yourself to silence first.")
@@ -26,22 +25,22 @@
invocation_type ="none"
..()
+/obj/effect/proc_holder/spell/mime/create_new_targeting()
+ return new /datum/spell_targeting/self
-/obj/effect/proc_holder/spell/targeted/mime/speak
+/obj/effect/proc_holder/spell/mime/speak
name = "Speech"
desc = "Make or break a vow of silence."
school = "mime"
panel = "Mime"
clothes_req = 0
charge_max = 3000
- range = -1
- include_user = 1
human_req = 1
action_icon_state = "mime_silence"
action_background_icon_state = "bg_mime"
-/obj/effect/proc_holder/spell/targeted/mime/speak/Click()
+/obj/effect/proc_holder/spell/mime/speak/Click()
if(!usr)
return
if(!ishuman(usr))
@@ -53,7 +52,7 @@
still_recharging_msg = "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)
+/obj/effect/proc_holder/spell/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)
@@ -63,7 +62,7 @@
//Advanced Mimery traitor item spells
-/obj/effect/proc_holder/spell/targeted/forcewall/mime
+/obj/effect/proc_holder/spell/forcewall/mime
name = "Invisible Greater Wall"
desc = "Form an invisible three tile wide blockade."
school = "mime"
@@ -74,14 +73,12 @@
charge_max = 600
sound = null
clothes_req = FALSE
- range = -1
- include_user = TRUE
action_icon_state = "mime_bigwall"
action_background_icon_state = "bg_mime"
large = TRUE
-/obj/effect/proc_holder/spell/targeted/forcewall/mime/Click()
+/obj/effect/proc_holder/spell/forcewall/mime/Click()
if(usr && usr.mind)
if(!usr.mind.miming)
to_chat(usr, "You must dedicate yourself to silence first.")
@@ -91,22 +88,20 @@
invocation_type ="none"
..()
-/obj/effect/proc_holder/spell/targeted/mime/fingergun
+/obj/effect/proc_holder/spell/mime/fingergun
name = "Finger Gun"
desc = "Shoot lethal, silencing bullets out of your fingers! 3 bullets available per cast. Use your fingers to holster them manually."
school = "mime"
panel = "Mime"
clothes_req = 0
charge_max = 300
- range = -1
- include_user = 1
human_req = 1
action_icon_state = "fingergun"
action_background_icon_state = "bg_mime"
var/gun = /obj/item/gun/projectile/revolver/fingergun
-/obj/effect/proc_holder/spell/targeted/mime/fingergun/cast(list/targets, mob/user = usr)
+/obj/effect/proc_holder/spell/mime/fingergun/cast(list/targets, mob/user = usr)
for(var/mob/living/carbon/human/C in targets)
if(!istype(C.get_active_hand(), gun) && !istype(C.get_inactive_hand(), gun))
to_chat(user, "You draw your fingers!")
@@ -116,14 +111,14 @@
to_chat(user, "Holster your fingers first.")
revert_cast(user)
-/obj/effect/proc_holder/spell/targeted/mime/fingergun/fake
+/obj/effect/proc_holder/spell/mime/fingergun/fake
desc = "Pretend you're shooting bullets out of your fingers! 3 bullets available per cast. Use your fingers to holster them manually."
gun = /obj/item/gun/projectile/revolver/fingergun/fake
// Mime Spellbooks
/obj/item/spellbook/oneuse/mime
- spell = /obj/effect/proc_holder/spell/aoe_turf/conjure/mime_wall
+ spell = /obj/effect/proc_holder/spell/aoe_turf/conjure/build/mime_wall
spellname = "Invisible Wall"
name = "Miming Manual : "
desc = "It contains various pictures of mimes mid-performance, aswell as some illustrated tutorials."
@@ -150,19 +145,19 @@
/obj/item/spellbook/oneuse/mime/onlearned(mob/user)
used = 1
- if(!locate(/obj/effect/proc_holder/spell/targeted/mime/speak) in user.mind.spell_list) //add vow of silence if not known by user
- user.mind.AddSpell(new /obj/effect/proc_holder/spell/targeted/mime/speak)
+ if(!locate(/obj/effect/proc_holder/spell/mime/speak) in user.mind.spell_list) //add vow of silence if not known by user
+ user.mind.AddSpell(new /obj/effect/proc_holder/spell/mime/speak)
to_chat(user, "You have learned how to use silence to improve your performance.")
/obj/item/spellbook/oneuse/mime/fingergun
- spell = /obj/effect/proc_holder/spell/targeted/mime/fingergun
+ spell = /obj/effect/proc_holder/spell/mime/fingergun
spellname = "Finger Gun"
desc = "It contains illustrations of guns and how to mime them."
/obj/item/spellbook/oneuse/mime/fingergun/fake
- spell = /obj/effect/proc_holder/spell/targeted/mime/fingergun/fake
+ spell = /obj/effect/proc_holder/spell/mime/fingergun/fake
/obj/item/spellbook/oneuse/mime/greaterwall
- spell = /obj/effect/proc_holder/spell/targeted/forcewall/mime
+ spell = /obj/effect/proc_holder/spell/forcewall/mime
spellname = "Invisible Greater Wall"
desc = "It contains illustrations of the great walls of human history."
diff --git a/code/datums/spells/mime_malaise.dm b/code/datums/spells/mime_malaise.dm
index 03d5c07fb0f..5d56c103112 100644
--- a/code/datums/spells/mime_malaise.dm
+++ b/code/datums/spells/mime_malaise.dm
@@ -1,4 +1,4 @@
-/obj/effect/proc_holder/spell/targeted/touch/mime_malaise
+/obj/effect/proc_holder/spell/touch/mime_malaise
name = "Mime Malaise"
desc = "A spell popular with theater nerd wizards and contrarian pranksters, this spell will put on a mime costume on the target, \
stun them so that they may contemplate Art, and silence them. \
diff --git a/code/datums/spells/mimic.dm b/code/datums/spells/mimic.dm
index 4f7ba9f6951..adac49bdbcf 100644
--- a/code/datums/spells/mimic.dm
+++ b/code/datums/spells/mimic.dm
@@ -1,15 +1,11 @@
-/obj/effect/proc_holder/spell/targeted/click/mimic
+/obj/effect/proc_holder/spell/mimic
name = "Mimic"
desc = "Learn a new form to mimic or become one of your known forms"
clothes_req = FALSE
charge_max = 3 SECONDS
- include_user = TRUE // To change forms
action_icon_state = "genetic_morph"
- allowed_type = /atom/movable
- auto_target_single = FALSE
- click_radius = -1
selection_activated_message = "Click on a target to remember it's form. Click on yourself to change form."
- create_logs = FALSE
+ create_attack_logs = FALSE
action_icon_state = "morph_mimic"
/// Which form is currently selected
var/datum/mimic_form/selected_form
@@ -25,7 +21,15 @@
var/static/list/black_listed_form_types = list(/obj/screen, /obj/singularity, /obj/effect, /mob/living/simple_animal/hostile/megafauna, /atom/movable/lighting_object, /obj/machinery/dna_vault,
/obj/machinery/power/bluespace_tap, /obj/structure/sign/barsign, /obj/machinery/atmospherics/unary/cryo_cell)
-/obj/effect/proc_holder/spell/targeted/click/mimic/valid_target(atom/target, user)
+/obj/effect/proc_holder/spell/mimic/create_new_targeting()
+ var/datum/spell_targeting/click/T = new
+ T.include_user = TRUE // To change forms
+ T.allowed_type = /atom/movable
+ T.try_auto_target = FALSE
+ T.click_radius = -1
+ return T
+
+/obj/effect/proc_holder/spell/mimic/valid_target(atom/target, user)
if(is_type_in_list(target, black_listed_form_types))
return FALSE
if(istype(target, /atom/movable))
@@ -36,7 +40,7 @@
return FALSE
return ..()
-/obj/effect/proc_holder/spell/targeted/click/mimic/cast(list/targets, mob/user)
+/obj/effect/proc_holder/spell/mimic/cast(list/targets, mob/user)
var/atom/movable/A = targets[1]
if(A == user)
INVOKE_ASYNC(src, .proc/pick_form, user)
@@ -44,7 +48,7 @@
INVOKE_ASYNC(src, .proc/remember_form, A, user)
-/obj/effect/proc_holder/spell/targeted/click/mimic/proc/remember_form(atom/movable/A, mob/user)
+/obj/effect/proc_holder/spell/mimic/proc/remember_form(atom/movable/A, mob/user)
if(A.name in available_forms)
to_chat(user, "[A] is already an available form.")
revert_cast(user)
@@ -68,7 +72,7 @@
available_forms[A.name] = new /datum/mimic_form(A, user)
to_chat(user, "You learn the form of [A].")
-/obj/effect/proc_holder/spell/targeted/click/mimic/proc/pick_form(mob/user)
+/obj/effect/proc_holder/spell/mimic/proc/pick_form(mob/user)
if(!length(available_forms) && !selected_form)
to_chat(user, "No available forms. Learn more forms by using this spell on other objects first.")
revert_cast(user)
@@ -94,7 +98,7 @@
return
take_form(available_forms[what], user)
-/obj/effect/proc_holder/spell/targeted/click/mimic/proc/take_form(datum/mimic_form/form, mob/user)
+/obj/effect/proc_holder/spell/mimic/proc/take_form(datum/mimic_form/form, mob/user)
var/old_name = "[user]"
if(ishuman(user))
// Not fully finished yet
@@ -117,10 +121,10 @@
selected_form = form
-/obj/effect/proc_holder/spell/targeted/click/mimic/proc/show_change_form_message(mob/user, old_name, new_name)
+/obj/effect/proc_holder/spell/mimic/proc/show_change_form_message(mob/user, old_name, new_name)
user.visible_message("[old_name] contorts and slowly becomes [new_name]!", "You take form of [new_name].", "You hear loud cracking noises!")
-/obj/effect/proc_holder/spell/targeted/click/mimic/proc/restore_form(mob/user, show_message = TRUE)
+/obj/effect/proc_holder/spell/mimic/proc/restore_form(mob/user, show_message = TRUE)
selected_form = null
var/old_name = "[user]"
@@ -142,21 +146,21 @@
UnregisterSignal(user, list(COMSIG_PARENT_EXAMINE, COMSIG_MOB_DEATH))
-/obj/effect/proc_holder/spell/targeted/click/mimic/proc/show_restore_form_message(mob/user, old_name, new_name)
+/obj/effect/proc_holder/spell/mimic/proc/show_restore_form_message(mob/user, old_name, new_name)
user.visible_message("[old_name] shakes and contorts and quickly becomes [new_name]!", "You take return to your normal self.", "You hear loud cracking noises!")
-/obj/effect/proc_holder/spell/targeted/click/mimic/proc/examine_override(datum/source, mob/user, list/examine_list)
+/obj/effect/proc_holder/spell/mimic/proc/examine_override(datum/source, mob/user, list/examine_list)
examine_list.Cut()
examine_list += selected_form.examine_text
if(!perfect_disguise && get_dist(user, source) <= 3)
examine_list += "It doesn't look quite right..."
-/obj/effect/proc_holder/spell/targeted/click/mimic/proc/on_death(mob/user, gibbed)
+/obj/effect/proc_holder/spell/mimic/proc/on_death(mob/user, gibbed)
if(!gibbed)
restore_form(user, FALSE)
show_death_message(user)
-/obj/effect/proc_holder/spell/targeted/click/mimic/proc/show_death_message(mob/user)
+/obj/effect/proc_holder/spell/mimic/proc/show_death_message(mob/user)
user.visible_message("[user] shakes and contorts as [user.p_they()] die[user.p_s()], returning to [user.p_their()] true form!", "Your disguise fails as your life forces drain away.", "You hear loud cracking noises followed by a thud!")
@@ -174,30 +178,34 @@
name = form.name
-/obj/effect/proc_holder/spell/targeted/click/mimic/morph
+/obj/effect/proc_holder/spell/mimic/morph
action_background_icon_state = "bg_morph"
-/obj/effect/proc_holder/spell/targeted/click/mimic/morph/valid_target(atom/target, user)
+/obj/effect/proc_holder/spell/mimic/morph/create_new_handler()
+ var/datum/spell_handler/morph/H = new
+ return H
+
+/obj/effect/proc_holder/spell/mimic/morph/valid_target(atom/target, user)
if(target != user && istype(target, /mob/living/simple_animal/hostile/morph))
return FALSE
return ..()
-/obj/effect/proc_holder/spell/targeted/click/mimic/morph/take_form(datum/mimic_form/form, mob/living/simple_animal/hostile/morph/user)
+/obj/effect/proc_holder/spell/mimic/morph/take_form(datum/mimic_form/form, mob/living/simple_animal/hostile/morph/user)
..()
user.assume()
-/obj/effect/proc_holder/spell/targeted/click/mimic/morph/restore_form(mob/living/simple_animal/hostile/morph/user, show_message = TRUE)
+/obj/effect/proc_holder/spell/mimic/morph/restore_form(mob/living/simple_animal/hostile/morph/user, show_message = TRUE)
..()
user.restore()
-/obj/effect/proc_holder/spell/targeted/click/mimic/morph/show_change_form_message(mob/user, old_name, new_name)
+/obj/effect/proc_holder/spell/mimic/morph/show_change_form_message(mob/user, old_name, new_name)
user.visible_message("[old_name] suddenly twists and changes shape, becoming a copy of [new_name]!", \
"You twist your body and assume the form of [new_name].")
-/obj/effect/proc_holder/spell/targeted/click/mimic/morph/show_restore_form_message(mob/user, old_name, new_name)
+/obj/effect/proc_holder/spell/mimic/morph/show_restore_form_message(mob/user, old_name, new_name)
user.visible_message("[old_name] suddenly collapses in on itself, dissolving into a pile of green flesh!", \
"You reform to your normal body.")
-/obj/effect/proc_holder/spell/targeted/click/mimic/morph/show_death_message(mob/user)
+/obj/effect/proc_holder/spell/mimic/morph/show_death_message(mob/user)
user.visible_message("[user] twists and dissolves into a pile of green flesh!", \
"Your skin ruptures! Your flesh breaks apart! No disguise can ward off de--")
diff --git a/code/datums/spells/mind_transfer.dm b/code/datums/spells/mind_transfer.dm
index e4924ee1c2f..2c3b26c6693 100644
--- a/code/datums/spells/mind_transfer.dm
+++ b/code/datums/spells/mind_transfer.dm
@@ -1,4 +1,4 @@
-/obj/effect/proc_holder/spell/targeted/click/mind_transfer
+/obj/effect/proc_holder/spell/mind_transfer
name = "Mind Transfer"
desc = "This spell allows the user to switch bodies with a target."
@@ -7,8 +7,6 @@
clothes_req = 0
invocation = "GIN'YU CAPAN"
invocation_type = "whisper"
- range = 1
- click_radius = 0 // Still gotta be pretty accurate
selection_activated_message = "You prepare to transfer your mind. Click on a target to cast the spell."
selection_deactivated_message = "You decide that your current form is good enough."
cooldown_min = 200 //100 deciseconds reduction per rank
@@ -17,9 +15,14 @@
var/paralysis_amount_victim = 20 //how much the victim is paralysed for after the spell
action_icon_state = "mindswap"
-/obj/effect/proc_holder/spell/targeted/click/mind_transfer/valid_target(mob/living/target, user)
- if(!..())
- return FALSE
+/obj/effect/proc_holder/spell/mind_transfer/create_new_targeting()
+ var/datum/spell_targeting/click/T = new()
+ T.allowed_type = /mob/living
+ T.range = 1
+ T.click_radius = 0
+ return T
+
+/obj/effect/proc_holder/spell/mind_transfer/valid_target(mob/living/target, mob/user)
return target.stat != DEAD && target.key && target.mind
/*
@@ -27,9 +30,9 @@ Urist: I don't feel like figuring out how you store object spells so I'm leaving
Make sure spells that are removed from spell_list are actually removed and deleted when mind transfering.
Also, you never added distance checking after target is selected. I've went ahead and did that.
*/
-/obj/effect/proc_holder/spell/targeted/click/mind_transfer/cast(list/targets, mob/user = usr)
+/obj/effect/proc_holder/spell/mind_transfer/cast(list/targets, mob/user = usr)
- var/mob/living/target = targets[range]
+ var/mob/living/target = targets[1]
if(user.suiciding)
to_chat(user, "You're killing yourself! You can't concentrate enough to do this!")
diff --git a/code/datums/spells/night_vision.dm b/code/datums/spells/night_vision.dm
index 1327b4ffcee..cc90dbbe45d 100644
--- a/code/datums/spells/night_vision.dm
+++ b/code/datums/spells/night_vision.dm
@@ -1,4 +1,4 @@
-/obj/effect/proc_holder/spell/targeted/night_vision
+/obj/effect/proc_holder/spell/night_vision
name = "Toggle Nightvision"
desc = "Toggle your nightvision mode."
@@ -6,10 +6,11 @@
clothes_req = 0
message = "You toggle your night vision!"
- range = -1
- include_user = 1
-/obj/effect/proc_holder/spell/targeted/night_vision/cast(list/targets, mob/user = usr)
+/obj/effect/proc_holder/spell/night_vision/create_new_targeting()
+ return new /datum/spell_targeting/self
+
+/obj/effect/proc_holder/spell/night_vision/cast(list/targets, mob/user = usr)
for(var/mob/living/target in targets)
switch(target.lighting_alpha)
if (LIGHTING_PLANE_ALPHA_VISIBLE)
diff --git a/code/datums/spells/projectile.dm b/code/datums/spells/projectile.dm
index 955aa6e3537..a9789ba4795 100644
--- a/code/datums/spells/projectile.dm
+++ b/code/datums/spells/projectile.dm
@@ -1,5 +1,4 @@
-/obj/effect/proc_holder/spell/targeted/projectile
- name = "Projectile"
+/obj/effect/proc_holder/spell/projectile
desc = "This spell summons projectiles which try to hit the targets."
var/proj_icon = 'icons/obj/projectiles.dmi'
@@ -11,7 +10,7 @@
var/proj_trail_icon = 'icons/obj/wizard.dmi'
var/proj_trail_icon_state = "trail"
- var/proj_type = "/obj/effect/proc_holder/spell/targeted" //IMPORTANT use only subtypes of this
+ var/proj_type = "/obj/effect/proc_holder/spell" //IMPORTANT use only subtypes of this
var/proj_lingering = 0 //if it lingers or disappears upon hitting an obstacle
var/proj_homing = 1 //if it follows the target
@@ -21,16 +20,16 @@
var/proj_lifespan = 15 //in deciseconds * proj_step_delay
var/proj_step_delay = 1 //lower = faster
-/obj/effect/proc_holder/spell/targeted/projectile/cast(list/targets, mob/user = usr)
+/obj/effect/proc_holder/spell/projectile/cast(list/targets, mob/user = usr)
for(var/mob/living/target in targets)
spawn(0)
- var/obj/effect/proc_holder/spell/targeted/projectile
+ var/obj/effect/proc_holder/spell/projectile
if(istext(proj_type))
var/projectile_type = text2path(proj_type)
projectile = new projectile_type(user)
if(istype(proj_type,/obj/effect/proc_holder/spell))
- projectile = new /obj/effect/proc_holder/spell/targeted/trigger(user)
+ projectile = new /obj/effect/proc_holder/spell/trigger(user)
projectile:linked_spells += proj_type
projectile.icon = proj_icon
projectile.icon_state = proj_icon_state
diff --git a/code/datums/spells/rathens.dm b/code/datums/spells/rathens.dm
index 4d98be324b2..939769f435b 100644
--- a/code/datums/spells/rathens.dm
+++ b/code/datums/spells/rathens.dm
@@ -1,17 +1,19 @@
-/obj/effect/proc_holder/spell/targeted/rathens
+/obj/effect/proc_holder/spell/rathens
name = "Rathen's Secret"
desc = "Summons a powerful shockwave around you that tears the appendix and limbs off of enemies."
charge_max = 500
clothes_req = 1
invocation = "APPEN NATH!"
invocation_type = "shout"
- max_targets = 0
- range = 7
cooldown_min = 200
- selection_type = "view"
action_icon_state = "lungpunch"
-/obj/effect/proc_holder/spell/targeted/rathens/cast(list/targets, mob/user = usr)
+/obj/effect/proc_holder/spell/rathens/create_new_targeting()
+ var/datum/spell_targeting/targeted/T = new()
+ T.max_targets = INFINITY
+ return T
+
+/obj/effect/proc_holder/spell/rathens/cast(list/targets, mob/user = usr)
for(var/mob/living/carbon/human/H in targets)
var/datum/effect_system/smoke_spread/s = new
s.set_up(5, 0, H)
diff --git a/code/datums/spells/rod_form.dm b/code/datums/spells/rod_form.dm
index 265d0423a95..bde964a854a 100644
--- a/code/datums/spells/rod_form.dm
+++ b/code/datums/spells/rod_form.dm
@@ -1,12 +1,10 @@
-/obj/effect/proc_holder/spell/targeted/rod_form
+/obj/effect/proc_holder/spell/rod_form
name = "Rod Form"
desc = "Take on the form of an immovable rod, destroying all in your path."
clothes_req = 1
human_req = 0
charge_max = 600
cooldown_min = 200
- range = -1
- include_user = 1
invocation = "CLANG!"
invocation_type = "shout"
action_icon_state = "immrod"
@@ -15,7 +13,10 @@
sound = 'sound/effects/whoosh.ogg'
var/rod_delay = 2
-/obj/effect/proc_holder/spell/targeted/rod_form/cast(list/targets,mob/user = usr)
+/obj/effect/proc_holder/spell/rod_form/create_new_targeting()
+ return new /datum/spell_targeting/self
+
+/obj/effect/proc_holder/spell/rod_form/cast(list/targets,mob/user = usr)
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(M, M.dir, (15 + spell_level * 3)), rod_delay)
diff --git a/code/datums/spells/shapeshift.dm b/code/datums/spells/shapeshift.dm
index 52aa5a266c3..577d0ce573c 100644
--- a/code/datums/spells/shapeshift.dm
+++ b/code/datums/spells/shapeshift.dm
@@ -1,12 +1,10 @@
-/obj/effect/proc_holder/spell/targeted/shapeshift
+/obj/effect/proc_holder/spell/shapeshift
name = "Shapechange"
desc = "Take on the shape of another for a time to use their natural abilities. Once you've made your choice it cannot be changed."
clothes_req = 0
human_req = 0
charge_max = 200
cooldown_min = 50
- range = -1
- include_user = 1
invocation = "RAC'WA NO!"
invocation_type = "shout"
action_icon_state = "shapeshift"
@@ -19,7 +17,10 @@
/mob/living/simple_animal/bot/ed209,
/mob/living/simple_animal/hostile/construct/armoured)
-/obj/effect/proc_holder/spell/targeted/shapeshift/cast(list/targets, mob/user = usr)
+/obj/effect/proc_holder/spell/shapeshift/create_new_targeting()
+ return new /datum/spell_targeting/self
+
+/obj/effect/proc_holder/spell/shapeshift/cast(list/targets, mob/user = usr)
for(var/mob/living/M in targets)
if(!shapeshift_type)
var/list/animal_list = list()
@@ -35,7 +36,7 @@
else
Shapeshift(M)
-/obj/effect/proc_holder/spell/targeted/shapeshift/proc/Shapeshift(mob/living/caster)
+/obj/effect/proc_holder/spell/shapeshift/proc/Shapeshift(mob/living/caster)
for(var/mob/living/M in caster)
if(M.status_flags & GODMODE)
to_chat(caster, "You're already shapeshifted!")
@@ -52,7 +53,7 @@
caster.mind.transfer_to(shape)
-/obj/effect/proc_holder/spell/targeted/shapeshift/proc/Restore(mob/living/shape)
+/obj/effect/proc_holder/spell/shapeshift/proc/Restore(mob/living/shape)
var/mob/living/caster
for(var/mob/living/M in shape)
if(M in current_casters)
@@ -71,7 +72,7 @@
shape.mind.transfer_to(caster)
qdel(shape) //Gib it maybe ?
-/obj/effect/proc_holder/spell/targeted/shapeshift/dragon
+/obj/effect/proc_holder/spell/shapeshift/dragon
name = "Dragon Form"
desc = "Take on the shape a lesser ash drake after a short delay."
invocation = "*scream"
@@ -81,7 +82,7 @@
current_casters = list()
possible_shapes = list(/mob/living/simple_animal/hostile/megafauna/dragon/lesser)
-/obj/effect/proc_holder/spell/targeted/shapeshift/dragon/Shapeshift(mob/living/caster)
+/obj/effect/proc_holder/spell/shapeshift/dragon/Shapeshift(mob/living/caster)
caster.visible_message("[caster] screams in agony as bones and claws erupt out of their flesh!",
"You begin channeling the transformation.")
if(!do_after(caster, 5 SECONDS, FALSE, caster))
@@ -89,7 +90,7 @@
return
return ..()
-/obj/effect/proc_holder/spell/targeted/shapeshift/bats
+/obj/effect/proc_holder/spell/shapeshift/bats
name = "Bat Form"
desc = "Take on the shape of a swarm of bats."
invocation = "none"
@@ -102,7 +103,7 @@
current_casters = list()
possible_shapes = list(/mob/living/simple_animal/hostile/scarybat/adminvampire)
-/obj/effect/proc_holder/spell/targeted/shapeshift/hellhound
+/obj/effect/proc_holder/spell/shapeshift/hellhound
name = "Lesser Hellhound Form"
desc = "Take on the shape of a Hellhound."
invocation = "none"
@@ -116,7 +117,7 @@
current_casters = list()
possible_shapes = list(/mob/living/simple_animal/hostile/hellhound)
-/obj/effect/proc_holder/spell/targeted/shapeshift/hellhound/greater
+/obj/effect/proc_holder/spell/shapeshift/hellhound/greater
name = "Greater Hellhound Form"
shapeshift_type = /mob/living/simple_animal/hostile/hellhound/greater
current_shapes = list(/mob/living/simple_animal/hostile/hellhound/greater)
diff --git a/code/datums/spells/summonitem.dm b/code/datums/spells/summonitem.dm
index b5bbdd08608..95e4ea6314c 100644
--- a/code/datums/spells/summonitem.dm
+++ b/code/datums/spells/summonitem.dm
@@ -1,4 +1,4 @@
-/obj/effect/proc_holder/spell/targeted/summonitem
+/obj/effect/proc_holder/spell/summonitem
name = "Instant Summons"
desc = "This spell can be used to recall a previously marked item to your hand from anywhere in the universe."
school = "transmutation"
@@ -6,17 +6,18 @@
clothes_req = 0
invocation = "GAR YOK"
invocation_type = "whisper"
- range = -1
level_max = 0 //cannot be improved
cooldown_min = 100
- include_user = 1
var/obj/marked_item
/// List of objects which will result in the spell stopping with the recursion search
var/static/list/blacklisted_summons = list(/obj/machinery/computer/cryopod = TRUE, /obj/machinery/atmospherics = TRUE, /obj/structure/disposalholder = TRUE, /obj/machinery/disposal = TRUE)
action_icon_state = "summons"
-/obj/effect/proc_holder/spell/targeted/summonitem/cast(list/targets, mob/user = usr)
+/obj/effect/proc_holder/spell/summonitem/create_new_targeting()
+ return new /datum/spell_targeting/self
+
+/obj/effect/proc_holder/spell/summonitem/cast(list/targets, mob/user = usr)
for(var/mob/living/target in targets)
var/list/hand_items = list(target.get_active_hand(),target.get_inactive_hand())
var/butterfingers = 0
diff --git a/code/datums/spells/touch_attacks.dm b/code/datums/spells/touch_attacks.dm
index c242a1aa52f..f021e6aa821 100644
--- a/code/datums/spells/touch_attacks.dm
+++ b/code/datums/spells/touch_attacks.dm
@@ -1,11 +1,12 @@
-/obj/effect/proc_holder/spell/targeted/touch
+/obj/effect/proc_holder/spell/touch
var/hand_path = /obj/item/melee/touch_attack
var/obj/item/melee/touch_attack/attached_hand = null
invocation_type = "none" //you scream on connecting, not summoning
- include_user = 1
- range = -1
-/obj/effect/proc_holder/spell/targeted/touch/Click(mob/user = usr)
+/obj/effect/proc_holder/spell/touch/create_new_targeting()
+ return new /datum/spell_targeting/self
+
+/obj/effect/proc_holder/spell/touch/Click(mob/user = usr)
if(attached_hand)
qdel(attached_hand)
charge_counter = charge_max
@@ -14,7 +15,7 @@
return 0
..()
-/obj/effect/proc_holder/spell/targeted/touch/cast(list/targets, mob/user = usr)
+/obj/effect/proc_holder/spell/touch/cast(list/targets, mob/user = usr)
for(var/mob/living/carbon/target in targets)
if(!attached_hand)
if(!ChargeHand(target))
@@ -23,7 +24,7 @@
charge_counter = 0
sleep(1)
-/obj/effect/proc_holder/spell/targeted/touch/proc/ChargeHand(mob/living/carbon/user)
+/obj/effect/proc_holder/spell/touch/proc/ChargeHand(mob/living/carbon/user)
var/hand_handled = 1
attached_hand = new hand_path(src)
if(user.hand) //left active hand
@@ -44,7 +45,7 @@
return 1
-/obj/effect/proc_holder/spell/targeted/touch/disintegrate
+/obj/effect/proc_holder/spell/touch/disintegrate
name = "Disintegrate"
desc = "This spell charges your hand with vile energy that can be used to violently explode victims."
hand_path = /obj/item/melee/touch_attack/disintegrate
@@ -56,7 +57,7 @@
action_icon_state = "gib"
-/obj/effect/proc_holder/spell/targeted/touch/flesh_to_stone
+/obj/effect/proc_holder/spell/touch/flesh_to_stone
name = "Flesh to Stone"
desc = "This spell charges your hand with the power to turn victims into inert statues for a long period of time."
hand_path = /obj/item/melee/touch_attack/fleshtostone
diff --git a/code/datums/spells/trigger.dm b/code/datums/spells/trigger.dm
index bc768cef57b..6737afac953 100644
--- a/code/datums/spells/trigger.dm
+++ b/code/datums/spells/trigger.dm
@@ -1,25 +1,24 @@
-/obj/effect/proc_holder/spell/targeted/trigger
- name = "Trigger"
+/obj/effect/proc_holder/spell/trigger
desc = "This spell triggers another spell or a few."
var/list/linked_spells = list() //those are just referenced by the trigger spell and are unaffected by it directly
var/list/starting_spells = list() //those are added on New() to contents from default spells and are deleted when the trigger spell is deleted to prevent memory leaks
-/obj/effect/proc_holder/spell/targeted/trigger/New()
+/obj/effect/proc_holder/spell/trigger/New()
..()
for(var/spell in starting_spells)
var/spell_to_add = text2path(spell)
new spell_to_add(src) //should result in adding to contents, needs testing
-/obj/effect/proc_holder/spell/targeted/trigger/Destroy()
+/obj/effect/proc_holder/spell/trigger/Destroy()
for(var/spell in contents)
qdel(spell)
linked_spells = null
starting_spells = null
return ..()
-/obj/effect/proc_holder/spell/targeted/trigger/cast(list/targets, mob/user = usr)
+/obj/effect/proc_holder/spell/trigger/cast(list/targets, mob/user = usr)
for(var/mob/living/target in targets)
for(var/obj/effect/proc_holder/spell/spell in contents)
spell.perform(list(target), 0, user = user)
diff --git a/code/datums/spells/turf_teleport.dm b/code/datums/spells/turf_teleport.dm
index 53568db8940..ad737a629be 100644
--- a/code/datums/spells/turf_teleport.dm
+++ b/code/datums/spells/turf_teleport.dm
@@ -1,4 +1,4 @@
-/obj/effect/proc_holder/spell/targeted/turf_teleport
+/obj/effect/proc_holder/spell/turf_teleport
name = "Turf Teleport"
desc = "This spell teleports the target to the turf in range."
nonabstract_req = 1
@@ -14,7 +14,10 @@
var/sound1 = 'sound/weapons/zapbang.ogg'
var/sound2 = 'sound/weapons/zapbang.ogg'
-/obj/effect/proc_holder/spell/targeted/turf_teleport/cast(list/targets,mob/living/user = usr)
+/obj/effect/proc_holder/spell/turf_teleport/create_new_targeting()
+ return new /datum/spell_targeting/self
+
+/obj/effect/proc_holder/spell/turf_teleport/cast(list/targets,mob/living/user = usr)
if(sound1)
playsound(get_turf(user), sound1, 50,1)
diff --git a/code/datums/spells/wizard.dm b/code/datums/spells/wizard.dm
index acaeeb41487..14274b568e6 100644
--- a/code/datums/spells/wizard.dm
+++ b/code/datums/spells/wizard.dm
@@ -1,4 +1,4 @@
-/obj/effect/proc_holder/spell/targeted/projectile/magic_missile
+/obj/effect/proc_holder/spell/projectile/magic_missile
name = "Magic Missile"
desc = "This spell fires several, slow moving, magic projectiles at nearby targets."
@@ -7,15 +7,12 @@
clothes_req = 1
invocation = "FORTI GY AMA"
invocation_type = "shout"
- range = 7
cooldown_min = 60 //35 deciseconds reduction per rank
- max_targets = 0
-
proj_icon_state = "magicm"
proj_name = "a magic missile"
proj_lingering = 1
- proj_type = "/obj/effect/proc_holder/spell/targeted/inflict_handler/magic_missile"
+ proj_type = "/obj/effect/proc_holder/spell/inflict_handler/magic_missile"
proj_lifespan = 20
proj_step_delay = 5
@@ -28,12 +25,18 @@
sound = 'sound/magic/magic_missile.ogg'
-/obj/effect/proc_holder/spell/targeted/inflict_handler/magic_missile
+/obj/effect/proc_holder/spell/projectile/magic_missile/create_new_targeting()
+ var/datum/spell_targeting/targeted/T = new()
+ T.allowed_type = /mob/living
+ T.max_targets = INFINITY
+ return T
+
+/obj/effect/proc_holder/spell/inflict_handler/magic_missile
amt_weakened = 3
sound = 'sound/magic/mm_hit.ogg'
-/obj/effect/proc_holder/spell/targeted/projectile/honk_missile
+/obj/effect/proc_holder/spell/projectile/honk_missile
name = "Honk Missile"
desc = "This spell fires several, slow moving, magic bikehorns at nearby targets."
@@ -42,16 +45,13 @@
clothes_req = 0
invocation = "HONK GY AMA"
invocation_type = "shout"
- range = 7
cooldown_min = 60 //35 deciseconds reduction per rank
- max_targets = 0
-
proj_icon = 'icons/obj/items.dmi'
proj_icon_state = "bike_horn"
proj_name = "A bike horn"
proj_lingering = 1
- proj_type = "/obj/effect/proc_holder/spell/targeted/inflict_handler/honk_missile"
+ proj_type = "/obj/effect/proc_holder/spell/inflict_handler/honk_missile"
proj_lifespan = 20
proj_step_delay = 5
@@ -65,7 +65,13 @@
sound = 'sound/items/bikehorn.ogg'
-/obj/effect/proc_holder/spell/targeted/inflict_handler/honk_missile
+/obj/effect/proc_holder/spell/projectile/honk_missile/create_new_targeting()
+ var/datum/spell_targeting/targeted/T = new()
+ T.allowed_type = /mob/living
+ T.max_targets = INFINITY
+ return T
+
+/obj/effect/proc_holder/spell/inflict_handler/honk_missile
amt_weakened = 3
sound = 'sound/items/bikehorn.ogg'
@@ -74,7 +80,10 @@
desc = "This always-on spell allows you to cast magic without your garments."
action_icon_state = "no_clothes"
-/obj/effect/proc_holder/spell/targeted/genetic/mutate
+/obj/effect/proc_holder/spell/noclothes/create_new_targeting()
+ return new /datum/spell_targeting/self // Dummy value
+
+/obj/effect/proc_holder/spell/genetic/mutate
name = "Mutate"
desc = "This spell causes you to turn into a hulk and gain laser vision for a short while."
@@ -84,8 +93,6 @@
invocation = "BIRUZ BENNAR"
invocation_type = "shout"
message = "You feel strong! You feel a pressure building behind your eyes!"
- range = -1
- include_user = 1
centcom_cancast = 0
traits = list(TRAIT_LASEREYES)
@@ -95,11 +102,14 @@
action_icon_state = "mutate"
sound = 'sound/magic/mutate.ogg'
-/obj/effect/proc_holder/spell/targeted/genetic/mutate/Initialize(mapload)
+/obj/effect/proc_holder/spell/genetic/mutate/Initialize(mapload)
. = ..()
mutations = list(GLOB.hulkblock)
-/obj/effect/proc_holder/spell/targeted/smoke
+/obj/effect/proc_holder/spell/genetic/mutate/create_new_targeting()
+ return new /datum/spell_targeting/self
+
+/obj/effect/proc_holder/spell/smoke
name = "Smoke"
desc = "This spell spawns a cloud of choking smoke at your location and does not require wizard garb."
@@ -108,8 +118,6 @@
clothes_req = 0
invocation = "none"
invocation_type = "none"
- range = -1
- include_user = 1
cooldown_min = 20 //25 deciseconds reduction per rank
smoke_spread = 2
@@ -117,15 +125,16 @@
action_icon_state = "smoke"
-/obj/effect/proc_holder/spell/targeted/emplosion/disable_tech
+/obj/effect/proc_holder/spell/smoke/create_new_targeting()
+ return new /datum/spell_targeting/self
+
+/obj/effect/proc_holder/spell/emplosion/disable_tech
name = "Disable Tech"
desc = "This spell disables all weapons, cameras and most other technology in range."
charge_max = 400
clothes_req = 1
invocation = "NEC CANTIO"
invocation_type = "shout"
- range = -1
- include_user = 1
cooldown_min = 200 //50 deciseconds reduction per rank
emp_heavy = 6
@@ -133,7 +142,7 @@
sound = 'sound/magic/disable_tech.ogg'
-/obj/effect/proc_holder/spell/targeted/turf_teleport/blink
+/obj/effect/proc_holder/spell/turf_teleport/blink
name = "Blink"
desc = "This spell randomly teleports you a short distance."
@@ -142,8 +151,6 @@
clothes_req = 1
invocation = "none"
invocation_type = "none"
- range = -1
- include_user = 1
cooldown_min = 5 //4 deciseconds reduction per rank
@@ -160,7 +167,10 @@
sound1 = 'sound/magic/blink.ogg'
sound2 = 'sound/magic/blink.ogg'
-/obj/effect/proc_holder/spell/targeted/area_teleport/teleport
+/obj/effect/proc_holder/spell/turf_teleport/blink/create_new_targeting()
+ return new /datum/spell_targeting/self
+
+/obj/effect/proc_holder/spell/area_teleport/teleport
name = "Teleport"
desc = "This spell teleports you to a type of area of your selection."
@@ -169,8 +179,6 @@
clothes_req = 1
invocation = "SCYAR NILA"
invocation_type = "shout"
- range = -1
- include_user = 1
cooldown_min = 200 //100 deciseconds reduction per rank
smoke_spread = 1
@@ -181,7 +189,10 @@
sound1 = 'sound/magic/teleport_diss.ogg'
sound2 = 'sound/magic/teleport_app.ogg'
-/obj/effect/proc_holder/spell/targeted/forcewall
+/obj/effect/proc_holder/spell/area_teleport/teleport/create_new_targeting()
+ return new /datum/spell_targeting/self
+
+/obj/effect/proc_holder/spell/forcewall
name = "Force Wall"
desc = "This spell creates a small unbreakable wall that only you can pass through, and does not need wizard garb. Lasts 30 seconds."
@@ -192,13 +203,14 @@
invocation_type = "whisper"
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
var/large = FALSE
-/obj/effect/proc_holder/spell/targeted/forcewall/cast(list/targets, mob/user = usr)
+/obj/effect/proc_holder/spell/forcewall/create_new_targeting()
+ return new /datum/spell_targeting/self
+
+/obj/effect/proc_holder/spell/forcewall/cast(list/targets, mob/user = usr)
new wall_type(get_turf(user), user)
if(large) //Extra THICK
if(user.dir == SOUTH || user.dir == NORTH)
@@ -208,7 +220,7 @@
new wall_type(get_step(user, NORTH), user)
new wall_type(get_step(user, SOUTH), user)
-/obj/effect/proc_holder/spell/targeted/forcewall/greater
+/obj/effect/proc_holder/spell/forcewall/greater
name = "Greater Force Wall"
desc = "Create a larger magical barrier that only you can pass through, but requires wizard garb. Lasts 30 seconds."
@@ -224,13 +236,17 @@
clothes_req = 1
invocation = "TOKI WO TOMARE"
invocation_type = "shout"
- range = 0
cooldown_min = 100
summon_amt = 1
action_icon_state = "time"
summon_type = list(/obj/effect/timestop/wizard)
+/obj/effect/proc_holder/spell/aoe_turf/conjure/timestop/create_new_targeting()
+ var/datum/spell_targeting/aoe/turf/T = new()
+ T.range = 0
+ return T
+
/obj/effect/proc_holder/spell/aoe_turf/conjure/carp
name = "Summon Carp"
desc = "This spell conjures a simple carp."
@@ -240,12 +256,16 @@
clothes_req = 1
invocation = "NOUK FHUNMM SACP RISSKA"
invocation_type = "shout"
- range = 1
summon_type = list(/mob/living/simple_animal/hostile/carp)
cast_sound = 'sound/magic/summon_karp.ogg'
+/obj/effect/proc_holder/spell/aoe_turf/conjure/carp/create_new_targeting()
+ var/datum/spell_targeting/aoe/turf/T = new()
+ T.range = 1
+ return T
+
/obj/effect/proc_holder/spell/aoe_turf/conjure/construct
name = "Artificer"
desc = "This spell conjures a construct which may be controlled by Shades"
@@ -255,13 +275,17 @@
clothes_req = 0
invocation = "none"
invocation_type = "none"
- range = 0
summon_type = list(/obj/structure/constructshell)
action_icon_state = "artificer"
cast_sound = 'sound/magic/summonitems_generic.ogg'
+/obj/effect/proc_holder/spell/aoe_turf/conjure/construct/create_new_targeting()
+ var/datum/spell_targeting/aoe/turf/T = new()
+ T.range = 0
+ return T
+
/obj/effect/proc_holder/spell/aoe_turf/conjure/creature
name = "Summon Creature Swarm"
desc = "This spell tears the fabric of reality, allowing horrific daemons to spill forth"
@@ -272,12 +296,16 @@
invocation = "IA IA"
invocation_type = "shout"
summon_amt = 10
- range = 3
summon_type = list(/mob/living/simple_animal/hostile/creature)
cast_sound = 'sound/magic/summonitems_generic.ogg'
-/obj/effect/proc_holder/spell/targeted/trigger/blind
+/obj/effect/proc_holder/spell/aoe_turf/conjure/creature/create_new_targeting()
+ var/datum/spell_targeting/aoe/turf/T = new()
+ T.range = 3
+ return T
+
+/obj/effect/proc_holder/spell/trigger/blind
name = "Blind"
desc = "This spell temporarily blinds a single person and does not require wizard garb."
@@ -289,21 +317,29 @@
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")
+ starting_spells = list("/obj/effect/proc_holder/spell/inflict_handler/blind","/obj/effect/proc_holder/spell/genetic/blind")
action_icon_state = "blind"
-/obj/effect/proc_holder/spell/targeted/inflict_handler/blind
+/obj/effect/proc_holder/spell/trigger/blind/create_new_targeting()
+ var/datum/spell_targeting/click/C = new()
+ C.allowed_type = /mob/living
+ return C
+
+/obj/effect/proc_holder/spell/inflict_handler/blind
amt_eye_blind = 10
amt_eye_blurry = 20
sound = 'sound/magic/blind.ogg'
-/obj/effect/proc_holder/spell/targeted/genetic/blind
+/obj/effect/proc_holder/spell/genetic/blind
traits = list(TRAIT_BLIND)
duration = 300
sound = 'sound/magic/blind.ogg'
-/obj/effect/proc_holder/spell/targeted/click/fireball
+/obj/effect/proc_holder/spell/genetic/blind/create_new_targeting()
+ return new /datum/spell_targeting/self // Dummy value since it is never used by an user directly
+
+/obj/effect/proc_holder/spell/fireball
name = "Fireball"
desc = "This spell fires a fireball at a target and does not require wizard garb."
@@ -312,14 +348,10 @@
clothes_req = FALSE
invocation = "ONI SOMA"
invocation_type = "shout"
- auto_target_single = FALSE // Having this true won't ever find a single target and is just lost processing power
- range = 20
cooldown_min = 20 //10 deciseconds reduction per rank
- click_radius = -1
selection_activated_message = "Your prepare to cast your fireball spell! Left-click to cast at a target!"
selection_deactivated_message = "You extinguish your fireball...for now."
- allowed_type = /atom // FIRE AT EVERYTHING
var/fireball_type = /obj/item/projectile/magic/fireball
action_icon_state = "fireball0"
@@ -327,13 +359,18 @@
active = FALSE
-/obj/effect/proc_holder/spell/targeted/click/fireball/update_icon()
+/obj/effect/proc_holder/spell/fireball/create_new_targeting()
+ var/datum/spell_targeting/clicked_atom/C = new()
+ C.range = 20
+ return C
+
+/obj/effect/proc_holder/spell/fireball/update_icon()
if(!action)
return
action.button_icon_state = "fireball[active]"
action.UpdateButtonIcon()
-/obj/effect/proc_holder/spell/targeted/click/fireball/cast(list/targets, mob/living/user = usr)
+/obj/effect/proc_holder/spell/fireball/cast(list/targets, mob/living/user = usr)
var/target = targets[1] //There is only ever one target for fireball
var/turf/T = user.loc
var/turf/U = get_step(user, user.dir) // Get the tile infront of the move, based on their direction
@@ -355,14 +392,17 @@
clothes_req = TRUE
invocation = "GITTAH WEIGH"
invocation_type = "shout"
- range = 5
cooldown_min = 150
- selection_type = "view"
sound = 'sound/magic/repulse.ogg'
var/maxthrow = 5
var/sparkle_path = /obj/effect/temp_visual/gravpush
action_icon_state = "repulse"
+/obj/effect/proc_holder/spell/aoe_turf/repulse/create_new_targeting()
+ var/datum/spell_targeting/aoe/turf/T = new()
+ T.range = 5
+ return T
+
/obj/effect/proc_holder/spell/aoe_turf/repulse/cast(list/targets, mob/user = usr, stun_amt = 2)
var/list/thrownatoms = list()
var/atom/throwtarget
@@ -394,21 +434,24 @@
spawn(0)
AM.throw_at(throwtarget, ((clamp((maxthrow - (clamp(distfromcaster - 2, 0, distfromcaster))), 3, maxthrow))), 1)//So stuff gets tossed around at the same time.
-/obj/effect/proc_holder/spell/targeted/sacred_flame
+/obj/effect/proc_holder/spell/sacred_flame
name = "Sacred Flame"
desc = "Makes everyone around you more flammable, and lights yourself on fire."
charge_max = 60
clothes_req = 0
invocation = "FI'RAN DADISKO"
invocation_type = "shout"
- max_targets = 0
- range = 6
- include_user = 1
- selection_type = "view"
action_icon_state = "sacredflame"
sound = 'sound/magic/fireball.ogg'
-/obj/effect/proc_holder/spell/targeted/sacred_flame/cast(list/targets, mob/user = usr)
+/obj/effect/proc_holder/spell/sacred_flame/create_new_targeting()
+ var/datum/spell_targeting/aoe/A = new()
+ A.include_user = TRUE
+ A.range = 6
+ A.allowed_type = /mob/living
+ return A
+
+/obj/effect/proc_holder/spell/sacred_flame/cast(list/targets, mob/user = usr)
for(var/mob/living/L in targets)
L.adjust_fire_stacks(20)
if(isliving(user))
diff --git a/code/game/dna/mutations/disabilities.dm b/code/game/dna/mutations/disabilities.dm
index a03c686140a..ad5e37f859a 100644
--- a/code/game/dna/mutations/disabilities.dm
+++ b/code/game/dna/mutations/disabilities.dm
@@ -482,13 +482,13 @@
desc = "The subject becomes able to convert excess cellular energy into thermal energy."
activation_messages = list("You suddenly feel rather hot.")
deactivation_messages = list("You no longer feel uncomfortably hot.")
- spelltype = /obj/effect/proc_holder/spell/targeted/immolate
+ spelltype = /obj/effect/proc_holder/spell/immolate
/datum/mutation/grant_spell/immolate/New()
..()
block = GLOB.immolateblock
-/obj/effect/proc_holder/spell/targeted/immolate
+/obj/effect/proc_holder/spell/immolate
name = "Incendiary Mitochondria"
desc = "The subject becomes able to convert excess cellular energy into thermal energy."
panel = "Abilities"
@@ -499,14 +499,14 @@
clothes_req = 0
stat_allowed = 0
invocation_type = "none"
- range = -1
- selection_type = "range"
var/list/compatible_mobs = list(/mob/living/carbon/human)
- include_user = 1
action_icon_state = "genetic_incendiary"
-/obj/effect/proc_holder/spell/targeted/immolate/cast(list/targets, mob/living/user = usr)
+/obj/effect/proc_holder/spell/immolate/create_new_targeting()
+ return new /datum/spell_targeting/self
+
+/obj/effect/proc_holder/spell/immolate/cast(list/targets, mob/living/user = usr)
var/mob/living/carbon/L = user
L.adjust_fire_stacks(0.5)
L.visible_message("[L.name] suddenly bursts into flames!")
diff --git a/code/game/dna/mutations/powers.dm b/code/game/dna/mutations/powers.dm
index 20c37357c50..a7e8e952cc1 100644
--- a/code/game/dna/mutations/powers.dm
+++ b/code/game/dna/mutations/powers.dm
@@ -280,13 +280,13 @@
activation_messages = list("You notice a strange cold tingle in your fingertips.")
deactivation_messages = list("Your fingers feel warmer.")
instability = GENE_INSTABILITY_MODERATE
- spelltype = /obj/effect/proc_holder/spell/targeted/click/cryokinesis
+ spelltype = /obj/effect/proc_holder/spell/cryokinesis
/datum/mutation/grant_spell/cryo/New()
..()
block = GLOB.cryoblock
-/obj/effect/proc_holder/spell/targeted/click/cryokinesis
+/obj/effect/proc_holder/spell/cryokinesis
name = "Cryokinesis"
desc = "Drops the bodytemperature of another person."
panel = "Abilities"
@@ -297,20 +297,23 @@
clothes_req = FALSE
stat_allowed = FALSE
- click_radius = 0
- auto_target_single = FALSE // Give the clueless geneticists a way out and to have them not target themselves
selection_activated_message = "Your mind grow cold. Click on a target to cast the spell."
selection_deactivated_message = "Your mind returns to normal."
- allowed_type = /mob/living/carbon
invocation_type = "none"
- range = 7
- selection_type = "range"
- include_user = TRUE
var/list/compatible_mobs = list(/mob/living/carbon/human)
action_icon_state = "genetic_cryo"
-/obj/effect/proc_holder/spell/targeted/click/cryokinesis/cast(list/targets, mob/user = usr)
+/obj/effect/proc_holder/spell/cryokinesis/create_new_targeting()
+ var/datum/spell_targeting/click/T = new()
+ T.allowed_type = /mob/living/carbon
+ T.click_radius = 0
+ T.try_auto_target = FALSE // Give the clueless geneticists a way out and to have them not target themselves
+ T.selection_type = SPELL_SELECTION_RANGE
+ T.include_user = TRUE
+ return T
+
+/obj/effect/proc_holder/spell/cryokinesis/cast(list/targets, mob/user = usr)
var/mob/living/carbon/C = targets[1]
@@ -349,13 +352,13 @@
deactivation_messages = list("You don't feel quite so hungry anymore.")
instability = GENE_INSTABILITY_MINOR
- spelltype=/obj/effect/proc_holder/spell/targeted/eat
+ spelltype=/obj/effect/proc_holder/spell/eat
/datum/mutation/grant_spell/mattereater/New()
..()
block = GLOB.eatblock
-/obj/effect/proc_holder/spell/targeted/eat
+/obj/effect/proc_holder/spell/eat
name = "Eat"
desc = "Eat just about anything!"
panel = "Abilities"
@@ -366,34 +369,25 @@
clothes_req = 0
stat_allowed = 0
invocation_type = "none"
- range = 1
- selection_type = "view"
action_icon_state = "genetic_eat"
- var/list/types_allowed = list(
- /obj/item,
- /mob/living/simple_animal/pet,
- /mob/living/simple_animal/hostile,
- /mob/living/simple_animal/parrot,
- /mob/living/simple_animal/crab,
- /mob/living/simple_animal/mouse,
- /mob/living/carbon/human,
- /mob/living/simple_animal/slime,
- /mob/living/carbon/alien/larva,
- /mob/living/simple_animal/slime,
- /mob/living/simple_animal/chick,
- /mob/living/simple_animal/chicken,
- /mob/living/simple_animal/lizard,
- /mob/living/simple_animal/cow,
- /mob/living/simple_animal/spiderbot
- )
- var/list/own_blacklist = list(
- /obj/item/organ,
- /obj/item/implant
- )
+/obj/effect/proc_holder/spell/eat/create_new_targeting()
+ return new /datum/spell_targeting/matter_eater
-/obj/effect/proc_holder/spell/targeted/eat/proc/doHeal(mob/user)
+/obj/effect/proc_holder/spell/eat/can_cast(mob/user = usr, charge_check = TRUE, show_message = FALSE)
+ . = ..()
+ if(!.)
+ return
+ var/can_eat = TRUE
+ if(iscarbon(user))
+ var/mob/living/carbon/C = user
+ if((C.head && (C.head.flags_cover & HEADCOVERSMOUTH)) || (C.wear_mask && (C.wear_mask.flags_cover & MASKCOVERSMOUTH) && !C.wear_mask.mask_adjusted))
+ to_chat(C, "Your mouth is covered, preventing you from eating!")
+ can_eat = FALSE
+ return can_eat
+
+/obj/effect/proc_holder/spell/eat/proc/doHeal(mob/user)
if(ishuman(user))
var/mob/living/carbon/human/H = user
for(var/name in H.bodyparts_by_name)
@@ -407,46 +401,9 @@
H.UpdateDamageIcon()
H.updatehealth()
-/obj/effect/proc_holder/spell/targeted/eat/choose_targets(mob/user = usr)
- var/list/targets = new /list()
- var/list/possible_targets = new /list()
- if(!check_mouth(user))
- revert_cast(user)
- return
- for(var/atom/movable/O in view_or_range(range, user, selection_type))
- if((O in user) && is_type_in_list(O,own_blacklist))
- continue
- if(is_type_in_list(O,types_allowed))
- if(isanimal(O))
- var/mob/living/simple_animal/SA = O
- if(!SA.gold_core_spawnable)
- continue
- possible_targets += O
-
- targets += input("Choose the target of your hunger.", "Targeting") as null|anything in possible_targets
-
- if(!targets.len || !targets[1]) //doesn't waste the spell
- revert_cast(user)
- return
-
- if(!check_mouth(user))
- revert_cast(user)
- return
-
- perform(targets, user = user)
-
-/obj/effect/proc_holder/spell/targeted/eat/proc/check_mouth(mob/user = usr)
- var/can_eat = TRUE
- if(iscarbon(user))
- var/mob/living/carbon/C = user
- if((C.head && (C.head.flags_cover & HEADCOVERSMOUTH)) || (C.wear_mask && (C.wear_mask.flags_cover & MASKCOVERSMOUTH) && !C.wear_mask.mask_adjusted))
- to_chat(C, "Your mouth is covered, preventing you from eating!")
- can_eat = FALSE
- return can_eat
-
-/obj/effect/proc_holder/spell/targeted/eat/cast(list/targets, mob/user = usr)
+/obj/effect/proc_holder/spell/eat/cast(list/targets, mob/user = usr)
if(!targets.len)
to_chat(user, "No target found in range.")
return
@@ -500,18 +457,16 @@
deactivation_messages = list("Your leg muscles shrink back to normal.")
instability = GENE_INSTABILITY_MINOR
- spelltype =/obj/effect/proc_holder/spell/targeted/leap
+ spelltype =/obj/effect/proc_holder/spell/leap
/datum/mutation/grant_spell/jumpy/New()
..()
block = GLOB.jumpblock
-/obj/effect/proc_holder/spell/targeted/leap
+/obj/effect/proc_holder/spell/leap
name = "Jump"
desc = "Leap great distances!"
panel = "Abilities"
- range = -1
- include_user = 1
charge_type = "recharge"
charge_max = 60
@@ -522,7 +477,10 @@
action_icon_state = "genetic_jump"
-/obj/effect/proc_holder/spell/targeted/leap/cast(list/targets, mob/user = usr)
+/obj/effect/proc_holder/spell/leap/create_new_targeting()
+ return new /datum/spell_targeting/self
+
+/obj/effect/proc_holder/spell/leap/cast(list/targets, mob/user = usr)
var/failure = FALSE
if(istype(user.loc,/mob/) || user.lying || user.stunned || user.buckled || user.stat)
to_chat(user, "You can't jump right now!")
@@ -590,7 +548,7 @@
name = "Polymorphism"
desc = "Enables the subject to reconfigure their appearance to mimic that of others."
- spelltype =/obj/effect/proc_holder/spell/targeted/click/polymorph
+ spelltype =/obj/effect/proc_holder/spell/polymorph
//cooldown = 1800
activation_messages = list("You don't feel entirely like yourself somehow.")
deactivation_messages = list("You feel secure in your identity.")
@@ -600,7 +558,7 @@
..()
block = GLOB.polymorphblock
-/obj/effect/proc_holder/spell/targeted/click/polymorph
+/obj/effect/proc_holder/spell/polymorph
name = "Polymorph"
desc = "Mimic the appearance of others!"
panel = "Abilities"
@@ -609,19 +567,22 @@
clothes_req = FALSE
stat_allowed = FALSE
- click_radius = -1 // Precision required
- auto_target_single = FALSE // Safety to not turn into monkey (420)
selection_activated_message = "You body becomes unstable. Click on a target to cast transform into them."
selection_deactivated_message = "Your body calms down again."
- allowed_type = /mob/living/carbon/human
invocation_type = "none"
- range = 1
- selection_type = "range"
action_icon_state = "genetic_poly"
-/obj/effect/proc_holder/spell/targeted/click/polymorph/cast(list/targets, mob/user = usr)
+/obj/effect/proc_holder/spell/polymorph/create_new_targeting()
+ var/datum/spell_targeting/click/T = new()
+ T.try_auto_target = FALSE
+ T.click_radius = -1
+ T.range = 1
+ T.selection_type = SPELL_SELECTION_RANGE
+ return T
+
+/obj/effect/proc_holder/spell/polymorph/cast(list/targets, mob/user = usr)
var/mob/living/carbon/human/target = targets[1]
user.visible_message("[user]'s body shifts and contorts.")
@@ -641,7 +602,7 @@
name = "Empathic Thought"
desc = "The subject becomes able to read the minds of others for certain information."
- spelltype = /obj/effect/proc_holder/spell/targeted/empath
+ spelltype = /obj/effect/proc_holder/spell/empath
activation_messages = list("You suddenly notice more about others than you did before.")
deactivation_messages = list("You no longer feel able to sense intentions.")
instability = GENE_INSTABILITY_MINOR
@@ -650,7 +611,7 @@
..()
block = GLOB.empathblock
-/obj/effect/proc_holder/spell/targeted/empath
+/obj/effect/proc_holder/spell/empath
name = "Read Mind"
desc = "Read the minds of others for information."
charge_max = 180
@@ -658,24 +619,16 @@
human_req = TRUE
stat_allowed = CONSCIOUS
invocation_type = "none"
- range = -2
- selection_type = "range"
action_icon_state = "genetic_empath"
-/obj/effect/proc_holder/spell/targeted/empath/choose_targets(mob/user = usr)
- var/list/possible_targets = list()
- for(var/mob/living/carbon/C in range(7, user))
- possible_targets += C
- var/target = input("Choose the target to spy on.", "Targeting") as null|mob in possible_targets
+/obj/effect/proc_holder/spell/empath/create_new_targeting()
+ var/datum/spell_targeting/targeted/T = new()
+ T.allowed_type = /mob/living/carbon
+ T.selection_type = SPELL_SELECTION_RANGE
+ return T
- if(!target) //doesn't waste the spell
- revert_cast(user)
- return
-
- perform(list(target), user = user)
-
-/obj/effect/proc_holder/spell/targeted/empath/cast(list/targets, mob/user = usr)
+/obj/effect/proc_holder/spell/empath/cast(list/targets, mob/user = usr)
for(var/mob/living/carbon/M in targets)
if(!iscarbon(M))
to_chat(user, "You may only use this on other organic beings.")
@@ -750,7 +703,7 @@
if(M.dna?.GetSEState(GLOB.empathblock))
to_chat(M, "You sense [user.name] reading your mind.")
- else if(prob(5) || M.mind.assigned_role=="Chaplain")
+ else if(prob(5) || M.mind?.assigned_role=="Chaplain")
to_chat(M, "You sense someone intruding upon your thoughts...")
///////////////////Vanilla Morph////////////////////////////////////
@@ -758,7 +711,7 @@
/datum/mutation/grant_spell/morph
name = "Morphism"
desc = "Enables the subject to reconfigure their appearance to that of any human."
- spelltype =/obj/effect/proc_holder/spell/targeted/morph
+ spelltype =/obj/effect/proc_holder/spell/morph
activation_messages = list("Your body feels if can alter its appearance.")
deactivation_messages = list("Your body doesn't feel capable of altering its appearance.")
instability = GENE_INSTABILITY_MINOR
@@ -767,7 +720,7 @@
..()
block = GLOB.morphblock
-/obj/effect/proc_holder/spell/targeted/morph
+/obj/effect/proc_holder/spell/morph
name = "Morph"
desc = "Mimic the appearance of your choice!"
panel = "Abilities"
@@ -776,13 +729,13 @@
clothes_req = 0
stat_allowed = 0
invocation_type = "none"
- range = -1
- include_user = 1
- selection_type = "range"
action_icon_state = "genetic_morph"
-/obj/effect/proc_holder/spell/targeted/morph/cast(list/targets, mob/user = usr)
+/obj/effect/proc_holder/spell/morph/create_new_targeting()
+ return new /datum/spell_targeting/self
+
+/obj/effect/proc_holder/spell/morph/cast(list/targets, mob/user = usr)
if(!ishuman(user))
return
@@ -937,7 +890,7 @@
deactivation_messages = list("You no longer feel you can project your thoughts.")
instability = GENE_INSTABILITY_MINOR
- spelltype =/obj/effect/proc_holder/spell/targeted/remotetalk
+ spelltype =/obj/effect/proc_holder/spell/remotetalk
/datum/mutation/grant_spell/remotetalk/New()
..()
@@ -945,15 +898,15 @@
/datum/mutation/grant_spell/remotetalk/activate(mob/living/M)
..()
- M.AddSpell(new /obj/effect/proc_holder/spell/targeted/mindscan(null))
+ M.AddSpell(new /obj/effect/proc_holder/spell/mindscan(null))
/datum/mutation/grant_spell/remotetalk/deactivate(mob/user)
..()
for(var/obj/effect/proc_holder/spell/S in user.mob_spell_list)
- if(istype(S, /obj/effect/proc_holder/spell/targeted/mindscan))
+ if(istype(S, /obj/effect/proc_holder/spell/mindscan))
user.RemoveSpell(S)
-/obj/effect/proc_holder/spell/targeted/remotetalk
+/obj/effect/proc_holder/spell/remotetalk
name = "Project Mind"
desc = "Make people understand your thoughts!"
charge_max = 0
@@ -961,31 +914,13 @@
clothes_req = 0
stat_allowed = 0
invocation_type = "none"
- range = -2
- selection_type = "range"
action_icon_state = "genetic_project"
-/obj/effect/proc_holder/spell/targeted/remotetalk/choose_targets(mob/user = usr)
- var/list/targets = new /list()
- var/list/validtargets = user.get_telepathic_targets()
+/obj/effect/proc_holder/spell/remotetalk/create_new_targeting()
+ return new /datum/spell_targeting/telepathic
- if(!length(validtargets))
- to_chat(user, "There are no valid targets!")
- start_recharge()
- return
-
- var/target_name = input("Choose the target to talk to.", "Targeting") as null|anything in validtargets
-
- var/mob/living/target
- if(!target_name || !(target = validtargets[target_name]))
- revert_cast(user)
- return
-
- targets += target
- perform(targets, user = user)
-
-/obj/effect/proc_holder/spell/targeted/remotetalk/cast(list/targets, mob/user = usr)
+/obj/effect/proc_holder/spell/remotetalk/cast(list/targets, mob/user = usr)
if(!ishuman(user)) return
var/say = input("What do you wish to say") as text|null
if(!say || usr.stat)
@@ -1004,38 +939,20 @@
for(var/mob/dead/observer/G in GLOB.player_list)
G.show_message("Telepathic message from [user] ([ghost_follow_link(user, ghost=G)]) to [target] ([ghost_follow_link(target, ghost=G)]): [say]")
-/obj/effect/proc_holder/spell/targeted/mindscan
+/obj/effect/proc_holder/spell/mindscan
name = "Scan Mind"
desc = "Offer people a chance to share their thoughts!"
charge_max = 0
clothes_req = 0
stat_allowed = 0
invocation_type = "none"
- range = -2
- selection_type = "range"
action_icon_state = "genetic_mindscan"
var/list/available_targets = list()
-/obj/effect/proc_holder/spell/targeted/mindscan/choose_targets(mob/user = usr)
- var/list/targets = list()
- var/list/validtargets = user.get_telepathic_targets()
+/obj/effect/proc_holder/spell/mindscan/create_new_targeting()
+ return new /datum/spell_targeting/telepathic
- if(!length(validtargets))
- to_chat(user, "There are no valid targets!")
- start_recharge()
- return
-
- var/target_name = input("Choose the target to listen to.", "Targeting") as null|anything in validtargets
-
- var/mob/living/target
- if(!target_name || !(target = validtargets[target_name]))
- revert_cast(user)
- return
-
- targets += target
- perform(targets, user = user)
-
-/obj/effect/proc_holder/spell/targeted/mindscan/cast(list/targets, mob/user = usr)
+/obj/effect/proc_holder/spell/mindscan/cast(list/targets, mob/user = usr)
if(!ishuman(user))
return
for(var/mob/living/target in targets)
@@ -1047,13 +964,13 @@
available_targets += target
addtimer(CALLBACK(src, .proc/removeAvailability, target), 100)
-/obj/effect/proc_holder/spell/targeted/mindscan/proc/removeAvailability(mob/living/target)
+/obj/effect/proc_holder/spell/mindscan/proc/removeAvailability(mob/living/target)
if(target in available_targets)
available_targets -= target
if(!(target in available_targets))
target.show_message("You feel the sensation fade...")
-/obj/effect/proc_holder/spell/targeted/mindscan/Topic(href, href_list)
+/obj/effect/proc_holder/spell/mindscan/Topic(href, href_list)
var/mob/living/user
if(href_list["user"])
user = locateUID(href_list["user"])
@@ -1079,7 +996,7 @@
for(var/mob/dead/observer/G in GLOB.player_list)
G.show_message("Telepathic response from [target] ([ghost_follow_link(target, ghost=G)]) to [user] ([ghost_follow_link(user, ghost=G)]): [say]")
-/obj/effect/proc_holder/spell/targeted/mindscan/Destroy()
+/obj/effect/proc_holder/spell/mindscan/Destroy()
available_targets.Cut()
return ..()
@@ -1089,14 +1006,14 @@
deactivation_messages = list("Your mind can no longer can see things from afar.")
instability = GENE_INSTABILITY_MINOR
- spelltype =/obj/effect/proc_holder/spell/targeted/remoteview
+ spelltype =/obj/effect/proc_holder/spell/remoteview
/datum/mutation/grant_spell/remoteview/New()
..()
block = GLOB.remoteviewblock
-/obj/effect/proc_holder/spell/targeted/remoteview
+/obj/effect/proc_holder/spell/remoteview
name = "Remote View"
desc = "Spy on people from any range!"
charge_max = 100
@@ -1104,33 +1021,13 @@
clothes_req = 0
stat_allowed = 0
invocation_type = "none"
- range = -2
- selection_type = "range"
action_icon_state = "genetic_view"
-/obj/effect/proc_holder/spell/targeted/remoteview/choose_targets(mob/user = usr)
- var/list/targets = list()
- var/list/remoteviewers = list()
- for(var/mob/M in GLOB.alive_mob_list)
- if(M == user)
- continue
- if(M.dna?.GetSEState(GLOB.psyresistblock))
- continue
- if(M.dna?.GetSEState(GLOB.remoteviewblock))
- remoteviewers += M
- if(!LAZYLEN(remoteviewers))
- to_chat(user, "No valid targets with remote view were found!")
- start_recharge()
- return
- targets += input("Choose the target to spy on.", "Targeting") as null|anything in remoteviewers
- if(!targets)
- to_chat(user, "You decide against remote viewing.")
- start_recharge()
- return
- perform(targets, user = user)
+/obj/effect/proc_holder/spell/remoteview/create_new_targeting()
+ return new /datum/spell_targeting/remoteview
-/obj/effect/proc_holder/spell/targeted/remoteview/cast(list/targets, mob/user = usr)
+/obj/effect/proc_holder/spell/remoteview/cast(list/targets, mob/user = usr)
var/mob/living/carbon/human/H
if(ishuman(user))
H = user
diff --git a/code/game/gamemodes/miniantags/morph/morph.dm b/code/game/gamemodes/miniantags/morph/morph.dm
index 5bf147c2b75..65f49fb26b3 100644
--- a/code/game/gamemodes/miniantags/morph/morph.dm
+++ b/code/game/gamemodes/miniantags/morph/morph.dm
@@ -45,11 +45,11 @@
/// How much weaken a successful ambush attack applies
var/ambush_weaken = 3
/// The spell the morph uses to morph
- var/obj/effect/proc_holder/spell/targeted/click/mimic/morph/mimic_spell
+ var/obj/effect/proc_holder/spell/mimic/morph/mimic_spell
/// The ambush action used by the morph
- var/obj/effect/proc_holder/spell/morph/ambush/ambush_spell
+ var/obj/effect/proc_holder/spell/morph_spell/ambush/ambush_spell
/// The spell the morph uses to pass through airlocks
- var/obj/effect/proc_holder/spell/targeted/click/pass_airlock/pass_airlock_spell
+ var/obj/effect/proc_holder/spell/morph_spell/pass_airlock/pass_airlock_spell
/// How much the morph has gathered in terms of food. Used to reproduce and such
var/gathered_food = 20 // Start with a bit to use abilities
@@ -60,8 +60,8 @@
AddSpell(mimic_spell)
ambush_spell = new
AddSpell(ambush_spell)
- AddSpell(new /obj/effect/proc_holder/spell/morph/reproduce)
- AddSpell(new /obj/effect/proc_holder/spell/morph/open_vent)
+ AddSpell(new /obj/effect/proc_holder/spell/morph_spell/reproduce)
+ AddSpell(new /obj/effect/proc_holder/spell/morph_spell/open_vent)
pass_airlock_spell = new
AddSpell(pass_airlock_spell)
@@ -78,8 +78,8 @@
/mob/living/simple_animal/hostile/morph/wizard/New()
. = ..()
- AddSpell(new /obj/effect/proc_holder/spell/targeted/smoke)
- AddSpell(new /obj/effect/proc_holder/spell/targeted/forcewall)
+ AddSpell(new /obj/effect/proc_holder/spell/smoke)
+ AddSpell(new /obj/effect/proc_holder/spell/forcewall)
/mob/living/simple_animal/hostile/morph/proc/try_eat(atom/movable/A)
@@ -139,7 +139,7 @@
*/
/mob/living/simple_animal/hostile/morph/proc/add_food(amount)
gathered_food += amount
- for(var/obj/effect/proc_holder/spell/morph/MS in mind.spell_list)
+ for(var/obj/effect/proc_holder/spell/morph_spell/MS in mind.spell_list)
MS.updateButtonIcon()
diff --git a/code/game/gamemodes/miniantags/morph/spells/ambush.dm b/code/game/gamemodes/miniantags/morph/spells/ambush.dm
index 1fc68648704..b7d88f92bbf 100644
--- a/code/game/gamemodes/miniantags/morph/spells/ambush.dm
+++ b/code/game/gamemodes/miniantags/morph/spells/ambush.dm
@@ -1,32 +1,29 @@
#define MORPH_AMBUSH_PERFECTION_TIME 15 SECONDS
-/obj/effect/proc_holder/spell/morph/ambush
+/obj/effect/proc_holder/spell/morph_spell/ambush
name = "Prepare Ambush"
desc = "Prepare an ambush. Dealing significantly more damage on the first hit and you will weaken the target. Only works while morphed. If the target tries to use you with their hands then you will do even more damage. \
Keeping still for another 10 seconds will perfect your disguise."
action_icon_state = "morph_ambush"
charge_max = 8 SECONDS
-/obj/effect/proc_holder/spell/morph/ambush/cast_check(charge_check = TRUE, start_recharge = TRUE, mob/living/simple_animal/hostile/morph/user = usr)
- if(!istype(user))
- return ..() // Message is in there
+/obj/effect/proc_holder/spell/morph_spell/ambush/create_new_targeting()
+ return new /datum/spell_targeting/self
+
+/obj/effect/proc_holder/spell/morph_spell/ambush/can_cast(mob/living/simple_animal/hostile/morph/user, charge_check, show_message)
+ . = ..()
+ if(!.)
+ return
if(!user.morphed)
- to_chat(user, "You can only prepare an ambush if you're disguised!")
+ if(show_message)
+ to_chat(user, "You can only prepare an ambush if you're disguised!")
return FALSE
if(user.ambush_prepared)
- to_chat(user, "You are already prepared!")
+ if(show_message)
+ to_chat(user, "You are already prepared!")
return FALSE
- return ..()
-/obj/effect/proc_holder/spell/morph/ambush/can_cast(mob/living/simple_animal/hostile/morph/user, charge_check, show_message)
- if(!istype(user) || !user.morphed || user.ambush_prepared)
- return FALSE
- return ..()
-
-/obj/effect/proc_holder/spell/morph/ambush/choose_targets(mob/user)
- perform(list(user), TRUE, user, FALSE)
-
-/obj/effect/proc_holder/spell/morph/ambush/cast(list/targets, mob/living/simple_animal/hostile/morph/user)
+/obj/effect/proc_holder/spell/morph_spell/ambush/cast(list/targets, mob/living/simple_animal/hostile/morph/user)
to_chat(user, "You start preparing an ambush.")
if(!do_after(user, 6 SECONDS, FALSE, user, TRUE, list(CALLBACK(src, .proc/prepare_check, user)), FALSE))
if(!user.morphed)
@@ -36,7 +33,7 @@
return
user.prepare_ambush()
-/obj/effect/proc_holder/spell/morph/ambush/proc/prepare_check(mob/living/simple_animal/hostile/morph/user)
+/obj/effect/proc_holder/spell/morph_spell/ambush/proc/prepare_check(mob/living/simple_animal/hostile/morph/user)
return !user.morphed
/datum/status_effect/morph_ambush
diff --git a/code/game/gamemodes/miniantags/morph/spells/morph_spell.dm b/code/game/gamemodes/miniantags/morph/spells/morph_spell.dm
index 08d2944df2b..a4d14866051 100644
--- a/code/game/gamemodes/miniantags/morph/spells/morph_spell.dm
+++ b/code/game/gamemodes/miniantags/morph/spells/morph_spell.dm
@@ -1,36 +1,15 @@
-/obj/effect/proc_holder/spell/morph
+/obj/effect/proc_holder/spell/morph_spell
action_background_icon_state = "bg_morph"
clothes_req = FALSE
/// How much food it costs the morph to use this
var/hunger_cost = 0
-/obj/effect/proc_holder/spell/morph/Initialize(mapload)
+/obj/effect/proc_holder/spell/morph_spell/Initialize(mapload)
. = ..()
if(hunger_cost)
name = "[name] ([hunger_cost])"
-/obj/effect/proc_holder/spell/morph/cast_check(charge_check = TRUE, start_recharge = TRUE, mob/living/simple_animal/hostile/morph/user = usr)
- if(!istype(user))
- to_chat(user, "You should not be able to use this abilty! Report this as a bug on github please.")
- stack_trace()
- log_debug("[user] has the spell [src] while he is not a morph")
- return FALSE
- if(user.gathered_food < hunger_cost)
- to_chat(user, "You require at least [hunger_cost] stored food to use this ability!")
- return FALSE
- return ..()
-
-/obj/effect/proc_holder/spell/morph/can_cast(mob/living/simple_animal/hostile/morph/user, charge_check, show_message)
- if(!istype(user) || user.gathered_food < hunger_cost)
- return FALSE
- return ..()
-
-/obj/effect/proc_holder/spell/morph/before_cast(list/targets, mob/living/simple_animal/hostile/morph/user)
- user.use_food(hunger_cost)
- if(hunger_cost)
- to_chat(user, "You have [user.gathered_food] left to use.")
-
-/obj/effect/proc_holder/spell/morph/revert_cast(mob/living/simple_animal/hostile/morph/user)
- user.add_food(hunger_cost)
- to_chat(user, "You have [user.gathered_food] left to use.")
- ..()
+/obj/effect/proc_holder/spell/morph_spell/create_new_handler()
+ var/datum/spell_handler/morph/H = new
+ H.hunger_cost = hunger_cost
+ return H
diff --git a/code/game/gamemodes/miniantags/morph/spells/open_vent.dm b/code/game/gamemodes/miniantags/morph/spells/open_vent.dm
index e2409635d1d..bd44b567033 100644
--- a/code/game/gamemodes/miniantags/morph/spells/open_vent.dm
+++ b/code/game/gamemodes/miniantags/morph/spells/open_vent.dm
@@ -1,25 +1,26 @@
-/obj/effect/proc_holder/spell/morph/open_vent
+/obj/effect/proc_holder/spell/morph_spell/open_vent
name = "Open Vents"
desc = "Spit out acidic puke on nearby vents or scrubbers. Will take a little while for the acid to take effect. Not usable from inside a vent."
action_icon_state = "acid_vent"
charge_max = 10 SECONDS
hunger_cost = 10
-/obj/effect/proc_holder/spell/morph/open_vent/choose_targets(mob/user)
- var/list/targets = list()
- for(var/obj/machinery/atmospherics/unary/U in view(user, 1))
- if(istype(U, /obj/machinery/atmospherics/unary/vent_scrubber))
- var/obj/machinery/atmospherics/unary/vent_scrubber/S = U
- if(S.welded)
- targets += S
- else if(istype(U, /obj/machinery/atmospherics/unary/vent_pump))
- var/obj/machinery/atmospherics/unary/vent_scrubber/V = U
- if(V.welded)
- targets += V
+/obj/effect/proc_holder/spell/morph_spell/open_vent/create_new_targeting()
+ var/datum/spell_targeting/aoe/T = new
+ T.range = 1
+ T.allowed_type = /obj/machinery/atmospherics/unary
+ return T
- perform(targets, TRUE, user)
+/obj/effect/proc_holder/spell/morph_spell/open_vent/valid_target(target, user)
+ if(istype(target, /obj/machinery/atmospherics/unary/vent_scrubber))
+ var/obj/machinery/atmospherics/unary/vent_scrubber/S = target
+ return S.welded
+ else if(istype(target, /obj/machinery/atmospherics/unary/vent_pump))
+ var/obj/machinery/atmospherics/unary/vent_scrubber/V = target
+ return V.welded
+ return FALSE
-/obj/effect/proc_holder/spell/morph/open_vent/cast(list/targets, mob/user)
+/obj/effect/proc_holder/spell/morph_spell/open_vent/cast(list/targets, mob/user)
if(!length(targets))
to_chat(user, "No nearby welded vents found!")
revert_cast(user)
@@ -35,7 +36,7 @@
addtimer(CALLBACK(src, .proc/unweld_vent, U), 2 SECONDS)
playsound(U, 'sound/items/welder.ogg', 100, TRUE)
-/obj/effect/proc_holder/spell/morph/open_vent/proc/unweld_vent(obj/machinery/atmospherics/unary/U)
+/obj/effect/proc_holder/spell/morph_spell/open_vent/proc/unweld_vent(obj/machinery/atmospherics/unary/U)
if(istype(U, /obj/machinery/atmospherics/unary/vent_scrubber))
var/obj/machinery/atmospherics/unary/vent_scrubber/S = U
S.welded = FALSE
diff --git a/code/game/gamemodes/miniantags/morph/spells/pass_airlock.dm b/code/game/gamemodes/miniantags/morph/spells/pass_airlock.dm
index 8334fd4cab9..a33855e1033 100644
--- a/code/game/gamemodes/miniantags/morph/spells/pass_airlock.dm
+++ b/code/game/gamemodes/miniantags/morph/spells/pass_airlock.dm
@@ -1,33 +1,32 @@
// TODO refactor when spell code is component based instead of OO based
-/obj/effect/proc_holder/spell/targeted/click/pass_airlock
+/obj/effect/proc_holder/spell/morph_spell/pass_airlock
name = "Pass Airlock"
desc = "Reform yourself so you can fit through a non bolted airlock. Takes a while to do and can only be used in a non disguised form."
action_background_icon_state = "bg_morph"
action_icon_state = "morph_airlock"
clothes_req = FALSE
charge_max = 10 SECONDS
- range = 1
- allowed_type = /obj/machinery/door/airlock
selection_activated_message = "Click on an airlock to try pass it."
- click_radius = -1
-/obj/effect/proc_holder/spell/targeted/click/pass_airlock/cast_check(charge_check = TRUE, start_recharge = TRUE, mob/living/simple_animal/hostile/morph/user = usr)
- if(!istype(user))
- to_chat(user, "You should not be able to use this abilty! Report this as a bug on github please.")
- stack_trace()
- log_debug("[user] has the spell [src] while he is not a morph")
- return FALSE
+/obj/effect/proc_holder/spell/morph_spell/pass_airlock/create_new_targeting()
+ var/datum/spell_targeting/click/T = new
+ T.range = 1
+ T.allowed_type = /obj/machinery/door/airlock
+ T.click_radius = -1
+ return T
+
+
+/obj/effect/proc_holder/spell/morph_spell/pass_airlock/can_cast(mob/living/simple_animal/hostile/morph/user, charge_check, show_message)
+ . = ..()
+ if(!.)
+ return
+
if(user.morphed)
- to_chat(user, "You can only pass through airlocks in your true form!")
+ if(show_message)
+ to_chat(user, "You can only pass through airlocks in your true form!")
return FALSE
- return ..()
-/obj/effect/proc_holder/spell/targeted/click/pass_airlock/can_cast(mob/living/simple_animal/hostile/morph/user, charge_check, show_message)
- if(!istype(user) || user.morphed)
- return FALSE
- return ..()
-
-/obj/effect/proc_holder/spell/targeted/click/pass_airlock/cast(list/targets, mob/living/simple_animal/hostile/morph/user)
+/obj/effect/proc_holder/spell/morph_spell/pass_airlock/cast(list/targets, mob/living/simple_animal/hostile/morph/user)
var/obj/machinery/door/airlock/A = targets[1]
if(A.locked)
to_chat(user, "[A] is bolted shut! You're unable to create a crack to pass through!")
@@ -48,5 +47,5 @@
user.forceMove(A.loc) // Move into the turf of the airlock
-/obj/effect/proc_holder/spell/targeted/click/pass_airlock/proc/pass_check(mob/living/simple_animal/hostile/morph/user, obj/machinery/door/airlock/A)
+/obj/effect/proc_holder/spell/morph_spell/pass_airlock/proc/pass_check(mob/living/simple_animal/hostile/morph/user, obj/machinery/door/airlock/A)
return user.morphed || A.locked
diff --git a/code/game/gamemodes/miniantags/morph/spells/reproduce.dm b/code/game/gamemodes/miniantags/morph/spells/reproduce.dm
index cd2b18af69b..517aa178381 100644
--- a/code/game/gamemodes/miniantags/morph/spells/reproduce.dm
+++ b/code/game/gamemodes/miniantags/morph/spells/reproduce.dm
@@ -1,28 +1,24 @@
-/obj/effect/proc_holder/spell/morph/reproduce
+/obj/effect/proc_holder/spell/morph_spell/reproduce
name = "Reproduce"
desc = "Split yourself in half making a new morph. Can only be used while on a floor. Makes you temporarily unable to vent crawl."
hunger_cost = 150 // 5 humans
charge_max = 30 SECONDS
action_icon_state = "morph_reproduce"
+ create_attack_logs = FALSE
+/obj/effect/proc_holder/spell/morph_spell/reproduce/create_new_targeting()
+ return new /datum/spell_targeting/self
-/obj/effect/proc_holder/spell/morph/reproduce/choose_targets(mob/user)
- perform(list(user), TRUE, user, FALSE)
-
-/obj/effect/proc_holder/spell/morph/reproduce/cast_check(charge_check = TRUE, start_recharge = TRUE, mob/living/simple_animal/hostile/morph/user = usr)
- if(!isturf(user.loc))
- to_chat(user, "You can only split while on flooring!")
- return FALSE
- return ..()
-
-/obj/effect/proc_holder/spell/morph/reproduce/can_cast(mob/living/simple_animal/hostile/morph/user, charge_check, show_message)
+/obj/effect/proc_holder/spell/morph_spell/reproduce/can_cast(mob/living/simple_animal/hostile/morph/user, charge_check, show_message)
. = ..()
if(!.)
return
if(!isturf(user.loc))
+ if(show_message)
+ to_chat(user, "You can only split while on flooring!")
return FALSE
-/obj/effect/proc_holder/spell/morph/reproduce/cast(list/targets, mob/living/simple_animal/hostile/morph/user)
+/obj/effect/proc_holder/spell/morph_spell/reproduce/cast(list/targets, mob/living/simple_animal/hostile/morph/user)
to_chat(user, "You prepare to split in two, making you unable to vent crawl!")
user.ventcrawler = FALSE // Temporarily disable it
var/list/candidates = SSghost_spawns.poll_candidates("Do you want to play as a morph?", ROLE_MORPH, TRUE, poll_time = 10 SECONDS, source = /mob/living/simple_animal/hostile/morph)
diff --git a/code/game/gamemodes/miniantags/revenant/revenant.dm b/code/game/gamemodes/miniantags/revenant/revenant.dm
index b35d28c24bd..cf69b197e6b 100644
--- a/code/game/gamemodes/miniantags/revenant/revenant.dm
+++ b/code/game/gamemodes/miniantags/revenant/revenant.dm
@@ -193,8 +193,8 @@
SSticker.mode.traitors |= mind //Necessary for announcing
/mob/living/simple_animal/revenant/proc/giveSpells()
- mind.AddSpell(new /obj/effect/proc_holder/spell/targeted/night_vision/revenant(null))
- mind.AddSpell(new /obj/effect/proc_holder/spell/targeted/revenant_transmit(null))
+ mind.AddSpell(new /obj/effect/proc_holder/spell/night_vision/revenant(null))
+ mind.AddSpell(new /obj/effect/proc_holder/spell/revenant_transmit(null))
mind.AddSpell(new /obj/effect/proc_holder/spell/aoe_turf/revenant/overload(null))
mind.AddSpell(new /obj/effect/proc_holder/spell/aoe_turf/revenant/defile(null))
mind.AddSpell(new /obj/effect/proc_holder/spell/aoe_turf/revenant/malfunction(null))
diff --git a/code/game/gamemodes/miniantags/revenant/revenant_abilities.dm b/code/game/gamemodes/miniantags/revenant/revenant_abilities.dm
index fdb7458b7aa..5b24c2f1990 100644
--- a/code/game/gamemodes/miniantags/revenant/revenant_abilities.dm
+++ b/code/game/gamemodes/miniantags/revenant/revenant_abilities.dm
@@ -106,7 +106,7 @@
return
//Toggle night vision: lets the revenant toggle its night vision
-/obj/effect/proc_holder/spell/targeted/night_vision/revenant
+/obj/effect/proc_holder/spell/night_vision/revenant
charge_max = 0
panel = "Revenant Abilities"
message = "You toggle your night vision."
@@ -114,18 +114,21 @@
action_background_icon_state = "bg_revenant"
//Transmit: the revemant's only direct way to communicate. Sends a single message silently to a single mob
-/obj/effect/proc_holder/spell/targeted/revenant_transmit
+/obj/effect/proc_holder/spell/revenant_transmit
name = "Transmit"
desc = "Telepathically transmits a message to the target."
panel = "Revenant Abilities"
charge_max = 0
clothes_req = 0
- range = 7
- include_user = 0
action_icon_state = "r_transmit"
action_background_icon_state = "bg_revenant"
-/obj/effect/proc_holder/spell/targeted/revenant_transmit/cast(list/targets, mob/living/simple_animal/revenant/user = usr)
+/obj/effect/proc_holder/spell/revenant_transmit/create_new_targeting()
+ var/datum/spell_targeting/targeted/T = new()
+ T.allowed_type = /mob/living
+ return T
+
+/obj/effect/proc_holder/spell/revenant_transmit/cast(list/targets, mob/living/simple_animal/revenant/user = usr)
for(var/mob/living/M in targets)
spawn(0)
var/msg = stripped_input(user, "What do you wish to tell [M]?", null, "")
@@ -193,13 +196,17 @@
name = "Overload Lights"
desc = "Directs a large amount of essence into nearby electrical lights, causing lights to shock those nearby."
charge_max = 200
- range = 5
stun = 30
cast_amount = 45
var/shock_range = 2
var/shock_damage = 20
action_icon_state = "overload_lights"
+/obj/effect/proc_holder/spell/aoe_turf/revenant/create_new_targeting()
+ var/datum/spell_targeting/aoe/turf/T = new()
+ T.range = 5
+ return T
+
/obj/effect/proc_holder/spell/aoe_turf/revenant/overload/cast(list/targets, mob/living/simple_animal/revenant/user = usr)
if(attempt_cast(user))
for(var/turf/T in targets)
@@ -232,13 +239,17 @@
name = "Defile"
desc = "Twists and corrupts the nearby area as well as dispelling holy auras on floors."
charge_max = 150
- range = 4
stun = 10
reveal = 40
unlock_amount = 75
cast_amount = 30
action_icon_state = "defile"
+/obj/effect/proc_holder/spell/aoe_turf/revenant/defile/create_new_targeting()
+ var/datum/spell_targeting/aoe/turf/T = new()
+ T.range = 4
+ return T
+
/obj/effect/proc_holder/spell/aoe_turf/revenant/defile/cast(list/targets, mob/living/simple_animal/revenant/user = usr)
if(!attempt_cast(user))
return
@@ -252,11 +263,15 @@
name = "Malfunction"
desc = "Corrupts and damages nearby machines and mechanical objects."
charge_max = 200
- range = 2
cast_amount = 45
unlock_amount = 150
action_icon_state = "malfunction"
+/obj/effect/proc_holder/spell/aoe_turf/revenant/malfunction/create_new_targeting()
+ var/datum/spell_targeting/aoe/turf/T = new()
+ T.range = 2
+ return T
+
//A note to future coders: do not replace this with an EMP because it will wreck malf AIs and gang dominators and everyone will hate you.
/obj/effect/proc_holder/spell/aoe_turf/revenant/malfunction/cast(list/targets, mob/living/simple_animal/revenant/user = usr)
if(attempt_cast(user))
diff --git a/code/game/gamemodes/miniantags/slaughter/slaughter.dm b/code/game/gamemodes/miniantags/slaughter/slaughter.dm
index f388ac2367b..7a2b56ed375 100644
--- a/code/game/gamemodes/miniantags/slaughter/slaughter.dm
+++ b/code/game/gamemodes/miniantags/slaughter/slaughter.dm
@@ -137,34 +137,32 @@
to emerge from it. You are fast, powerful, and almost invincible. By dragging a dead or unconscious body into a blood pool with you, you will consume it after a time and fully regain \
your health. You may use the ability 'Sense Victims' in your Cultist tab to locate a random, living heretic."
-/obj/effect/proc_holder/spell/targeted/sense_victims
+/obj/effect/proc_holder/spell/sense_victims
name = "Sense Victims"
desc = "Sense the location of heretics"
charge_max = 0
clothes_req = 0
- range = 20
cooldown_min = 0
overlay = null
action_icon_state = "bloodcrawl"
action_background_icon_state = "bg_cult"
panel = "Demon"
-/obj/effect/proc_holder/spell/targeted/sense_victims/cast(list/targets, mob/user)
- var/list/victims = targets
- for(var/mob/living/L in GLOB.alive_mob_list)
- if(!L.stat && !iscultist(L) && L.key && L != usr)
- victims.Add(L)
- if(!targets.len)
- to_chat(usr, "You could not locate any sapient heretics for the Slaughter.")
- return 0
- var/mob/living/victim = pick(victims)
+/obj/effect/proc_holder/spell/sense_victims/create_new_targeting()
+ return new /datum/spell_targeting/alive_mob_list
+
+/obj/effect/proc_holder/spell/sense_victims/valid_target(mob/living/target, user)
+ return target.stat == CONSCIOUS && target.key && !iscultist(target) // Only conscious, non cultist players
+
+/obj/effect/proc_holder/spell/sense_victims/cast(list/targets, mob/user)
+ var/mob/living/victim = targets[1]
to_chat(victim, "You feel an awful sense of being watched...")
victim.Stun(3) //HUE
var/area/A = get_area(victim)
if(!A)
- to_chat(usr, "You could not locate any sapient heretics for the Slaughter.")
+ to_chat(user, "You could not locate any sapient heretics for the Slaughter.")
return 0
- to_chat(usr, "You sense a terrified soul at [A]. Show [A.p_them()] the error of [A.p_their()] ways.")
+ to_chat(user, "You sense a terrified soul at [A]. Show [A.p_them()] the error of [A.p_their()] ways.")
/mob/living/simple_animal/slaughter/cult/New()
..()
@@ -189,7 +187,7 @@
S.mind.special_role = "Harbinger of the Slaughter"
to_chat(S, playstyle_string)
SSticker.mode.add_cultist(S.mind)
- var/obj/effect/proc_holder/spell/targeted/sense_victims/SV = new
+ var/obj/effect/proc_holder/spell/sense_victims/SV = new
AddSpell(SV)
var/datum/objective/new_objective = new /datum/objective
new_objective.owner = S.mind
diff --git a/code/game/gamemodes/shadowling/shadowling.dm b/code/game/gamemodes/shadowling/shadowling.dm
index 63e0b668704..aec83c56209 100644
--- a/code/game/gamemodes/shadowling/shadowling.dm
+++ b/code/game/gamemodes/shadowling/shadowling.dm
@@ -141,7 +141,7 @@ Made by Xhuis
/datum/game_mode/proc/finalize_shadowling(datum/mind/shadow_mind)
var/mob/living/carbon/human/S = shadow_mind.current
- shadow_mind.AddSpell(new /obj/effect/proc_holder/spell/targeted/shadowling_hatch(null))
+ shadow_mind.AddSpell(new /obj/effect/proc_holder/spell/shadowling_hatch(null))
spawn(0)
shadow_mind.current.add_language("Shadowling Hivemind")
update_shadow_icons_added(shadow_mind)
@@ -160,8 +160,8 @@ Made by Xhuis
new_thrall_mind.current.create_attack_log("Became a thrall")
new_thrall_mind.current.create_log(CONVERSION_LOG, "Became a thrall")
new_thrall_mind.current.add_language("Shadowling Hivemind")
- new_thrall_mind.AddSpell(new /obj/effect/proc_holder/spell/targeted/lesser_shadow_walk(null))
- new_thrall_mind.AddSpell(new /obj/effect/proc_holder/spell/targeted/shadow_vision(null))
+ new_thrall_mind.AddSpell(new /obj/effect/proc_holder/spell/lesser_shadow_walk(null))
+ new_thrall_mind.AddSpell(new /obj/effect/proc_holder/spell/shadow_vision(null))
to_chat(new_thrall_mind.current, "You see the truth. Reality has been torn away and you realize what a fool you've been.")
to_chat(new_thrall_mind.current, "The shadowlings are your masters. Serve them above all else and ensure they complete their goals.")
to_chat(new_thrall_mind.current, "You may not harm other thralls or the shadowlings. However, you do not need to obey other thralls.")
@@ -220,7 +220,7 @@ Made by Xhuis
if(ishuman(shadow.current))
var/mob/living/carbon/human/H = shadow.current
if(!isshadowling(H))
- for(var/obj/effect/proc_holder/spell/targeted/shadowling_hatch/hatch_ability in shadow.spell_list)
+ for(var/obj/effect/proc_holder/spell/shadowling_hatch/hatch_ability in shadow.spell_list)
hatch_ability.cycles_unused++
if(!H.stunned && prob(20) && hatch_ability.cycles_unused > GLOB.configuration.gamemode.shadowling_max_age)
var/shadow_nag_messages = list("You can barely hold yourself in this lesser form!", "The urge to become something greater is overwhelming!", "You feel a burning passion to hatch free of this shell and assume godhood!")
diff --git a/code/game/gamemodes/shadowling/shadowling_abilities.dm b/code/game/gamemodes/shadowling/shadowling_abilities.dm
index c764028ac41..4b1ee7344ad 100644
--- a/code/game/gamemodes/shadowling/shadowling_abilities.dm
+++ b/code/game/gamemodes/shadowling/shadowling_abilities.dm
@@ -19,30 +19,31 @@
return 0
-/obj/effect/proc_holder/spell/targeted/click/glare //Stuns and mutes a human target, depending on the distance relative to the shadowling
+/obj/effect/proc_holder/spell/glare //Stuns and mutes a human target, depending on the distance relative to the shadowling
name = "Glare"
desc = "Stuns and mutes a target for a decent duration. Duration depends on the proximity to the target."
panel = "Shadowling Abilities"
charge_max = 300
clothes_req = FALSE
- range = 10 //has no effect beyond this range, so setting this makes invalid/useless targets not show up in popup
action_icon_state = "glare"
selection_activated_message = "Your prepare to your eyes for a stunning glare! Left-click to cast at a target!"
selection_deactivated_message = "Your eyes relax... for now."
- allowed_type = /mob/living/carbon/human
-/obj/effect/proc_holder/spell/targeted/click/glare/cast_check(charge_check = TRUE, start_recharge = TRUE, mob/living/user = usr)
+/obj/effect/proc_holder/spell/glare/create_new_targeting()
+ var/datum/spell_targeting/click/T = new()
+ T.range = 10
+ return T
+
+/obj/effect/proc_holder/spell/glare/cast_check(charge_check = TRUE, start_recharge = TRUE, mob/living/user = usr)
if(!shadowling_check(user))
return FALSE
return ..()
-/obj/effect/proc_holder/spell/targeted/click/glare/valid_target(mob/living/carbon/human/target, user)
- if(!..())
- return FALSE
+/obj/effect/proc_holder/spell/glare/valid_target(mob/living/carbon/human/target, user)
return !target.stat && !is_shadow_or_thrall(target)
-/obj/effect/proc_holder/spell/targeted/click/glare/cast(list/targets, mob/user = usr)
+/obj/effect/proc_holder/spell/glare/cast(list/targets, mob/user = usr)
var/mob/living/carbon/human/H = targets[1]
user.visible_message("[user]'s eyes flash a blinding red!")
@@ -63,7 +64,7 @@
to_chat(H, "A red light flashes across your vision, and your mind tries to resist them.. you are exhausted.. you are not able to speak..")
addtimer(CALLBACK(src, .proc/do_stun, H, user, loss), duration SECONDS)
-/obj/effect/proc_holder/spell/targeted/click/glare/proc/do_stun(mob/living/carbon/human/target, user, stun_time)
+/obj/effect/proc_holder/spell/glare/proc/do_stun(mob/living/carbon/human/target, user, stun_time)
if(!istype(target) || target.stat)
return
target.Stun(stun_time)
@@ -76,10 +77,14 @@
panel = "Shadowling Abilities"
charge_max = 150 //Short cooldown because people can just turn the lights back on
clothes_req = 0
- range = 5
var/blacklisted_lights = list(/obj/item/flashlight/flare, /obj/item/flashlight/slime)
action_icon_state = "veil"
+/obj/effect/proc_holder/spell/aoe_turf/veil/create_new_targeting()
+ var/datum/spell_targeting/aoe/turf/T = new()
+ T.range = 5
+ return T
+
/obj/effect/proc_holder/spell/aoe_turf/veil/cast_check(charge_check = TRUE, start_recharge = TRUE, mob/user = usr)
if(!shadowling_check(user))
return FALSE
@@ -95,22 +100,23 @@
for(var/atom/A in T.contents)
A.extinguish_light()
-/obj/effect/proc_holder/spell/targeted/shadow_walk
+/obj/effect/proc_holder/spell/shadow_walk
name = "Shadow Walk"
desc = "Phases you into the space between worlds for a short time, allowing movement through walls and invisbility."
panel = "Shadowling Abilities"
charge_max = 300 //Used to be twice this, buffed
clothes_req = 0
- range = -1
- include_user = 1
action_icon_state = "shadow_walk"
-/obj/effect/proc_holder/spell/targeted/shadow_walk/cast_check(charge_check = TRUE, start_recharge = TRUE, mob/user = usr)
+/obj/effect/proc_holder/spell/shadow_walk/create_new_targeting()
+ return new /datum/spell_targeting/self
+
+/obj/effect/proc_holder/spell/shadow_walk/cast_check(charge_check = TRUE, start_recharge = TRUE, mob/user = usr)
if(!shadowling_check(user))
return FALSE
return ..()
-/obj/effect/proc_holder/spell/targeted/shadow_walk/cast(list/targets, mob/user = usr)
+/obj/effect/proc_holder/spell/shadow_walk/cast(list/targets, mob/user = usr)
for(var/mob/living/target in targets)
playsound(user.loc, 'sound/effects/bamf.ogg', 50, 1)
target.visible_message("[target] vanishes in a puff of black mist!", "You enter the space between worlds as a passageway.")
@@ -130,17 +136,18 @@
target.alpha = 255
target.forceMove(user.loc)
-/obj/effect/proc_holder/spell/targeted/lesser_shadow_walk
+/obj/effect/proc_holder/spell/lesser_shadow_walk
name = "Guise"
desc = "Wraps your form in shadows, making you harder to see."
panel = "Thrall Abilities"
charge_max = 1200
clothes_req = 0
- range = -1
- include_user = 1
action_icon_state = "shadow_walk"
-/obj/effect/proc_holder/spell/targeted/lesser_shadow_walk/cast(list/targets, mob/user = usr)
+/obj/effect/proc_holder/spell/lesser_shadow_walk/create_new_targeting()
+ return new /datum/spell_targeting/self
+
+/obj/effect/proc_holder/spell/lesser_shadow_walk/cast(list/targets, mob/user = usr)
for(var/mob/living/target in targets)
target.visible_message("[target] suddenly fades away!", "You veil yourself in darkness, making you harder to see.")
target.alpha = 10
@@ -149,17 +156,18 @@
target.alpha = initial(target.alpha)
-/obj/effect/proc_holder/spell/targeted/shadow_vision
+/obj/effect/proc_holder/spell/shadow_vision
name = "Thrall Darksight"
desc = "Gives you night vision."
panel = "Thrall Abilities"
charge_max = 0
- range = -1
- include_user = 1
clothes_req = 0
action_icon_state = "darksight"
-/obj/effect/proc_holder/spell/targeted/shadow_vision/cast(list/targets, mob/user = usr)
+/obj/effect/proc_holder/spell/shadow_vision/create_new_targeting()
+ return new /datum/spell_targeting/self
+
+/obj/effect/proc_holder/spell/shadow_vision/cast(list/targets, mob/user = usr)
for(var/mob/living/target in targets)
if(!istype(target) || !ishuman(target))
return
@@ -175,11 +183,15 @@
name = "Icy Veins"
desc = "Instantly freezes the blood of nearby people, stunning them and causing burn damage."
panel = "Shadowling Abilities"
- range = 5
charge_max = 250
clothes_req = 0
action_icon_state = "icy_veins"
+/obj/effect/proc_holder/spell/aoe_turf/flashfreeze/create_new_targeting()
+ var/datum/spell_targeting/aoe/turf/T = new()
+ T.range = 5
+ return T
+
/obj/effect/proc_holder/spell/aoe_turf/flashfreeze/cast_check(charge_check = TRUE, start_recharge = TRUE, mob/living/user = usr)
if(!shadowling_check(user))
return FALSE
@@ -206,22 +218,25 @@
M.reagents.add_reagent("frostoil", 15) //Half of a cryosting
-/obj/effect/proc_holder/spell/targeted/click/enthrall //Turns a target into the shadowling's slave. This overrides all previous loyalties
+/obj/effect/proc_holder/spell/enthrall //Turns a target into the shadowling's slave. This overrides all previous loyalties
name = "Enthrall"
desc = "Allows you to enslave a conscious, non-braindead, non-catatonic human to your will. This takes some time to cast."
panel = "Shadowling Abilities"
charge_max = 0
clothes_req = FALSE
- range = 1 //Adjacent to user
var/enthralling = FALSE
action_icon_state = "enthrall"
- click_radius = -1 // Precision baby
selection_activated_message = "Your prepare your mind to entrall a mortal. Left-click to cast at a target!"
selection_deactivated_message = "Your mind relaxes."
- allowed_type = /mob/living/carbon/human
-/obj/effect/proc_holder/spell/targeted/click/enthrall/cast_check(charge_check = TRUE, start_recharge = TRUE, mob/living/user = usr)
+/obj/effect/proc_holder/spell/enthrall/create_new_targeting()
+ var/datum/spell_targeting/click/T = new()
+ T.range = 1
+ T.click_radius = -1
+ return T
+
+/obj/effect/proc_holder/spell/enthrall/cast_check(charge_check = TRUE, start_recharge = TRUE, mob/living/user = usr)
if(enthralling)
to_chat(user, "You're already enthralling someone!")
return FALSE
@@ -229,12 +244,10 @@
return FALSE
return ..()
-/obj/effect/proc_holder/spell/targeted/click/enthrall/valid_target(mob/living/carbon/human/target, user)
- if(!..())
- return FALSE
+/obj/effect/proc_holder/spell/enthrall/valid_target(mob/living/carbon/human/target, user)
return target.key && target.mind && !target.stat && !is_shadow_or_thrall(target) && target.client
-/obj/effect/proc_holder/spell/targeted/click/enthrall/cast(list/targets, mob/user = usr)
+/obj/effect/proc_holder/spell/enthrall/cast(list/targets, mob/user = usr)
var/mob/living/carbon/human/ling = user
listclearnulls(SSticker.mode.shadowling_thralls)
if(!(ling.mind in SSticker.mode.shadows))
@@ -275,17 +288,18 @@
SSticker.mode.add_thrall(target.mind)
target.mind.special_role = SPECIAL_ROLE_SHADOWLING_THRALL
-/obj/effect/proc_holder/spell/targeted/shadowling_regenarmor //Resets a shadowling's species to normal, removes genetic defects, and re-equips their armor
+/obj/effect/proc_holder/spell/shadowling_regenarmor //Resets a shadowling's species to normal, removes genetic defects, and re-equips their armor
name = "Rapid Re-Hatch"
desc = "Re-forms protective chitin that may be lost during cloning or similar processes."
panel = "Shadowling Abilities"
charge_max = 600
- range = -1
- include_user = 1
clothes_req = 0
action_icon_state = "regen_armor"
-/obj/effect/proc_holder/spell/targeted/shadowling_regenarmor/cast(list/targets, mob/user = usr)
+/obj/effect/proc_holder/spell/shadowling_regenarmor/create_new_targeting()
+ return new /datum/spell_targeting/self
+
+/obj/effect/proc_holder/spell/shadowling_regenarmor/cast(list/targets, mob/user = usr)
if(!is_shadow(user))
to_chat(user, "You must be a shadowling to do this!")
charge_counter = charge_max
@@ -306,26 +320,27 @@
H.equip_to_slot_or_del(new /obj/item/clothing/mask/gas/shadowling(H), slot_wear_mask)
H.equip_to_slot_or_del(new /obj/item/clothing/glasses/shadowling(H), slot_glasses)
-/obj/effect/proc_holder/spell/targeted/collective_mind //Lets a shadowling bring together their thralls' strength, granting new abilities and a headcount
+/obj/effect/proc_holder/spell/collective_mind //Lets a shadowling bring together their thralls' strength, granting new abilities and a headcount
name = "Collective Hivemind"
desc = "Gathers the power of all of your thralls and compares it to what is needed for ascendance. Also gains you new abilities."
panel = "Shadowling Abilities"
charge_max = 300 //30 second cooldown to prevent spam
clothes_req = 0
- range = -1
- include_user = 1
var/blind_smoke_acquired
var/screech_acquired
var/nullChargeAcquired
var/reviveThrallAcquired
action_icon_state = "collective_mind"
-/obj/effect/proc_holder/spell/targeted/collective_mind/cast_check(charge_check = TRUE, start_recharge = TRUE, mob/living/user = usr)
+/obj/effect/proc_holder/spell/collective_mind/create_new_targeting()
+ return new /datum/spell_targeting/self
+
+/obj/effect/proc_holder/spell/collective_mind/cast_check(charge_check = TRUE, start_recharge = TRUE, mob/living/user = usr)
if(!shadowling_check(user))
return FALSE
return ..()
-/obj/effect/proc_holder/spell/targeted/collective_mind/cast(list/targets, mob/user = usr)
+/obj/effect/proc_holder/spell/collective_mind/cast(list/targets, mob/user = usr)
for(var/mob/living/target in targets)
var/thralls = 0
var/victory_threshold = SSticker.mode.required_thralls
@@ -351,7 +366,7 @@
blind_smoke_acquired = 1
to_chat(target, "The power of your thralls has granted you the Blinding Smoke ability. \
It will create a choking cloud that will blind any non-thralls who enter.")
- target.mind.AddSpell(new /obj/effect/proc_holder/spell/targeted/blindness_smoke(null))
+ target.mind.AddSpell(new /obj/effect/proc_holder/spell/blindness_smoke(null))
if(thralls >= CEILING(7 * SSticker.mode.thrall_ratio, 1) && !nullChargeAcquired)
nullChargeAcquired = 1
@@ -363,7 +378,7 @@
reviveThrallAcquired = 1
to_chat(target, "The power of your thralls has granted you the Black Recuperation ability. \
This will, after a short time, bring a dead thrall completely back to life with no bodily defects.")
- target.mind.AddSpell(new /obj/effect/proc_holder/spell/targeted/click/reviveThrall(null))
+ target.mind.AddSpell(new /obj/effect/proc_holder/spell/reviveThrall(null))
if(thralls < victory_threshold)
to_chat(target, "You do not have the power to ascend. You require [victory_threshold] thralls, but only [thralls] living thralls are present.")
@@ -373,12 +388,12 @@
to_chat(target, "You may find Ascendance in the Shadowling Evolution tab.")
for(M in GLOB.alive_mob_list)
if(is_shadow(M))
- var/obj/effect/proc_holder/spell/targeted/collective_mind/CM
+ var/obj/effect/proc_holder/spell/collective_mind/CM
if(CM in M.mind.spell_list)
M.mind.spell_list -= CM
qdel(CM)
- M.mind.RemoveSpell(/obj/effect/proc_holder/spell/targeted/shadowling_hatch)
- M.mind.AddSpell(new /obj/effect/proc_holder/spell/targeted/shadowling_ascend(null))
+ M.mind.RemoveSpell(/obj/effect/proc_holder/spell/shadowling_hatch)
+ M.mind.AddSpell(new /obj/effect/proc_holder/spell/shadowling_ascend(null))
if(M == user)
to_chat(M, "You project this power to the rest of the shadowlings.")
else
@@ -387,22 +402,23 @@
-/obj/effect/proc_holder/spell/targeted/blindness_smoke
+/obj/effect/proc_holder/spell/blindness_smoke
name = "Blindness Smoke"
desc = "Spews a cloud of smoke which will blind enemies."
panel = "Shadowling Abilities"
charge_max = 600
clothes_req = 0
- range = -1
- include_user = 1
action_icon_state = "black_smoke"
-/obj/effect/proc_holder/spell/targeted/blindness_smoke/cast_check(charge_check = TRUE, start_recharge = TRUE, mob/living/user = usr)
+/obj/effect/proc_holder/spell/blindness_smoke/create_new_targeting()
+ return new /datum/spell_targeting/self
+
+/obj/effect/proc_holder/spell/blindness_smoke/cast_check(charge_check = TRUE, start_recharge = TRUE, mob/living/user = usr)
if(!shadowling_check(user))
return FALSE
return ..()
-/obj/effect/proc_holder/spell/targeted/blindness_smoke/cast(list/targets, mob/user = usr) //Extremely hacky
+/obj/effect/proc_holder/spell/blindness_smoke/cast(list/targets, mob/user = usr) //Extremely hacky
for(var/mob/living/target in targets)
target.visible_message("[target] suddenly bends over and coughs out a cloud of black smoke, which begins to spread rapidly!")
to_chat(target, "You regurgitate a vast cloud of blinding smoke.")
@@ -443,11 +459,14 @@
name = "Sonic Screech"
desc = "Deafens, stuns, and confuses nearby people. Also shatters windows."
panel = "Shadowling Abilities"
- range = 7
charge_max = 300
clothes_req = 0
action_icon_state = "screech"
+/obj/effect/proc_holder/spell/aoe_turf/unearthly_screech/create_new_targeting()
+ var/datum/spell_targeting/aoe/turf/T = new()
+ return T
+
/obj/effect/proc_holder/spell/aoe_turf/unearthly_screech/cast_check(charge_check = TRUE, start_recharge = TRUE, mob/living/user = usr)
if(!shadowling_check(user))
return FALSE
@@ -487,6 +506,10 @@
clothes_req = FALSE
action_icon_state = "null_charge"
+/obj/effect/proc_holder/spell/aoe_turf/null_charge/create_new_targeting()
+ var/datum/spell_targeting/aoe/turf/T = new()
+ return T
+
/obj/effect/proc_holder/spell/aoe_turf/null_charge/cast_check(charge_check = TRUE, start_recharge = TRUE, mob/living/user = usr)
if(!shadowling_check(user))
return FALSE
@@ -534,32 +557,31 @@
-/obj/effect/proc_holder/spell/targeted/click/reviveThrall
+/obj/effect/proc_holder/spell/reviveThrall
name = "Black Recuperation"
desc = "Revives or empowers a thrall."
panel = "Shadowling Abilities"
- range = 1
charge_max = 600
clothes_req = FALSE
- include_user = FALSE
action_icon_state = "revive_thrall"
- click_radius = -1 // Precision baby
selection_activated_message = "You start focusing your powers on mending wounds of allies. Left-click to cast at a target!"
selection_deactivated_message = "Your mind relaxes."
- allowed_type = /mob/living/carbon/human
-/obj/effect/proc_holder/spell/targeted/click/reviveThrall/cast_check(charge_check = TRUE, start_recharge = TRUE, mob/living/user = usr)
+/obj/effect/proc_holder/spell/reviveThrall/create_new_targeting()
+ var/datum/spell_targeting/click/T = new()
+ T.click_radius = -1
+ T.range = 1
+ return T
+
+/obj/effect/proc_holder/spell/reviveThrall/cast_check(charge_check = TRUE, start_recharge = TRUE, mob/living/user = usr)
if(!shadowling_check(user))
return FALSE
return ..()
-/obj/effect/proc_holder/spell/targeted/click/reviveThrall/valid_target(mob/living/carbon/human/target, user)
- if(!..())
- return FALSE
-
+/obj/effect/proc_holder/spell/reviveThrall/valid_target(mob/living/carbon/human/target, user)
return is_thrall(target)
-/obj/effect/proc_holder/spell/targeted/click/reviveThrall/cast(list/targets, mob/user = usr)
+/obj/effect/proc_holder/spell/reviveThrall/cast(list/targets, mob/user = usr)
var/mob/living/carbon/human/thrallToRevive = targets[1]
if(thrallToRevive.stat == CONSCIOUS)
if(isshadowlinglesser(thrallToRevive))
@@ -597,9 +619,9 @@
"You feel new power flow into you. You have been gifted by your masters. You now closely resemble them. You are empowered in \
darkness but wither slowly in light. In addition, you now have glare and true shadow walk.")
thrallToRevive.set_species(/datum/species/shadow/ling/lesser)
- thrallToRevive.mind.RemoveSpell(/obj/effect/proc_holder/spell/targeted/lesser_shadow_walk)
- thrallToRevive.mind.AddSpell(new /obj/effect/proc_holder/spell/targeted/click/glare(null))
- thrallToRevive.mind.AddSpell(new /obj/effect/proc_holder/spell/targeted/shadow_walk(null))
+ thrallToRevive.mind.RemoveSpell(/obj/effect/proc_holder/spell/lesser_shadow_walk)
+ thrallToRevive.mind.AddSpell(new /obj/effect/proc_holder/spell/glare(null))
+ thrallToRevive.mind.AddSpell(new /obj/effect/proc_holder/spell/shadow_walk(null))
else if(thrallToRevive.stat == DEAD)
user.visible_message("[user] kneels over [thrallToRevive], placing [user.p_their()] hands on [thrallToRevive.p_their()] chest.", \
"You crouch over the body of your thrall and begin gathering energy...")
@@ -624,26 +646,29 @@
to_chat(user, "The target must be awake to empower or dead to revive.")
revert_cast(user)
-/obj/effect/proc_holder/spell/targeted/click/shadowling_extend_shuttle
+/obj/effect/proc_holder/spell/shadowling_extend_shuttle
name = "Destroy Engines"
desc = "Extends the time of the emergency shuttle's arrival by ten minutes using a life force of our enemy. Shuttle will be unable to be recalled. This can only be used once."
panel = "Shadowling Abilities"
- range = 1
clothes_req = FALSE
charge_max = 600
- click_radius = -1 // Precision baby
selection_activated_message = "You start gathering destructive powers to delay the shuttle. Left-click to cast at a target!"
selection_deactivated_message = "Your mind relaxes."
- allowed_type = /mob/living/carbon/human
action_icon_state = "extend_shuttle"
var/global/extendlimit = 0
-/obj/effect/proc_holder/spell/targeted/click/shadowling_extend_shuttle/cast_check(charge_check = TRUE, start_recharge = TRUE, mob/living/user = usr)
+/obj/effect/proc_holder/spell/shadowling_extend_shuttle/create_new_targeting()
+ var/datum/spell_targeting/click/T = new()
+ T.click_radius = -1
+ T.range = 1
+ return T
+
+/obj/effect/proc_holder/spell/shadowling_extend_shuttle/cast_check(charge_check = TRUE, start_recharge = TRUE, mob/living/user = usr)
if(!shadowling_check(user))
return FALSE
return ..()
-/obj/effect/proc_holder/spell/targeted/click/shadowling_extend_shuttle/can_cast(mob/user = usr, charge_check = TRUE, show_message = FALSE)
+/obj/effect/proc_holder/spell/shadowling_extend_shuttle/can_cast(mob/user = usr, charge_check = TRUE, show_message = FALSE)
if(extendlimit == 1)
if(show_message)
to_chat(user, "Shuttle was already delayed.")
@@ -654,13 +679,11 @@
return FALSE
return ..()
-/obj/effect/proc_holder/spell/targeted/click/shadowling_extend_shuttle/valid_target(mob/living/carbon/human/target, user)
- if(!..())
- return FALSE
+/obj/effect/proc_holder/spell/shadowling_extend_shuttle/valid_target(mob/living/carbon/human/target, user)
return !target.stat && !is_shadow_or_thrall(target)
-/obj/effect/proc_holder/spell/targeted/click/shadowling_extend_shuttle/cast(list/targets, mob/user = usr)
+/obj/effect/proc_holder/spell/shadowling_extend_shuttle/cast(list/targets, mob/user = usr)
var/mob/living/carbon/human/target = targets[1]
user.visible_message("[user]'s eyes flash a bright red!", \
@@ -688,19 +711,21 @@
// ASCENDANT ABILITIES BEYOND THIS POINT //
-/obj/effect/proc_holder/spell/targeted/click/annihilate
+/obj/effect/proc_holder/spell/annihilate
name = "Annihilate"
desc = "Gibs someone instantly."
panel = "Ascendant"
- range = 7
charge_max = FALSE
clothes_req = FALSE
action_icon_state = "annihilate"
selection_activated_message = "You start thinking about gibs. Left-click to cast at a target!"
selection_deactivated_message = "Your mind relaxes."
- allowed_type = /mob/living/carbon/human
-/obj/effect/proc_holder/spell/targeted/click/annihilate/cast(list/targets, mob/user = usr)
+/obj/effect/proc_holder/spell/annihilate/create_new_targeting()
+ var/datum/spell_targeting/click/T = new()
+ return T
+
+/obj/effect/proc_holder/spell/annihilate/cast(list/targets, mob/user = usr)
var/mob/living/simple_animal/ascendant_shadowling/SHA = user
if(SHA.phasing)
to_chat(user, "You are not in the same plane of existence. Unphase first.")
@@ -723,21 +748,23 @@
-/obj/effect/proc_holder/spell/targeted/click/hypnosis
+/obj/effect/proc_holder/spell/hypnosis
name = "Hypnosis"
desc = "Instantly enthralls a human."
panel = "Ascendant"
- range = 7
charge_max = FALSE
clothes_req = FALSE
action_icon_state = "enthrall"
- click_radius = -1
selection_activated_message = "You start preparing to mindwash over a mortal mind. Left-click to cast at a target!"
selection_deactivated_message = "Your mind relaxes."
- allowed_type = /mob/living/carbon/human
-/obj/effect/proc_holder/spell/targeted/click/hypnosis/can_cast(mob/living/simple_animal/ascendant_shadowling/user = usr, charge_check = TRUE, show_message = FALSE)
+/obj/effect/proc_holder/spell/hypnosis/create_new_targeting()
+ var/datum/spell_targeting/click/T = new()
+ T.click_radius = -1
+ return T
+
+/obj/effect/proc_holder/spell/hypnosis/can_cast(mob/living/simple_animal/ascendant_shadowling/user = usr, charge_check = TRUE, show_message = FALSE)
if(!istype(user))
return FALSE
if(user.phasing)
@@ -746,12 +773,10 @@
return FALSE
return ..()
-/obj/effect/proc_holder/spell/targeted/click/hypnosis/valid_target(mob/living/carbon/human/target, user)
- if(!..())
- return FALSE
+/obj/effect/proc_holder/spell/hypnosis/valid_target(mob/living/carbon/human/target, user)
return !is_shadow_or_thrall(target) && target.ckey && target.mind && !target.stat
-/obj/effect/proc_holder/spell/targeted/click/hypnosis/cast(list/targets, mob/user = usr)
+/obj/effect/proc_holder/spell/hypnosis/cast(list/targets, mob/user = usr)
var/mob/living/carbon/human/target = targets[1]
to_chat(user, "You instantly rearrange [target]'s memories, hyptonitizing [target.p_them()] into a thrall.")
@@ -762,17 +787,18 @@
-/obj/effect/proc_holder/spell/targeted/shadowling_phase_shift
+/obj/effect/proc_holder/spell/shadowling_phase_shift
name = "Phase Shift"
desc = "Phases you into the space between worlds at will, allowing you to move through walls and become invisible."
panel = "Ascendant"
- range = -1
- include_user = 1
charge_max = 15
clothes_req = 0
action_icon_state = "shadow_walk"
-/obj/effect/proc_holder/spell/targeted/shadowling_phase_shift/cast(list/targets, mob/user = usr)
+/obj/effect/proc_holder/spell/shadowling_phase_shift/create_new_targeting()
+ return new /datum/spell_targeting/self
+
+/obj/effect/proc_holder/spell/shadowling_phase_shift/cast(list/targets, mob/user = usr)
var/mob/living/simple_animal/ascendant_shadowling/SHA = user
for(SHA in targets)
SHA.phasing = !SHA.phasing
@@ -793,11 +819,15 @@
name = "Lightning Storm"
desc = "Shocks everyone nearby."
panel = "Ascendant"
- range = 6
charge_max = 100
clothes_req = 0
action_icon_state = "lightning_storm"
+/obj/effect/proc_holder/spell/aoe_turf/ascendant_storm/create_new_targeting()
+ var/datum/spell_targeting/aoe/turf/T = new()
+ T.range = 6
+ return T
+
/obj/effect/proc_holder/spell/aoe_turf/ascendant_storm/cast(list/targets, mob/user = usr)
var/mob/living/simple_animal/ascendant_shadowling/SHA = user
if(SHA.phasing)
@@ -818,17 +848,18 @@
target.take_organ_damage(0,50)
user.Beam(target,icon_state="red_lightning",icon='icons/effects/effects.dmi',time=1)
-/obj/effect/proc_holder/spell/targeted/shadowlingAscendantTransmit
+/obj/effect/proc_holder/spell/shadowlingAscendantTransmit
name = "Ascendant Broadcast"
desc = "Sends a message to the whole wide world."
panel = "Ascendant"
charge_max = 200
clothes_req = 0
- range = -1
- include_user = 1
action_icon_state = "transmit"
-/obj/effect/proc_holder/spell/targeted/shadowlingAscendantTransmit/cast(list/targets, mob/user = usr)
+/obj/effect/proc_holder/spell/shadowlingAscendantTransmit/create_new_targeting()
+ return new /datum/spell_targeting/self
+
+/obj/effect/proc_holder/spell/shadowlingAscendantTransmit/cast(list/targets, mob/user = usr)
for(var/mob/living/simple_animal/ascendant_shadowling/target in targets)
var/text = stripped_input(target, "What do you want to say to everything on and near [station_name()]?.", "Transmit to World", "")
if(!text)
diff --git a/code/game/gamemodes/shadowling/special_shadowling_abilities.dm b/code/game/gamemodes/shadowling/special_shadowling_abilities.dm
index 4007ce3c77a..c6840601cc9 100644
--- a/code/game/gamemodes/shadowling/special_shadowling_abilities.dm
+++ b/code/game/gamemodes/shadowling/special_shadowling_abilities.dm
@@ -1,17 +1,18 @@
//In here: Hatch and Ascendance
GLOBAL_LIST_INIT(possibleShadowlingNames, list("U'ruan", "Y`shej", "Nex", "Hel-uae", "Noaey'gief", "Mii`mahza", "Amerziox", "Gyrg-mylin", "Kanet'pruunance", "Vigistaezian")) //Unpronouncable 2: electric boogalo)
-/obj/effect/proc_holder/spell/targeted/shadowling_hatch
+/obj/effect/proc_holder/spell/shadowling_hatch
name = "Hatch"
desc = "Casts off your disguise."
panel = "Shadowling Evolution"
charge_max = 3000
clothes_req = 0
- range = -1
- include_user = 1
action_icon_state = "hatch"
var/cycles_unused = 0
-/obj/effect/proc_holder/spell/targeted/shadowling_hatch/cast(list/targets, mob/user = usr)
+/obj/effect/proc_holder/spell/shadowling_hatch/create_new_targeting()
+ return new /datum/spell_targeting/self
+
+/obj/effect/proc_holder/spell/shadowling_hatch/cast(list/targets, mob/user = usr)
if(user.stat || !ishuman(user) || !user || !is_shadow(user || isinspace(user)))
return
if(!isturf(user.loc))
@@ -99,35 +100,36 @@ GLOBAL_LIST_INIT(possibleShadowlingNames, list("U'ruan", "Y`shej", "Nex", "Hel-u
sleep(10)
to_chat(H, "Your powers are awoken. You may now live to your fullest extent. Remember your goal. Cooperate with your thralls and allies.")
H.ExtinguishMob()
- H.mind.AddSpell(new /obj/effect/proc_holder/spell/targeted/click/enthrall(null))
- H.mind.AddSpell(new /obj/effect/proc_holder/spell/targeted/click/glare(null))
+ H.mind.AddSpell(new /obj/effect/proc_holder/spell/enthrall(null))
+ H.mind.AddSpell(new /obj/effect/proc_holder/spell/glare(null))
H.mind.AddSpell(new /obj/effect/proc_holder/spell/aoe_turf/veil(null))
- H.mind.AddSpell(new /obj/effect/proc_holder/spell/targeted/shadow_walk(null))
+ H.mind.AddSpell(new /obj/effect/proc_holder/spell/shadow_walk(null))
H.mind.AddSpell(new /obj/effect/proc_holder/spell/aoe_turf/flashfreeze(null))
- H.mind.AddSpell(new /obj/effect/proc_holder/spell/targeted/collective_mind(null))
- H.mind.AddSpell(new /obj/effect/proc_holder/spell/targeted/shadowling_regenarmor(null))
- H.mind.AddSpell(new /obj/effect/proc_holder/spell/targeted/click/shadowling_extend_shuttle(null))
+ H.mind.AddSpell(new /obj/effect/proc_holder/spell/collective_mind(null))
+ H.mind.AddSpell(new /obj/effect/proc_holder/spell/shadowling_regenarmor(null))
+ H.mind.AddSpell(new /obj/effect/proc_holder/spell/shadowling_extend_shuttle(null))
QDEL_NULL(H.hud_used)
H.hud_used = new /datum/hud/human(H, ui_style2icon(H.client.prefs.UI_style), H.client.prefs.UI_style_color, H.client.prefs.UI_style_alpha)
H.hud_used.show_hud(H.hud_used.hud_version)
-/obj/effect/proc_holder/spell/targeted/shadowling_ascend
+/obj/effect/proc_holder/spell/shadowling_ascend
name = "Ascend"
desc = "Enters your true form."
panel = "Shadowling Evolution"
charge_max = 3000
clothes_req = 0
- range = -1
- include_user = 1
action_icon_state = "ascend"
-/obj/effect/proc_holder/spell/targeted/shadowling_ascend/cast_check(charge_check = TRUE, start_recharge = TRUE, mob/living/user = usr)
+/obj/effect/proc_holder/spell/shadowling_ascend/create_new_targeting()
+ return new /datum/spell_targeting/self
+
+/obj/effect/proc_holder/spell/shadowling_ascend/cast_check(charge_check = TRUE, start_recharge = TRUE, mob/living/user = usr)
if(!shadowling_check(user))
return FALSE
return ..()
-/obj/effect/proc_holder/spell/targeted/shadowling_ascend/cast(list/targets, mob/user = usr)
+/obj/effect/proc_holder/spell/shadowling_ascend/cast(list/targets, mob/user = usr)
var/mob/living/carbon/human/H = user
for(H in targets)
var/hatch_or_no = alert(H,"It is time to ascend. Are you sure about this?",,"Yes","No")
@@ -175,11 +177,11 @@ GLOBAL_LIST_INIT(possibleShadowlingNames, list("U'ruan", "Y`shej", "Nex", "Hel-u
H.mind.transfer_to(A)
A.name = H.real_name
A.languages = H.languages
- A.mind.AddSpell(new /obj/effect/proc_holder/spell/targeted/click/annihilate(null))
- A.mind.AddSpell(new /obj/effect/proc_holder/spell/targeted/click/hypnosis(null))
- A.mind.AddSpell(new /obj/effect/proc_holder/spell/targeted/shadowling_phase_shift(null))
+ A.mind.AddSpell(new /obj/effect/proc_holder/spell/annihilate(null))
+ A.mind.AddSpell(new /obj/effect/proc_holder/spell/hypnosis(null))
+ A.mind.AddSpell(new /obj/effect/proc_holder/spell/shadowling_phase_shift(null))
A.mind.AddSpell(new /obj/effect/proc_holder/spell/aoe_turf/ascendant_storm(null))
- A.mind.AddSpell(new /obj/effect/proc_holder/spell/targeted/shadowlingAscendantTransmit(null))
+ A.mind.AddSpell(new /obj/effect/proc_holder/spell/shadowlingAscendantTransmit(null))
if(A.real_name)
A.real_name = H.real_name
H.invisibility = 60 //This is pretty bad, but is also necessary for the shuttle call to function properly
diff --git a/code/game/gamemodes/vampire/vampire.dm b/code/game/gamemodes/vampire/vampire.dm
index 695a7a4853e..9cd494c3705 100644
--- a/code/game/gamemodes/vampire/vampire.dm
+++ b/code/game/gamemodes/vampire/vampire.dm
@@ -221,12 +221,12 @@ You are weak to holy things, starlight and fire. Don't go into space and avoid t
/// Nullrods and holywater make their abilities cost more
var/nullified = 0
/// a list of powers that all vampires unlock and at what blood level they unlock them, the rest of their powers are found in the vampire_subclass datum
- var/list/upgrade_tiers = list(/obj/effect/proc_holder/spell/self/vampire/rejuvenate = 0,
- /obj/effect/proc_holder/spell/mob_aoe/glare = 0,
+ var/list/upgrade_tiers = list(/obj/effect/proc_holder/spell/vampire/self/rejuvenate = 0,
+ /obj/effect/proc_holder/spell/vampire/glare = 0,
/datum/vampire_passive/vision = 100,
- /obj/effect/proc_holder/spell/self/vampire/specialize = 150,
+ /obj/effect/proc_holder/spell/vampire/self/specialize = 150,
/datum/vampire_passive/regen = 200,
- /obj/effect/proc_holder/spell/targeted/turf_teleport/shadow_step = 250)
+ /obj/effect/proc_holder/spell/turf_teleport/shadow_step = 250)
/// list of the peoples UIDs that we have drained, and how much blood from each one
var/list/drained_humans = list()
diff --git a/code/game/gamemodes/vampire/vampire_powers/gargantua_powers.dm b/code/game/gamemodes/vampire/vampire_powers/gargantua_powers.dm
index 046a51f60e6..f60d71c76f9 100644
--- a/code/game/gamemodes/vampire/vampire_powers/gargantua_powers.dm
+++ b/code/game/gamemodes/vampire/vampire_powers/gargantua_powers.dm
@@ -1,4 +1,4 @@
-/obj/effect/proc_holder/spell/self/vampire/blood_swell
+/obj/effect/proc_holder/spell/vampire/self/blood_swell
name = "Blood Swell (30)"
desc = "You infuse your body with blood, making you highly resistant to stuns and physical damage. However, this makes you unable to fire ranged weapons while it is active."
gain_desc = "You have gained the ability to temporarly resist large amounts of stuns and physical damage."
@@ -6,7 +6,7 @@
required_blood = 30
action_icon_state = "blood_swell"
-/obj/effect/proc_holder/spell/self/vampire/blood_swell/cast(list/targets, mob/user)
+/obj/effect/proc_holder/spell/vampire/self/blood_swell/cast(list/targets, mob/user)
var/mob/living/target = targets[1]
if(ishuman(target))
var/mob/living/carbon/human/H = target
@@ -15,14 +15,14 @@
/datum/vampire_passive/blood_swell_upgrade
gain_desc = "While blood swell is active all of your melee attacks deal increased damage."
-/obj/effect/proc_holder/spell/self/vampire/overwhelming_force
+/obj/effect/proc_holder/spell/vampire/self/overwhelming_force
name = "Overwhelming Force"
desc = "When toggled you will automatically pry open doors that you bump into if you do not have access."
gain_desc = "You have gained the ability to force open doors at a small blood cost."
charge_max = 2 SECONDS
action_icon_state = "OH_YEAAAAH"
-/obj/effect/proc_holder/spell/self/vampire/overwhelming_force/cast(list/targets, mob/user)
+/obj/effect/proc_holder/spell/vampire/self/overwhelming_force/cast(list/targets, mob/user)
if(!HAS_TRAIT_FROM(user, TRAIT_FORCE_DOORS, VAMPIRE_TRAIT))
to_chat(user, "You feel MIGHTY!")
ADD_TRAIT(user, TRAIT_FORCE_DOORS, VAMPIRE_TRAIT)
@@ -33,7 +33,7 @@
user.move_resist = MOVE_FORCE_DEFAULT
user.status_flags |= CANPUSH
-/obj/effect/proc_holder/spell/self/vampire/blood_rush
+/obj/effect/proc_holder/spell/vampire/self/blood_rush
name = "Blood Rush (30)"
desc = "Infuse yourself with blood magic to boost your movement speed."
gain_desc = "You have gained the ability to temporarily move at high speeds."
@@ -41,39 +41,34 @@
required_blood = 30
action_icon_state = "blood_rush"
-/obj/effect/proc_holder/spell/self/vampire/blood_rush/cast(list/targets, mob/user)
+/obj/effect/proc_holder/spell/vampire/self/blood_rush/cast(list/targets, mob/user)
var/mob/living/target = targets[1]
if(ishuman(target))
var/mob/living/carbon/human/H = target
to_chat(H, "You feel a rush of energy!")
H.apply_status_effect(STATUS_EFFECT_BLOOD_RUSH)
-/obj/effect/proc_holder/spell/targeted/click/charge
+/obj/effect/proc_holder/spell/vampire/charge
name = "Charge (30)"
desc = "You charge at wherever you click on screen, dealing large amounts of damage, stunning and destroying walls and other objects."
gain_desc = "You can now charge at a target on screen, dealing massive damage and destroying structures."
required_blood = 30
charge_max = 30 SECONDS
- vampire_ability = TRUE
- panel = "Vampire"
- school = "vampire"
- action_background_icon_state = "bg_vampire"
action_icon_state = "vampire_charge"
- allowed_type = /atom
- range = 7
- auto_target_single = FALSE
- click_radius = -1
-/obj/effect/proc_holder/spell/targeted/click/charge/can_cast(mob/user, charge_check, show_message)
+/obj/effect/proc_holder/spell/vampire/charge/create_new_targeting()
+ return new /datum/spell_targeting/clicked_atom
+
+/obj/effect/proc_holder/spell/vampire/charge/can_cast(mob/user, charge_check, show_message)
var/mob/living/L = user
if(L.IsWeakened() || L.resting)
return FALSE
return ..()
-/obj/effect/proc_holder/spell/targeted/click/charge/cast(list/targets, mob/user)
+/obj/effect/proc_holder/spell/vampire/charge/cast(list/targets, mob/user)
var/target = targets[1]
if(isliving(user))
var/mob/living/L = user
L.apply_status_effect(STATUS_EFFECT_CHARGING)
- L.throw_at(target, range, 1, L, FALSE, callback = CALLBACK(L, /mob/living/.proc/remove_status_effect, STATUS_EFFECT_CHARGING))
+ L.throw_at(target, targeting.range, 1, L, FALSE, callback = CALLBACK(L, /mob/living/.proc/remove_status_effect, STATUS_EFFECT_CHARGING))
diff --git a/code/game/gamemodes/vampire/vampire_powers/hemomancer_powers.dm b/code/game/gamemodes/vampire/vampire_powers/hemomancer_powers.dm
index 81ebe5a7ae0..77df8021812 100644
--- a/code/game/gamemodes/vampire/vampire_powers/hemomancer_powers.dm
+++ b/code/game/gamemodes/vampire/vampire_powers/hemomancer_powers.dm
@@ -1,4 +1,4 @@
-/obj/effect/proc_holder/spell/self/vampire/vamp_claws
+/obj/effect/proc_holder/spell/vampire/self/vamp_claws
name = "Vampiric Claws (30)"
desc = "You channel blood magics to forge deadly vampiric claws that leech blood and strike rapidly. Cannot be used if you are holding something that cannot be dropped."
gain_desc = "You have gained the ability to forge your hands into vampiric claws."
@@ -6,7 +6,7 @@
required_blood = 30
action_icon_state = "vampire_claws"
-/obj/effect/proc_holder/spell/self/vampire/vamp_claws/cast(mob/user)
+/obj/effect/proc_holder/spell/vampire/self/vamp_claws/cast(mob/user)
if(user.l_hand || user.r_hand)
to_chat(user, "You drop what was in your hands as large blades spring from your fingers!")
user.drop_l_hand()
@@ -17,7 +17,7 @@
user.put_in_hands(claws)
-/obj/effect/proc_holder/spell/self/vampire/vamp_claws/can_cast(mob/user, charge_check, show_message)
+/obj/effect/proc_holder/spell/vampire/self/vamp_claws/can_cast(mob/user, charge_check, show_message)
var/mob/living/L = user
if(L.canUnEquip(L.l_hand) && L.canUnEquip(L.r_hand))
return ..()
@@ -82,16 +82,13 @@
to_chat(user, "You dispel your claws!")
qdel(src)
-/obj/effect/proc_holder/spell/targeted/click/blood_tendrils
+/obj/effect/proc_holder/spell/vampire/blood_tendrils
name = "Blood Tendrils (10)"
desc = "You summon blood tendrils from bluespace after a delay to ensnare people in an area, slowing them down."
gain_desc = "You have gained the ability to summon blood tendrils to slow people down in an area that you target."
required_blood = 10
- vampire_ability = TRUE
- click_radius = 1
charge_max = 30 SECONDS
- allowed_type = /atom
panel = "Vampire"
school = "vampire"
action_background_icon_state = "bg_vampire"
@@ -102,8 +99,14 @@
selection_activated_message = "You channel blood magics to weaken the bluespace veil. Left-click to cast at a target area!"
selection_deactivated_message = "Your magics subside."
+/obj/effect/proc_holder/spell/vampire/blood_tendrils/create_new_targeting()
+ var/datum/spell_targeting/click/T = new
+ T.allowed_type = /atom
+ T.try_auto_target = FALSE
+ return T
-/obj/effect/proc_holder/spell/targeted/click/blood_tendrils/cast(list/targets, mob/user)
+
+/obj/effect/proc_holder/spell/vampire/blood_tendrils/cast(list/targets, mob/user)
var/turf/T = get_turf(targets[1]) // there should only ever be one entry in targets for this spell
for(var/turf/simulated/blood_turf in view(area_of_affect, T))
@@ -113,7 +116,7 @@
addtimer(CALLBACK(src, .proc/apply_slowdown, T, area_of_affect, 3, user), 0.5 SECONDS)
-/obj/effect/proc_holder/spell/targeted/click/blood_tendrils/proc/apply_slowdown(turf/T, distance, slowed_amount, mob/user)
+/obj/effect/proc_holder/spell/vampire/blood_tendrils/proc/apply_slowdown(turf/T, distance, slowed_amount, mob/user)
for(var/mob/living/L in range(distance, T))
if(L.affects_vampire(user))
L.AdjustSlowed(slowed_amount)
@@ -128,13 +131,12 @@
/obj/effect/temp_visual/blood_tendril/long
duration = 2 SECONDS
-/obj/effect/proc_holder/spell/targeted/ethereal_jaunt/blood_pool
+/obj/effect/proc_holder/spell/ethereal_jaunt/blood_pool
name = "Sanguine Pool (50)"
desc = "You shift your form into a pool of blood, making you invulnerable and able to move through anything that's not a wall or space. You leave a trail of blood behind you when you do this."
gain_desc = "You have gained the ability to shift into a pool of blood, allowing you to evade pursuers with great mobility."
- vampire_ability = TRUE
- required_blood = 50
jaunt_duration = 3 SECONDS
+ clothes_req = FALSE
panel = "Vampire"
school = "vampire"
action_background_icon_state = "bg_vampire"
@@ -146,19 +148,33 @@
jaunt_in_time = 0
sound1 = 'sound/misc/enter_blood.ogg'
-/obj/effect/proc_holder/spell/blood_eruption
+/obj/effect/proc_holder/spell/ethereal_jaunt/blood_pool/create_new_handler()
+ var/datum/spell_handler/vampire/H = new
+ H.required_blood = 50
+ return H
+
+/obj/effect/proc_holder/spell/vampire/blood_eruption
name = "Blood Eruption (100)"
desc = "Every pool of blood in 4 tiles erupts with a spike of living blood, damaging anyone stood on it."
gain_desc = "You have gained the ability to weaponise pools of blood to damage those stood on them."
- vampire_ability = TRUE
required_blood = 100
charge_max = 200 SECONDS
- panel = "Vampire"
- school = "vampire"
- action_background_icon_state = "bg_vampire"
action_icon_state = "blood_spikes"
-/obj/effect/proc_holder/spell/blood_eruption/cast(list/targets, mob/user)
+/obj/effect/proc_holder/spell/vampire/blood_eruption/create_new_targeting()
+ var/datum/spell_targeting/aoe/T = new
+ T.range = 4
+ T.allowed_type = /mob/living
+ return T
+
+/obj/effect/proc_holder/spell/vampire/blood_eruption/valid_target(mob/living/target, user)
+ var/turf/T = get_turf(target)
+ if(locate(/obj/effect/decal/cleanable/blood) in T)
+ if(target.affects_vampire(user) && !isLivingSSD(target))
+ return TRUE
+ return FALSE
+
+/obj/effect/proc_holder/spell/vampire/blood_eruption/cast(list/targets, mob/user)
for(var/mob/living/L in targets)
var/turf/T = get_turf(L)
var/obj/effect/decal/cleanable/blood/B = locate(/obj/effect/decal/cleanable/blood) in T
@@ -168,26 +184,12 @@
L.apply_damage(50, BRUTE, BODY_ZONE_CHEST)
L.visible_message("[L] gets impaled by a spike of living blood!")
-/obj/effect/proc_holder/spell/blood_eruption/choose_targets(mob/user)
- var/list/targets = list()
- for(var/mob/living/L in view(4, user))
- var/turf/T = get_turf(L)
- if(locate(/obj/effect/decal/cleanable/blood) in T)
- if(L.affects_vampire(user) && !isLivingSSD(L))
- targets.Add(L)
-
- if(!length(targets))
- revert_cast(user)
- return
-
- perform(targets)
-
/obj/effect/temp_visual/blood_spike
icon = 'icons/effects/vampire_effects.dmi'
icon_state = "bloodspike_white"
duration = 0.3 SECONDS
-/obj/effect/proc_holder/spell/self/vampire/blood_spill
+/obj/effect/proc_holder/spell/vampire/self/blood_spill
name = "The Blood Bringers Rite"
desc = "When toggled, everyone around you begins to bleed profusely."
gain_desc = "You have gained the ability to rip the very life force out of people and absorb it, healing you."
@@ -195,7 +197,7 @@
action_icon_state = "blood_bringers_rite"
required_blood = 10
-/obj/effect/proc_holder/spell/self/vampire/blood_spill/cast(list/targets, mob/user)
+/obj/effect/proc_holder/spell/vampire/self/blood_spill/cast(list/targets, mob/user)
var/mob/target = targets[1]
if(!target.mind.vampire.get_ability(/datum/vampire_passive/blood_spill))
target.mind.vampire.force_add_ability(/datum/vampire_passive/blood_spill)
diff --git a/code/game/gamemodes/vampire/vampire_powers/umbrae_powers.dm b/code/game/gamemodes/vampire/vampire_powers/umbrae_powers.dm
index c86b3647db5..e16950b37f4 100644
--- a/code/game/gamemodes/vampire/vampire_powers/umbrae_powers.dm
+++ b/code/game/gamemodes/vampire/vampire_powers/umbrae_powers.dm
@@ -1,21 +1,21 @@
-/obj/effect/proc_holder/spell/self/vampire/cloak
+/obj/effect/proc_holder/spell/vampire/self/cloak
name = "Cloak of Darkness"
desc = "Toggles whether you are currently cloaking yourself in darkness. When in darkness and toggled on, you move at increased speeds."
gain_desc = "You have gained the Cloak of Darkness ability, which when toggled makes you nearly invisible and highly agile in the shroud of darkness."
action_icon_state = "vampire_cloak"
charge_max = 2 SECONDS
-/obj/effect/proc_holder/spell/self/vampire/cloak/New()
+/obj/effect/proc_holder/spell/vampire/self/cloak/New()
..()
update_name()
-/obj/effect/proc_holder/spell/self/vampire/cloak/proc/update_name()
+/obj/effect/proc_holder/spell/vampire/self/cloak/proc/update_name()
var/mob/living/user = loc
if(!ishuman(user) || !user.mind || !user.mind.vampire)
return
action.button.name = "[initial(name)] ([user.mind.vampire.iscloaking ? "Deactivate" : "Activate"])"
-/obj/effect/proc_holder/spell/self/vampire/cloak/cast(list/targets, mob/user = usr)
+/obj/effect/proc_holder/spell/vampire/self/cloak/cast(list/targets, mob/user = usr)
var/datum/vampire/V = user.mind.vampire
V.iscloaking = !V.iscloaking
if(ishuman(user))
@@ -34,21 +34,21 @@
SIGNAL_HANDLER
mind.vampire.handle_vampire_cloak()
-/obj/effect/proc_holder/spell/targeted/click/shadow_snare
+/obj/effect/proc_holder/spell/vampire/shadow_snare
name = "Shadow Snare (20)"
desc = "You summon a trap on the ground. When crossed it will blind the target, extinguish any lights they may have, and ensnare them."
gain_desc = "You have gained the ability to summon a trap that will blind, ensnare, and turn off the lights of anyone who crosses it."
charge_max = 20 SECONDS
required_blood = 20
- vampire_ability = TRUE
- allowed_type = /turf/simulated
- click_radius = -1
- panel = "Vampire"
- school = "vampire"
- action_background_icon_state = "bg_vampire"
action_icon_state = "shadow_snare"
-/obj/effect/proc_holder/spell/targeted/click/shadow_snare/cast(list/targets, mob/user)
+/obj/effect/proc_holder/spell/vampire/shadow_snare/create_new_targeting()
+ var/datum/spell_targeting/click/T = new
+ T.allowed_type = /turf/simulated
+ T.click_radius = -1
+ return T
+
+/obj/effect/proc_holder/spell/vampire/shadow_snare/cast(list/targets, mob/user)
var/turf/target = targets[1]
new /obj/item/restraints/legcuffs/beartrap/shadow_snare(target)
@@ -100,22 +100,22 @@
STOP_PROCESSING(SSobj, src)
return ..()
-/obj/effect/proc_holder/spell/targeted/click/dark_passage
+/obj/effect/proc_holder/spell/vampire/dark_passage
name = "Dark Passage (30)"
desc = "You teleport to a targeted turf."
gain_desc = "You have gained the ability to blink a short distance towards a targeted turf."
charge_max = 40 SECONDS
required_blood = 30
- vampire_ability = TRUE
- allowed_type = /turf/simulated
- click_radius = 0
centcom_cancast = FALSE
action_icon_state = "dark_passage"
- panel = "Vampire"
- school = "vampire"
- action_background_icon_state = "bg_vampire"
-/obj/effect/proc_holder/spell/targeted/click/dark_passage/cast(list/targets, mob/user)
+/obj/effect/proc_holder/spell/vampire/dark_passage/create_new_targeting()
+ var/datum/spell_targeting/click/T = new
+ T.click_radius = 0
+ T.allowed_type = /turf/simulated
+ return T
+
+/obj/effect/proc_holder/spell/vampire/dark_passage/cast(list/targets, mob/user)
var/turf/target = get_turf(targets[1])
new /obj/effect/temp_visual/vamp_mist_out(get_turf(user))
@@ -127,24 +127,29 @@
icon = 'icons/mob/mob.dmi'
icon_state = "mist"
-/obj/effect/proc_holder/spell/aoe_turf/vamp_extinguish
+/obj/effect/proc_holder/spell/vampire/vamp_extinguish
name = "Extinguish"
desc = "You extinguish any light source in an area around you."
gain_desc = "You have gained the ability to extinguish nearby light sources."
charge_max = 20 SECONDS
- vampire_ability = TRUE
- panel = "Vampire"
- school = "vampire"
- action_background_icon_state = "bg_vampire"
action_icon_state = "vampire_extinguish"
+ create_attack_logs = FALSE
+ create_custom_logs = TRUE
-/obj/effect/proc_holder/spell/aoe_turf/vamp_extinguish/cast(list/targets, mob/user = usr)
+/obj/effect/proc_holder/spell/vampire/vamp_extinguish/create_new_targeting()
+ var/datum/spell_targeting/aoe/turf/T = new
+ return T
+
+/obj/effect/proc_holder/spell/vampire/write_custom_logs(list/targets, mob/user)
+ add_attack_logs(user, null, "Extinguished all lights around them using [src]", ATKLOG_ALL)
+
+/obj/effect/proc_holder/spell/vampire/vamp_extinguish/cast(list/targets, mob/user = usr)
for(var/turf/T in targets)
T.extinguish_light()
for(var/atom/A in T.contents)
A.extinguish_light()
-/obj/effect/proc_holder/spell/self/vampire/eternal_darkness
+/obj/effect/proc_holder/spell/vampire/self/eternal_darkness
name = "Eternal Darkness"
desc = "When toggled, you shroud the area around you in darkness and slowly lower the body temperature of people nearby."
gain_desc = "You have gained the ability to shroud the area around you in darkness, only the strongest of lights can pierce your unholy powers."
@@ -153,7 +158,7 @@
required_blood = 5
var/shroud_power = -4
-/obj/effect/proc_holder/spell/self/vampire/eternal_darkness/cast(list/targets, mob/user)
+/obj/effect/proc_holder/spell/vampire/self/eternal_darkness/cast(list/targets, mob/user)
var/mob/target = targets[1]
if(!target.mind.vampire.get_ability(/datum/vampire_passive/eternal_darkness))
target.mind.vampire.force_add_ability(/datum/vampire_passive/eternal_darkness)
diff --git a/code/game/gamemodes/vampire/vampire_powers/vampire_powers.dm b/code/game/gamemodes/vampire/vampire_powers/vampire_powers.dm
index ea89c3c91cd..11ddfbb6857 100644
--- a/code/game/gamemodes/vampire/vampire_powers/vampire_powers.dm
+++ b/code/game/gamemodes/vampire/vampire_powers/vampire_powers.dm
@@ -11,47 +11,27 @@
return FALSE
return TRUE
-/obj/effect/proc_holder/spell/self/choose_targets(mob/user = usr)
- perform(list(user))
+/obj/effect/proc_holder/spell/vampire
+ panel = "Vampire"
+ school = "vampire"
+ action_background_icon_state = "bg_vampire"
+ human_req = TRUE
+ clothes_req = FALSE
+ /// How much blood this ability costs to use
+ var/required_blood
+ var/deduct_blood_on_cast = TRUE
-/obj/effect/proc_holder/spell/mob_aoe/choose_targets(mob/user = usr)
- var/list/targets[0]
- for(var/mob/living/L in view(range, user))
- if(L == user)
- continue
- targets += L
- if(!length(targets))
- revert_cast(user)
- return
+/obj/effect/proc_holder/spell/vampire/create_new_handler()
+ var/datum/spell_handler/vampire/H = new
+ H.required_blood = required_blood
+ H.deduct_blood_on_cast = deduct_blood_on_cast
+ return H
- perform(targets, user = user)
+/obj/effect/proc_holder/spell/vampire/self
-/obj/effect/proc_holder/spell/proc/before_cast_vampire(list/targets)
- // sanity check before we cast
- if(!usr.mind || !usr.mind.vampire)
- targets.Cut()
- return FALSE
-
- if(!required_blood)
- return
-
- // enforce blood
- var/datum/vampire/vampire = usr.mind.vampire
- var/blood_cost_modifier = 1 + vampire.nullified / 100
- var/blood_cost = round(required_blood * blood_cost_modifier)
-
- if(blood_cost <= vampire.bloodusable)
- if(!deduct_blood_on_cast) //don't take the blood yet if this is false!
- return
- vampire.bloodusable -= blood_cost
- SSblackbox.record_feedback("tally", "vampire_powers_used", 1, "[name]")
- to_chat(usr, "You have [vampire.bloodusable] left to use.")
- return TRUE
- else
- // stop!!
- targets.Cut()
- return FALSE
+/obj/effect/proc_holder/spell/vampire/self/create_new_targeting()
+ return new /datum/spell_targeting/self
/datum/vampire_passive
var/gain_desc
@@ -66,21 +46,15 @@
owner = null
return ..()
-/obj/effect/proc_holder/spell/self/vampire
- vampire_ability = TRUE
- panel = "Vampire"
- school = "vampire"
- action_background_icon_state = "bg_vampire"
-
-/obj/effect/proc_holder/spell/self/vampire/rejuvenate
+/obj/effect/proc_holder/spell/vampire/self/rejuvenate
name = "Rejuvenate"
desc = "Use reserve blood to enliven your body, removing any incapacitating effects."
action_icon_state = "vampire_rejuvinate"
charge_max = 200
stat_allowed = 1
-/obj/effect/proc_holder/spell/self/vampire/rejuvenate/cast(list/targets, mob/user = usr)
+/obj/effect/proc_holder/spell/vampire/self/rejuvenate/cast(list/targets, mob/user = usr)
var/mob/living/U = user
U.SetWeakened(0)
@@ -94,7 +68,7 @@
if(rejuv_bonus)
INVOKE_ASYNC(src, .proc/heal, U, rejuv_bonus)
-/obj/effect/proc_holder/spell/self/vampire/rejuvenate/proc/heal(mob/living/user, rejuv_bonus)
+/obj/effect/proc_holder/spell/vampire/self/rejuvenate/proc/heal(mob/living/user, rejuv_bonus)
for(var/i in 1 to 5)
user.adjustBruteLoss(-2 * rejuv_bonus)
user.adjustOxyLoss(-5 * rejuv_bonus)
@@ -117,29 +91,29 @@
return 1
-/obj/effect/proc_holder/spell/self/vampire/specialize
+/obj/effect/proc_holder/spell/vampire/self/specialize
name = "Choose Specialization"
desc = "Choose what sub-class of vampire you want to evolve into."
gain_desc = "You can now choose what specialization of vampire you want to evolve into."
charge_max = 2 SECONDS
action_icon_state = "select_class"
-/obj/effect/proc_holder/spell/self/vampire/specialize/cast(mob/user)
+/obj/effect/proc_holder/spell/vampire/self/specialize/cast(mob/user)
ui_interact(user)
-/obj/effect/proc_holder/spell/self/vampire/specialize/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, datum/tgui/master_ui = null, datum/ui_state/state = GLOB.always_state)
+/obj/effect/proc_holder/spell/vampire/self/specialize/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, datum/tgui/master_ui = null, datum/ui_state/state = GLOB.always_state)
ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
if(!ui)
ui = new(user, src, ui_key, "SpecMenu", "Specialisation Menu", 900, 600, master_ui, state)
ui.set_autoupdate(FALSE)
ui.open()
-/obj/effect/proc_holder/spell/self/vampire/specialize/ui_data(mob/user)
+/obj/effect/proc_holder/spell/vampire/self/specialize/ui_data(mob/user)
var/datum/vampire/vamp = user.mind.vampire
var/list/data = list("subclasses" = vamp.subclass)
return data
-/obj/effect/proc_holder/spell/self/vampire/specialize/ui_act(action, list/params)
+/obj/effect/proc_holder/spell/vampire/self/specialize/ui_act(action, list/params)
if(..())
return
var/datum/vampire/vamp = usr.mind.vampire
@@ -170,17 +144,18 @@
check_vampire_upgrade(announce)
SSblackbox.record_feedback("nested tally", "vampire_subclasses", 1, list("[new_subclass.name]"))
-/obj/effect/proc_holder/spell/mob_aoe/glare
+/obj/effect/proc_holder/spell/vampire/glare
name = "Glare"
desc = "Your eyes flash, stunning and silencing anyone infront of you. It has lesser effects for those around you."
action_icon_state = "vampire_glare"
charge_max = 30 SECONDS
- stat_allowed = 1
- range = 1
- vampire_ability = TRUE
- panel = "Vampire"
- school = "vampire"
- action_background_icon_state = "bg_vampire"
+ stat_allowed = TRUE
+
+/obj/effect/proc_holder/spell/vampire/glare/create_new_targeting()
+ var/datum/spell_targeting/aoe/T = new
+ T.allowed_type = /mob/living
+ T.range = 1
+ return T
/// No deviation at all. Flashed from the front or front-left/front-right. Alternatively, flashed in direct view.
#define DEVIATION_NONE 3
@@ -189,7 +164,7 @@
/// Full deviation. Flashed from directly behind or behind-left/behind-rack. Not flashed at all.
#define DEVIATION_FULL 1
-/obj/effect/proc_holder/spell/mob_aoe/glare/cast(list/targets, mob/living/user = usr)
+/obj/effect/proc_holder/spell/vampire/glare/cast(list/targets, mob/living/user = usr)
if(ishuman(user))
var/mob/living/carbon/human/H = user
if(istype(H.glasses, /obj/item/clothing/glasses/sunglasses/blindfold))
@@ -225,7 +200,7 @@
to_chat(target, "You are blinded by [user]'s glare.")
add_attack_logs(user, target, "(Vampire) Glared at")
-/obj/effect/proc_holder/spell/mob_aoe/glare/proc/calculate_deviation(mob/victim, mob/attacker)
+/obj/effect/proc_holder/spell/vampire/glare/proc/calculate_deviation(mob/victim, mob/attacker)
// Are they on the same tile? We'll return partial deviation. This may be someone flashing while lying down
if(victim.loc == attacker.loc)
return DEVIATION_PARTIAL
@@ -268,7 +243,7 @@
/datum/vampire_passive/full
gain_desc = "You have reached your full potential. You are no longer weak to the effects of anything holy and your vision has improved greatly."
-/obj/effect/proc_holder/spell/targeted/raise_vampires
+/obj/effect/proc_holder/spell/vampire/raise_vampires
name = "Raise Vampires"
desc = "Summons deadly vampires from bluespace."
school = "transmutation"
@@ -277,18 +252,17 @@
human_req = 1
invocation = "none"
invocation_type = "none"
- max_targets = 0
- range = 3
cooldown_min = 20
action_icon_state = "revive_thrall"
- vampire_ability = TRUE
sound = 'sound/magic/wandodeath.ogg'
- panel = "Vampire"
- school = "vampire"
- action_background_icon_state = "bg_vampire"
gain_desc = "You have gained the ability to Raise Vampires. This extremely powerful AOE ability affects all humans near you. Vampires/thralls are healed. Corpses are raised as vampires. Others are stunned, then brain damaged, then killed."
-/obj/effect/proc_holder/spell/targeted/raise_vampires/cast(list/targets, mob/user = usr)
+/obj/effect/proc_holder/spell/vampire/raise_vampires/create_new_targeting()
+ var/datum/spell_targeting/aoe/T = new
+ T.range = 3
+ return T
+
+/obj/effect/proc_holder/spell/vampire/raise_vampires/cast(list/targets, mob/user = usr)
new /obj/effect/temp_visual/cult/sparks(user.loc)
var/turf/T = get_turf(user)
to_chat(user, "You call out within bluespace, summoning more vampiric spirits to aid you!")
@@ -298,7 +272,7 @@
raise_vampire(user, H)
-/obj/effect/proc_holder/spell/targeted/raise_vampires/proc/raise_vampire(mob/M, mob/living/carbon/human/H)
+/obj/effect/proc_holder/spell/vampire/raise_vampires/proc/raise_vampire(mob/M, mob/living/carbon/human/H)
if(!istype(M) || !istype(H))
return
if(!H.mind)
@@ -342,18 +316,15 @@
H.revive()
H.Weaken(20)
-/obj/effect/proc_holder/spell/targeted/turf_teleport/shadow_step
+/obj/effect/proc_holder/spell/turf_teleport/shadow_step
name = "Shadow Step (30)"
desc = "Teleport to a nearby dark region"
gain_desc = "You have gained the ability to shadowstep, which makes you disappear into nearby shadows at the cost of blood."
action_icon_state = "shadowblink"
charge_max = 20
- required_blood = 30
+ clothes_req = FALSE
centcom_cancast = FALSE
- vampire_ability = TRUE
include_space = FALSE
- range = -1
- include_user = TRUE
panel = "Vampire"
school = "vampire"
action_background_icon_state = "bg_vampire"
@@ -367,24 +338,33 @@
sound1 = null
sound2 = null
+/obj/effect/proc_holder/spell/turf_teleport/shadow_step/create_new_handler()
+ var/datum/spell_handler/vampire/H = new
+ H.required_blood = 30
+ return H
+
// pure adminbus at the moment
/proc/isvampirethrall(mob/living/M)
return istype(M) && M.mind && SSticker.mode && (M.mind in SSticker.mode.vampire_enthralled)
-/obj/effect/proc_holder/spell/targeted/enthrall
+/obj/effect/proc_holder/spell/vampire/enthrall
name = "Enthrall (150)"
desc = "You use a large portion of your power to sway those loyal to none to be loyal to you only."
gain_desc = "You have gained the ability to thrall people to your will."
action_icon_state = "vampire_enthrall"
required_blood = 150
deduct_blood_on_cast = FALSE
- vampire_ability = TRUE
- humans_only = TRUE
panel = "Vampire"
school = "vampire"
action_background_icon_state = "bg_vampire"
-/obj/effect/proc_holder/spell/targeted/enthrall/cast(list/targets, mob/user = usr)
+/obj/effect/proc_holder/spell/vampire/enthrall/create_new_targeting()
+ var/datum/spell_targeting/click/T = new
+ T.range = 1
+ T.click_radius = 0
+ return T
+
+/obj/effect/proc_holder/spell/vampire/enthrall/cast(list/targets, mob/user = usr)
var/datum/vampire/vampire = user.mind.vampire
for(var/mob/living/target in targets)
user.visible_message("[user] bites [target]'s neck!", "You bite [target]'s neck and begin the flow of power.")
@@ -392,14 +372,14 @@
if(do_mob(user, target, 50))
if(can_enthrall(user, target))
handle_enthrall(user, target)
- var/blood_cost_modifier = 1 + vampire.nullified/100
- var/blood_cost = round(required_blood * blood_cost_modifier)
+ var/datum/spell_handler/vampire/V = custom_handler
+ var/blood_cost = V.calculate_blood_cost(vampire)
vampire.bloodusable -= blood_cost //we take the blood after enthralling, not before
else
revert_cast(user)
to_chat(user, "You or your target either moved or you dont have enough usable blood.")
-/obj/effect/proc_holder/spell/targeted/enthrall/proc/can_enthrall(mob/living/user, mob/living/carbon/C)
+/obj/effect/proc_holder/spell/vampire/enthrall/proc/can_enthrall(mob/living/user, mob/living/carbon/C)
var/enthrall_safe = 0
for(var/obj/item/implant/mindshield/L in C)
if(L && L.implanted)
@@ -429,7 +409,7 @@
return FALSE
return TRUE
-/obj/effect/proc_holder/spell/targeted/enthrall/proc/handle_enthrall(mob/living/user, mob/living/carbon/human/H)
+/obj/effect/proc_holder/spell/vampire/enthrall/proc/handle_enthrall(mob/living/user, mob/living/carbon/human/H)
if(!istype(H))
return 0
var/ref = "\ref[user.mind]"
diff --git a/code/game/gamemodes/vampire/vampire_subclasses.dm b/code/game/gamemodes/vampire/vampire_subclasses.dm
index 88811d5910f..0747d0a32c0 100644
--- a/code/game/gamemodes/vampire/vampire_subclasses.dm
+++ b/code/game/gamemodes/vampire/vampire_subclasses.dm
@@ -19,52 +19,52 @@
/datum/vampire_subclass/umbrae
name = "umbrae"
- standard_powers = list(/obj/effect/proc_holder/spell/self/vampire/cloak = 150,
- /obj/effect/proc_holder/spell/targeted/click/shadow_snare = 250,
- /obj/effect/proc_holder/spell/targeted/click/dark_passage = 400,
- /obj/effect/proc_holder/spell/aoe_turf/vamp_extinguish = 600)
+ standard_powers = list(/obj/effect/proc_holder/spell/vampire/self/cloak = 150,
+ /obj/effect/proc_holder/spell/vampire/shadow_snare = 250,
+ /obj/effect/proc_holder/spell/vampire/dark_passage = 400,
+ /obj/effect/proc_holder/spell/vampire/vamp_extinguish = 600)
fully_powered_abilities = list(/datum/vampire_passive/full,
- /obj/effect/proc_holder/spell/self/vampire/eternal_darkness,
+ /obj/effect/proc_holder/spell/vampire/self/eternal_darkness,
/datum/vampire_passive/xray)
/datum/vampire_subclass/hemomancer
name = "hemomancer"
- standard_powers = list(/obj/effect/proc_holder/spell/self/vampire/vamp_claws = 150,
- /obj/effect/proc_holder/spell/targeted/click/blood_tendrils = 250,
- /obj/effect/proc_holder/spell/targeted/ethereal_jaunt/blood_pool = 400,
- /obj/effect/proc_holder/spell/blood_eruption = 600)
+ standard_powers = list(/obj/effect/proc_holder/spell/vampire/self/vamp_claws = 150,
+ /obj/effect/proc_holder/spell/vampire/blood_tendrils = 250,
+ /obj/effect/proc_holder/spell/ethereal_jaunt/blood_pool = 400,
+ /obj/effect/proc_holder/spell/vampire/blood_eruption = 600)
fully_powered_abilities = list(/datum/vampire_passive/full,
- /obj/effect/proc_holder/spell/self/vampire/blood_spill)
+ /obj/effect/proc_holder/spell/vampire/self/blood_spill)
/datum/vampire_subclass/gargantua
name = "gargantua"
- standard_powers = list(/obj/effect/proc_holder/spell/self/vampire/blood_swell = 150,
- /obj/effect/proc_holder/spell/self/vampire/blood_rush = 250,
+ standard_powers = list(/obj/effect/proc_holder/spell/vampire/self/blood_swell = 150,
+ /obj/effect/proc_holder/spell/vampire/self/blood_rush = 250,
/datum/vampire_passive/blood_swell_upgrade = 400,
- /obj/effect/proc_holder/spell/self/vampire/overwhelming_force = 600)
+ /obj/effect/proc_holder/spell/vampire/self/overwhelming_force = 600)
fully_powered_abilities = list(/datum/vampire_passive/full,
- /obj/effect/proc_holder/spell/targeted/click/charge)
+ /obj/effect/proc_holder/spell/vampire/charge)
improved_rejuv_healing = TRUE
/datum/vampire_subclass/ancient
name = "ancient"
- standard_powers = list(/obj/effect/proc_holder/spell/self/vampire/vamp_claws,
- /obj/effect/proc_holder/spell/self/vampire/blood_swell,
- /obj/effect/proc_holder/spell/self/vampire/cloak,
- /obj/effect/proc_holder/spell/targeted/click/blood_tendrils,
- /obj/effect/proc_holder/spell/self/vampire/blood_rush,
- /obj/effect/proc_holder/spell/targeted/click/shadow_snare,
- /obj/effect/proc_holder/spell/targeted/ethereal_jaunt/blood_pool,
+ standard_powers = list(/obj/effect/proc_holder/spell/vampire/self/vamp_claws,
+ /obj/effect/proc_holder/spell/vampire/self/blood_swell,
+ /obj/effect/proc_holder/spell/vampire/self/cloak,
+ /obj/effect/proc_holder/spell/vampire/blood_tendrils,
+ /obj/effect/proc_holder/spell/vampire/self/blood_rush,
+ /obj/effect/proc_holder/spell/vampire/shadow_snare,
+ /obj/effect/proc_holder/spell/ethereal_jaunt/blood_pool,
/datum/vampire_passive/blood_swell_upgrade,
- /obj/effect/proc_holder/spell/targeted/click/dark_passage,
- /obj/effect/proc_holder/spell/blood_eruption,
- /obj/effect/proc_holder/spell/self/vampire/overwhelming_force,
- /obj/effect/proc_holder/spell/aoe_turf/vamp_extinguish,
- /obj/effect/proc_holder/spell/targeted/raise_vampires,
- /obj/effect/proc_holder/spell/targeted/enthrall,
+ /obj/effect/proc_holder/spell/vampire/dark_passage,
+ /obj/effect/proc_holder/spell/vampire/blood_eruption,
+ /obj/effect/proc_holder/spell/vampire/self/overwhelming_force,
+ /obj/effect/proc_holder/spell/vampire/vamp_extinguish,
+ /obj/effect/proc_holder/spell/vampire/raise_vampires,
+ /obj/effect/proc_holder/spell/vampire/enthrall,
/datum/vampire_passive/full,
- /obj/effect/proc_holder/spell/self/vampire/blood_spill,
- /obj/effect/proc_holder/spell/targeted/click/charge,
- /obj/effect/proc_holder/spell/self/vampire/eternal_darkness,
+ /obj/effect/proc_holder/spell/vampire/self/blood_spill,
+ /obj/effect/proc_holder/spell/vampire/charge,
+ /obj/effect/proc_holder/spell/vampire/self/eternal_darkness,
/datum/vampire_passive/xray)
improved_rejuv_healing = TRUE
diff --git a/code/game/gamemodes/wizard/artefact.dm b/code/game/gamemodes/wizard/artefact.dm
index ddace2bf4ed..643f3288758 100644
--- a/code/game/gamemodes/wizard/artefact.dm
+++ b/code/game/gamemodes/wizard/artefact.dm
@@ -43,21 +43,21 @@
to_chat(M, "You are the [H.real_name]'s apprentice! You are bound by magic contract to follow [H.p_their()] orders and help [H.p_them()] in accomplishing their goals.")
switch(action)
if("destruction")
- M.mind.AddSpell(new /obj/effect/proc_holder/spell/targeted/projectile/magic_missile(null))
- M.mind.AddSpell(new /obj/effect/proc_holder/spell/targeted/click/fireball(null))
+ M.mind.AddSpell(new /obj/effect/proc_holder/spell/projectile/magic_missile(null))
+ M.mind.AddSpell(new /obj/effect/proc_holder/spell/fireball(null))
to_chat(M, "Your service has not gone unrewarded, however. Studying under [H.real_name], you have learned powerful, destructive spells. You are able to cast magic missile and fireball.")
if("bluespace")
- M.mind.AddSpell(new /obj/effect/proc_holder/spell/targeted/area_teleport/teleport(null))
- M.mind.AddSpell(new /obj/effect/proc_holder/spell/targeted/ethereal_jaunt(null))
+ M.mind.AddSpell(new /obj/effect/proc_holder/spell/area_teleport/teleport(null))
+ M.mind.AddSpell(new /obj/effect/proc_holder/spell/ethereal_jaunt(null))
to_chat(M, "Your service has not gone unrewarded, however. Studying under [H.real_name], you have learned reality bending mobility spells. You are able to cast teleport and ethereal jaunt.")
if("healing")
- M.mind.AddSpell(new /obj/effect/proc_holder/spell/targeted/charge(null))
- M.mind.AddSpell(new /obj/effect/proc_holder/spell/targeted/forcewall(null))
+ M.mind.AddSpell(new /obj/effect/proc_holder/spell/charge(null))
+ M.mind.AddSpell(new /obj/effect/proc_holder/spell/forcewall(null))
M.equip_to_slot_or_del(new /obj/item/gun/magic/staff/healing(M), slot_r_hand)
to_chat(M, "Your service has not gone unrewarded, however. Studying under [H.real_name], you have learned livesaving survival spells. You are able to cast charge and forcewall.")
if("robeless")
M.mind.AddSpell(new /obj/effect/proc_holder/spell/aoe_turf/knock(null))
- M.mind.AddSpell(new /obj/effect/proc_holder/spell/targeted/click/mind_transfer(null))
+ M.mind.AddSpell(new /obj/effect/proc_holder/spell/mind_transfer(null))
to_chat(M, "Your service has not gone unrewarded, however. Studying under [H.real_name], you have learned stealthy, robeless spells. You are able to cast knock and mindswap.")
M.equip_to_slot_or_del(new /obj/item/radio/headset(M), slot_l_ear)
diff --git a/code/game/gamemodes/wizard/godhand.dm b/code/game/gamemodes/wizard/godhand.dm
index 409a1801e40..02c5f7b3f9b 100644
--- a/code/game/gamemodes/wizard/godhand.dm
+++ b/code/game/gamemodes/wizard/godhand.dm
@@ -3,7 +3,7 @@
desc = "High Five?"
var/catchphrase = "High Five!"
var/on_use_sound = null
- var/obj/effect/proc_holder/spell/targeted/touch/attached_spell
+ var/obj/effect/proc_holder/spell/touch/attached_spell
icon_state = "syndballoon"
item_state = null
flags = ABSTRACT | NODROP | DROPDEL
diff --git a/code/game/gamemodes/wizard/soulstone.dm b/code/game/gamemodes/wizard/soulstone.dm
index 6aa1e1ce742..139f33ca174 100644
--- a/code/game/gamemodes/wizard/soulstone.dm
+++ b/code/game/gamemodes/wizard/soulstone.dm
@@ -351,9 +351,9 @@
if(SS.purified)
make_holy()
// Replace regular soulstone summoning with purified soulstones
- if(is_type_in_list(/obj/effect/proc_holder/spell/aoe_turf/conjure/soulstone, mob_spell_list))
- RemoveSpell(/obj/effect/proc_holder/spell/aoe_turf/conjure/soulstone)
- AddSpell(new /obj/effect/proc_holder/spell/aoe_turf/conjure/soulstone/holy)
+ if(is_type_in_list(/obj/effect/proc_holder/spell/aoe_turf/conjure/build/soulstone, mob_spell_list))
+ RemoveSpell(/obj/effect/proc_holder/spell/aoe_turf/conjure/build/soulstone)
+ AddSpell(new /obj/effect/proc_holder/spell/aoe_turf/conjure/build/soulstone/holy)
else if(iscultist(src)) // Re-grant cult actions, lost in the transfer
var/datum/action/innate/cult/comm/CC = new
diff --git a/code/game/gamemodes/wizard/spellbook.dm b/code/game/gamemodes/wizard/spellbook.dm
index 927b9472ad4..c6ebf4a3d35 100644
--- a/code/game/gamemodes/wizard/spellbook.dm
+++ b/code/game/gamemodes/wizard/spellbook.dm
@@ -100,96 +100,96 @@
//Offensive
/datum/spellbook_entry/blind
name = "Blind"
- spell_type = /obj/effect/proc_holder/spell/targeted/trigger/blind
+ spell_type = /obj/effect/proc_holder/spell/trigger/blind
log_name = "BD"
category = "Offensive"
cost = 1
/datum/spellbook_entry/lightningbolt
name = "Lightning Bolt"
- spell_type = /obj/effect/proc_holder/spell/targeted/lightning
+ spell_type = /obj/effect/proc_holder/spell/lightning
log_name = "LB"
category = "Offensive"
cost = 1
/datum/spellbook_entry/cluwne
name = "Curse of the Cluwne"
- spell_type = /obj/effect/proc_holder/spell/targeted/touch/cluwne
+ spell_type = /obj/effect/proc_holder/spell/touch/cluwne
log_name = "CC"
category = "Offensive"
/datum/spellbook_entry/banana_touch
name = "Banana Touch"
- spell_type = /obj/effect/proc_holder/spell/targeted/touch/banana
+ spell_type = /obj/effect/proc_holder/spell/touch/banana
log_name = "BT"
cost = 1
/datum/spellbook_entry/mime_malaise
name = "Mime Malaise"
- spell_type = /obj/effect/proc_holder/spell/targeted/touch/mime_malaise
+ spell_type = /obj/effect/proc_holder/spell/touch/mime_malaise
log_name = "MI"
cost = 1
/datum/spellbook_entry/horseman
name = "Curse of the Horseman"
- spell_type = /obj/effect/proc_holder/spell/targeted/click/horsemask
+ spell_type = /obj/effect/proc_holder/spell/horsemask
log_name = "HH"
category = "Offensive"
/datum/spellbook_entry/disintegrate
name = "Disintegrate"
- spell_type = /obj/effect/proc_holder/spell/targeted/touch/disintegrate
+ spell_type = /obj/effect/proc_holder/spell/touch/disintegrate
log_name = "DG"
category = "Offensive"
/datum/spellbook_entry/fireball
name = "Fireball"
- spell_type = /obj/effect/proc_holder/spell/targeted/click/fireball
+ spell_type = /obj/effect/proc_holder/spell/fireball
log_name = "FB"
category = "Offensive"
/datum/spellbook_entry/fleshtostone
name = "Flesh to Stone"
- spell_type = /obj/effect/proc_holder/spell/targeted/touch/flesh_to_stone
+ spell_type = /obj/effect/proc_holder/spell/touch/flesh_to_stone
log_name = "FS"
category = "Offensive"
/datum/spellbook_entry/mutate
name = "Mutate"
- spell_type = /obj/effect/proc_holder/spell/targeted/genetic/mutate
+ spell_type = /obj/effect/proc_holder/spell/genetic/mutate
log_name = "MU"
category = "Offensive"
/datum/spellbook_entry/rod_form
name = "Rod Form"
- spell_type = /obj/effect/proc_holder/spell/targeted/rod_form
+ spell_type = /obj/effect/proc_holder/spell/rod_form
log_name = "RF"
category = "Offensive"
/datum/spellbook_entry/infinite_guns
name = "Lesser Summon Guns"
- spell_type = /obj/effect/proc_holder/spell/targeted/infinite_guns
+ spell_type = /obj/effect/proc_holder/spell/infinite_guns
log_name = "IG"
category = "Offensive"
//Defensive
/datum/spellbook_entry/disabletech
name = "Disable Tech"
- spell_type = /obj/effect/proc_holder/spell/targeted/emplosion/disable_tech
+ spell_type = /obj/effect/proc_holder/spell/emplosion/disable_tech
log_name = "DT"
category = "Defensive"
cost = 1
/datum/spellbook_entry/forcewall
name = "Force Wall"
- spell_type = /obj/effect/proc_holder/spell/targeted/forcewall
+ spell_type = /obj/effect/proc_holder/spell/forcewall
log_name = "FW"
category = "Defensive"
cost = 1
/datum/spellbook_entry/greaterforcewall
name = "Greater Force Wall"
- spell_type = /obj/effect/proc_holder/spell/targeted/forcewall/greater
+ spell_type = /obj/effect/proc_holder/spell/forcewall/greater
log_name = "GFW"
category = "Defensive"
cost = 1
@@ -203,21 +203,21 @@
/datum/spellbook_entry/smoke
name = "Smoke"
- spell_type = /obj/effect/proc_holder/spell/targeted/smoke
+ spell_type = /obj/effect/proc_holder/spell/smoke
log_name = "SM"
category = "Defensive"
cost = 1
/datum/spellbook_entry/lichdom
name = "Bind Soul"
- spell_type = /obj/effect/proc_holder/spell/targeted/lichdom
+ spell_type = /obj/effect/proc_holder/spell/lichdom
log_name = "LD"
category = "Defensive"
is_ragin_restricted = TRUE
/datum/spellbook_entry/magicm
name = "Magic Missile"
- spell_type = /obj/effect/proc_holder/spell/targeted/projectile/magic_missile
+ spell_type = /obj/effect/proc_holder/spell/projectile/magic_missile
log_name = "MM"
category = "Defensive"
@@ -229,7 +229,7 @@
/datum/spellbook_entry/sacred_flame
name = "Sacred Flame and Fire Immunity"
- spell_type = /obj/effect/proc_holder/spell/targeted/sacred_flame
+ spell_type = /obj/effect/proc_holder/spell/sacred_flame
cost = 1
log_name = "SF"
category = "Defensive"
@@ -256,13 +256,13 @@
/datum/spellbook_entry/blink
name = "Blink"
- spell_type = /obj/effect/proc_holder/spell/targeted/turf_teleport/blink
+ spell_type = /obj/effect/proc_holder/spell/turf_teleport/blink
log_name = "BL"
category = "Mobility"
/datum/spellbook_entry/jaunt
name = "Ethereal Jaunt"
- spell_type = /obj/effect/proc_holder/spell/targeted/ethereal_jaunt
+ spell_type = /obj/effect/proc_holder/spell/ethereal_jaunt
log_name = "EJ"
category = "Mobility"
@@ -275,27 +275,27 @@
/datum/spellbook_entry/mindswap
name = "Mindswap"
- spell_type = /obj/effect/proc_holder/spell/targeted/click/mind_transfer
+ spell_type = /obj/effect/proc_holder/spell/mind_transfer
log_name = "MT"
category = "Mobility"
/datum/spellbook_entry/teleport
name = "Teleport"
- spell_type = /obj/effect/proc_holder/spell/targeted/area_teleport/teleport
+ spell_type = /obj/effect/proc_holder/spell/area_teleport/teleport
log_name = "TP"
category = "Mobility"
//Assistance
/datum/spellbook_entry/charge
name = "Charge"
- spell_type = /obj/effect/proc_holder/spell/targeted/charge
+ spell_type = /obj/effect/proc_holder/spell/charge
log_name = "CH"
category = "Assistance"
cost = 1
/datum/spellbook_entry/summonitem
name = "Summon Item"
- spell_type = /obj/effect/proc_holder/spell/targeted/summonitem
+ spell_type = /obj/effect/proc_holder/spell/summonitem
log_name = "IS"
category = "Assistance"
cost = 1
@@ -900,7 +900,7 @@
//Single Use Spellbooks
/obj/item/spellbook/oneuse
- var/spell = /obj/effect/proc_holder/spell/targeted/projectile/magic_missile //just a placeholder to avoid runtimes if someone spawned the generic
+ var/spell = /obj/effect/proc_holder/spell/projectile/magic_missile //just a placeholder to avoid runtimes if someone spawned the generic
var/spellname = "sandbox"
var/used = 0
name = "spellbook of "
@@ -944,7 +944,7 @@
return
/obj/item/spellbook/oneuse/fireball
- spell = /obj/effect/proc_holder/spell/targeted/click/fireball
+ spell = /obj/effect/proc_holder/spell/fireball
spellname = "fireball"
icon_state = "bookfireball"
desc = "This book feels warm to the touch."
@@ -955,7 +955,7 @@
qdel(src)
/obj/item/spellbook/oneuse/smoke
- spell = /obj/effect/proc_holder/spell/targeted/smoke
+ spell = /obj/effect/proc_holder/spell/smoke
spellname = "smoke"
icon_state = "booksmoke"
desc = "This book is overflowing with the dank arts."
@@ -966,7 +966,7 @@
user.adjust_nutrition(-200)
/obj/item/spellbook/oneuse/blind
- spell = /obj/effect/proc_holder/spell/targeted/trigger/blind
+ spell = /obj/effect/proc_holder/spell/trigger/blind
spellname = "blind"
icon_state = "bookblind"
desc = "This book looks blurry, no matter how you look at it."
@@ -977,7 +977,7 @@
user.EyeBlind(10)
/obj/item/spellbook/oneuse/mindswap
- spell = /obj/effect/proc_holder/spell/targeted/click/mind_transfer
+ spell = /obj/effect/proc_holder/spell/mind_transfer
spellname = "mindswap"
icon_state = "bookmindswap"
desc = "This book's cover is pristine, though its pages look ragged and torn."
@@ -1001,7 +1001,7 @@
to_chat(user, "You stare at the book some more, but there doesn't seem to be anything else to learn...")
return
- var/obj/effect/proc_holder/spell/targeted/click/mind_transfer/swapper = new
+ var/obj/effect/proc_holder/spell/mind_transfer/swapper = new
swapper.cast(user, stored_swap)
to_chat(stored_swap, "You're suddenly somewhere else... and someone else?!")
@@ -1009,7 +1009,7 @@
stored_swap = null
/obj/item/spellbook/oneuse/forcewall
- spell = /obj/effect/proc_holder/spell/targeted/forcewall
+ spell = /obj/effect/proc_holder/spell/forcewall
spellname = "forcewall"
icon_state = "bookforcewall"
desc = "This book has a dedication to mimes everywhere inside the front cover."
@@ -1033,7 +1033,7 @@
user.Weaken(20)
/obj/item/spellbook/oneuse/horsemask
- spell = /obj/effect/proc_holder/spell/targeted/click/horsemask
+ spell = /obj/effect/proc_holder/spell/horsemask
spellname = "horses"
icon_state = "bookhorses"
desc = "This book is more horse than your mind has room for."
@@ -1053,7 +1053,7 @@
to_chat(user, "I say thee neigh")
/obj/item/spellbook/oneuse/charge
- spell = /obj/effect/proc_holder/spell/targeted/charge
+ spell = /obj/effect/proc_holder/spell/charge
spellname = "charging"
icon_state = "bookcharge"
desc = "This book is made of 100% post-consumer wizard."
@@ -1064,7 +1064,7 @@
empulse(src, 1, 1)
/obj/item/spellbook/oneuse/summonitem
- spell = /obj/effect/proc_holder/spell/targeted/summonitem
+ spell = /obj/effect/proc_holder/spell/summonitem
spellname = "instant summons"
icon_state = "booksummons"
desc = "This book is bright and garish, very hard to miss."
@@ -1075,13 +1075,13 @@
qdel(src)
/obj/item/spellbook/oneuse/fake_gib
- spell = /obj/effect/proc_holder/spell/targeted/touch/fake_disintegrate
+ spell = /obj/effect/proc_holder/spell/touch/fake_disintegrate
spellname = "disintegrate"
icon_state = "bookfireball"
desc = "This book feels like it will rip stuff apart."
/obj/item/spellbook/oneuse/sacredflame
- spell = /obj/effect/proc_holder/spell/targeted/sacred_flame
+ spell = /obj/effect/proc_holder/spell/sacred_flame
spellname = "sacred flame"
icon_state = "booksacredflame"
desc = "Become one with the flames that burn within... and invite others to do so as well."
diff --git a/code/game/gamemodes/wizard/wizloadouts.dm b/code/game/gamemodes/wizard/wizloadouts.dm
index 518b9a68ca8..f99e30ab275 100644
--- a/code/game/gamemodes/wizard/wizloadouts.dm
+++ b/code/game/gamemodes/wizard/wizloadouts.dm
@@ -8,8 +8,8 @@
As this set lacks any form of healing or resurrection, healing items should be acquired from the station, and you should be careful to avoid being hurt in the first place.
\
Provides Mutate, Ethereal Jaunt, Blink, Magic Missile, and Disintegrate."
log_name = "OM"
- spells_path = list(/obj/effect/proc_holder/spell/targeted/genetic/mutate, /obj/effect/proc_holder/spell/targeted/ethereal_jaunt, /obj/effect/proc_holder/spell/targeted/turf_teleport/blink, \
- /obj/effect/proc_holder/spell/targeted/projectile/magic_missile, /obj/effect/proc_holder/spell/targeted/touch/disintegrate)
+ spells_path = list(/obj/effect/proc_holder/spell/genetic/mutate, /obj/effect/proc_holder/spell/ethereal_jaunt, /obj/effect/proc_holder/spell/turf_teleport/blink, \
+ /obj/effect/proc_holder/spell/projectile/magic_missile, /obj/effect/proc_holder/spell/touch/disintegrate)
/datum/spellbook_entry/loadout/lich
name = "Defense Focus : Lich"
@@ -18,8 +18,8 @@
Care should be taken in hiding the item you choose as your phylactery after using Bind Soul, as you cannot revive if it destroyed or too far from your body!
\
Provides Bind Soul, Ethereal Jaunt, Fireball, Rod Form, Disable Tech, and Greater Forcewall."
log_name = "DL"
- spells_path = list(/obj/effect/proc_holder/spell/targeted/lichdom, /obj/effect/proc_holder/spell/targeted/ethereal_jaunt, /obj/effect/proc_holder/spell/targeted/click/fireball, \
- /obj/effect/proc_holder/spell/targeted/rod_form, /obj/effect/proc_holder/spell/targeted/emplosion/disable_tech, /obj/effect/proc_holder/spell/targeted/forcewall/greater)
+ spells_path = list(/obj/effect/proc_holder/spell/lichdom, /obj/effect/proc_holder/spell/ethereal_jaunt, /obj/effect/proc_holder/spell/fireball, \
+ /obj/effect/proc_holder/spell/rod_form, /obj/effect/proc_holder/spell/emplosion/disable_tech, /obj/effect/proc_holder/spell/forcewall/greater)
is_ragin_restricted = TRUE
/datum/spellbook_entry/loadout/wands
@@ -30,8 +30,8 @@
Provides a Belt of Wands, Charge, Ethereal Jaunt, Blink, Repulse, and Disintegrate."
log_name = "UW"
items_path = list(/obj/item/storage/belt/wands/full)
- spells_path = list(/obj/effect/proc_holder/spell/targeted/charge, /obj/effect/proc_holder/spell/targeted/ethereal_jaunt, /obj/effect/proc_holder/spell/targeted/turf_teleport/blink, \
- /obj/effect/proc_holder/spell/aoe_turf/repulse, /obj/effect/proc_holder/spell/targeted/touch/disintegrate)
+ spells_path = list(/obj/effect/proc_holder/spell/charge, /obj/effect/proc_holder/spell/ethereal_jaunt, /obj/effect/proc_holder/spell/turf_teleport/blink, \
+ /obj/effect/proc_holder/spell/aoe_turf/repulse, /obj/effect/proc_holder/spell/touch/disintegrate)
//Unique loadouts, which are more gimmicky. Should contain some unique spell or item that separates it from just buying standard wiz spells, and be balanced around a 10 spell point cost.
/datum/spellbook_entry/loadout/mimewiz
@@ -41,14 +41,14 @@
log_name = "SHH"
items_path = list(/obj/item/spellbook/oneuse/mime/fingergun, /obj/item/spellbook/oneuse/mime/greaterwall, /obj/item/clothing/suit/wizrobe/mime, /obj/item/clothing/head/wizard/mime, \
/obj/item/clothing/mask/gas/mime/wizard, /obj/item/clothing/shoes/sandal/marisa, /obj/item/cane, /obj/item/stack/tape_roll)
- spells_path = list(/obj/effect/proc_holder/spell/targeted/ethereal_jaunt, /obj/effect/proc_holder/spell/targeted/turf_teleport/blink, /obj/effect/proc_holder/spell/targeted/area_teleport/teleport, \
- /obj/effect/proc_holder/spell/targeted/touch/mime_malaise, /obj/effect/proc_holder/spell/aoe_turf/knock, /obj/effect/proc_holder/spell/aoe_turf/conjure/timestop)
+ spells_path = list(/obj/effect/proc_holder/spell/ethereal_jaunt, /obj/effect/proc_holder/spell/turf_teleport/blink, /obj/effect/proc_holder/spell/area_teleport/teleport, \
+ /obj/effect/proc_holder/spell/touch/mime_malaise, /obj/effect/proc_holder/spell/aoe_turf/knock, /obj/effect/proc_holder/spell/aoe_turf/conjure/timestop)
category = "Unique"
destroy_spellbook = TRUE
/datum/spellbook_entry/loadout/mimewiz/Buy(mob/living/carbon/human/user, obj/item/spellbook/book)
if(user.mind)
- user.mind.AddSpell(new /obj/effect/proc_holder/spell/targeted/mime/speak(null))
+ user.mind.AddSpell(new /obj/effect/proc_holder/spell/mime/speak(null))
user.mind.miming = TRUE
..()
@@ -60,13 +60,13 @@
Provides a .357 Revolver, 4 speedloaders of ammo, Ethereal Jaunt, Blink, Summon Item, No Clothes, and Bind Soul, with a unique outfit."
log_name = "GR"
items_path = list(/obj/item/gun/projectile/revolver, /obj/item/ammo_box/a357, /obj/item/ammo_box/a357, /obj/item/ammo_box/a357, /obj/item/ammo_box/a357, /obj/item/clothing/under/syndicate)
- spells_path = list(/obj/effect/proc_holder/spell/targeted/ethereal_jaunt, /obj/effect/proc_holder/spell/targeted/turf_teleport/blink, \
- /obj/effect/proc_holder/spell/targeted/summonitem, /obj/effect/proc_holder/spell/noclothes, /obj/effect/proc_holder/spell/targeted/lichdom/gunslinger)
+ spells_path = list(/obj/effect/proc_holder/spell/ethereal_jaunt, /obj/effect/proc_holder/spell/turf_teleport/blink, \
+ /obj/effect/proc_holder/spell/summonitem, /obj/effect/proc_holder/spell/noclothes, /obj/effect/proc_holder/spell/lichdom/gunslinger)
category = "Unique"
destroy_spellbook = TRUE
is_ragin_restricted = TRUE
-/obj/effect/proc_holder/spell/targeted/lichdom/gunslinger/equip_lich(mob/living/carbon/human/H)
+/obj/effect/proc_holder/spell/lichdom/gunslinger/equip_lich(mob/living/carbon/human/H)
H.equip_to_slot_or_del(new /obj/item/clothing/suit/storage/det_suit(H), slot_wear_suit)
H.equip_to_slot_or_del(new /obj/item/clothing/shoes/combat(H), slot_shoes)
H.equip_to_slot_or_del(new /obj/item/clothing/gloves/combat(H), slot_gloves)
diff --git a/code/game/jobs/job/support.dm b/code/game/jobs/job/support.dm
index e0c3ae19e97..e44e5541e4c 100644
--- a/code/game/jobs/job/support.dm
+++ b/code/game/jobs/job/support.dm
@@ -374,8 +374,8 @@
return
if(H.mind)
- H.mind.AddSpell(new /obj/effect/proc_holder/spell/aoe_turf/conjure/mime_wall(null))
- H.mind.AddSpell(new /obj/effect/proc_holder/spell/targeted/mime/speak(null))
+ H.mind.AddSpell(new /obj/effect/proc_holder/spell/aoe_turf/conjure/build/mime_wall(null))
+ H.mind.AddSpell(new /obj/effect/proc_holder/spell/mime/speak(null))
H.mind.miming = 1
diff --git a/code/game/jobs/job/support_chaplain.dm b/code/game/jobs/job/support_chaplain.dm
index 443a5941bb8..3e48b210f49 100644
--- a/code/game/jobs/job/support_chaplain.dm
+++ b/code/game/jobs/job/support_chaplain.dm
@@ -80,7 +80,7 @@
B.deity_name = new_deity
SSblackbox.record_feedback("text", "religion_deity", 1, "[new_deity]", 1)
- user.AddSpell(new /obj/effect/proc_holder/spell/targeted/click/chaplain_bless(null))
+ user.AddSpell(new /obj/effect/proc_holder/spell/chaplain_bless(null))
if(SSticker)
SSticker.Bible_deity_name = B.deity_name
diff --git a/code/modules/awaymissions/mission_code/academy.dm b/code/modules/awaymissions/mission_code/academy.dm
index 84e3bc8183d..18c642a1a8a 100644
--- a/code/modules/awaymissions/mission_code/academy.dm
+++ b/code/modules/awaymissions/mission_code/academy.dm
@@ -200,7 +200,7 @@
H.key = C.key
to_chat(H, "You are a servant of [user.real_name]. You must do everything in your power to follow their orders.")
- var/obj/effect/proc_holder/spell/targeted/summonmob/S = new
+ var/obj/effect/proc_holder/spell/summonmob/S = new
S.target_mob = H
user.mind.AddSpell(S)
@@ -234,23 +234,24 @@
glasses = /obj/item/clothing/glasses/monocle
gloves = /obj/item/clothing/gloves/color/white
-/obj/effect/proc_holder/spell/targeted/summonmob
+/obj/effect/proc_holder/spell/summonmob
name = "Summon Servant"
desc = "This spell can be used to call your servant, whenever you need it."
charge_max = 100
clothes_req = 0
invocation = "JE VES"
invocation_type = "whisper"
- range = -1
level_max = 0 //cannot be improved
cooldown_min = 100
- include_user = 1
var/mob/living/target_mob
action_icon_state = "summons"
-/obj/effect/proc_holder/spell/targeted/summonmob/cast(list/targets, mob/user = usr)
+/obj/effect/proc_holder/spell/summonmob/create_new_targeting()
+ return new /datum/spell_targeting/self
+
+/obj/effect/proc_holder/spell/summonmob/cast(list/targets, mob/user = usr)
if(!target_mob)
return
var/turf/Start = get_turf(user)
diff --git a/code/modules/awaymissions/mission_code/ghost_role_spawners/golems.dm b/code/modules/awaymissions/mission_code/ghost_role_spawners/golems.dm
index c1e1c158665..9387ba4cec2 100644
--- a/code/modules/awaymissions/mission_code/ghost_role_spawners/golems.dm
+++ b/code/modules/awaymissions/mission_code/ghost_role_spawners/golems.dm
@@ -113,8 +113,8 @@
else
H.rename_character(null, name)
if(is_species(H, /datum/species/golem/tranquillite) && H.mind)
- H.mind.AddSpell(new /obj/effect/proc_holder/spell/aoe_turf/conjure/mime_wall(null))
- H.mind.AddSpell(new /obj/effect/proc_holder/spell/targeted/mime/speak(null))
+ H.mind.AddSpell(new /obj/effect/proc_holder/spell/aoe_turf/conjure/build/mime_wall(null))
+ H.mind.AddSpell(new /obj/effect/proc_holder/spell/mime/speak(null))
H.mind.miming = TRUE
if(has_owner)
diff --git a/code/modules/awaymissions/mission_code/ruins/wizardcrash.dm b/code/modules/awaymissions/mission_code/ruins/wizardcrash.dm
index 75fbbf698e6..bbf91842852 100644
--- a/code/modules/awaymissions/mission_code/ruins/wizardcrash.dm
+++ b/code/modules/awaymissions/mission_code/ruins/wizardcrash.dm
@@ -5,7 +5,7 @@
info = "To the Magnificent Z.A.P.
A small mining base has been created within our territory by wandless scum. Send them a message from the wizard federation they will not forget. I know your kind is rather fragile, but a group of lightly armed miners should not pose any threat to you at all. Just be warned they have a security cyborg for self defence, you might want to tune your spells to that threat. I look forward to hearing of your success.
Grand Magus Abra the Wonderous"
/obj/item/spellbook/oneuse/emp
- spell = /obj/effect/proc_holder/spell/targeted/emplosion/disable_tech
+ spell = /obj/effect/proc_holder/spell/emplosion/disable_tech
spellname = "Disable Technology"
icon_state = "bookcharge" //it's a lightning bolt, seems appropriate enough
desc = "For the tech-hating wizard on the go."
diff --git a/code/modules/mining/lavaland/loot/ashdragon_loot.dm b/code/modules/mining/lavaland/loot/ashdragon_loot.dm
index 34a0a6a66d2..383206a7f6a 100644
--- a/code/modules/mining/lavaland/loot/ashdragon_loot.dm
+++ b/code/modules/mining/lavaland/loot/ashdragon_loot.dm
@@ -128,7 +128,7 @@
if(2)
to_chat(user, "Power courses through you! You can now shift your form at will.")
if(user.mind)
- var/obj/effect/proc_holder/spell/targeted/shapeshift/dragon/D = new
+ var/obj/effect/proc_holder/spell/shapeshift/dragon/D = new
user.mind.AddSpell(D)
if(3)
to_chat(user, "You feel like you could walk straight through lava now.")
diff --git a/code/modules/mining/lavaland/loot/colossus_loot.dm b/code/modules/mining/lavaland/loot/colossus_loot.dm
index fb608d1b359..3ff68c2791b 100644
--- a/code/modules/mining/lavaland/loot/colossus_loot.dm
+++ b/code/modules/mining/lavaland/loot/colossus_loot.dm
@@ -365,7 +365,7 @@
ADD_TRAIT(L, TRAIT_MUTE, STASIS_MUTE)
L.status_flags |= GODMODE
L.mind.transfer_to(holder_animal)
- var/obj/effect/proc_holder/spell/targeted/exit_possession/P = new /obj/effect/proc_holder/spell/targeted/exit_possession
+ var/obj/effect/proc_holder/spell/exit_possession/P = new /obj/effect/proc_holder/spell/exit_possession
holder_animal.mind.AddSpell(P)
holder_animal.verbs -= /mob/living/verb/pulled
@@ -377,7 +377,7 @@
L.notransform = 0
if(holder_animal && !QDELETED(holder_animal))
holder_animal.mind.transfer_to(L)
- L.mind.RemoveSpell(/obj/effect/proc_holder/spell/targeted/exit_possession)
+ L.mind.RemoveSpell(/obj/effect/proc_holder/spell/exit_possession)
if(kill || !isanimal(loc))
L.death(0)
..()
@@ -388,20 +388,19 @@
/obj/structure/closet/stasis/ex_act()
return
-/obj/effect/proc_holder/spell/targeted/exit_possession
+/obj/effect/proc_holder/spell/exit_possession
name = "Exit Possession"
desc = "Exits the body you are possessing"
charge_max = 60
clothes_req = 0
invocation_type = "none"
- max_targets = 1
- range = -1
- include_user = 1
- selection_type = "view"
action_icon_state = "exit_possession"
sound = null
-/obj/effect/proc_holder/spell/targeted/exit_possession/cast(list/targets, mob/user = usr)
+/obj/effect/proc_holder/spell/exit_possession/create_new_targeting()
+ return new /datum/spell_targeting/self
+
+/obj/effect/proc_holder/spell/exit_possession/cast(list/targets, mob/user = usr)
if(!isfloorturf(user.loc))
return
var/datum/mind/target_mind = user.mind
@@ -413,4 +412,4 @@
qdel(S)
break
current.gib()
- target_mind.RemoveSpell(/obj/effect/proc_holder/spell/targeted/exit_possession)
+ target_mind.RemoveSpell(/obj/effect/proc_holder/spell/exit_possession)
diff --git a/code/modules/mob/dead/observer/observer.dm b/code/modules/mob/dead/observer/observer.dm
index f7f91a8baa9..8b33e3cc645 100644
--- a/code/modules/mob/dead/observer/observer.dm
+++ b/code/modules/mob/dead/observer/observer.dm
@@ -44,7 +44,7 @@ GLOBAL_VAR_INIT(observer_default_invisibility, INVISIBILITY_OBSERVER)
/mob/dead/observer/proc/open_spawners_menu)
// Our new boo spell.
- AddSpell(new /obj/effect/proc_holder/spell/targeted/click/boo(null))
+ AddSpell(new /obj/effect/proc_holder/spell/boo(null))
can_reenter_corpse = flags & GHOST_CAN_REENTER
started_as_observer = flags & GHOST_IS_OBSERVER
diff --git a/code/modules/mob/dead/observer/spells.dm b/code/modules/mob/dead/observer/spells.dm
index 6cb5d898082..be911ef1a65 100644
--- a/code/modules/mob/dead/observer/spells.dm
+++ b/code/modules/mob/dead/observer/spells.dm
@@ -9,13 +9,11 @@ GLOBAL_LIST_INIT(boo_phrases, list(
"It feels like someone's standing behind you.",
))
-/obj/effect/proc_holder/spell/targeted/click/boo
+/obj/effect/proc_holder/spell/boo
name = "Boo!"
desc = "Fuck with the living."
selection_deactivated_message = "Your presence will not be known. For now."
selection_activated_message = "You prepare to reach across the veil. Left-click to influence a target!"
- auto_target_single = FALSE
- allowed_type = /atom // No subtypes are safe from spookage.
ghost = TRUE
@@ -27,12 +25,17 @@ GLOBAL_LIST_INIT(boo_phrases, list(
stat_allowed = 1
invocation = ""
invocation_type = "none"
- range = 20
// no need to spam admins regarding boo casts
- create_logs = FALSE
+ create_attack_logs = FALSE
-/obj/effect/proc_holder/spell/targeted/click/boo/cast(list/targets, mob/user = usr)
+/obj/effect/proc_holder/spell/boo/create_new_targeting()
+ var/datum/spell_targeting/click/T = new()
+ T.allowed_type = /atom
+ T.try_auto_target = FALSE
+ return T
+
+/obj/effect/proc_holder/spell/boo/cast(list/targets, mob/user = usr)
var/atom/target = targets[1]
ASSERT(istype(target))
diff --git a/code/modules/mob/living/carbon/human/species/golem.dm b/code/modules/mob/living/carbon/human/species/golem.dm
index 6cb2dc54bd2..95642f9f3c6 100644
--- a/code/modules/mob/living/carbon/human/species/golem.dm
+++ b/code/modules/mob/living/carbon/human/species/golem.dm
@@ -656,8 +656,8 @@
H.equip_to_slot_or_del(new /obj/item/reagent_containers/food/drinks/bottle/bottleofnothing(H), slot_r_store)
H.equip_to_slot_or_del(new /obj/item/cane(H), slot_l_hand)
if(H.mind)
- H.mind.AddSpell(new /obj/effect/proc_holder/spell/aoe_turf/conjure/mime_wall(null))
- H.mind.AddSpell(new /obj/effect/proc_holder/spell/targeted/mime/speak(null))
+ H.mind.AddSpell(new /obj/effect/proc_holder/spell/aoe_turf/conjure/build/mime_wall(null))
+ H.mind.AddSpell(new /obj/effect/proc_holder/spell/mime/speak(null))
H.mind.miming = TRUE
/datum/unarmed_attack/golem/tranquillite
diff --git a/code/modules/mob/living/carbon/superheroes.dm b/code/modules/mob/living/carbon/superheroes.dm
index e3f534421df..220844a84d9 100644
--- a/code/modules/mob/living/carbon/superheroes.dm
+++ b/code/modules/mob/living/carbon/superheroes.dm
@@ -83,7 +83,7 @@
/datum/superheroes/griffin
name = "The Griffin"
- default_spells = list(/obj/effect/proc_holder/spell/targeted/click/recruit)
+ default_spells = list(/obj/effect/proc_holder/spell/recruit)
class = "Supervillain"
desc = "You are The Griffin, the ultimate supervillain. You thrive on chaos and have no respect for the supposed authority \
of the command staff of this station. Along with your gang of dim-witted yet trusty henchmen, you will be able to execute \
@@ -107,7 +107,7 @@
desc = "You are LightnIan, the lord of lightning! A freak electrical accident while working in the station's kennel \
has given you mastery over lightning and a peculiar desire to sniff butts. Although you are a recent addition to the \
station's hero roster, you intend to leave your mark."
- default_spells = list(/obj/effect/proc_holder/spell/targeted/lightning/lightnian)
+ default_spells = list(/obj/effect/proc_holder/spell/lightning/lightnian)
/datum/superheroes/lightnian/equip(mob/living/carbon/human/H)
..()
@@ -126,7 +126,7 @@
desc = "You were a roboticist, once. Now you are Electro-Negmatic, a name this station will learn to fear. You designed \
your costume to resemble E-N, your faithful dog that some callous RD destroyed because it was sparking up the plasma. You \
intend to take your revenge and make them all pay thanks to your magnetic powers."
- default_spells = list(/obj/effect/proc_holder/spell/targeted/magnet)
+ default_spells = list(/obj/effect/proc_holder/spell/magnet)
/datum/superheroes/electro/equip(mob/living/carbon/human/H)
..()
@@ -144,21 +144,24 @@
//The Griffin's special recruit abilitiy
-/obj/effect/proc_holder/spell/targeted/click/recruit
+/obj/effect/proc_holder/spell/recruit
name = "Recruit Greyshirt"
desc = "Allows you to recruit a conscious, non-braindead, non-catatonic human to be part of the Greyshirts, your personal henchmen. This works on Assistants only and you can recruit a maximum of 3!."
charge_max = 450
clothes_req = FALSE
- range = 1 //Adjacent to user
action_icon_state = "spell_greytide"
var/recruiting = 0
- click_radius = -1
selection_activated_message = "You start preparing a mindblowing monologue. Left-click to cast at a target!"
selection_deactivated_message = "You decide to save your brilliance for another day."
- allowed_type = /mob/living/carbon/human
-/obj/effect/proc_holder/spell/targeted/click/recruit/can_cast(mob/user = usr, charge_check = TRUE, show_message = FALSE)
+/obj/effect/proc_holder/spell/recruit/create_new_targeting()
+ var/datum/spell_targeting/click/T = new()
+ T.click_radius = -1
+ T.range = 1
+ return T
+
+/obj/effect/proc_holder/spell/recruit/can_cast(mob/user = usr, charge_check = TRUE, show_message = FALSE)
if(SSticker.mode.greyshirts.len >= 3)
if(show_message)
to_chat(user, "You have already recruited the maximum number of henchmen.")
@@ -169,13 +172,10 @@
return FALSE
return ..()
-/obj/effect/proc_holder/spell/targeted/click/recruit/valid_target(mob/living/carbon/human/target, user)
- if(!..())
- return FALSE
-
+/obj/effect/proc_holder/spell/recruit/valid_target(mob/living/carbon/human/target, user)
return target.ckey && !target.stat
-/obj/effect/proc_holder/spell/targeted/click/recruit/cast(list/targets,mob/living/user = usr)
+/obj/effect/proc_holder/spell/recruit/cast(list/targets,mob/living/user = usr)
var/mob/living/carbon/human/target = targets[1]
if(target.mind.assigned_role != "Assistant")
to_chat(user, "You can only recruit Assistants.")
diff --git a/code/modules/mob/living/simple_animal/constructs.dm b/code/modules/mob/living/simple_animal/constructs.dm
index c19fcadd240..38bfa66f4b9 100644
--- a/code/modules/mob/living/simple_animal/constructs.dm
+++ b/code/modules/mob/living/simple_animal/constructs.dm
@@ -130,7 +130,7 @@
construct_type = "juggernaut"
mob_size = MOB_SIZE_LARGE
move_resist = MOVE_FORCE_STRONG
- construct_spells = list(/obj/effect/proc_holder/spell/targeted/night_vision, /obj/effect/proc_holder/spell/aoe_turf/conjure/lesserforcewall)
+ construct_spells = list(/obj/effect/proc_holder/spell/night_vision, /obj/effect/proc_holder/spell/aoe_turf/conjure/build/lesserforcewall)
force_threshold = 11
playstyle_string = "You are a Juggernaut. Though slow, your shell can withstand extreme punishment, \
create shield walls, rip apart enemies and walls alike, and even deflect energy weapons."
@@ -173,7 +173,7 @@
attacktext = "slashes"
attack_sound = 'sound/weapons/bladeslice.ogg'
construct_type = "wraith"
- construct_spells = list(/obj/effect/proc_holder/spell/targeted/night_vision, /obj/effect/proc_holder/spell/targeted/ethereal_jaunt/shift)
+ construct_spells = list(/obj/effect/proc_holder/spell/night_vision, /obj/effect/proc_holder/spell/ethereal_jaunt/shift)
retreat_distance = 2 //AI wraiths will move in and out of combat
playstyle_string = "You are a Wraith. Though relatively fragile, you are fast, deadly, and even able to phase through walls."
@@ -203,13 +203,13 @@
minimum_distance = 10 //AI artificers will flee like fuck
attack_sound = 'sound/weapons/punch2.ogg'
construct_type = "builder"
- construct_spells = list(/obj/effect/proc_holder/spell/targeted/night_vision,
- /obj/effect/proc_holder/spell/targeted/projectile/magic_missile/lesser,
+ construct_spells = list(/obj/effect/proc_holder/spell/night_vision,
+ /obj/effect/proc_holder/spell/projectile/magic_missile/lesser,
/obj/effect/proc_holder/spell/aoe_turf/conjure/construct/lesser,
- /obj/effect/proc_holder/spell/aoe_turf/conjure/wall,
- /obj/effect/proc_holder/spell/aoe_turf/conjure/floor,
- /obj/effect/proc_holder/spell/aoe_turf/conjure/pylon,
- /obj/effect/proc_holder/spell/aoe_turf/conjure/soulstone)
+ /obj/effect/proc_holder/spell/aoe_turf/conjure/build/wall,
+ /obj/effect/proc_holder/spell/aoe_turf/conjure/build/floor,
+ /obj/effect/proc_holder/spell/aoe_turf/conjure/build/pylon,
+ /obj/effect/proc_holder/spell/aoe_turf/conjure/build/soulstone)
playstyle_string = "You are an Artificer. You are incredibly weak and fragile, but you are able to construct fortifications, \
use magic missile, repair allied constructs (by clicking on them), \
@@ -310,10 +310,10 @@
environment_smash = ENVIRONMENT_SMASH_RWALLS
attack_sound = 'sound/weapons/tap.ogg'
construct_type = "harvester"
- construct_spells = list(/obj/effect/proc_holder/spell/targeted/night_vision,
- /obj/effect/proc_holder/spell/aoe_turf/conjure/wall,
- /obj/effect/proc_holder/spell/aoe_turf/conjure/floor,
- /obj/effect/proc_holder/spell/targeted/smoke/disable)
+ construct_spells = list(/obj/effect/proc_holder/spell/night_vision,
+ /obj/effect/proc_holder/spell/aoe_turf/conjure/build/wall,
+ /obj/effect/proc_holder/spell/aoe_turf/conjure/build/floor,
+ /obj/effect/proc_holder/spell/smoke/disable)
retreat_distance = 2 //AI harvesters will move in and out of combat, like wraiths, but shittier
playstyle_string = "You are a Harvester. You are not strong, but your powers of domination will assist you in your role: \
Bring those who still cling to this world of illusion back to the master so they may know Truth."
diff --git a/code/modules/mob/living/simple_animal/hostile/hellhound.dm b/code/modules/mob/living/simple_animal/hostile/hellhound.dm
index d22ca2e708f..b145fb25344 100644
--- a/code/modules/mob/living/simple_animal/hostile/hellhound.dm
+++ b/code/modules/mob/living/simple_animal/hostile/hellhound.dm
@@ -119,8 +119,8 @@
/mob/living/simple_animal/hostile/hellhound/greater/New()
. = ..()
// Movement
- AddSpell(new /obj/effect/proc_holder/spell/targeted/ethereal_jaunt/shift)
- var/obj/effect/proc_holder/spell/targeted/area_teleport/teleport/telespell = new
+ AddSpell(new /obj/effect/proc_holder/spell/ethereal_jaunt/shift)
+ var/obj/effect/proc_holder/spell/area_teleport/teleport/telespell = new
telespell.clothes_req = FALSE
telespell.invocation_type = "none"
AddSpell(telespell)
@@ -128,7 +128,7 @@
knockspell.invocation_type = "none"
AddSpell(knockspell)
// Defense
- var/obj/effect/proc_holder/spell/targeted/forcewall/greater/wallspell = new
+ var/obj/effect/proc_holder/spell/forcewall/greater/wallspell = new
wallspell.clothes_req = FALSE
wallspell.invocation_type = "none"
AddSpell(wallspell)
diff --git a/code/modules/mob/living/simple_animal/hostile/megafauna/drake.dm b/code/modules/mob/living/simple_animal/hostile/megafauna/drake.dm
index 54e2efacf4a..391129bd666 100644
--- a/code/modules/mob/living/simple_animal/hostile/megafauna/drake.dm
+++ b/code/modules/mob/living/simple_animal/hostile/megafauna/drake.dm
@@ -645,13 +645,17 @@ Difficulty: Medium
sound = 'sound/magic/tail_swing.ogg'
charge_max = 150
clothes_req = FALSE
- range = 1
cooldown_min = 150
invocation_type = "none"
sparkle_path = /obj/effect/temp_visual/dir_setting/tailsweep
action_icon_state = "tailsweep"
action_background_icon_state = "bg_alien"
+/obj/effect/proc_holder/spell/aoe_turf/repulse/spacedragon/create_new_targeting()
+ var/datum/spell_targeting/aoe/turf/T = new()
+ T.range = 1
+ return T
+
/obj/effect/proc_holder/spell/aoe_turf/repulse/spacedragon/cast(list/targets, mob/user = usr)
if(iscarbon(user))
var/mob/living/carbon/C = user
diff --git a/code/modules/mob/living/simple_animal/hostile/retaliate/kangaroo.dm b/code/modules/mob/living/simple_animal/hostile/retaliate/kangaroo.dm
index 0d4a84f7532..60a4caa393c 100644
--- a/code/modules/mob/living/simple_animal/hostile/retaliate/kangaroo.dm
+++ b/code/modules/mob/living/simple_animal/hostile/retaliate/kangaroo.dm
@@ -28,7 +28,7 @@
/mob/living/simple_animal/hostile/retaliate/kangaroo/New()
. = ..()
// Leap spell, player-only usage
- AddSpell(new /obj/effect/proc_holder/spell/targeted/leap)
+ AddSpell(new /obj/effect/proc_holder/spell/leap)
/mob/living/simple_animal/hostile/retaliate/kangaroo/AttackingTarget()
if(client && a_intent != INTENT_HARM)
diff --git a/code/modules/mob/living/simple_animal/hostile/statue.dm b/code/modules/mob/living/simple_animal/hostile/statue.dm
index 5d61ef9cba5..334c635a546 100644
--- a/code/modules/mob/living/simple_animal/hostile/statue.dm
+++ b/code/modules/mob/living/simple_animal/hostile/statue.dm
@@ -58,7 +58,7 @@
// Give spells
AddSpell(new /obj/effect/proc_holder/spell/aoe_turf/flicker_lights(null))
AddSpell(new /obj/effect/proc_holder/spell/aoe_turf/blindness(null))
- AddSpell(new /obj/effect/proc_holder/spell/targeted/night_vision(null))
+ AddSpell(new /obj/effect/proc_holder/spell/night_vision(null))
// Set creator
if(creator)
@@ -162,7 +162,11 @@
charge_max = 300
clothes_req = 0
- range = 14
+
+/obj/effect/proc_holder/spell/aoe_turf/flicker_lights/create_new_targeting()
+ var/datum/spell_targeting/aoe/turf/T = new()
+ T.range = 14
+ return T
/obj/effect/proc_holder/spell/aoe_turf/flicker_lights/cast(list/targets, mob/user = usr)
for(var/turf/T in targets)
@@ -178,7 +182,11 @@
message = "You glare your eyes."
charge_max = 600
clothes_req = 0
- range = 10
+
+/obj/effect/proc_holder/spell/aoe_turf/blindness/create_new_targeting()
+ var/datum/spell_targeting/aoe/turf/T = new()
+ T.range = 10
+ return T
/obj/effect/proc_holder/spell/aoe_turf/blindness/cast(list/targets, mob/user = usr)
for(var/mob/living/L in GLOB.alive_mob_list)
diff --git a/code/modules/unit_tests/_unit_tests.dm b/code/modules/unit_tests/_unit_tests.dm
index fb0878dee9c..077d2efe464 100644
--- a/code/modules/unit_tests/_unit_tests.dm
+++ b/code/modules/unit_tests/_unit_tests.dm
@@ -10,6 +10,7 @@
#include "reagent_id_typos.dm"
#include "rustg_version.dm"
#include "spawn_humans.dm"
+#include "spell_targeting_test.dm"
#include "sql.dm"
#include "subsystem_init.dm"
#include "subsystem_metric_sanity.dm"
diff --git a/code/modules/unit_tests/spell_targeting_test.dm b/code/modules/unit_tests/spell_targeting_test.dm
new file mode 100644
index 00000000000..250a66458f9
--- /dev/null
+++ b/code/modules/unit_tests/spell_targeting_test.dm
@@ -0,0 +1,10 @@
+/datum/unit_test/spell_targeting/Run()
+ var/list/bad_spells = list()
+ for(var/obj/effect/proc_holder/spell/S as anything in typesof(/obj/effect/proc_holder/spell))
+ if(initial(S.name) == "Spell")
+ continue // Skip abstract spells
+ S = new S
+ if(!S.targeting)
+ bad_spells += S
+ if(length(bad_spells))
+ Fail("Spells without targeting found: [bad_spells.Join(", ")]")
diff --git a/paradise.dme b/paradise.dme
index 76d347ae2f2..3ebe54cb774 100644
--- a/paradise.dme
+++ b/paradise.dme
@@ -79,6 +79,7 @@
#include "code\__DEFINES\shuttle.dm"
#include "code\__DEFINES\sight.dm"
#include "code\__DEFINES\sound.dm"
+#include "code\__DEFINES\spell.dm"
#include "code\__DEFINES\stat.dm"
#include "code\__DEFINES\station_goals.dm"
#include "code\__DEFINES\status_effects.dm"
@@ -409,6 +410,20 @@
#include "code\datums\outfits\vv_outfit.dm"
#include "code\datums\ruins\lavaland.dm"
#include "code\datums\ruins\space.dm"
+#include "code\datums\spell_handler\morph.dm"
+#include "code\datums\spell_handler\spell_handler.dm"
+#include "code\datums\spell_handler\vampire.dm"
+#include "code\datums\spell_targeting\alive_mobs.dm"
+#include "code\datums\spell_targeting\aoe.dm"
+#include "code\datums\spell_targeting\click.dm"
+#include "code\datums\spell_targeting\clicked_atom.dm"
+#include "code\datums\spell_targeting\matter_eater_targeting.dm"
+#include "code\datums\spell_targeting\reachable_turfs.dm"
+#include "code\datums\spell_targeting\remoteview_targeting.dm"
+#include "code\datums\spell_targeting\self.dm"
+#include "code\datums\spell_targeting\spell_targeting.dm"
+#include "code\datums\spell_targeting\targeted.dm"
+#include "code\datums\spell_targeting\telepathic.dm"
#include "code\datums\spells\area_teleport.dm"
#include "code\datums\spells\banana_touch.dm"
#include "code\datums\spells\bloodcrawl.dm"
@@ -418,10 +433,8 @@
#include "code\datums\spells\conjure.dm"
#include "code\datums\spells\conjure_item.dm"
#include "code\datums\spells\construct_spells.dm"
-#include "code\datums\spells\dumbfire.dm"
#include "code\datums\spells\emplosion.dm"
#include "code\datums\spells\ethereal_jaunt.dm"
-#include "code\datums\spells\explosion.dm"
#include "code\datums\spells\fake_gib.dm"
#include "code\datums\spells\genetic.dm"
#include "code\datums\spells\horsemask.dm"