heretics from tg (with changes)
This commit is contained in:
@@ -224,7 +224,15 @@ GLOBAL_LIST_INIT(spells, typesof(/obj/effect/proc_holder/spell)) //needed for th
|
||||
/obj/effect/proc_holder/spell/proc/choose_targets(mob/user = usr) //depends on subtype - /targeted or /aoe_turf
|
||||
return
|
||||
|
||||
/obj/effect/proc_holder/spell/proc/can_target(mob/living/target)
|
||||
/**
|
||||
* can_target: Checks if we are allowed to cast the spell on a target.
|
||||
*
|
||||
* Arguments:
|
||||
* * target The atom that is being targeted by the spell.
|
||||
* * user The mob using the spell.
|
||||
* * silent If the checks should not give any feedback messages.
|
||||
*/
|
||||
/obj/effect/proc_holder/spell/proc/can_target(atom/target, mob/user, silent = FALSE)
|
||||
return TRUE
|
||||
|
||||
/obj/effect/proc_holder/spell/proc/start_recharge()
|
||||
@@ -296,6 +304,13 @@ GLOBAL_LIST_INIT(spells, typesof(/obj/effect/proc_holder/spell)) //needed for th
|
||||
/obj/effect/proc_holder/spell/proc/cast(list/targets,mob/user = usr)
|
||||
return
|
||||
|
||||
/obj/effect/proc_holder/spell/proc/view_or_range(distance = world.view, center=usr, type="view")
|
||||
switch(type)
|
||||
if("view")
|
||||
. = view(distance,center)
|
||||
if("range")
|
||||
. = range(distance,center)
|
||||
|
||||
/obj/effect/proc_holder/spell/proc/revert_cast(mob/user = usr) //resets recharge or readds a charge
|
||||
switch(charge_type)
|
||||
if("recharge")
|
||||
@@ -345,7 +360,7 @@ GLOBAL_LIST_INIT(spells, typesof(/obj/effect/proc_holder/spell)) //needed for th
|
||||
switch(max_targets)
|
||||
if(0) //unlimited
|
||||
for(var/mob/living/target in view_or_range(range, user, selection_type))
|
||||
if(!can_target(target))
|
||||
if(!can_target(target, user, TRUE))
|
||||
continue
|
||||
targets += target
|
||||
if(1) //single target can be picked
|
||||
@@ -357,7 +372,7 @@ GLOBAL_LIST_INIT(spells, typesof(/obj/effect/proc_holder/spell)) //needed for th
|
||||
for(var/mob/living/M in view_or_range(range, user, selection_type))
|
||||
if(!include_user && user == M)
|
||||
continue
|
||||
if(!can_target(M))
|
||||
if(!can_target(M, user, TRUE))
|
||||
continue
|
||||
possible_targets += M
|
||||
|
||||
@@ -365,7 +380,7 @@ GLOBAL_LIST_INIT(spells, typesof(/obj/effect/proc_holder/spell)) //needed for th
|
||||
//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 null|mob in possible_targets
|
||||
M = input("Choose the target for the spell.", "Targeting") as null|mob in sortNames(possible_targets)
|
||||
else
|
||||
switch(random_target_priority)
|
||||
if(TARGET_RANDOM)
|
||||
@@ -385,7 +400,7 @@ GLOBAL_LIST_INIT(spells, typesof(/obj/effect/proc_holder/spell)) //needed for th
|
||||
else
|
||||
var/list/possible_targets = list()
|
||||
for(var/mob/living/target in view_or_range(range, user, selection_type))
|
||||
if(!can_target(target))
|
||||
if(!can_target(target, user, TRUE))
|
||||
continue
|
||||
possible_targets += target
|
||||
for(var/i=1,i<=max_targets,i++)
|
||||
@@ -411,7 +426,7 @@ GLOBAL_LIST_INIT(spells, typesof(/obj/effect/proc_holder/spell)) //needed for th
|
||||
var/list/targets = list()
|
||||
|
||||
for(var/turf/target in view_or_range(range,user,selection_type))
|
||||
if(!can_target(target))
|
||||
if(!can_target(target, user, TRUE))
|
||||
continue
|
||||
if(!(target in view_or_range(inner_radius,user,selection_type)))
|
||||
targets += target
|
||||
|
||||
@@ -0,0 +1,117 @@
|
||||
/obj/effect/proc_holder/spell/cone
|
||||
name = "Cone of Nothing"
|
||||
desc = "Does nothing in a cone! Wow!"
|
||||
school = "evocation"
|
||||
charge_max = 100
|
||||
clothes_req = FALSE
|
||||
invocation = "FUKAN NOTHAN"
|
||||
invocation_type = "shout"
|
||||
sound = 'sound/magic/forcewall.ogg'
|
||||
action_icon_state = "shield"
|
||||
range = -1
|
||||
cooldown_min = 0.5 SECONDS
|
||||
///This controls how many levels the cone has, increase this value to make a bigger cone.
|
||||
var/cone_levels = 3
|
||||
///This value determines if the cone penetrates walls.
|
||||
var/respect_density = FALSE
|
||||
|
||||
/obj/effect/proc_holder/spell/cone/choose_targets(mob/user = usr)
|
||||
perform(null, user=user)
|
||||
|
||||
///This proc creates a list of turfs that are hit by the cone
|
||||
/obj/effect/proc_holder/spell/cone/proc/cone_helper(var/turf/starter_turf, var/dir_to_use, var/cone_levels = 3)
|
||||
var/list/turfs_to_return = list()
|
||||
var/turf/turf_to_use = starter_turf
|
||||
var/turf/left_turf
|
||||
var/turf/right_turf
|
||||
var/right_dir
|
||||
var/left_dir
|
||||
switch(dir_to_use)
|
||||
if(NORTH)
|
||||
left_dir = WEST
|
||||
right_dir = EAST
|
||||
if(SOUTH)
|
||||
left_dir = EAST
|
||||
right_dir = WEST
|
||||
if(EAST)
|
||||
left_dir = NORTH
|
||||
right_dir = SOUTH
|
||||
if(WEST)
|
||||
left_dir = SOUTH
|
||||
right_dir = NORTH
|
||||
|
||||
|
||||
for(var/i in 1 to cone_levels)
|
||||
var/list/level_turfs = list()
|
||||
turf_to_use = get_step(turf_to_use, dir_to_use)
|
||||
level_turfs += turf_to_use
|
||||
if(i != 1)
|
||||
left_turf = get_step(turf_to_use, left_dir)
|
||||
level_turfs += left_turf
|
||||
right_turf = get_step(turf_to_use, right_dir)
|
||||
level_turfs += right_turf
|
||||
for(var/left_i in 1 to i -calculate_cone_shape(i))
|
||||
if(left_turf.density && respect_density)
|
||||
break
|
||||
left_turf = get_step(left_turf, left_dir)
|
||||
level_turfs += left_turf
|
||||
for(var/right_i in 1 to i -calculate_cone_shape(i))
|
||||
if(right_turf.density && respect_density)
|
||||
break
|
||||
right_turf = get_step(right_turf, right_dir)
|
||||
level_turfs += right_turf
|
||||
turfs_to_return += list(level_turfs)
|
||||
if(i == cone_levels)
|
||||
continue
|
||||
if(turf_to_use.density && respect_density)
|
||||
break
|
||||
return turfs_to_return
|
||||
|
||||
/obj/effect/proc_holder/spell/cone/cast(list/targets,mob/user = usr)
|
||||
var/list/cone_turfs = cone_helper(get_turf(user), user.dir, cone_levels)
|
||||
for(var/list/turf_list in cone_turfs)
|
||||
do_cone_effects(turf_list)
|
||||
|
||||
///This proc does obj, mob and turf cone effects on all targets in a list
|
||||
/obj/effect/proc_holder/spell/cone/proc/do_cone_effects(list/target_turf_list, level)
|
||||
for(var/target_turf in target_turf_list)
|
||||
if(!target_turf) //if turf is no longer there
|
||||
continue
|
||||
do_turf_cone_effect(target_turf, level)
|
||||
if(isopenturf(target_turf))
|
||||
var/turf/open/open_turf = target_turf
|
||||
for(var/movable_content in open_turf)
|
||||
if(isobj(movable_content))
|
||||
do_obj_cone_effect(movable_content, level)
|
||||
else if(isliving(movable_content))
|
||||
do_mob_cone_effect(movable_content, level)
|
||||
|
||||
///This proc deterimines how the spell will affect turfs.
|
||||
/obj/effect/proc_holder/spell/cone/proc/do_turf_cone_effect(turf/target_turf, level)
|
||||
return
|
||||
|
||||
///This proc deterimines how the spell will affect objects.
|
||||
/obj/effect/proc_holder/spell/cone/proc/do_obj_cone_effect(obj/target_obj, level)
|
||||
return
|
||||
|
||||
///This proc deterimines how the spell will affect mobs.
|
||||
/obj/effect/proc_holder/spell/cone/proc/do_mob_cone_effect(mob/living/target_mob, level)
|
||||
return
|
||||
|
||||
///This proc adjusts the cones width depending on the level.
|
||||
/obj/effect/proc_holder/spell/cone/proc/calculate_cone_shape(current_level)
|
||||
var/end_taper_start = round(cone_levels * 0.8)
|
||||
if(current_level > end_taper_start)
|
||||
return (current_level % end_taper_start) * 2 //someone more talented and probably come up with a better formula.
|
||||
else
|
||||
return 2
|
||||
|
||||
///This type of cone gradually affects each level of the cone instead of affecting the entire area at once.
|
||||
/obj/effect/proc_holder/spell/cone/staggered
|
||||
|
||||
/obj/effect/proc_holder/spell/cone/staggered/cast(list/targets,mob/user = usr)
|
||||
var/level_counter = 0
|
||||
var/list/cone_turfs = cone_helper(get_turf(user), user.dir, cone_levels)
|
||||
for(var/list/turf_list in cone_turfs)
|
||||
level_counter++
|
||||
addtimer(CALLBACK(src, .proc/do_cone_effects, turf_list, level_counter), 2 * level_counter)
|
||||
@@ -49,8 +49,8 @@
|
||||
var/projectile_type = text2path(proj_type)
|
||||
projectile = new projectile_type(user)
|
||||
else if(istype(proj_type, /obj/effect/proc_holder/spell))
|
||||
projectile = new /obj/effect/proc_holder/spell/targeted/trigger(user)
|
||||
var/obj/effect/proc_holder/spell/targeted/trigger/T = projectile
|
||||
projectile = new /obj/effect/proc_holder/spell/pointed/trigger(user)
|
||||
var/obj/effect/proc_holder/spell/pointed/trigger/T = projectile
|
||||
T.linked_spells += proj_type
|
||||
else
|
||||
projectile = new proj_type(user)
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
action_icon_state = "jaunt"
|
||||
|
||||
/obj/effect/proc_holder/spell/targeted/ethereal_jaunt/cast(list/targets,mob/user = usr) //magnets, so mostly hardcoded
|
||||
playsound(get_turf(user), 'sound/magic/ethereal_enter.ogg', 50, 1, -1)
|
||||
play_sound("enter",user)
|
||||
for(var/mob/living/target in targets)
|
||||
INVOKE_ASYNC(src, .proc/do_jaunt, target)
|
||||
|
||||
@@ -42,7 +42,7 @@
|
||||
ADD_TRAIT(target, TRAIT_MOBILITY_NOMOVE, src)
|
||||
target.update_mobility()
|
||||
holder.reappearing = 1
|
||||
playsound(get_turf(target), 'sound/magic/ethereal_exit.ogg', 50, 1, -1)
|
||||
play_sound("exit",target)
|
||||
sleep(25 - jaunt_in_time)
|
||||
new jaunt_in_type(mobloc, holder.dir)
|
||||
target.setDir(holder.dir)
|
||||
@@ -63,6 +63,13 @@
|
||||
steam.set_up(10, 0, mobloc)
|
||||
steam.start()
|
||||
|
||||
/obj/effect/proc_holder/spell/targeted/ethereal_jaunt/proc/play_sound(type,mob/living/target)
|
||||
switch(type)
|
||||
if("enter")
|
||||
playsound(get_turf(target), 'sound/magic/ethereal_enter.ogg', 50, TRUE, -1)
|
||||
if("exit")
|
||||
playsound(get_turf(target), 'sound/magic/ethereal_exit.ogg', 50, TRUE, -1)
|
||||
|
||||
/obj/effect/dummy/phased_mob/spell_jaunt
|
||||
name = "water"
|
||||
icon = 'icons/effects/effects.dmi'
|
||||
|
||||
@@ -1,88 +0,0 @@
|
||||
/obj/effect/proc_holder/spell/targeted/mind_transfer
|
||||
name = "Mind Transfer"
|
||||
desc = "This spell allows the user to switch bodies with a target."
|
||||
|
||||
school = "transmutation"
|
||||
charge_max = 600
|
||||
clothes_req = NONE
|
||||
invocation = "GIN'YU CAPAN"
|
||||
invocation_type = "whisper"
|
||||
range = 1
|
||||
cooldown_min = 200 //100 deciseconds reduction per rank
|
||||
var/unconscious_amount_caster = 400 //how much the caster is stunned for after the spell
|
||||
var/unconscious_amount_victim = 400 //how much the victim is stunned for after the spell
|
||||
|
||||
action_icon_state = "mindswap"
|
||||
|
||||
/*
|
||||
Urist: I don't feel like figuring out how you store object spells so I'm leaving this for you to do.
|
||||
Make sure spells that are removed from spell_list are actually removed and deleted when mind transferring.
|
||||
Also, you never added distance checking after target is selected. I've went ahead and did that.
|
||||
*/
|
||||
/obj/effect/proc_holder/spell/targeted/mind_transfer/cast(list/targets, mob/living/user = usr, distanceoverride, silent = FALSE)
|
||||
if(!targets.len)
|
||||
if(!silent)
|
||||
to_chat(user, "<span class='warning'>No mind found!</span>")
|
||||
return
|
||||
|
||||
if(targets.len > 1)
|
||||
if(!silent)
|
||||
to_chat(user, "<span class='warning'>Too many minds! You're not a hive damnit!</span>")
|
||||
return
|
||||
|
||||
var/mob/living/target = targets[1]
|
||||
|
||||
var/t_He = target.p_they(TRUE)
|
||||
var/t_is = target.p_are()
|
||||
|
||||
if(!(target in oview(range)) && !distanceoverride)//If they are not in overview after selection. Do note that !() is necessary for in to work because ! takes precedence over it.
|
||||
if(!silent)
|
||||
to_chat(user, "<span class='warning'>[t_He] [t_is] too far away!</span>")
|
||||
return
|
||||
|
||||
if(ismegafauna(target))
|
||||
if(!silent)
|
||||
to_chat(user, "<span class='warning'>This creature is too powerful to control!</span>")
|
||||
return
|
||||
|
||||
if(target.stat == DEAD)
|
||||
if(!silent)
|
||||
to_chat(user, "<span class='warning'>You don't particularly want to be dead!</span>")
|
||||
return
|
||||
|
||||
if(!target.key || !target.mind)
|
||||
if(!silent)
|
||||
to_chat(user, "<span class='warning'>[t_He] appear[target.p_s()] to be catatonic! Not even magic can affect [target.p_their()] vacant mind.</span>")
|
||||
return
|
||||
|
||||
if(user.suiciding)
|
||||
if(!silent)
|
||||
to_chat(user, "<span class='warning'>You're killing yourself! You can't concentrate enough to do this!</span>")
|
||||
return
|
||||
|
||||
var/datum/mind/TM = target.mind
|
||||
if(target.anti_magic_check(TRUE, FALSE) || TM.has_antag_datum(/datum/antagonist/wizard) || TM.has_antag_datum(/datum/antagonist/cult) || TM.has_antag_datum(/datum/antagonist/clockcult) || TM.has_antag_datum(/datum/antagonist/changeling) || TM.has_antag_datum(/datum/antagonist/rev) || target.key[1] == "@")
|
||||
if(!silent)
|
||||
to_chat(user, "<span class='warning'>[target.p_their(TRUE)] mind is resisting your spell!</span>")
|
||||
return
|
||||
|
||||
var/mob/living/victim = target//The target of the spell whos body will be transferred to.
|
||||
var/mob/living/caster = user//The wizard/whomever doing the body transferring.
|
||||
|
||||
//MIND TRANSFER BEGIN
|
||||
var/mob/dead/observer/ghost = victim.ghostize(FALSE, TRUE)
|
||||
caster.mind.transfer_to(victim)
|
||||
|
||||
ghost.mind.transfer_to(caster)
|
||||
if(ghost.key)
|
||||
ghost.transfer_ckey(caster) //have to transfer the key since the mind was not active
|
||||
qdel(ghost)
|
||||
|
||||
//MIND TRANSFER END
|
||||
|
||||
//Here we knock both mobs out for a time.
|
||||
caster.Unconscious(unconscious_amount_caster)
|
||||
victim.Unconscious(unconscious_amount_victim)
|
||||
SEND_SOUND(caster, sound('sound/magic/mandswap.ogg'))
|
||||
SEND_SOUND(victim, sound('sound/magic/mandswap.ogg'))// only the caster and victim hear the sounds, that way no one knows for sure if the swap happened
|
||||
return TRUE
|
||||
+27
-24
@@ -1,51 +1,54 @@
|
||||
/obj/effect/proc_holder/spell/targeted/barnyardcurse
|
||||
/obj/effect/proc_holder/spell/pointed/barnyardcurse
|
||||
name = "Curse of the Barnyard"
|
||||
desc = "This spell dooms an unlucky soul to possess the speech and facial attributes of a barnyard animal."
|
||||
school = "transmutation"
|
||||
charge_type = "recharge"
|
||||
charge_max = 150
|
||||
charge_counter = 0
|
||||
clothes_req = NONE
|
||||
stat_allowed = 0
|
||||
clothes_req = FALSE
|
||||
stat_allowed = FALSE
|
||||
invocation = "KN'A FTAGHU, PUCK 'BTHNK!"
|
||||
invocation_type = "shout"
|
||||
range = 7
|
||||
cooldown_min = 30
|
||||
selection_type = "range"
|
||||
var/list/compatible_mobs = list(/mob/living/carbon/human, /mob/living/carbon/monkey)
|
||||
|
||||
ranged_mousepointer = 'icons/effects/mouse_pointers/barn_target.dmi'
|
||||
action_icon_state = "barn"
|
||||
active_msg = "You prepare to curse a target..."
|
||||
deactive_msg = "You dispel the curse..."
|
||||
/// List of mobs which are allowed to be a target of the spell
|
||||
var/static/list/compatible_mobs_typecache = typecacheof(list(/mob/living/carbon/human, /mob/living/carbon/monkey))
|
||||
|
||||
/obj/effect/proc_holder/spell/targeted/barnyardcurse/cast(list/targets, mob/user = usr)
|
||||
/obj/effect/proc_holder/spell/pointed/barnyardcurse/cast(list/targets, mob/user)
|
||||
if(!targets.len)
|
||||
to_chat(user, "<span class='notice'>No target found in range.</span>")
|
||||
return
|
||||
to_chat(user, "<span class='warning'>No target found in range!</span>")
|
||||
return FALSE
|
||||
if(!can_target(targets[1], user))
|
||||
return FALSE
|
||||
|
||||
var/mob/living/carbon/target = targets[1]
|
||||
|
||||
if(!(target.type in compatible_mobs))
|
||||
to_chat(user, "<span class='notice'>You are unable to curse [target]'s head!</span>")
|
||||
return
|
||||
|
||||
if(!(target in oview(range)))
|
||||
to_chat(user, "<span class='notice'>[target.p_theyre(TRUE)] too far away!</span>")
|
||||
return
|
||||
|
||||
if(target.anti_magic_check())
|
||||
to_chat(user, "<span class='warning'>The spell had no effect!</span>")
|
||||
target.visible_message("<span class='danger'>[target]'s face bursts into flames, which instantly burst outward, leaving [target] unharmed!</span>", \
|
||||
"<span class='danger'>Your face starts burning up, but the flames are repulsed by your anti-magic protection!</span>")
|
||||
return
|
||||
"<span class='danger'>Your face starts burning up, but the flames are repulsed by your anti-magic protection!</span>")
|
||||
return FALSE
|
||||
|
||||
var/list/masks = list(/obj/item/clothing/mask/pig/cursed, /obj/item/clothing/mask/cowmask/cursed, /obj/item/clothing/mask/horsehead/cursed)
|
||||
|
||||
var/choice = pick(masks)
|
||||
var/obj/item/clothing/mask/magichead = new choice(get_turf(target))
|
||||
magichead.flags_inv = null
|
||||
|
||||
target.visible_message("<span class='danger'>[target]'s face bursts into flames, and a barnyard animal'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 barnyard animal!</span>")
|
||||
if(!target.dropItemToGround(target.wear_mask))
|
||||
qdel(target.wear_mask)
|
||||
target.equip_to_slot_if_possible(magichead, SLOT_WEAR_MASK, 1, 1)
|
||||
|
||||
target.equip_to_slot_if_possible(magichead, ITEM_SLOT_MASK, 1, 1)
|
||||
target.flash_act()
|
||||
|
||||
/obj/effect/proc_holder/spell/pointed/barnyardcurse/can_target(atom/target, mob/user, silent)
|
||||
. = ..()
|
||||
if(!.)
|
||||
return FALSE
|
||||
if(!is_type_in_typecache(target, compatible_mobs_typecache))
|
||||
if(!silent)
|
||||
to_chat(user, "<span class='warning'>You are unable to curse [target]!</span>")
|
||||
return FALSE
|
||||
return TRUE
|
||||
@@ -0,0 +1,35 @@
|
||||
/obj/effect/proc_holder/spell/pointed/trigger/blind
|
||||
name = "Blind"
|
||||
desc = "This spell temporarily blinds a single target."
|
||||
school = "transmutation"
|
||||
charge_max = 300
|
||||
clothes_req = FALSE
|
||||
invocation = "STI KALY"
|
||||
invocation_type = "whisper"
|
||||
message = "<span class='notice'>Your eyes cry out in pain!</span>"
|
||||
cooldown_min = 50 //12 deciseconds reduction per rank
|
||||
starting_spells = list("/obj/effect/proc_holder/spell/targeted/inflict_handler/blind", "/obj/effect/proc_holder/spell/targeted/genetic/blind")
|
||||
ranged_mousepointer = 'icons/effects/mouse_pointers/blind_target.dmi'
|
||||
action_icon_state = "blind"
|
||||
active_msg = "You prepare to blind a target..."
|
||||
|
||||
/obj/effect/proc_holder/spell/targeted/inflict_handler/blind
|
||||
amt_eye_blind = 10
|
||||
amt_eye_blurry = 20
|
||||
sound = 'sound/magic/blind.ogg'
|
||||
|
||||
/obj/effect/proc_holder/spell/targeted/genetic/blind
|
||||
mutations = list(BLINDMUT)
|
||||
duration = 300
|
||||
charge_max = 400 // needs to be higher than the duration or it'll be permanent
|
||||
sound = 'sound/magic/blind.ogg'
|
||||
|
||||
/obj/effect/proc_holder/spell/pointed/trigger/blind/can_target(atom/target, mob/user, silent)
|
||||
. = ..()
|
||||
if(!.)
|
||||
return FALSE
|
||||
if(!isliving(target))
|
||||
if(!silent)
|
||||
to_chat(user, "<span class='warning'>You can only blind living beings!</span>")
|
||||
return FALSE
|
||||
return TRUE
|
||||
@@ -0,0 +1,103 @@
|
||||
/obj/effect/proc_holder/spell/pointed/mind_transfer
|
||||
name = "Mind Transfer"
|
||||
desc = "This spell allows the user to switch bodies with a target next to him."
|
||||
school = "transmutation"
|
||||
charge_max = 600
|
||||
clothes_req = FALSE
|
||||
invocation = "GIN'YU CAPAN"
|
||||
invocation_type = "whisper"
|
||||
range = 1
|
||||
cooldown_min = 200 //100 deciseconds reduction per rank
|
||||
ranged_mousepointer = 'icons/effects/mouse_pointers/mindswap_target.dmi'
|
||||
action_icon_state = "mindswap"
|
||||
active_msg = "You prepare to swap minds with a target..."
|
||||
/// For how long is the caster stunned for after the spell
|
||||
var/unconscious_amount_caster = 40 SECONDS
|
||||
/// For how long is the victim stunned for after the spell
|
||||
var/unconscious_amount_victim = 40 SECONDS
|
||||
|
||||
/obj/effect/proc_holder/spell/pointed/mind_transfer/cast(list/targets, mob/living/user, silent = FALSE)
|
||||
if(!targets.len)
|
||||
if(!silent)
|
||||
to_chat(user, "<span class='warning'>No mind found!</span>")
|
||||
return FALSE
|
||||
if(targets.len > 1)
|
||||
if(!silent)
|
||||
to_chat(user, "<span class='warning'>Too many minds! You're not a hive damnit!</span>")
|
||||
return FALSE
|
||||
if(!can_target(targets[1], user, silent))
|
||||
return FALSE
|
||||
|
||||
var/mob/living/victim = targets[1] //The target of the spell whos body will be transferred to.
|
||||
var/datum/mind/VM = victim.mind
|
||||
if(victim.anti_magic_check(TRUE, FALSE) || VM.has_antag_datum(/datum/antagonist/wizard) || VM.has_antag_datum(/datum/antagonist/cult) || VM.has_antag_datum(/datum/antagonist/changeling) || VM.has_antag_datum(/datum/antagonist/rev) || victim.key[1] == "@")
|
||||
if(!silent)
|
||||
to_chat(user, "<span class='warning'>[victim.p_their(TRUE)] mind is resisting your spell!</span>")
|
||||
return FALSE
|
||||
if(istype(victim, /mob/living/simple_animal/hostile/guardian))
|
||||
var/mob/living/simple_animal/hostile/guardian/stand = victim
|
||||
if(stand.summoner)
|
||||
victim = stand.summoner
|
||||
|
||||
//You should not be able to enter one of the most powerful side-antags as a fucking wizard.
|
||||
if(istype(victim,/mob/living/simple_animal/slaughter))
|
||||
to_chat(user, "<span class='warning'>The devilish contract doesn't include the 'mind swappable' package, please try again another lifetime.</span>")
|
||||
return
|
||||
|
||||
//MIND TRANSFER BEGIN
|
||||
var/mob/dead/observer/ghost = victim.ghostize()
|
||||
user.mind.transfer_to(victim)
|
||||
|
||||
ghost.mind.transfer_to(user)
|
||||
if(ghost.key)
|
||||
user.key = ghost.key //have to transfer the key since the mind was not active
|
||||
qdel(ghost)
|
||||
//MIND TRANSFER END
|
||||
|
||||
//Here we knock both mobs out for a time.
|
||||
user.Unconscious(unconscious_amount_caster)
|
||||
victim.Unconscious(unconscious_amount_victim)
|
||||
SEND_SOUND(user, sound('sound/magic/mandswap.ogg'))
|
||||
SEND_SOUND(victim, sound('sound/magic/mandswap.ogg')) // only the caster and victim hear the sounds, that way no one knows for sure if the swap happened
|
||||
return TRUE
|
||||
|
||||
/obj/effect/proc_holder/spell/pointed/mind_transfer/can_target(atom/target, mob/user, silent)
|
||||
. = ..()
|
||||
if(!.)
|
||||
return FALSE
|
||||
if(!isliving(target))
|
||||
if(!silent)
|
||||
to_chat(user, "<span class='warning'>You can only swap minds with living beings!</span>")
|
||||
return FALSE
|
||||
if(user == target)
|
||||
if(!silent)
|
||||
to_chat(user, "<span class='warning'>You can't swap minds with yourself!</span>")
|
||||
return FALSE
|
||||
|
||||
var/mob/living/victim = target
|
||||
var/t_He = victim.p_they(TRUE)
|
||||
|
||||
if(ismegafauna(victim))
|
||||
if(!silent)
|
||||
to_chat(user, "<span class='warning'>This creature is too powerful to control!</span>")
|
||||
return FALSE
|
||||
if(victim.stat == DEAD)
|
||||
if(!silent)
|
||||
to_chat(user, "<span class='warning'>You don't particularly want to be dead!</span>")
|
||||
return FALSE
|
||||
if(!victim.key || !victim.mind)
|
||||
if(!silent)
|
||||
to_chat(user, "<span class='warning'>[t_He] appear[victim.p_s()] to be catatonic! Not even magic can affect [victim.p_their()] vacant mind.</span>")
|
||||
return FALSE
|
||||
if(user.suiciding)
|
||||
if(!silent)
|
||||
to_chat(user, "<span class='warning'>You're killing yourself! You can't concentrate enough to do this!</span>")
|
||||
return FALSE
|
||||
if(istype(victim, /mob/living/simple_animal/hostile/guardian))
|
||||
var/mob/living/simple_animal/hostile/guardian/stand = victim
|
||||
if(stand.summoner)
|
||||
if(stand.summoner == user)
|
||||
if(!silent)
|
||||
to_chat(user, "<span class='warning'>Swapping minds with your own guardian would just put you back into your own head!</span>")
|
||||
return FALSE
|
||||
return TRUE
|
||||
@@ -0,0 +1,105 @@
|
||||
/obj/effect/proc_holder/spell/pointed
|
||||
name = "pointed spell"
|
||||
ranged_mousepointer = 'icons/effects/mouse_pointers/throw_target.dmi'
|
||||
action_icon_state = "projectile"
|
||||
/// Message showing to the spell owner upon deactivating pointed spell.
|
||||
var/deactive_msg = "You dispel the magic..."
|
||||
/// Message showing to the spell owner upon activating pointed spell.
|
||||
var/active_msg = "You prepare to use the spell on a target..."
|
||||
/// Variable dictating if the user is allowed to cast a spell on himself.
|
||||
var/self_castable = FALSE
|
||||
/// Variable dictating if the spell will use turf based aim assist
|
||||
var/aim_assist = TRUE
|
||||
|
||||
/obj/effect/proc_holder/spell/pointed/Trigger(mob/user, skip_can_cast = TRUE)
|
||||
if(!istype(user))
|
||||
return
|
||||
var/msg
|
||||
if(!can_cast(user))
|
||||
msg = "<span class='warning'>You can no longer cast [name]!</span>"
|
||||
remove_ranged_ability(msg)
|
||||
return
|
||||
if(active)
|
||||
msg = "<span class='notice'>[deactive_msg]</span>"
|
||||
remove_ranged_ability(msg)
|
||||
else
|
||||
msg = "<span class='notice'>[active_msg] <B>Left-click to activate spell on a target!</B></span>"
|
||||
add_ranged_ability(user, msg, TRUE)
|
||||
on_activation(user)
|
||||
|
||||
/obj/effect/proc_holder/spell/pointed/on_lose(mob/living/user)
|
||||
remove_ranged_ability()
|
||||
|
||||
/obj/effect/proc_holder/spell/pointed/remove_ranged_ability(msg)
|
||||
. = ..()
|
||||
on_deactivation(ranged_ability_user)
|
||||
|
||||
/obj/effect/proc_holder/spell/pointed/add_ranged_ability(mob/living/user, msg, forced)
|
||||
. = ..()
|
||||
on_activation(user)
|
||||
|
||||
/**
|
||||
* on_activation: What happens upon pointed spell activation.
|
||||
*
|
||||
* Arguments:
|
||||
* * user The mob interacting owning the spell.
|
||||
*/
|
||||
/obj/effect/proc_holder/spell/pointed/proc/on_activation(mob/user)
|
||||
return
|
||||
|
||||
/**
|
||||
* on_activation: What happens upon pointed spell deactivation.
|
||||
*
|
||||
* Arguments:
|
||||
* * user The mob interacting owning the spell.
|
||||
*/
|
||||
/obj/effect/proc_holder/spell/pointed/proc/on_deactivation(mob/user)
|
||||
return
|
||||
|
||||
/obj/effect/proc_holder/spell/pointed/update_icon()
|
||||
if(!action)
|
||||
return
|
||||
if(active)
|
||||
action.button_icon_state = "[action_icon_state]1"
|
||||
else
|
||||
action.button_icon_state = "[action_icon_state]"
|
||||
action.UpdateButtonIcon()
|
||||
|
||||
/obj/effect/proc_holder/spell/pointed/InterceptClickOn(mob/living/caller, params, atom/target)
|
||||
if(..())
|
||||
return TRUE
|
||||
if(aim_assist && isturf(target))
|
||||
var/list/possible_targets = list()
|
||||
for(var/A in target)
|
||||
if(intercept_check(caller, A, TRUE))
|
||||
possible_targets += A
|
||||
if(possible_targets.len == 1)
|
||||
target = possible_targets[1]
|
||||
if(!intercept_check(caller, target))
|
||||
return TRUE
|
||||
if(!cast_check(FALSE, caller))
|
||||
return TRUE
|
||||
perform(list(target), user = caller)
|
||||
remove_ranged_ability()
|
||||
return TRUE // Do not do any underlying actions after the spell cast
|
||||
|
||||
/**
|
||||
* intercept_check: Specific spell checks for InterceptClickOn() targets.
|
||||
*
|
||||
* Arguments:
|
||||
* * user The mob using the ranged spell via intercept.
|
||||
* * target The atom that is being targeted by the spell via intercept.
|
||||
* * silent If the checks should produce not any feedback messages for the user.
|
||||
*/
|
||||
/obj/effect/proc_holder/spell/pointed/proc/intercept_check(mob/user, atom/target, silent = FALSE)
|
||||
if(!self_castable && target == user)
|
||||
if(!silent)
|
||||
to_chat(user, "<span class='warning'>You cannot cast the spell on yourself!</span>")
|
||||
return FALSE
|
||||
if(!(target in view_or_range(range, user, selection_type)))
|
||||
if(!silent)
|
||||
to_chat(user, "<span class='warning'>[target.p_theyre(TRUE)] too far away!</span>")
|
||||
return FALSE
|
||||
if(!can_target(target, user, silent))
|
||||
return FALSE
|
||||
return TRUE
|
||||
@@ -37,8 +37,8 @@
|
||||
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)
|
||||
var/obj/effect/proc_holder/spell/targeted/trigger/T = projectile
|
||||
projectile = new /obj/effect/proc_holder/spell/pointed/trigger(user)
|
||||
var/obj/effect/proc_holder/spell/pointed/trigger/T = projectile
|
||||
T.linked_spells += proj_type
|
||||
projectile.icon = proj_icon
|
||||
projectile.icon_state = proj_icon_state
|
||||
|
||||
@@ -1,30 +1,26 @@
|
||||
/obj/effect/proc_holder/spell/targeted/trigger
|
||||
/obj/effect/proc_holder/spell/pointed/trigger
|
||||
name = "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/Initialize()
|
||||
/obj/effect/proc_holder/spell/pointed/trigger/Initialize()
|
||||
. = ..()
|
||||
|
||||
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/pointed/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/pointed/trigger/cast(list/targets,mob/user = usr)
|
||||
playMagSound()
|
||||
for(var/mob/living/target in targets)
|
||||
for(var/obj/effect/proc_holder/spell/spell in contents)
|
||||
spell.perform(list(target),0)
|
||||
for(var/obj/effect/proc_holder/spell/spell in linked_spells)
|
||||
spell.perform(list(target),0)
|
||||
|
||||
return
|
||||
@@ -207,40 +207,12 @@
|
||||
summon_type = list(/mob/living/simple_animal/hostile/netherworld)
|
||||
cast_sound = 'sound/magic/summonitems_generic.ogg'
|
||||
|
||||
/obj/effect/proc_holder/spell/targeted/trigger/blind
|
||||
name = "Blind"
|
||||
desc = "This spell temporarily blinds a single person and does not require wizard garb."
|
||||
|
||||
school = "transmutation"
|
||||
charge_max = 300
|
||||
clothes_req = NONE
|
||||
invocation = "STI KALY"
|
||||
invocation_type = "whisper"
|
||||
message = "<span class='notice'>Your eyes cry out in pain!</span>"
|
||||
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")
|
||||
|
||||
action_icon_state = "blind"
|
||||
|
||||
/obj/effect/proc_holder/spell/aoe_turf/conjure/creature/cult
|
||||
name = "Summon Creatures (DANGEROUS)"
|
||||
clothes_req = SPELL_CULT_GARB
|
||||
charge_max = 5000
|
||||
summon_amt = 2
|
||||
|
||||
|
||||
|
||||
/obj/effect/proc_holder/spell/targeted/inflict_handler/blind
|
||||
amt_eye_blind = 10
|
||||
amt_eye_blurry = 20
|
||||
sound = 'sound/magic/blind.ogg'
|
||||
|
||||
/obj/effect/proc_holder/spell/targeted/genetic/blind
|
||||
mutations = list(BLINDMUT)
|
||||
duration = 300
|
||||
sound = 'sound/magic/blind.ogg'
|
||||
|
||||
/obj/effect/proc_holder/spell/aoe_turf/repulse
|
||||
name = "Repulse"
|
||||
desc = "This spell throws everything around the user away."
|
||||
|
||||
Reference in New Issue
Block a user