Event stuff, but also Squeak component (#7285)

This commit is contained in:
BlackMajor
2023-12-11 14:40:47 +13:00
committed by GitHub
parent 835e207c5c
commit 92c744dfec
32 changed files with 831 additions and 78 deletions
@@ -0,0 +1,180 @@
//You know, with some intelligent coding.. you could add onto this code to handle the turf based footstep sounds, and be away with those turf lists all together
//Partial squeak port from tg. Commented out stuff we don't have.
/datum/component/squeak
var/static/list/default_squeak_sounds = list('sound/items/bikehorn.ogg'=1, 'sound/voice/quack.ogg'=1)
var/list/override_squeak_sounds
var/mob/holder
var/squeak_chance = 100
var/volume = 30
// This is so shoes don't squeak every step
var/steps = 0
var/step_delay = 1
// This is to stop squeak spam from inhand usage
var/last_use = 0
var/use_delay = 20
///extra-range for this component's sound
var/sound_extra_range = -1
/*
///when sounds start falling off for the squeak
var/sound_falloff_distance = 1
///sound exponent for squeak. Defaults to 10 as squeaking is loud and annoying enough.
var/sound_falloff_exponent = 10
*/
/* Disposals stuff we don't have
///what we set connect_loc to if parent is an item
var/static/list/item_connections = list(
COMSIG_ATOM_ENTERED = PROC_REF(play_squeak_crossed),
)
*/
/datum/component/squeak/Initialize(custom_sounds, volume_override, chance_override, step_delay_override, use_delay_override, extrarange)
if(!isatom(parent))
return COMPONENT_INCOMPATIBLE
RegisterSignals(parent, list(COMSIG_ATOM_ENTERED, COMSIG_ATOM_BLOB_ACT, COMSIG_ATOM_HULK_ATTACK), PROC_REF(play_squeak))
if(ismovable(parent))
RegisterSignals(parent, list(COMSIG_MOVABLE_BUMP, COMSIG_MOVABLE_IMPACT, COMSIG_PROJECTILE_BEFORE_FIRE), PROC_REF(play_squeak))
//Disposals stuff we don't have
//AddComponent(/datum/component/connect_loc_behalf, parent, item_connections)
//RegisterSignal(parent, COMSIG_MOVABLE_DISPOSING, PROC_REF(disposing_react))
if(isitem(parent))
//RegisterSignals(parent, list(COMSIG_ITEM_ATTACK, COMSIG_ITEM_ATTACK_ATOM, COMSIG_ITEM_HIT_REACT), PROC_REF(play_squeak))
RegisterSignal(parent, COMSIG_ITEM_ATTACK_SELF, PROC_REF(use_squeak))
RegisterSignal(parent, COMSIG_ITEM_EQUIPPED, PROC_REF(on_equip))
RegisterSignal(parent, COMSIG_ITEM_DROPPED, PROC_REF(on_drop))
if(istype(parent, /obj/item/clothing/shoes))
RegisterSignal(parent, COMSIG_SHOES_STEP_ACTION, PROC_REF(step_squeak))
else if(isstructure(parent))
RegisterSignal(parent, COMSIG_ATOM_ATTACK_HAND, PROC_REF(use_squeak))
else if(ismob(parent) || ismecha(parent))
RegisterSignal(parent, COMSIG_MOVABLE_MOVED, PROC_REF(step_squeak))
/*
if(istype(parent, /obj/item/organ/internal/liver))
// Liver squeaking is depending on them functioning like a clown's liver
RegisterSignal(parent, SIGNAL_REMOVETRAIT(TRAIT_COMEDY_METABOLISM), PROC_REF(on_comedy_metabolism_removal))
*/
override_squeak_sounds = custom_sounds
if(chance_override)
squeak_chance = chance_override
if(volume_override)
volume = volume_override
if(isnum(step_delay_override))
step_delay = step_delay_override
if(isnum(use_delay_override))
use_delay = use_delay_override
if(isnum(extrarange))
sound_extra_range = extrarange
/*
if(isnum(falloff_exponent))
sound_falloff_exponent = falloff_exponent
if(isnum(fallof_distance))
sound_falloff_distance = fallof_distance
*/
/*
/datum/component/squeak/UnregisterFromParent()
. = ..()
qdel(GetComponent(/datum/component/connect_loc_behalf))
*/
/datum/component/squeak/proc/play_squeak(var/volume_mod = 1)
SIGNAL_HANDLER
if(prob(squeak_chance))
if(!override_squeak_sounds)
playsound(parent, pick_weight(default_squeak_sounds), volume * volume_mod, TRUE, sound_extra_range)
else
playsound(parent, pick_weight(override_squeak_sounds), volume * volume_mod, TRUE, sound_extra_range)
/datum/component/squeak/proc/step_squeak(obj/item/clothing/shoes/source, var/running)
SIGNAL_HANDLER
/*
var/mob/living/carbon/human/owner = source.loc
if(CHECK_MOVE_LOOP_FLAGS(owner, MOVEMENT_LOOP_OUTSIDE_CONTROL))
return
*/
if(running == "walk")
running = 0.25
else
running = 1
if(steps > step_delay)
play_squeak(running)
steps = 0
else
steps++
return 1
/datum/component/squeak/proc/play_squeak_crossed(datum/source, atom/movable/arrived, atom/old_loc, list/atom/old_locs)
SIGNAL_HANDLER
/* We don't have abstract items yet
if(isitem(arrived))
var/obj/item/I = arrived
if(I.item_flags & ABSTRACT)
return
//Annoyingly, our flight code doesn't set the movement_type, nor do we have a define for it. So I'm not adding it yet.
//if(arrived.movement_type & (FLYING|FLOATING) || !arrived.has_gravity())
*/
if(!arrived.has_gravity())
return
if(ismob(arrived) && !arrived.density) // Prevents 10 overlapping mice from making an unholy sound while moving
return
var/atom/current_parent = parent
if(isturf(current_parent?.loc))
play_squeak()
/datum/component/squeak/proc/use_squeak()
SIGNAL_HANDLER
if(last_use + use_delay < world.time)
last_use = world.time
play_squeak()
/datum/component/squeak/proc/on_equip(datum/source, mob/equipper, slot)
SIGNAL_HANDLER
holder = equipper
//RegisterSignal(holder, COMSIG_MOVABLE_DISPOSING, PROC_REF(disposing_react), override=TRUE)
RegisterSignal(holder, COMSIG_PARENT_QDELETING, PROC_REF(holder_deleted), override=TRUE)
//override for the preqdeleted is necessary because putting parent in hands sends the signal that this proc is registered towards,
//so putting an object in hands and then equipping the item on a clothing slot (without dropping it first)
//will always runtime without override = TRUE
/datum/component/squeak/proc/on_drop(datum/source, mob/user)
SIGNAL_HANDLER
//UnregisterSignal(user, COMSIG_MOVABLE_DISPOSING)
UnregisterSignal(user, COMSIG_PARENT_QDELETING)
holder = null
///just gets rid of the reference to holder in the case that theyre qdeleted
/datum/component/squeak/proc/holder_deleted(datum/source, datum/possible_holder)
SIGNAL_HANDLER
if(possible_holder == holder)
holder = null
/* We don't have comsigs set up for these
// Disposal pipes related shits
/datum/component/squeak/proc/disposing_react(datum/source, obj/structure/disposalholder/disposal_holder, obj/machinery/disposal/disposal_source)
SIGNAL_HANDLER
//We don't need to worry about unregistering this signal as it will happen for us automaticaly when the holder is qdeleted
RegisterSignal(disposal_holder, COMSIG_ATOM_DIR_CHANGE, PROC_REF(holder_dir_change))
/datum/component/squeak/proc/holder_dir_change(datum/source, old_dir, new_dir)
SIGNAL_HANDLER
//If the dir changes it means we're going through a bend in the pipes, let's pretend we bumped the wall
if(old_dir != new_dir)
play_squeak()
/datum/component/squeak/proc/on_comedy_metabolism_removal(datum/source, trait)
SIGNAL_HANDLER
qdel(src)
*/
@@ -0,0 +1,103 @@
var/static/list/mapped_autostrips = list()
var/static/list/mapped_autostrips_mob = list()
/*
This should actually be refactored if it ever needs to be used again into just being
an event controller with more graceful solutions.
Creating lockers was not graceful, in practice, and creates clutter, for example.
Repurpose this idea into a self contained machine in the future that stores and auto-equips someones gear.
But for now, for what it's been used for, it works.
*/
//Admin tool to automatically strip a human victim of all their equipment and genetics powers, and store them in a closet.
//Equips Vox/Zaddat survival gear, and a few basic pieces of clothing
/obj/effect/step_trigger/autostrip
name = "Autostrip trigger. Set the targetid to match the effect/autostriptarget"
var/targetid = "Default"
var/obj/effect/autostriptarget/target
var/obj/effect/autostriptarget/mob/Mtarget
var/remove_implants = 0 //Havn't bothered to implement this yet
var/remove_mutations = 0
/obj/effect/step_trigger/autostrip/Initialize(mapload)
. = ..()
initMappedLink()
/obj/effect/step_trigger/autostrip/Trigger(mob/living/carbon/human/H as mob)
if(!istype(H))
return
if(!target)
if(!initMappedLink())
return
if(Mtarget)
H.forceMove(Mtarget.loc)
var/obj/locker = new /obj/structure/closet/secure_closet/mind(target.loc, mind_target = H.mind)
for(var/obj/item/W in H)
if(istype(W, /obj/item/weapon/implant/backup) || istype(W, /obj/item/device/nif))
continue //VOREStation Edit
if(H.drop_from_inventory(W))
W.forceMove(locker)
if(remove_mutations)
var/needs_update = H.mutations.len > 0
for(var/entry in H.mutations)
var/mut
switch(entry)
if(TK)
mut = TELEBLOCK
if(XRAY)
mut = XRAYBLOCK
if(HULK)
mut = HULKBLOCK
if(mRemotetalk)
mut = REMOTETALKBLOCK
if(COLD_RESISTANCE)
mut = FIREBLOCK
if(mut)
new /obj/item/weapon/dnainjector/safe(locker, block_type = mut)
H.dna.SetSEState(mut,0)
H.mutations = list()
H.disabilities = 0
H.sdisabilities = 0
if(needs_update)
domutcheck(H,null,MUTCHK_FORCED)
H.update_mutations()
if(H.species.name == SPECIES_VOX || SPECIES_ZADDAT) //Species that 'actually' require survival gear to live. The rest don't.
H.species.equip_survival_gear(H)
H.equip_to_slot_or_del(new /obj/item/clothing/under/chameleon(H), slot_w_uniform)
H.equip_to_slot_or_del(new /obj/item/clothing/shoes/sandal(H),slot_shoes)
H.equip_to_slot_or_del(new /obj/item/device/radio/headset(H),slot_l_ear)
H.equip_to_slot_or_del(new /obj/item/clothing/under/permit(H), slot_l_hand)
/obj/effect/step_trigger/autostrip/proc/initMappedLink()
. = FALSE
target = mapped_autostrips[targetid]
Mtarget = mapped_autostrips_mob[targetid]
if(target)
. = TRUE
/obj/effect/autostriptarget
name = "Autostrip target. Link me via targetid to an autostrip trigger."
icon = 'icons/mob/screen1.dmi'
icon_state = "no_item1"
var/targetid = "Default"
unacidable = 1
layer = 99
anchored = 1
invisibility = 99
/obj/effect/autostriptarget/Initialize(mapload)
. = ..()
if(targetid)
mapped_autostrips[targetid] = src
/obj/effect/autostriptarget/mob
name = "Autostrip target to send mobs to."
/obj/effect/autostriptarget/mob/Initialize(mapload)
if(targetid)
mapped_autostrips_mob[targetid] = src
@@ -0,0 +1,85 @@
/obj/item/device/radio/headset/casino
name = "radio headset"
desc = "An updated, modular intercom that fits over the head with extra comfortable for the hardworking casino luxury crew. Has encryption key for scamm-... Kind casino staff channel."
icon = 'icons/obj/casino_ch.dmi'
icon_state = "headset"
origin_tech = list(TECH_ILLEGAL = 2)
ks1type = /obj/item/device/encryptionkey/raider
//Badmin piece of clothing that applies a few effects to a mob, used specifically for events with "hunters"
//This just helps me equip the hunters a little easier
/obj/item/device/radio/headset/event
name = "totally normal headset"
desc = "A headset with numerous toolkits appended to it, applying a wide variety of effects to its wearer set as per its manufacturer."
icon_state = "cent_headset_alt"
item_state = "headset"
var/mob/living/carbon/human/wearer
var/effect_icon = 'modular_chomp/icons/effects/effects.dmi' //Cosmetic Effect that will be applied to the mob as an overlay
var/effect_icon_state = "arrow2"
var/image/effect_overlay = null //Reference to an overlay so we can remove it on unequip
var/overlay_offset_y = 32
//Spells that will be added on equip
var/list/spells = list("/spell/targeted/unrestricted/mend", "/spell/targeted/unrestricted/plasmastun")
var/list/remove_spells = list() //Reference to spells that'll get removed
var/slowdown_to_set = 0.5
var/item_slowdown_reset = 0 //Vars to copy and reset later
var/slowdown_reset = 0
light_range = 6
light_power = 0 //Set this to 0 if you don't want a light
light_color = "#ffaaaa"
var/tele_threshold = 50
var/telex = 16
var/teley = 16
var/telez = 0 //Set this in-round if you want a return point with fake health
/obj/item/device/radio/headset/event/equipped(var/mob/living/carbon/human/H)
if(H && ((H.l_ear == src) || (H.r_ear == src)))
wearer = H
if(light_power)
set_light(light_range,light_power,light_color,1)
if(effect_icon)
effect_overlay = image(effect_icon, effect_icon_state, pixel_y = overlay_offset_y*H.size_multiplier)
effect_overlay.appearance_flags |= (RESET_COLOR|PIXEL_SCALE)
effect_overlay.plane = PLANE_LIGHTING_ABOVE
effect_overlay.layer = MOB_LAYER
H.add_overlay(effect_overlay)
if(spells.len)
for(var/thing in spells)
var/spell/SP = new thing(H)
H.add_spell(SP)
remove_spells += SP
if(slowdown_to_set != 0)
slowdown_reset = H.species.slowdown
item_slowdown_reset = H.species.item_slowdown_mod
H.species.slowdown = slowdown_to_set
H.species.item_slowdown_mod = 0
/obj/item/device/radio/headset/event/dropped(var/mob/living/carbon/human/H)
..()
if(wearer)
wearer = null
if(light_power)
light_on = 0
if(effect_icon)
H.cut_overlay(effect_overlay)
if(remove_spells.len)
for(var/spell/SP in remove_spells)
H.remove_spell(SP)
qdel(SP)
if(slowdown_to_set != 0)
H.species.slowdown = slowdown_reset
H.species.item_slowdown_mod = item_slowdown_reset
/obj/item/device/radio/headset/event/handle_shield(mob/user, var/damage, atom/damage_source = null, mob/attacker = null, var/def_zone = null, var/attack_text = "the attack")
if(!telez)
return FALSE
tele_threshold -= damage
if(tele_threshold <= 0)
var/datum/effect/effect/system/spark_spread/spark_system = new /datum/effect/effect/system/spark_spread()
spark_system.set_up(5, 0, user.loc)
spark_system.start()
playsound(src, "sparks", 50, 1)
user.visible_message("<span class='danger'>[user] is abruptly flung somewhere else in response to the damage!</span>")
do_teleport(user, locate(telex,teley,telez), local = 0, bohsafe = 1)
tele_threshold = initial(tele_threshold)
return TRUE
@@ -0,0 +1,46 @@
//Same as regular injector, but without the radiation
//Using for events, set the block to the desired gene
//Note, genetics code is incredibly scuffed, sometimes blocks just won't activate unless you do it multiple times????
/obj/item/weapon/dnainjector/safe
desc = "A slightly safer DNA injector"
datatype = DNA2_BUF_SE
value = 0xFFF
/obj/item/weapon/dnainjector/safe/New(var/block_type)
block = block_type
..()
/obj/item/weapon/dnainjector/safe/inject(mob/M as mob, mob/user as mob)
/*
if (!(NOCLONE in M.mutations)) // prevents drained people from having their DNA changed
if (buf.types & DNA2_BUF_UI)
if (!block) //isolated block?
M.UpdateAppearance(buf.dna.UI.Copy())
if (buf.types & DNA2_BUF_UE) //unique enzymes? yes
M.real_name = buf.dna.real_name
M.name = buf.dna.real_name
uses--
else
M.dna.SetUIValue(block,src.GetValue())
M.UpdateAppearance()
uses--
if (buf.types & DNA2_BUF_SE)
if (!block) //isolated block?
M.dna.SE = buf.dna.SE.Copy()
M.dna.UpdateSE()
else
M.dna.SetSEValue(block,src.GetValue())
domutcheck(M, null, block!=null)
uses--
if(prob(5))
trigger_side_effect(M)
*/
M.dna.SetSEState(block,1)
domutcheck(M,null,MUTCHK_FORCED)
M.update_mutations()
spawn(0)//this prevents the collapse of space-time continuum
if (user)
user.drop_from_inventory(src)
qdel(src)
return uses
@@ -0,0 +1,5 @@
/obj/item/weapon/melee/shock_maul/harmless
name = "rubber concussion maul"
desc = "A variant of the concussion maul that staggers and weakens victims. Despite their screams, does no real damage."
damtype = HALLOSS
launch_force = 0
@@ -0,0 +1,42 @@
/obj/structure/closet/secure_closet/mind
name = "mind secured locker"
var/datum/mind/owner
var/self_del = 1
anchored = 0
/obj/structure/closet/secure_closet/mind/New(var/datum/mind/mind_target, var/del_self = 1)
.=..()
self_del = del_self
if(mind_target)
owner = mind_target
name = "Owned by [owner.name]"
if(owner.current)
var/icon/I = get_flat_icon(owner.current, dir=SOUTH, no_anim=TRUE)
var/image/IM = image(I, pixel_x = (32 - I.Width()))
//icon2base64(get_flat_icon(owner.current,dir=SOUTH,no_anim=TRUE))
/*
I.appearance_flags |= (RESET_COLOR|PIXEL_SCALE)
I.plane = MOB_PLANE
I.layer = MOB_LAYER
*/
add_overlay(IM)
qdel(I)
/obj/structure/closet/secure_closet/mind/allowed(mob/user)
if(user.mind == owner)
return TRUE
else
return FALSE
/obj/structure/closet/secure_closet/mind/open()
.=..()
if(self_del)
qdel(src)
/obj/structure/closet/secure_closet/mind/LateInitialize()
if(ispath(closet_appearance))
closet_appearance = GLOB.closet_appearances[closet_appearance]
if(istype(closet_appearance))
icon = closet_appearance.icon
color = null
update_icon()
@@ -216,3 +216,14 @@
B.digest_brute = 20
B.special_entrance_sound = 'sound/machines/blender.ogg'
B.recycling = TRUE
/obj/structure/toilet/item/Initialize(mapload)
..()
return INITIALIZE_HINT_LATELOAD
/obj/structure/toilet/item/LateInitialize()
if(istype(loc, /mob/living)) return
var/obj/item/I
for(I in loc)
if(I.density || I.anchored || I == src) continue
I.forceMove(src)
@@ -0,0 +1,31 @@
/obj/item/clothing/shoes/mech_shoes
name = "mech shoes"
desc = "Thud thud."
icon_state = "nothing"
armor = list(melee = 30, bullet = 10, laser = 10, energy = 15, bomb = 20, bio = 0, rad = 0) // Same as loadout jackboots.
siemens_coefficient = 0.7 // Same as loadout jackboots.
force = 2
species_restricted = null
var/list/squeak_sound = list("mechstep"=1) //Squeak sound list. Necessary so our subtypes can have different sounds loaded into their component
/obj/item/clothing/shoes/mech_shoes/Initialize(mapload)
.=..()
LoadComponent(/datum/component/squeak, squeak_sound, 15*step_volume_mod)
/obj/item/clothing/shoes/mech_shoes/light
name = "light mech shoes"
desc = "Thud thud, but quieter."
squeak_sound = list("powerloaderstep"=1)
/obj/item/clothing/shoes/mech_shoes/heavy
name = "heavy mech shoes"
desc = "Thud thud, but heavy."
squeak_sound = list('modular_chomp/sound/mob/footstep_large.ogg'=1,'modular_chomp/sound/mob/footstep_large2.ogg'=1)
step_volume_mod = 4
/obj/item/clothing/shoes/clown_shoes
var/list/squeak_sound = list("clownstep"=1)
/obj/item/clothing/shoes/clown_shoes/Initialize(mapload)
.=..()
LoadComponent(/datum/component/squeak, squeak_sound, 20*step_volume_mod)
@@ -0,0 +1,30 @@
//Adminspawn item for hunters who're doing kidnaps during events
/obj/item/weapon/pen/autostun
desc = "A well made and expensive fountain pen. This one has gold accents."
icon_state = "blueg_fountain"
var/stun_duration = 10
/obj/item/weapon/pen/autostun/attack(mob/living/M as mob, mob/user as mob)
if(!istype(M))
return
M.Stun(stun_duration)
/obj/item/weapon/pen/autostun/paralyse
desc = "A well made and expensive fountain pen. This one has gold accents."
/obj/item/weapon/pen/autostun/paralyse/attack(mob/living/M as mob, mob/user as mob)
if(!istype(M))
return
M.Paralyse(stun_duration)
/obj/item/weapon/pen/autostun/weaken
desc = "A well made and expensive fountain pen. This one has gold accents."
/obj/item/weapon/pen/autostun/weaken/attack(mob/living/M as mob, mob/user as mob)
if(!istype(M))
return
M.Weaken(stun_duration)
@@ -0,0 +1,24 @@
/obj/item/weapon/gun/energy/taser/disabler/slow
name = "plasma snare device"
desc = "A modified disabler adjusted to impulse a target with a restrictive slowdown."
icon_state = "disabler"
projectile_type = /obj/item/projectile/energy/plasmastun/slow
charge_cost = 480
self_recharge = 1
recharge_time = 3
/obj/item/projectile/energy/plasmastun/slow
name = "plasma pulse"
icon_state = "plasma_stun"
fire_sound = 'sound/weapons/weaponsounds_laserstrong.ogg'
armor_penetration = 10
range = 9
damage = 0
agony = 0
vacuum_traversal = 1
hud_state = "plasma_rifle_blast"
/obj/item/projectile/energy/plasmastun/slow/on_hit(var/atom/target)
if(isliving(target))
var/mob/living/L = target
L.add_modifier(/datum/modifier/entangled, 10 SECONDS)
+169
View File
@@ -0,0 +1,169 @@
//This is pretty much just copied from construct_spells but adjusted so anyone can use them
/spell/targeted/unrestricted
name = "Base Unrestricted Spell"
desc = "If you see this, you should probably remind coders to refactor spell code."
range = -1
school = "evocation"
charge_type = Sp_RECHARGE
invocation_type = SpI_NONE
spell_flags = INCLUDEUSER
hud_state = "const_rune"
smoke_amt = 0
charge_max = 10
var/obj/item/weapon/spell/unrestricted/spell_obj = null //This is the var that determines what Technomancer-style spell is put into their hands.
/spell/targeted/unrestricted/cast(list/targets, mob/living/user)
user.place_spell_in_hand(spell_obj)
/obj/item/weapon/spell/unrestricted
name = "a spell"
desc = "Remind the devs to refactor spell code."
icon = 'icons/obj/spells.dmi'
icon_state = "generic"
item_icons = list(
slot_l_hand_str = 'icons/mob/items/lefthand_spells.dmi',
slot_r_hand_str = 'icons/mob/items/righthand_spells.dmi',
)
throwforce = 0
force = 0
show_examine = FALSE
owner = null
core = null
cast_methods = null // Controls how the spell is casted.
aspect = ASPECT_UNHOLY // Not used for everything we do
toggled = 0 // Mainly used for overlays.
cooldown = 0 // If set, will add a cooldown overlay and adjust click delay. Must be a multiple of 5 for overlays.
cast_sound = null // Sound file played when this is used.
var/last_castcheck = null // The last time this spell was cast.
/obj/item/weapon/spell/unrestricted/New()
if(isliving(loc))
owner = loc
if(!owner)
qdel(src)
update_icon()
/obj/item/weapon/spell/unrestricted/run_checks()
if(owner)
if(world.time >= (last_castcheck + cooldown)) //Are they a cultist or a construct, and has the cooldown time passed?
last_castcheck = world.time
return 1
return 0
/obj/item/weapon/spell/unrestricted/pay_energy(var/amount)
if(owner)
return 1
/obj/item/weapon/spell/unrestricted/afterattack(atom/target, mob/user, proximity_flag, click_parameters)
if(!run_checks())
return
if(!proximity_flag)
if(cast_methods & CAST_RANGED)
on_ranged_cast(target, user)
else
if(istype(target, /obj/item/weapon/spell))
var/obj/item/weapon/spell/spell = target
if(spell.cast_methods & CAST_COMBINE)
spell.on_combine_cast(src, user)
return
if(cast_methods & CAST_MELEE)
on_melee_cast(target, user)
else if(cast_methods & CAST_RANGED) //Try to use a ranged method if a melee one doesn't exist.
on_ranged_cast(target, user)
if(cooldown)
var/effective_cooldown = round(cooldown, 5)
user.setClickCooldown(effective_cooldown)
flick("cooldown_[effective_cooldown]",src)
/obj/item/weapon/spell/unrestricted/projectile //This makes me angry, but we need the template, and we can't use it because special check overrides on the base.
name = "construct projectile template"
icon_state = "generic"
desc = "This is a generic template that shoots projectiles. If you can read this, the game broke!"
cast_methods = CAST_RANGED
var/obj/item/projectile/spell_projectile = null
var/pre_shot_delay = 0
var/fire_sound = null
var/energy_cost_per_shot = 5
/obj/item/weapon/spell/unrestricted/projectile/on_ranged_cast(atom/hit_atom, mob/living/user)
if(set_up(hit_atom, user))
var/obj/item/projectile/new_projectile = make_projectile(spell_projectile, user)
new_projectile.old_style_target(hit_atom)
new_projectile.firer = user //Don't shoot yourself while moving
new_projectile.fire()
log_attack("has casted [src] at \the [hit_atom].")
if(fire_sound)
playsound(src, fire_sound, 75, 1)
return 1
return 0
/obj/item/weapon/spell/unrestricted/projectile/proc/make_projectile(obj/item/projectile/projectile_type, mob/living/user)
var/obj/item/projectile/P = new projectile_type(get_turf(user))
return P
/obj/item/weapon/spell/unrestricted/projectile/proc/set_up(atom/hit_atom, mob/living/user)
if(spell_projectile)
if(pay_energy(energy_cost_per_shot))
if(pre_shot_delay)
var/image/target_image = image(icon = 'icons/obj/spells.dmi', loc = get_turf(hit_atom), icon_state = "target")
user << target_image
user.Stun(pre_shot_delay / 10)
sleep(pre_shot_delay)
qdel(target_image)
if(owner)
return TRUE
return FALSE // We got dropped before the firing occured.
return TRUE // No delay, no need to check.
return FALSE
//
// The actual spells
//
/spell/targeted/unrestricted/plasmastun
name = "Plasma Snare"
desc = "Fire a debillitating slowing projectile."
hud_state = "const_beam"
spell_obj = /obj/item/weapon/spell/unrestricted/projectile/plasmastun
/obj/item/weapon/spell/unrestricted/projectile/plasmastun
name = "plasma snare"
icon_state = "generic"
desc = "Your hands fire a debillitating slowing projectile."
cast_methods = CAST_RANGED
spell_projectile = /obj/item/projectile/energy/plasmastun/slow
pre_shot_delay = 0
cooldown = 5
fire_sound = 'sound/weapons/weaponsounds_laserstrong.ogg'
/spell/targeted/unrestricted/mend
name = "Mend Target"
desc = "Mend a target over time."
charge_max = 100
hud_state = "const_mend"
spell_obj = /obj/item/weapon/spell/unrestricted/mend
/obj/item/weapon/spell/unrestricted/mend
name = "mend target"
desc = "Mend the wounds of a target over time"
icon_state = "mend_wounds"
cast_methods = CAST_MELEE
aspect = ASPECT_UNHOLY
light_color = "#FF5C5C"
light_power = -2
light_on = TRUE
/obj/item/weapon/spell/unrestricted/mend/on_melee_cast(atom/hit_atom, mob/living/user, def_zone)
if(isliving(hit_atom))
var/mob/living/L = hit_atom
L.add_modifier(/datum/modifier/mend_occult, 150) //No need to change this, it does the job
qdel(src)