Magical fixes.

The wizard den is no longer pitch black.
Fixes targeted spells using the wrong caster/source.
Adds some missing checks using the caster source above.
Re-logging should no longer cause a loss of spell UI icons.
Mind transfer should no longer cause unintended spell loss.
This commit is contained in:
PsiOmegaDelta
2015-07-02 09:58:23 +02:00
parent bfe21b66c6
commit 616b4b60e4
12 changed files with 351 additions and 268 deletions

View File

@@ -1633,11 +1633,12 @@
#include "code\modules\spells\targeted\flesh_to_stone.dm" #include "code\modules\spells\targeted\flesh_to_stone.dm"
#include "code\modules\spells\targeted\genetic.dm" #include "code\modules\spells\targeted\genetic.dm"
#include "code\modules\spells\targeted\harvest.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\mind_transfer.dm"
#include "code\modules\spells\targeted\shift.dm" #include "code\modules\spells\targeted\shift.dm"
#include "code\modules\spells\targeted\subjugate.dm" #include "code\modules\spells\targeted\subjugate.dm"
#include "code\modules\spells\targeted\targeted.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\dumbfire.dm"
#include "code\modules\spells\targeted\projectile\fireball.dm" #include "code\modules\spells\targeted\projectile\fireball.dm"
#include "code\modules\spells\targeted\projectile\magic_missile.dm" #include "code\modules\spells\targeted\projectile\magic_missile.dm"

View File

@@ -12,6 +12,18 @@
var/mob/spell_holder 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() /obj/screen/movable/spell_master/MouseDrop()
if(showing) if(showing)
return return
@@ -57,16 +69,23 @@
/obj/screen/movable/spell_master/proc/add_spell(var/spell/spell) /obj/screen/movable/spell_master/proc/add_spell(var/spell/spell)
if(!spell) return if(!spell) return
for(var/obj/screen/spell/spellscreen in spell_objects) if(spell.connected_button) //we have one already, for some reason
if(spellscreen.spell == spell) if(spell.connected_button in spell_objects)
return
else
spell_objects.Add(spell.connected_button)
toggle_open(2)
return return
if(spell.spell_flags & NO_BUTTON) //no button to add if we don't get one if(spell.spell_flags & NO_BUTTON) //no button to add if we don't get one
return return
var/obj/screen/spell/newscreen = new var/obj/screen/spell/newscreen = PoolOrNew(/obj/screen/spell)
newscreen.spellmaster = src
newscreen.spell = spell newscreen.spell = spell
spell.connected_button = newscreen
if(!spell.override_base) //if it's not set, we do basic checks if(!spell.override_base) //if it's not set, we do basic checks
if(spell.spell_flags & CONSTRUCT_CHECK) if(spell.spell_flags & CONSTRUCT_CHECK)
newscreen.spell_base = "const" //construct spells newscreen.spell_base = "const" //construct spells
@@ -80,16 +99,13 @@
toggle_open(2) //forces the icons to refresh on screen toggle_open(2) //forces the icons to refresh on screen
/obj/screen/movable/spell_master/proc/remove_spell(var/spell/spell) /obj/screen/movable/spell_master/proc/remove_spell(var/spell/spell)
for(var/obj/screen/spell/s_object in spell_objects) qdel(spell.connected_button)
if(s_object.spell == spell)
spell_objects.Remove(s_object) spell.connected_button = null
qdel(s_object)
break
if(spell_objects.len) if(spell_objects.len)
toggle_open(showing + 1) toggle_open(showing + 1)
else else
spell_holder.spell_masters.Remove(src)
qdel(src) qdel(src)
/obj/screen/movable/spell_master/proc/silence_spells(var/amount) /obj/screen/movable/spell_master/proc/silence_spells(var/amount)
@@ -125,9 +141,18 @@
var/spell/spell = null var/spell/spell = null
var/handle_icon_updates = 0 var/handle_icon_updates = 0
var/obj/screen/movable/spell_master/spellmaster
var/icon/last_charged_icon 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) /obj/screen/spell/proc/update_charge(var/forced_update = 0)
if(!spell) if(!spell)
qdel(src) qdel(src)

View File

