diff --git a/baystation12.dme b/baystation12.dme index 510ef39501..7f3090e405 100644 --- a/baystation12.dme +++ b/baystation12.dme @@ -1633,11 +1633,12 @@ #include "code\modules\spells\targeted\flesh_to_stone.dm" #include "code\modules\spells\targeted\genetic.dm" #include "code\modules\spells\targeted\harvest.dm" -#include "code\modules\spells\targeted\horsemask.dm" #include "code\modules\spells\targeted\mind_transfer.dm" #include "code\modules\spells\targeted\shift.dm" #include "code\modules\spells\targeted\subjugate.dm" #include "code\modules\spells\targeted\targeted.dm" +#include "code\modules\spells\targeted\equip\equip.dm" +#include "code\modules\spells\targeted\equip\horsemask.dm" #include "code\modules\spells\targeted\projectile\dumbfire.dm" #include "code\modules\spells\targeted\projectile\fireball.dm" #include "code\modules\spells\targeted\projectile\magic_missile.dm" diff --git a/code/_onclick/hud/spell_screen_objects.dm b/code/_onclick/hud/spell_screen_objects.dm index ed208a588d..08c11e8680 100644 --- a/code/_onclick/hud/spell_screen_objects.dm +++ b/code/_onclick/hud/spell_screen_objects.dm @@ -12,6 +12,18 @@ var/mob/spell_holder +/obj/screen/movable/spell_master/Destroy() + ..() + for(var/obj/screen/spell/spells in spell_objects) + spells.spellmaster = null + spell_objects = null + if(spell_holder) + spell_holder.spell_masters -= src + +/obj/screen/movable/spell_master/ResetVars() + ..("spell_objects") + spell_objects = list() + /obj/screen/movable/spell_master/MouseDrop() if(showing) return @@ -57,16 +69,23 @@ /obj/screen/movable/spell_master/proc/add_spell(var/spell/spell) if(!spell) return - for(var/obj/screen/spell/spellscreen in spell_objects) - if(spellscreen.spell == spell) + if(spell.connected_button) //we have one already, for some reason + if(spell.connected_button in spell_objects) + return + else + spell_objects.Add(spell.connected_button) + toggle_open(2) return if(spell.spell_flags & NO_BUTTON) //no button to add if we don't get one return - var/obj/screen/spell/newscreen = new - + var/obj/screen/spell/newscreen = PoolOrNew(/obj/screen/spell) + newscreen.spellmaster = src newscreen.spell = spell + + spell.connected_button = newscreen + if(!spell.override_base) //if it's not set, we do basic checks if(spell.spell_flags & CONSTRUCT_CHECK) newscreen.spell_base = "const" //construct spells @@ -80,16 +99,13 @@ toggle_open(2) //forces the icons to refresh on screen /obj/screen/movable/spell_master/proc/remove_spell(var/spell/spell) - for(var/obj/screen/spell/s_object in spell_objects) - if(s_object.spell == spell) - spell_objects.Remove(s_object) - qdel(s_object) - break + qdel(spell.connected_button) + + spell.connected_button = null if(spell_objects.len) toggle_open(showing + 1) else - spell_holder.spell_masters.Remove(src) qdel(src) /obj/screen/movable/spell_master/proc/silence_spells(var/amount) @@ -125,9 +141,18 @@ var/spell/spell = null var/handle_icon_updates = 0 + var/obj/screen/movable/spell_master/spellmaster var/icon/last_charged_icon +/obj/screen/spell/Destroy() + ..() + if(spellmaster) + spellmaster.spell_objects -= src + if(spellmaster && !spellmaster.spell_objects.len) + qdel(spellmaster) + spellmaster = null + /obj/screen/spell/proc/update_charge(var/forced_update = 0) if(!spell) qdel(src) diff --git a/code/modules/mob/mob.dm b/code/modules/mob/mob.dm index 6c601c419e..14f67295d8 100644 --- a/code/modules/mob/mob.dm +++ b/code/modules/mob/mob.dm @@ -601,31 +601,35 @@ /mob/Stat() ..() + . = (client && client.inactivity < 1200) - if(client && client.holder) - if(statpanel("Status")) - statpanel("Status","Location:","([x], [y], [z])") - statpanel("Status","CPU:","[world.cpu]") - statpanel("Status","Instances:","[world.contents.len]") - if(statpanel("Status") && processScheduler && processScheduler.getIsRunning()) - for(var/datum/controller/process/P in processScheduler.processes) - statpanel("Status",P.getStatName(), P.getTickTime()) - else - statpanel("Status","processScheduler is not running.") + if(.) + if(client.holder) + if(statpanel("Status")) + statpanel("Status","Location:","([x], [y], [z])") + statpanel("Status","CPU:","[world.cpu]") + statpanel("Status","Instances:","[world.contents.len]") + if(statpanel("Status") && processScheduler && processScheduler.getIsRunning()) + for(var/datum/controller/process/P in processScheduler.processes) + statpanel("Status",P.getStatName(), P.getTickTime()) + else + statpanel("Status","processScheduler is not running.") - if(listed_turf && client) - if(!TurfAdjacent(listed_turf)) - listed_turf = null - else - statpanel(listed_turf.name, null, listed_turf) - for(var/atom/A in listed_turf) - if(!A.mouse_opacity) - continue - if(A.invisibility > see_invisible) - continue - if(is_type_in_list(A, shouldnt_see)) - continue - statpanel(listed_turf.name, null, A) + if(listed_turf && client) + if(!TurfAdjacent(listed_turf)) + listed_turf = null + else + statpanel(listed_turf.name, null, listed_turf) + for(var/atom/A in listed_turf) + if(!A.mouse_opacity) + continue + if(A.invisibility > see_invisible) + continue + if(is_type_in_list(A, shouldnt_see)) + continue + statpanel(listed_turf.name, null, A) + + sleep(4) //Prevent updating the stat panel for the next .4 seconds, prevents clientside latency from updates // facing verbs /mob/proc/canface() @@ -1026,4 +1030,4 @@ mob/proc/yank_out_object() /mob/proc/throw_mode_on() src.in_throw_mode = 1 if(src.throw_icon) - src.throw_icon.icon_state = "act_throw_on" \ No newline at end of file + src.throw_icon.icon_state = "act_throw_on" diff --git a/code/modules/spells/aoe_turf/aoe_turf.dm b/code/modules/spells/aoe_turf/aoe_turf.dm index 9a70eb18c6..3265761077 100644 --- a/code/modules/spells/aoe_turf/aoe_turf.dm +++ b/code/modules/spells/aoe_turf/aoe_turf.dm @@ -1,25 +1,25 @@ -/* -Aoe turf spells target a ring of tiles around the user -This ring has an outer radius (range) and an inner radius (inner_radius) -Aoe turf spells have two useful flags: IGNOREDENSE and IGNORESPACE. These are explained in setup.dm -*/ - -/spell/aoe_turf //affects all turfs in view or range (depends) - spell_flags = IGNOREDENSE - var/inner_radius = -1 //for all your ring spell needs - -/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))) - if(target.density && (spell_flags & IGNOREDENSE)) - continue - if(istype(target, /turf/space) && (spell_flags & IGNORESPACE)) - continue - targets += target - - if(!targets.len) //doesn't waste the spell - return - +/* +Aoe turf spells target a ring of tiles around the user +This ring has an outer radius (range) and an inner radius (inner_radius) +Aoe turf spells have two useful flags: IGNOREDENSE and IGNORESPACE. These are explained in setup.dm +*/ + +/spell/aoe_turf //affects all turfs in view or range (depends) + spell_flags = IGNOREDENSE + var/inner_radius = -1 //for all your ring spell needs + +/spell/aoe_turf/choose_targets(mob/user = usr) + var/list/targets = list() + + for(var/turf/target in view_or_range(range, holder, selection_type)) + if(!(target in view_or_range(inner_radius, holder, selection_type))) + if(target.density && (spell_flags & IGNOREDENSE)) + continue + if(istype(target, /turf/space) && (spell_flags & IGNORESPACE)) + continue + targets += target + + if(!targets.len) //doesn't waste the spell + return + return targets \ No newline at end of file diff --git a/code/modules/spells/spell_code.dm b/code/modules/spells/spell_code.dm index ba631391b4..2015fde1e0 100644 --- a/code/modules/spells/spell_code.dm +++ b/code/modules/spells/spell_code.dm @@ -1,9 +1,9 @@ var/list/spells = typesof(/spell) //needed for the badmin verb for now /spell - name = "Spell" - desc = "A spell" - parent_type = /atom/movable + var/name = "Spell" + var/desc = "A spell" + parent_type = /datum var/panel = "Spells"//What panel the proc holder needs to go on. var/school = "evocation" //not relevant at now, but may be important later if there are changes to how spells work. the ones I used for now will probably be changed... maybe spell presets? lacking flexibility but with some other benefit? @@ -25,8 +25,7 @@ var/list/spells = typesof(/spell) //needed for the badmin verb for now 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/atom/movable/holder //where the spell is. Normally the user, can be a projectile - + var/atom/movable/holder //where the spell is. Normally the user, can be an item var/duration = 0 //how long the spell lasts var/list/spell_levels = list(Sp_SPEED = 0, Sp_POWER = 0) //the current spell levels - total spell levels can be obtained by just adding the two values @@ -53,6 +52,8 @@ var/list/spells = typesof(/spell) //needed for the badmin verb for now var/hud_state = "" //name of the icon used in generating the spell hud object var/override_base = "" + var/obj/screen/connected_button + /////////////////////// ///SETUP AND PROCESS/// /////////////////////// @@ -69,11 +70,6 @@ var/list/spells = typesof(/spell) //needed for the badmin verb for now sleep(1) return -/spell/Click() - ..() - - perform(usr) - ///////////////// /////CASTING///// ///////////////// @@ -182,18 +178,18 @@ var/list/spells = typesof(/spell) //needed for the badmin verb for now /spell/proc/cast_check(skipcharge = 0,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 - if(!(src in user.spell_list)) + if(!(src in user.spell_list) && holder == user) user << "You shouldn't have this spell! Something's wrong." return 0 if(silenced > 0) return - var/turf/Turf = get_turf(user) - if(!Turf) - user << "You cannot cast spells in null space!" - - if(spell_flags & Z2NOCAST && (Turf.z in config.admin_levels)) //Certain spells are not allowed on the centcomm zlevel + var/turf/user_turf = get_turf(user) + if(!user_turf) + user << "You cannot cast spells in null space!" + + if(spell_flags & Z2NOCAST && (user_turf.z in config.admin_levels)) //Certain spells are not allowed on the centcomm zlevel return 0 if(spell_flags & CONSTRUCT_CHECK) @@ -201,7 +197,7 @@ var/list/spells = typesof(/spell) //needed for the badmin verb for now if(findNullRod(T)) return 0 - if(istype(user, /mob/living/simple_animal)) + if(istype(user, /mob/living/simple_animal) && holder == user) var/mob/living/simple_animal/SA = user if(SA.purge) SA << "The nullrod's power interferes with your own!" @@ -210,7 +206,7 @@ var/list/spells = typesof(/spell) //needed for the badmin verb for now if(!src.check_charge(skipcharge, user)) //sees if we can cast based on charges alone return 0 - if(!(spell_flags & GHOSTCAST)) + if(!(spell_flags & GHOSTCAST) && holder == user) if(user.stat && !(spell_flags & STATALLOWED)) usr << "Not when you're incapacitated." return 0 @@ -221,7 +217,7 @@ var/list/spells = typesof(/spell) //needed for the badmin verb for now return 0 var/spell/noclothes/spell = locate() in user.spell_list - if((spell_flags & NEEDSCLOTHES) && !(spell && istype(spell)))//clothes check + if((spell_flags & NEEDSCLOTHES) && !(spell && istype(spell)) && holder == user)//clothes check if(!user.wearing_wiz_garb()) return 0 diff --git a/code/modules/spells/spellbook.dm b/code/modules/spells/spellbook.dm index 7823a7b602..6ddaf6331a 100644 --- a/code/modules/spells/spellbook.dm +++ b/code/modules/spells/spellbook.dm @@ -211,7 +211,7 @@ temp = "You have learned knock." if("horseman") feedback_add_details("wizard_spell_learned","HH") //please do not change the abbreviation to keep data processing consistent. Add a unique id to any new spells - H.add_spell(new/spell/targeted/horsemask) + H.add_spell(new/spell/targeted/equip_item/horsemask) temp = "You have learned curse of the horseman." if("fleshtostone") feedback_add_details("wizard_spell_learned","FS") //please do not change the abbreviation to keep data processing consistent. Add a unique id to any new spells @@ -424,7 +424,7 @@ user.Weaken(20) /obj/item/weapon/spellbook/oneuse/horsemask - spell = /spell/targeted/horsemask + spell = /spell/targeted/equip_item/horsemask spellname = "horses" icon_state ="bookhorses" desc = "This book is more horse than your mind has room for." diff --git a/code/modules/spells/spells.dm b/code/modules/spells/spells.dm index d20eea00dc..2e7ee7b815 100644 --- a/code/modules/spells/spells.dm +++ b/code/modules/spells/spells.dm @@ -4,17 +4,26 @@ for(var/obj/screen/movable/spell_master/spell_master in spell_masters) spell_master.update_spells(0, src) -/mob/Stat() +/mob/Login() ..() - if(spell_list && spell_list.len && statpanel("Spells")) + if(spell_masters) + for(var/obj/screen/movable/spell_master/spell_master in spell_masters) + spell_master.toggle_open(1) + client.screen -= spell_master + +/mob/Stat() + . = ..() + if(. && spell_list && spell_list.len) for(var/spell/S in spell_list) + if((!S.connected_button) || !statpanel(S.panel)) + continue //Not showing the noclothes spell switch(S.charge_type) if(Sp_RECHARGE) - statpanel("Spells","[S.charge_counter/10.0]/[S.charge_max/10]",S) + statpanel(S.panel,"[S.charge_counter/10.0]/[S.charge_max/10]",S.connected_button) if(Sp_CHARGES) - statpanel("Spells","[S.charge_counter]/[S.charge_max]",S) + statpanel(S.panel,"[S.charge_counter]/[S.charge_max]",S.connected_button) if(Sp_HOLDVAR) - statpanel("Spells","[S.holder_var_type] [S.holder_var_amount]",S) + statpanel(S.panel,"[S.holder_var_type] [S.holder_var_amount]",S.connected_button) /mob/proc/add_spell(var/spell/spell_to_add, var/spell_base = "wiz_spell_ready", var/master_type = /obj/screen/movable/spell_master) if(!spell_masters) diff --git a/code/modules/spells/targeted/equip/equip.dm b/code/modules/spells/targeted/equip/equip.dm new file mode 100644 index 0000000000..735daf78e8 --- /dev/null +++ b/code/modules/spells/targeted/equip/equip.dm @@ -0,0 +1,40 @@ +//You can set duration to 0 to have the items last forever + +/spell/targeted/equip_item + name = "equipment spell" + + var/list/equipped_summons = list() //assoc list of text ids and paths to spawn + + var/list/summoned_items = list() //list of items we summoned and will dispose when the spell runs out + + var/delete_old = 1 //if the item previously in the slot is deleted - otherwise, it's dropped + +/spell/targeted/equip_item/cast(list/targets, mob/user = usr) + ..() + for(var/mob/living/L in targets) + for(var/slot_id in equipped_summons) + var/to_create = equipped_summons[slot_id] + slot_id = text2num(slot_id) //because the index is text, we access this instead + var/obj/item/new_item = summon_item(to_create) + var/obj/item/old_item = L.get_equipped_item(slot_id) + L.equip_to_slot(new_item, slot_id) + if(old_item) + L.remove_from_mob(old_item) + if(delete_old) + qdel(old_item) + else + old_item.loc = L.loc + + if(duration) + summoned_items += new_item //we store it in a list to remove later + + if(duration) + spawn(duration) + for(var/obj/item/to_remove in summoned_items) + if(istype(to_remove.loc, /mob)) + var/mob/M = to_remove.loc + M.remove_from_mob(to_remove) + qdel(to_remove) + +/spell/targeted/equip_item/proc/summon_item(var/newtype) + return new newtype diff --git a/code/modules/spells/targeted/horsemask.dm b/code/modules/spells/targeted/equip/horsemask.dm similarity index 66% rename from code/modules/spells/targeted/horsemask.dm rename to code/modules/spells/targeted/equip/horsemask.dm index dad2032b72..b5fbcf4fbb 100644 --- a/code/modules/spells/targeted/horsemask.dm +++ b/code/modules/spells/targeted/equip/horsemask.dm @@ -1,35 +1,38 @@ -/spell/targeted/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" - charge_type = Sp_RECHARGE - charge_max = 150 - charge_counter = 0 - spell_flags = 0 - invocation = "KN'A FTAGHU, PUCK 'BTHNK!" - invocation_type = SpI_SHOUT - range = 7 - max_targets = 1 - cooldown_min = 30 //30 deciseconds reduction per rank - selection_type = "range" - - compatible_mobs = list(/mob/living/carbon/human) - - hud_state = "wiz_horse" - -/spell/targeted/horsemask/cast(list/targets, mob/user = usr) - ..() - for(var/mob/living/target in targets) - var/obj/item/clothing/mask/horsehead/magichead = new /obj/item/clothing/mask/horsehead - magichead.canremove = 0 //curses! - magichead.flags_inv = null //so you can still see their face - magichead.voicechange = 1 //NEEEEIIGHH - target.visible_message( "[target]'s face lights up in fire, and after the event a horse's head takes its place!", \ - "Your face burns up, and shortly after the fire you realise you have the face of a horse!") - var/obj/old_mask = target.wear_mask - if(old_mask) - target.drop_from_inventory(old_mask) - qdel(old_mask) //get rid of this shit - target.equip_to_slot_if_possible(magichead, slot_wear_mask, 1, 1) - - flick("e_flash", target.flash) \ No newline at end of file +/spell/targeted/equip_item/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" + charge_type = Sp_RECHARGE + charge_max = 150 + charge_counter = 0 + spell_flags = 0 + invocation = "KN'A FTAGHU, PUCK 'BTHNK!" + invocation_type = SpI_SHOUT + range = 7 + max_targets = 1 + cooldown_min = 30 //30 deciseconds reduction per rank + selection_type = "range" + + compatible_mobs = list(/mob/living/carbon/human) + + hud_state = "wiz_horse" + +/spell/targeted/equip_item/horsemask/New() + ..() + equipped_summons = list("[slot_wear_mask]" = /obj/item/clothing/mask/horsehead) + +/spell/targeted/equip_item/horsemask/cast(list/targets, mob/user = usr) + ..() + for(var/mob/living/target in targets) + target.visible_message( "[target]'s face lights up in fire, and after the event a horse's head takes its place!", \ + "Your face burns up, and shortly after the fire you realise you have the face of a horse!") + flick("e_flash", target.flash) + +/spell/targeted/equip_item/horsemask/summon_item(var/new_type) + var/obj/item/new_item = new new_type + if(istype(new_item, /obj/item/clothing/mask/horsehead)) + var/obj/item/clothing/mask/horsehead/magichead = new_item + magichead.canremove = 0 //curses! + magichead.flags_inv = null //so you can still see their face + magichead.voicechange = 1 //NEEEEIIGHH + return new_item diff --git a/code/modules/spells/targeted/genetic.dm b/code/modules/spells/targeted/genetic.dm index 028cdafba0..045fbc7d41 100644 --- a/code/modules/spells/targeted/genetic.dm +++ b/code/modules/spells/targeted/genetic.dm @@ -57,7 +57,7 @@ code\game\dna\genes\goon_powers.dm spell_flags = Z2NOCAST | NEEDSCLOTHES | INCLUDEUSER invocation = "BIRUZ BENNAR" invocation_type = SpI_SHOUT - message = "\blue You feel strong! You feel a pressure building behind your eyes!" + message = "You feel strong! You feel a pressure building behind your eyes!" range = 0 max_targets = 1 diff --git a/code/modules/spells/targeted/mind_transfer.dm b/code/modules/spells/targeted/mind_transfer.dm index 2e1860da35..a3668a53d1 100644 --- a/code/modules/spells/targeted/mind_transfer.dm +++ b/code/modules/spells/targeted/mind_transfer.dm @@ -51,7 +51,10 @@ ghost.spell_list = victim.spell_list//If they have spells, transfer them. Now we basically have a backup mob. caster.mind.transfer_to(victim) - victim.spell_list = caster.spell_list//Now they are inside the victim's body. + victim.spell_list = list() //clear those out + for(var/spell/S in caster.spell_list) + victim.add_spell(S) //Now they are inside the victim's body - this also generates the HUD + caster.spell_list = list() //clean that out as well if(victim.mind.special_verbs.len)//To add all the special verbs for the original caster. for(var/V in caster.mind.special_verbs)//Not too important but could come into play. @@ -59,7 +62,9 @@ ghost.mind.transfer_to(caster) caster.key = ghost.key //have to transfer the key since the mind was not active - caster.spell_list = ghost.spell_list + for(var/spell/S in ghost.spell_list) + caster.add_spell(S) + ghost.spell_list = list() if(caster.mind.special_verbs.len)//If they had any special verbs, we add them here. for(var/V in caster.mind.special_verbs) @@ -71,4 +76,4 @@ //After a certain amount of time the victim gets a message about being in a different body. spawn(msg_wait) - caster << "\red You feel woozy and lightheaded. Your body doesn't seem like your own." + caster << "You feel woozy and lightheaded. Your body doesn't seem like your own." diff --git a/code/modules/spells/targeted/targeted.dm b/code/modules/spells/targeted/targeted.dm index 96bbab9905..498d363408 100644 --- a/code/modules/spells/targeted/targeted.dm +++ b/code/modules/spells/targeted/targeted.dm @@ -1,145 +1,145 @@ -/* -Targeted spells (with the exception of dumbfire) select from all the mobs in the defined range -Targeted spells have two useful flags: INCLUDEUSER and SELECTABLE. These are explained in setup.dm -*/ - - -/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, 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/amt_weakened = 0 - var/amt_paralysis = 0 - var/amt_stunned = 0 - - var/amt_dizziness = 0 - var/amt_confused = 0 - var/amt_stuttering = 0 - - //set to negatives for healing - var/amt_dam_fire = 0 - var/amt_dam_brute = 0 - var/amt_dam_oxy = 0 - var/amt_dam_tox = 0 - - var/amt_eye_blind = 0 - var/amt_eye_blurry = 0 - - var/list/compatible_mobs = list() - - -/spell/targeted/choose_targets(mob/user = usr) - var/list/targets = list() - - if(max_targets == 0) //unlimited - if(range == -2) - targets = living_mob_list - else - for(var/mob/living/target in view_or_range(range, user, selection_type)) - targets += target - - else if(max_targets == 1) //single target can be picked - if((range == 0 || range == -1) && spell_flags & INCLUDEUSER) - targets += user - else - var/list/possible_targets = list() - var/list/starting_targets - if(range == -2) - starting_targets = living_mob_list - else - starting_targets = view_or_range(range, user, selection_type) - - for(var/mob/living/M in starting_targets) - if(!(spell_flags & INCLUDEUSER) && M == user) - continue - if(compatible_mobs && compatible_mobs.len) - if(!is_type_in_list(M, compatible_mobs)) continue - if(compatible_mobs && compatible_mobs.len && !is_type_in_list(M, compatible_mobs)) - continue - possible_targets += M - - if(possible_targets.len) - if(spell_flags & SELECTABLE) //if we are allowed to choose. see setup.dm for details - var/mob/temp_target = input(user, "Choose the target for the spell.", "Targeting") as null|mob in possible_targets - if(temp_target) - targets += temp_target - else - targets += pick(possible_targets) - //Adds a safety check post-input to make sure those targets are actually in range. - - - else - var/list/possible_targets = list() - var/list/starting_targets - - if(range == -2) - starting_targets = living_mob_list - else - starting_targets = view_or_range(range, user, selection_type) - - for(var/mob/living/target in starting_targets) - if(!(spell_flags & INCLUDEUSER) && target == user) - continue - if(compatible_mobs && !is_type_in_list(target, compatible_mobs)) - continue - possible_targets += target - - if(spell_flags & SELECTABLE) - for(var/i = 1; i<=max_targets, i++) - if(!possible_targets.len) - break - var/mob/M = input(user, "Choose the target for the spell.", "Targeting") as null|mob in possible_targets - if(!M) - break - if(range != -2) - if(!(M in view_or_range(range, user, selection_type))) - continue - targets += M - possible_targets -= M - else - 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(!(spell_flags & INCLUDEUSER) && (user in targets)) - targets -= user - - if(compatible_mobs && compatible_mobs.len) - for(var/mob/living/target in targets) //filters out all the non-compatible mobs - if(!is_type_in_list(target, compatible_mobs)) - targets -= target - - return targets - -/spell/targeted/cast(var/list/targets, mob/user) - for(var/mob/living/target in targets) - if(range >= 0) - if(!(target in view_or_range(range, user, selection_type))) //filter at time of casting - targets -= target - continue - apply_spell_damage(target) - -/spell/targeted/proc/apply_spell_damage(mob/living/target) - target.adjustBruteLoss(amt_dam_brute) - target.adjustFireLoss(amt_dam_fire) - target.adjustToxLoss(amt_dam_tox) - target.adjustOxyLoss(amt_dam_oxy) - //disabling - target.Weaken(amt_weakened) - target.Paralyse(amt_paralysis) - target.Stun(amt_stunned) - if(amt_weakened || amt_paralysis || amt_stunned) - if(target.buckled) - target.buckled = null - target.eye_blind += amt_eye_blind - target.eye_blurry += amt_eye_blurry - target.dizziness += amt_dizziness - target.confused += amt_confused +/* +Targeted spells (with the exception of dumbfire) select from all the mobs in the defined range +Targeted spells have two useful flags: INCLUDEUSER and SELECTABLE. These are explained in setup.dm +*/ + + +/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, 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/amt_weakened = 0 + var/amt_paralysis = 0 + var/amt_stunned = 0 + + var/amt_dizziness = 0 + var/amt_confused = 0 + var/amt_stuttering = 0 + + //set to negatives for healing + var/amt_dam_fire = 0 + var/amt_dam_brute = 0 + var/amt_dam_oxy = 0 + var/amt_dam_tox = 0 + + var/amt_eye_blind = 0 + var/amt_eye_blurry = 0 + + var/list/compatible_mobs = list() + + +/spell/targeted/choose_targets(mob/user = usr) + var/list/targets = list() + + if(max_targets == 0) //unlimited + if(range == -2) + targets = living_mob_list + else + for(var/mob/living/target in view_or_range(range, holder, selection_type)) + targets += target + + else if(max_targets == 1) //single target can be picked + if((range == 0 || range == -1) && spell_flags & INCLUDEUSER) + targets += user + else + var/list/possible_targets = list() + var/list/starting_targets + if(range == -2) + starting_targets = living_mob_list + else + starting_targets = view_or_range(range, holder, selection_type) + + for(var/mob/living/M in starting_targets) + if(!(spell_flags & INCLUDEUSER) && M == user) + continue + if(compatible_mobs && compatible_mobs.len) + if(!is_type_in_list(M, compatible_mobs)) continue + if(compatible_mobs && compatible_mobs.len && !is_type_in_list(M, compatible_mobs)) + continue + possible_targets += M + + if(possible_targets.len) + if(spell_flags & SELECTABLE) //if we are allowed to choose. see setup.dm for details + var/mob/temp_target = input(user, "Choose the target for the spell.", "Targeting") as null|mob in possible_targets + if(temp_target) + targets += temp_target + else + targets += pick(possible_targets) + //Adds a safety check post-input to make sure those targets are actually in range. + + + else + var/list/possible_targets = list() + var/list/starting_targets + + if(range == -2) + starting_targets = living_mob_list + else + starting_targets = view_or_range(range, holder, selection_type) + + for(var/mob/living/target in starting_targets) + if(!(spell_flags & INCLUDEUSER) && target == user) + continue + if(compatible_mobs && !is_type_in_list(target, compatible_mobs)) + continue + possible_targets += target + + if(spell_flags & SELECTABLE) + for(var/i = 1; i<=max_targets, i++) + if(!possible_targets.len) + break + var/mob/M = input(user, "Choose the target for the spell.", "Targeting") as null|mob in possible_targets + if(!M) + break + if(range != -2) + if(!(M in view_or_range(range, holder, selection_type))) + continue + targets += M + possible_targets -= M + else + 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(!(spell_flags & INCLUDEUSER) && (user in targets)) + targets -= user + + if(compatible_mobs && compatible_mobs.len) + for(var/mob/living/target in targets) //filters out all the non-compatible mobs + if(!is_type_in_list(target, compatible_mobs)) + targets -= target + + return targets + +/spell/targeted/cast(var/list/targets, mob/user) + for(var/mob/living/target in targets) + if(range >= 0) + if(!(target in view_or_range(range, holder, selection_type))) //filter at time of casting + targets -= target + continue + apply_spell_damage(target) + +/spell/targeted/proc/apply_spell_damage(mob/living/target) + target.adjustBruteLoss(amt_dam_brute) + target.adjustFireLoss(amt_dam_fire) + target.adjustToxLoss(amt_dam_tox) + target.adjustOxyLoss(amt_dam_oxy) + //disabling + target.Weaken(amt_weakened) + target.Paralyse(amt_paralysis) + target.Stun(amt_stunned) + if(amt_weakened || amt_paralysis || amt_stunned) + if(target.buckled) + target.buckled = null + target.eye_blind += amt_eye_blind + target.eye_blurry += amt_eye_blurry + target.dizziness += amt_dizziness + target.confused += amt_confused target.stuttering += amt_stuttering \ No newline at end of file