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"