@@ -601,31 +601,35 @@
/mob/Stat() /mob/Stat()
..() ..()
. = (client && client.inactivity < 1200)
if(client && client.holder) if(.)
if(statpanel("Status")) if(client.holder)
statpanel("Status","Location:","([x], [y], [z])") if(statpanel("Status"))
statpanel("Status","CPU:","[world.cpu]") statpanel("Status","Location:","([x], [y], [z])")
statpanel("Status","Instances:","[world.contents.len]") statpanel("Status","CPU:","[world.cpu]")
if(statpanel("Status") && processScheduler && processScheduler.getIsRunning()) statpanel("Status","Instances:","[world.contents.len]")
for(var/datum/controller/process/P in processScheduler.processes) if(statpanel("Status") && processScheduler && processScheduler.getIsRunning())
statpanel("Status",P.getStatName(), P.getTickTime()) for(var/datum/controller/process/P in processScheduler.processes)
else statpanel("Status",P.getStatName(), P.getTickTime())
statpanel("Status","processScheduler is not running.") else
statpanel("Status","processScheduler is not running.")
if(listed_turf && client) if(listed_turf && client)
if(!TurfAdjacent(listed_turf)) if(!TurfAdjacent(listed_turf))
listed_turf = null listed_turf = null
else else
statpanel(listed_turf.name, null, listed_turf) statpanel(listed_turf.name, null, listed_turf)
for(var/atom/A in listed_turf) for(var/atom/A in listed_turf)
if(!A.mouse_opacity) if(!A.mouse_opacity)
continue continue
if(A.invisibility > see_invisible) if(A.invisibility > see_invisible)
continue continue
if(is_type_in_list(A, shouldnt_see)) if(is_type_in_list(A, shouldnt_see))
continue continue
statpanel(listed_turf.name, null, A) 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 // facing verbs
/mob/proc/canface() /mob/proc/canface()

View File

@@ -11,8 +11,8 @@ Aoe turf spells have two useful flags: IGNOREDENSE and IGNORESPACE. These are ex
/spell/aoe_turf/choose_targets(mob/user = usr) /spell/aoe_turf/choose_targets(mob/user = usr)
var/list/targets = list() var/list/targets = list()
for(var/turf/target in view_or_range(range,user,selection_type)) for(var/turf/target in view_or_range(range, holder, selection_type))
if(!(target in view_or_range(inner_radius,user,selection_type))) if(!(target in view_or_range(inner_radius, holder, selection_type)))
if(target.density && (spell_flags & IGNOREDENSE)) if(target.density && (spell_flags & IGNOREDENSE))
continue continue
if(istype(target, /turf/space) && (spell_flags & IGNORESPACE)) if(istype(target, /turf/space) && (spell_flags & IGNORESPACE))

View File

@@ -1,9 +1,9 @@
var/list/spells = typesof(/spell) //needed for the badmin verb for now var/list/spells = typesof(/spell) //needed for the badmin verb for now
/spell /spell
name = "Spell" var/name = "Spell"
desc = "A spell" var/desc = "A spell"
parent_type = /atom/movable parent_type = /datum
var/panel = "Spells"//What panel the proc holder needs to go on. 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? 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/range = 7 //the range of the spell; outer radius for aoe spells
var/message = "" //whatever it says to the guy affected by it var/message = "" //whatever it says to the guy affected by it
var/selection_type = "view" //can be "range" or "view" 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/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 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/hud_state = "" //name of the icon used in generating the spell hud object
var/override_base = "" var/override_base = ""
var/obj/screen/connected_button
/////////////////////// ///////////////////////
///SETUP AND PROCESS/// ///SETUP AND PROCESS///
/////////////////////// ///////////////////////
@@ -69,11 +70,6 @@ var/list/spells = typesof(/spell) //needed for the badmin verb for now
sleep(1) sleep(1)
return return
/spell/Click()
..()
perform(usr)
///////////////// /////////////////
/////CASTING///// /////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 /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 << "<span class='warning'>You shouldn't have this spell! Something's wrong.</span>" user << "<span class='warning'>You shouldn't have this spell! Something's wrong.</span>"
return 0 return 0
if(silenced > 0) if(silenced > 0)
return return
var/turf/Turf = get_turf(user) var/turf/user_turf = get_turf(user)
if(!Turf) if(!user_turf)
user << "<span class='warning'>You cannot cast spells in null space!</span>" user << "<span class='warning'>You cannot cast spells in null space!</span>"
if(spell_flags & Z2NOCAST && (Turf.z in config.admin_levels)) //Certain spells are not allowed on the centcomm zlevel if(spell_flags & Z2NOCAST && (user_turf.z in config.admin_levels)) //Certain spells are not allowed on the centcomm zlevel
return 0 return 0
if(spell_flags & CONSTRUCT_CHECK) if(spell_flags & CONSTRUCT_CHECK)
@@ -201,7 +197,7 @@ var/list/spells = typesof(/spell) //needed for the badmin verb for now
if(findNullRod(T)) if(findNullRod(T))
return 0 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 var/mob/living/simple_animal/SA = user
if(SA.purge) if(SA.purge)
SA << "<span class='warning'>The nullrod's power interferes with your own!</span>" SA << "<span class='warning'>The nullrod's power interferes with your own!</span>"
@@ -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 if(!src.check_charge(skipcharge, user)) //sees if we can cast based on charges alone
return 0 return 0
if(!(spell_flags & GHOSTCAST)) if(!(spell_flags & GHOSTCAST) && holder == user)
if(user.stat && !(spell_flags & STATALLOWED)) if(user.stat && !(spell_flags & STATALLOWED))
usr << "Not when you're incapacitated." usr << "Not when you're incapacitated."
return 0 return 0
@@ -221,7 +217,7 @@ var/list/spells = typesof(/spell) //needed for the badmin verb for now
return 0 return 0
var/spell/noclothes/spell = locate() in user.spell_list 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()) if(!user.wearing_wiz_garb())
return 0 return 0

View File

@@ -211,7 +211,7 @@
temp = "You have learned knock." temp = "You have learned knock."
if("horseman") 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 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." temp = "You have learned curse of the horseman."
if("fleshtostone") 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 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) user.Weaken(20)
/obj/item/weapon/spellbook/oneuse/horsemask /obj/item/weapon/spellbook/oneuse/horsemask
spell = /spell/targeted/horsemask spell = /spell/targeted/equip_item/horsemask
spellname = "horses" spellname = "horses"
icon_state ="bookhorses" icon_state ="bookhorses"
desc = "This book is more horse than your mind has room for." desc = "This book is more horse than your mind has room for."

View File

@@ -4,17 +4,26 @@
for(var/obj/screen/movable/spell_master/spell_master in spell_masters) for(var/obj/screen/movable/spell_master/spell_master in spell_masters)
spell_master.update_spells(0, src) 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) for(var/spell/S in spell_list)
if((!S.connected_button) || !statpanel(S.panel))
continue //Not showing the noclothes spell
switch(S.charge_type) switch(S.charge_type)
if(Sp_RECHARGE) 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) 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) 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) /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) if(!spell_masters)

View File

@@ -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

View File

@@ -1,4 +1,4 @@
/spell/targeted/horsemask /spell/targeted/equip_item/horsemask
name = "Curse of the Horseman" 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." 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" school = "transmutation"
@@ -17,19 +17,22 @@
hud_state = "wiz_horse" hud_state = "wiz_horse"
/spell/targeted/horsemask/cast(list/targets, mob/user = usr) /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) for(var/mob/living/target in targets)
var/obj/item/clothing/mask/horsehead/magichead = new /obj/item/clothing/mask/horsehead target.visible_message( "<span class='danger'>[target]'s face lights up in fire, and after the event a horse's head takes its place!</span>", \
"<span class='danger'>Your face burns up, and shortly after the fire you realise you have the face of a horse!</span>")
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.canremove = 0 //curses!
magichead.flags_inv = null //so you can still see their face magichead.flags_inv = null //so you can still see their face
magichead.voicechange = 1 //NEEEEIIGHH magichead.voicechange = 1 //NEEEEIIGHH
target.visible_message( "<span class='danger'>[target]'s face lights up in fire, and after the event a horse's head takes its place!</span>", \ return new_item
"<span class='danger'>Your face burns up, and shortly after the fire you realise you have the face of a horse!</span>")
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)

View File

@@ -57,7 +57,7 @@ code\game\dna\genes\goon_powers.dm
spell_flags = Z2NOCAST | NEEDSCLOTHES | INCLUDEUSER spell_flags = Z2NOCAST | NEEDSCLOTHES | INCLUDEUSER
invocation = "BIRUZ BENNAR" invocation = "BIRUZ BENNAR"
invocation_type = SpI_SHOUT invocation_type = SpI_SHOUT
message = "\blue You feel strong! You feel a pressure building behind your eyes!" message = "<span class='notice'>You feel strong! You feel a pressure building behind your eyes!</span>"
range = 0 range = 0
max_targets = 1 max_targets = 1

View File

@@ -51,7 +51,10 @@
ghost.spell_list = victim.spell_list//If they have spells, transfer them. Now we basically have a backup mob. ghost.spell_list = victim.spell_list//If they have spells, transfer them. Now we basically have a backup mob.
caster.mind.transfer_to(victim) 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. 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. 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) ghost.mind.transfer_to(caster)
caster.key = ghost.key //have to transfer the key since the mind was not active 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. if(caster.mind.special_verbs.len)//If they had any special verbs, we add them here.
for(var/V in caster.mind.special_verbs) 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. //After a certain amount of time the victim gets a message about being in a different body.
spawn(msg_wait) spawn(msg_wait)
caster << "\red You feel woozy and lightheaded. <b>Your body doesn't seem like your own.</b>" caster << "<span class='danger'>You feel woozy and lightheaded. Your body doesn't seem like your own.</span>"

View File

@@ -36,7 +36,7 @@ Targeted spells have two useful flags: INCLUDEUSER and SELECTABLE. These are exp
if(range == -2) if(range == -2)
targets = living_mob_list targets = living_mob_list
else else
for(var/mob/living/target in view_or_range(range, user, selection_type)) for(var/mob/living/target in view_or_range(range, holder, selection_type))
targets += target targets += target
else if(max_targets == 1) //single target can be picked else if(max_targets == 1) //single target can be picked
@@ -48,7 +48,7 @@ Targeted spells have two useful flags: INCLUDEUSER and SELECTABLE. These are exp
if(range == -2) if(range == -2)
starting_targets = living_mob_list starting_targets = living_mob_list
else else
starting_targets = view_or_range(range, user, selection_type) starting_targets = view_or_range(range, holder, selection_type)
for(var/mob/living/M in starting_targets) for(var/mob/living/M in starting_targets)
if(!(spell_flags & INCLUDEUSER) && M == user) if(!(spell_flags & INCLUDEUSER) && M == user)
@@ -76,7 +76,7 @@ Targeted spells have two useful flags: INCLUDEUSER and SELECTABLE. These are exp
if(range == -2) if(range == -2)
starting_targets = living_mob_list starting_targets = living_mob_list
else else
starting_targets = view_or_range(range, user, selection_type) starting_targets = view_or_range(range, holder, selection_type)
for(var/mob/living/target in starting_targets) for(var/mob/living/target in starting_targets)
if(!(spell_flags & INCLUDEUSER) && target == user) if(!(spell_flags & INCLUDEUSER) && target == user)
@@ -93,7 +93,7 @@ Targeted spells have two useful flags: INCLUDEUSER and SELECTABLE. These are exp
if(!M) if(!M)
break break
if(range != -2) if(range != -2)
if(!(M in view_or_range(range, user, selection_type))) if(!(M in view_or_range(range, holder, selection_type)))
continue continue
targets += M targets += M
possible_targets -= M possible_targets -= M
@@ -121,7 +121,7 @@ Targeted spells have two useful flags: INCLUDEUSER and SELECTABLE. These are exp
/spell/targeted/cast(var/list/targets, mob/user) /spell/targeted/cast(var/list/targets, mob/user)
for(var/mob/living/target in targets) for(var/mob/living/target in targets)
if(range >= 0) if(range >= 0)
if(!(target in view_or_range(range, user, selection_type))) //filter at time of casting if(!(target in view_or_range(range, holder, selection_type))) //filter at time of casting
targets -= target targets -= target
continue continue
apply_spell_damage(target) apply_spell_damage(target)