mirror of
https://github.com/Bubberstation/Bubberstation.git
synced 2026-07-11 08:06:33 +01:00
a33fd49968
This branch needs help, tons of datums to make for the customizable items. --------- Co-authored-by: Alexis <catmc8565@gmail.com>
1078 lines
42 KiB
Plaintext
1078 lines
42 KiB
Plaintext
/obj/item/melee/baton
|
|
name = "police baton"
|
|
desc = "A wooden truncheon for beating criminal scum."
|
|
desc_controls = "Left click to stun, right click to harm."
|
|
icon = 'icons/obj/weapons/baton.dmi'
|
|
icon_state = "classic_baton"
|
|
inhand_icon_state = "classic_baton"
|
|
worn_icon_state = "classic_baton"
|
|
icon_angle = -45
|
|
lefthand_file = 'icons/mob/inhands/equipment/security_lefthand.dmi'
|
|
righthand_file = 'icons/mob/inhands/equipment/security_righthand.dmi'
|
|
slot_flags = ITEM_SLOT_BELT
|
|
force = 12 //9 hit crit
|
|
w_class = WEIGHT_CLASS_NORMAL
|
|
wound_bonus = 15
|
|
sound_vary = TRUE
|
|
|
|
/// Whether this baton is active or not
|
|
var/active = TRUE
|
|
/// Used interally, you don't want to modify
|
|
var/cooldown_check = 0
|
|
/// Default wait time until can stun again.
|
|
var/cooldown = (4 SECONDS)
|
|
/// The length of the knockdown applied to a struck living, non-cyborg mob.
|
|
var/knockdown_time = (1.5 SECONDS)
|
|
/// If affect_cyborg is TRUE, this is how long we stun cyborgs for on a hit.
|
|
var/stun_time_cyborg = (5 SECONDS)
|
|
/// The length of the knockdown applied to the user on clumsy_check()
|
|
var/clumsy_knockdown_time = 18 SECONDS
|
|
/// How much stamina damage we deal on a successful hit against a living, non-cyborg mob.
|
|
var/stamina_damage = 55
|
|
/// How much armor does our baton ignore? This operates as armour penetration, but only applies to the stun attack.
|
|
var/stun_armour_penetration = 15 // pens very light / cosmetic armor
|
|
/// What armor does our stun attack check before delivering the attack?
|
|
var/armour_type_against_stun = MELEE
|
|
/// Chance of causing force_say() when stunning a human mob
|
|
var/force_say_chance = 33
|
|
/// Can we stun cyborgs?
|
|
var/affect_cyborg = FALSE
|
|
/// The path of the default sound to play when we stun something.
|
|
var/on_stun_sound = 'sound/effects/woodhit.ogg'
|
|
/// The volume of the above.
|
|
var/on_stun_volume = 75
|
|
/// Whether the stun attack is logged. Only relevant for abductor batons, which have different modes.
|
|
var/log_stun_attack = TRUE
|
|
/// Boolean on whether people with chunky fingers can use this baton.
|
|
var/chunky_finger_usable = FALSE
|
|
/// Boolean, if TRUE when we harmbaton someone we will also try to stun if the baton is active / not on cooldown.
|
|
var/stun_on_harmbaton = FALSE
|
|
|
|
/// Text shown when trying to stun someone while the baton is on cooldown.
|
|
var/wait_desc = ""
|
|
|
|
/// What term do we use to describe our baton being 'ready', or the phrase to use when var/active is TRUE.
|
|
var/activated_word = "ready"
|
|
|
|
/// The context to show when the baton is active and targeting a living thing
|
|
var/context_living_target_active = "Stun"
|
|
|
|
/// The context to show when the baton is active and targeting a living thing in combat mode
|
|
var/context_living_target_active_combat_mode = "Stun"
|
|
|
|
/// The context to show when the baton is inactive and targeting a living thing
|
|
var/context_living_target_inactive = "Prod"
|
|
|
|
/// The context to show when the baton is inactive and targeting a living thing in combat mode
|
|
var/context_living_target_inactive_combat_mode = "Attack"
|
|
|
|
/// The RMB context to show when the baton is active and targeting a living thing
|
|
var/context_living_rmb_active = "Attack"
|
|
|
|
/// The RMB context to show when the baton is inactive and targeting a living thing
|
|
var/context_living_rmb_inactive = "Attack"
|
|
|
|
/obj/item/melee/baton/Initialize(mapload)
|
|
. = ..()
|
|
|
|
register_item_context()
|
|
add_deep_lore()
|
|
|
|
/obj/item/melee/baton/add_weapon_description()
|
|
AddElement(/datum/element/weapon_description, attached_proc = PROC_REF(add_baton_notes))
|
|
|
|
/obj/item/melee/baton/proc/add_baton_notes()
|
|
var/list/readout = list()
|
|
|
|
if(affect_cyborg)
|
|
readout += "It can stun cyborgs for [round((stun_time_cyborg/10), 1)] seconds."
|
|
|
|
readout += "\n[active ? "It is currently [span_warning("[activated_word]")], and capable of stunning." : "It is [span_warning("not [activated_word]")], and not capable of stunning."]"
|
|
|
|
if(stamina_damage <= 0) // The advanced baton actually does have 0 stamina damage so...yeah.
|
|
readout += "Either it is [span_warning("completely unable to perform a stunning strike")], or it [span_warning("attacks via some unusual method")]."
|
|
return readout.Join("\n")
|
|
|
|
readout += "It takes [span_warning("[HITS_TO_CRIT(stamina_damage)] strike\s")] to stun an enemy."
|
|
|
|
readout += "\nThe effects of each strike can be mitigated by utilizing [span_warning("[armour_type_against_stun]")] armor."
|
|
|
|
readout += "\nIt has a stun armor-piercing capability of [span_warning("[stun_armour_penetration]%")]."
|
|
return readout.Join("\n")
|
|
|
|
/obj/item/melee/baton/proc/add_deep_lore()
|
|
return
|
|
|
|
/// Checks if we can actually USE the baton. Impure
|
|
/obj/item/melee/baton/proc/can_baton(mob/living/target, mob/living/user)
|
|
PROTECTED_PROC(TRUE)
|
|
if(clumsy_check(user, target))
|
|
return FALSE
|
|
|
|
if(!chunky_finger_usable && ishuman(user))
|
|
var/mob/living/carbon/human/human_user = user
|
|
if(human_user.check_chunky_fingers() && user.is_holding(src) && !HAS_MIND_TRAIT(user, TRAIT_CHUNKYFINGERS_IGNORE_BATON))
|
|
balloon_alert(human_user, "fingers are too big!")
|
|
return FALSE
|
|
|
|
return TRUE
|
|
|
|
// Stun attack
|
|
/obj/item/melee/baton/pre_attack(atom/target, mob/living/user, list/modifiers, list/attack_modifiers)
|
|
. = ..()
|
|
if(. || !isliving(target))
|
|
return .
|
|
|
|
if(!can_baton(target, user))
|
|
return TRUE
|
|
|
|
if(!COOLDOWN_FINISHED(src, cooldown_check))
|
|
if(wait_desc)
|
|
balloon_alert(user, wait_desc)
|
|
return TRUE
|
|
|
|
if(HAS_TRAIT_FROM(target, TRAIT_IWASBATONED, REF(user))) //no doublebaton abuse anon!
|
|
target.balloon_alert(user, "can't stun yet!")
|
|
return TRUE
|
|
|
|
if(active)
|
|
// when we continue to attack, deal 0 (brute) damage (just stun)
|
|
SET_ATTACK_FORCE(attack_modifiers, 0)
|
|
MUTE_ATTACK_HITSOUND(attack_modifiers)
|
|
HIDE_ATTACK_MESSAGES(attack_modifiers)
|
|
return .
|
|
|
|
// Harm attack
|
|
/obj/item/melee/baton/pre_attack_secondary(atom/target, mob/living/user, list/modifiers, list/attack_modifiers)
|
|
. = ..()
|
|
if(. != SECONDARY_ATTACK_CALL_NORMAL || !isliving(target))
|
|
return .
|
|
|
|
if(!can_baton(target, user))
|
|
return SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN
|
|
|
|
// call attack, NOT pre_attack
|
|
// (so we go directly to harming)
|
|
return SECONDARY_ATTACK_CONTINUE_CHAIN
|
|
|
|
// This is where stun gets applied
|
|
/obj/item/melee/baton/afterattack(atom/target, mob/user, list/modifiers, list/attack_modifiers)
|
|
if(!isliving(target) || !active || !COOLDOWN_FINISHED(src, cooldown_check) || HAS_TRAIT_FROM(target, TRAIT_IWASBATONED, REF(user)) || QDELETED(target))
|
|
return
|
|
// worst check in the chain but - right click = harmbaton
|
|
if(LAZYACCESS(modifiers, RIGHT_CLICK) && !stun_on_harmbaton)
|
|
return
|
|
|
|
finalize_baton_attack(target, user, modifiers)
|
|
|
|
var/list/desc
|
|
if(iscyborg(target))
|
|
desc = get_cyborg_stun_description(target, user)
|
|
if(!affect_cyborg)
|
|
playsound(src, 'sound/effects/bang.ogg', 10, TRUE) //bonk
|
|
else
|
|
desc = get_stun_description(target, user)
|
|
|
|
if(desc)
|
|
target.visible_message(desc["visible"], desc["local"], visible_message_flags = ALWAYS_SHOW_SELF_MESSAGE)
|
|
|
|
/obj/item/melee/baton/apply_fantasy_bonuses(bonus)
|
|
. = ..()
|
|
stamina_damage = modify_fantasy_variable("stamina_damage", stamina_damage, bonus * 4)
|
|
|
|
/obj/item/melee/baton/remove_fantasy_bonuses(bonus)
|
|
stamina_damage = reset_fantasy_variable("stamina_damage", stamina_damage)
|
|
return ..()
|
|
|
|
/obj/item/melee/baton/add_item_context(datum/source, list/context, atom/target, mob/living/user)
|
|
if (isturf(target))
|
|
return NONE
|
|
|
|
if (isobj(target))
|
|
context[SCREENTIP_CONTEXT_LMB] = "Attack"
|
|
else
|
|
if (active)
|
|
context[SCREENTIP_CONTEXT_RMB] = context_living_rmb_active
|
|
|
|
if (user.combat_mode)
|
|
context[SCREENTIP_CONTEXT_LMB] = context_living_target_active_combat_mode
|
|
else
|
|
context[SCREENTIP_CONTEXT_LMB] = context_living_target_active
|
|
else
|
|
context[SCREENTIP_CONTEXT_RMB] = context_living_rmb_inactive
|
|
|
|
if (user.combat_mode)
|
|
context[SCREENTIP_CONTEXT_LMB] = context_living_target_inactive_combat_mode
|
|
else
|
|
context[SCREENTIP_CONTEXT_LMB] = context_living_target_inactive
|
|
|
|
return CONTEXTUAL_SCREENTIP_SET
|
|
|
|
/// Wrapper for calling "stun()" and doing relevant vfx/sfx
|
|
/obj/item/melee/baton/proc/finalize_baton_attack(mob/living/target, mob/living/user, list/modifiers)
|
|
PROTECTED_PROC(TRUE)
|
|
COOLDOWN_START(src, cooldown_check, cooldown)
|
|
if(on_stun_sound)
|
|
playsound(src, on_stun_sound, on_stun_volume, TRUE, -1)
|
|
if(baton_effect(target, user, modifiers) && user)
|
|
set_batoned(target, user, cooldown)
|
|
log_combat(user, target, "stunned", src.name)
|
|
|
|
/// The actual "stun()" of the stun baton
|
|
/obj/item/melee/baton/proc/baton_effect(mob/living/target, mob/living/user, list/modifiers, stun_override)
|
|
PROTECTED_PROC(TRUE)
|
|
var/trait_check = HAS_TRAIT(target, TRAIT_BATON_RESISTANCE)
|
|
if(iscyborg(target))
|
|
if(!affect_cyborg)
|
|
return FALSE
|
|
target.flash_act(affect_silicon = TRUE)
|
|
target.Paralyze((isnull(stun_override) ? stun_time_cyborg : stun_override) * (trait_check ? 0.1 : 1))
|
|
additional_effects_cyborg(target, user)
|
|
else
|
|
if(ishuman(target))
|
|
var/mob/living/carbon/human/human_target = target
|
|
if(prob(force_say_chance))
|
|
human_target.force_say()
|
|
var/armour_block = target.run_armor_check(null, armour_type_against_stun, null, null, stun_armour_penetration)
|
|
target.apply_damage(stamina_damage, STAMINA, blocked = armour_block)
|
|
if(!trait_check)
|
|
target.Knockdown((isnull(stun_override) ? knockdown_time : stun_override))
|
|
additional_effects_non_cyborg(target, user)
|
|
SEND_SIGNAL(target, COMSIG_MOB_BATONED, user, src)
|
|
return TRUE
|
|
|
|
/// Default message for stunning a living, non-cyborg mob.
|
|
/obj/item/melee/baton/proc/get_stun_description(mob/living/target, mob/living/user)
|
|
PROTECTED_PROC(TRUE)
|
|
. = list()
|
|
.["visible"] = span_danger("[user] knocks [target] down with [src]!")
|
|
.["local"] = span_userdanger("[user] knocks you down with [src]!")
|
|
|
|
/// Default message for stunning a cyborg.
|
|
/obj/item/melee/baton/proc/get_cyborg_stun_description(mob/living/target, mob/living/user)
|
|
PROTECTED_PROC(TRUE)
|
|
. = list()
|
|
if(affect_cyborg)
|
|
.["visible"] = span_danger("[user] pulses [target]'s sensors with the baton!")
|
|
.["local"] = span_danger("You pulse [target]'s sensors with the baton!")
|
|
else
|
|
.["visible"] = span_danger("[user] tries to knock down [target] with [src], and predictably fails!") //look at this duuuuuude
|
|
.["local"] = span_userdanger("[user] tries to... knock you down with [src]?") //look at the top of his head!
|
|
|
|
/// Contains any special effects that we apply to living, non-cyborg mobs we stun. Does not include applying a knockdown, dealing stamina damage, etc.
|
|
/obj/item/melee/baton/proc/additional_effects_non_cyborg(mob/living/target, mob/living/user)
|
|
PROTECTED_PROC(TRUE)
|
|
return
|
|
|
|
/// Contains any special effects that we apply to cyborgs we stun. Does not include flashing the cyborg's screen, hardstunning them, etc.
|
|
/obj/item/melee/baton/proc/additional_effects_cyborg(mob/living/target, mob/living/user)
|
|
PROTECTED_PROC(TRUE)
|
|
return
|
|
|
|
/// Used in marking a target as being hit by a baton
|
|
/obj/item/melee/baton/proc/set_batoned(mob/living/target, mob/living/user, cooldown)
|
|
PRIVATE_PROC(TRUE)
|
|
if(!cooldown)
|
|
return
|
|
var/user_ref = REF(user) // avoids harddels.
|
|
ADD_TRAIT(target, TRAIT_IWASBATONED, user_ref)
|
|
addtimer(TRAIT_CALLBACK_REMOVE(target, TRAIT_IWASBATONED, user_ref), cooldown)
|
|
|
|
/obj/item/melee/baton/proc/clumsy_check(mob/living/user, mob/living/intented_target)
|
|
if(!active || !HAS_TRAIT(user, TRAIT_CLUMSY) || prob(50))
|
|
return FALSE
|
|
user.visible_message(span_danger("[user] accidentally hits [user.p_them()]self over the head with [src]! What a doofus!"), span_userdanger("You accidentally hit yourself over the head with [src]!"), visible_message_flags = ALWAYS_SHOW_SELF_MESSAGE)
|
|
|
|
if(iscyborg(user))
|
|
if(affect_cyborg)
|
|
user.flash_act(affect_silicon = TRUE)
|
|
user.Paralyze(clumsy_knockdown_time)
|
|
additional_effects_cyborg(user, user) // user is the target here
|
|
if(on_stun_sound)
|
|
playsound(src, on_stun_sound, on_stun_volume, TRUE, -1)
|
|
else
|
|
playsound(src, 'sound/effects/bang.ogg', 10, TRUE)
|
|
else
|
|
//straight up always force say for clumsy humans
|
|
if(ishuman(user))
|
|
var/mob/living/carbon/human/human_user = user
|
|
human_user.force_say()
|
|
user.Knockdown(clumsy_knockdown_time)
|
|
user.apply_damage(stamina_damage, STAMINA)
|
|
additional_effects_non_cyborg(user, user) // user is the target here
|
|
if(on_stun_sound)
|
|
playsound(src, on_stun_sound, on_stun_volume, TRUE, -1)
|
|
|
|
user.apply_damage(2 * force, BRUTE, BODY_ZONE_HEAD, attacking_item = src)
|
|
log_combat(user, user, "accidentally stun attacked [user.p_them()]self due to their clumsiness", src)
|
|
user.do_attack_animation(user)
|
|
|
|
/obj/item/conversion_kit
|
|
name = "conversion kit"
|
|
desc = "A strange box containing wood working tools and an instruction paper to turn stun batons into something else."
|
|
icon = 'icons/obj/storage/box.dmi'
|
|
icon_state = "uk"
|
|
custom_price = PAYCHECK_COMMAND * 4.5
|
|
|
|
/obj/item/melee/baton/telescopic
|
|
name = "telescopic baton"
|
|
desc = "A compact yet robust personal defense weapon. Can be concealed when folded."
|
|
icon = 'icons/obj/weapons/baton.dmi'
|
|
icon_state = "telebaton"
|
|
icon_angle = -45
|
|
lefthand_file = 'icons/mob/inhands/weapons/melee_lefthand.dmi'
|
|
righthand_file = 'icons/mob/inhands/weapons/melee_righthand.dmi'
|
|
inhand_icon_state = null
|
|
attack_verb_continuous = list("hits", "pokes")
|
|
attack_verb_simple = list("hit", "poke")
|
|
worn_icon_state = "tele_baton"
|
|
slot_flags = ITEM_SLOT_BELT
|
|
w_class = WEIGHT_CLASS_SMALL
|
|
item_flags = NONE
|
|
force = 0
|
|
exposed_wound_bonus = 5
|
|
clumsy_knockdown_time = 15 SECONDS
|
|
active = FALSE
|
|
activated_word = "extended"
|
|
var/folded_drop_sound = 'sound/items/baton/telescopic_baton_folded_drop.ogg'
|
|
var/folded_pickup_sound = 'sound/items/baton/telescopic_baton_folded_pickup.ogg'
|
|
var/unfolded_drop_sound = 'sound/items/baton/telescopic_baton_unfolded_drop.ogg'
|
|
var/unfolded_pickup_sound = 'sound/items/baton/telescopic_baton_unfolded_pickup.ogg'
|
|
pickup_sound = 'sound/items/baton/telescopic_baton_folded_pickup.ogg'
|
|
drop_sound = 'sound/items/baton/telescopic_baton_folded_drop.ogg'
|
|
sound_vary = TRUE
|
|
/// The sound effecte played when our baton is extended.
|
|
var/on_sound = 'sound/items/weapons/batonextend.ogg'
|
|
/// The inhand iconstate used when our baton is extended.
|
|
var/on_inhand_icon_state = "nullrod"
|
|
/// The force on extension.
|
|
var/active_force = 10
|
|
|
|
/obj/item/melee/baton/telescopic/Initialize(mapload)
|
|
. = ..()
|
|
AddComponent( \
|
|
/datum/component/transforming, \
|
|
force_on = active_force, \
|
|
hitsound_on = hitsound, \
|
|
w_class_on = WEIGHT_CLASS_NORMAL, \
|
|
clumsy_check = FALSE, \
|
|
attack_verb_continuous_on = list("smacks", "strikes", "cracks", "beats"), \
|
|
attack_verb_simple_on = list("smack", "strike", "crack", "beat"), \
|
|
)
|
|
RegisterSignal(src, COMSIG_TRANSFORMING_ON_TRANSFORM, PROC_REF(on_transform))
|
|
|
|
/obj/item/melee/baton/telescopic/additional_effects_non_cyborg(mob/living/target, mob/living/user)
|
|
target.apply_status_effect(/datum/status_effect/dazed)
|
|
|
|
/obj/item/melee/baton/telescopic/suicide_act(mob/living/user)
|
|
var/mob/living/carbon/human/human_user = user
|
|
var/obj/item/organ/brain/our_brain = human_user.get_organ_by_type(/obj/item/organ/brain)
|
|
|
|
user.visible_message(span_suicide("[user] stuffs [src] up [user.p_their()] nose and presses the 'extend' button! It looks like [user.p_theyre()] trying to clear [user.p_their()] mind."))
|
|
if(active)
|
|
playsound(src, on_sound, 50, TRUE)
|
|
add_fingerprint(user)
|
|
else
|
|
attack_self(user)
|
|
|
|
sleep(0.3 SECONDS)
|
|
if (QDELETED(human_user))
|
|
return
|
|
if(!QDELETED(our_brain))
|
|
human_user.organs -= our_brain
|
|
qdel(our_brain)
|
|
new /obj/effect/gibspawner/generic(human_user.drop_location(), human_user)
|
|
return BRUTELOSS
|
|
|
|
/*
|
|
* Signal proc for [COMSIG_TRANSFORMING_ON_TRANSFORM].
|
|
*
|
|
* Gives feedback to the user and makes it show up inhand.
|
|
*/
|
|
/obj/item/melee/baton/telescopic/proc/on_transform(obj/item/source, mob/user, active)
|
|
SIGNAL_HANDLER
|
|
|
|
src.active = active
|
|
inhand_icon_state = active ? on_inhand_icon_state : null // When inactive, there is no inhand icon_state.
|
|
if(user)
|
|
balloon_alert(user, active ? "extended" : "collapsed")
|
|
if(!active)
|
|
drop_sound = folded_drop_sound
|
|
pickup_sound = folded_pickup_sound
|
|
else
|
|
drop_sound = unfolded_drop_sound
|
|
pickup_sound = unfolded_pickup_sound
|
|
playsound(src, on_sound, 50, TRUE)
|
|
return COMPONENT_NO_DEFAULT_MESSAGE
|
|
|
|
/obj/item/melee/baton/telescopic/bronze
|
|
name = "bronze-capped telescopic baton"
|
|
desc = "A compact yet robust personal defense weapon. Can be concealed when folded. This one is ranked BRONZE, and thus has mediocre penetrative power."
|
|
icon_state = "telebaton_bronze"
|
|
|
|
/obj/item/melee/baton/telescopic/silver
|
|
name = "silver-capped telescopic baton"
|
|
desc = "A compact yet robust personal defense weapon. Can be concealed when folded. This one is ranked SILVER, and thus has decent penetrative power."
|
|
icon_state = "telebaton_silver"
|
|
stun_armour_penetration = 30 // strong enough to pen sec armor
|
|
|
|
/obj/item/melee/baton/telescopic/gold
|
|
name = "gold-capped telescopic baton"
|
|
desc = "A compact yet robust personal defense weapon. Can be concealed when folded. This one is ranked GOLD, and thus has exceptional penetrative power."
|
|
icon_state = "telebaton_gold"
|
|
stun_armour_penetration = 50 // strong enough to pen syndicate modsuits
|
|
|
|
/obj/item/melee/baton/telescopic/contractor_baton
|
|
name = "contractor baton"
|
|
desc = "A high tech telescopic stun baton, as developed by Cybersun Industries. Delivers a precise shock to a target's central nervous system to incapacitate them."
|
|
icon = 'icons/obj/weapons/baton.dmi'
|
|
icon_state = "contractor_baton"
|
|
worn_icon_state = "contractor_baton"
|
|
icon_angle = -45
|
|
lefthand_file = 'icons/mob/inhands/weapons/melee_lefthand.dmi'
|
|
righthand_file = 'icons/mob/inhands/weapons/melee_righthand.dmi'
|
|
slot_flags = ITEM_SLOT_BELT
|
|
w_class = WEIGHT_CLASS_SMALL
|
|
item_flags = NONE
|
|
force = 5
|
|
cooldown = 2.5 SECONDS
|
|
force_say_chance = 80 //very high force say chance because it's funny
|
|
stamina_damage = 85
|
|
stun_armour_penetration = 30 // strong enough to pen sec armor
|
|
clumsy_knockdown_time = 24 SECONDS
|
|
affect_cyborg = TRUE
|
|
wait_desc = "still charging!"
|
|
on_stun_sound = 'sound/items/weapons/contractor_baton/contractorbatonhit.ogg'
|
|
unfolded_drop_sound = 'sound/items/baton/contractor_baton_unfolded_pickup.ogg'
|
|
unfolded_pickup_sound = 'sound/items/baton/contractor_baton_unfolded_pickup.ogg'
|
|
|
|
on_inhand_icon_state = "contractor_baton_on"
|
|
on_sound = 'sound/items/weapons/contractorbatonextend.ogg'
|
|
active_force = 16
|
|
|
|
/obj/item/melee/baton/telescopic/contractor_baton/additional_effects_non_cyborg(mob/living/target, mob/living/user)
|
|
. = ..()
|
|
target.set_jitter_if_lower(40 SECONDS)
|
|
target.set_stutter_if_lower(40 SECONDS)
|
|
|
|
/obj/item/melee/baton/security
|
|
name = "stun baton"
|
|
desc = "The Secure Apprehension Device, as developed by Nanotrasen. Delivers a precise shock to a target's central nervous system to incapacitate them."
|
|
desc_controls = "Left click to stun, right click to harm."
|
|
icon = 'icons/obj/weapons/baton.dmi'
|
|
icon_state = "stunbaton"
|
|
base_icon_state = "stunbaton"
|
|
inhand_icon_state = "stunbaton"
|
|
worn_icon_state = "baton"
|
|
icon_angle = -45
|
|
force = 10
|
|
wound_bonus = 0
|
|
attack_verb_continuous = list("beats")
|
|
attack_verb_simple = list("beat")
|
|
armor_type = /datum/armor/baton_security
|
|
throwforce = 7
|
|
force_say_chance = 50
|
|
stamina_damage = 60
|
|
armour_type_against_stun = ENERGY
|
|
knockdown_time = 5 SECONDS
|
|
clumsy_knockdown_time = 15 SECONDS
|
|
cooldown = 2.5 SECONDS
|
|
on_stun_sound = 'sound/items/weapons/egloves.ogg'
|
|
on_stun_volume = 50
|
|
active = FALSE
|
|
stun_on_harmbaton = TRUE
|
|
wait_desc = "still charging!"
|
|
activated_word = "activated"
|
|
context_living_rmb_active = "Harmful Stun"
|
|
light_range = 1.5
|
|
light_system = OVERLAY_LIGHT
|
|
light_on = FALSE
|
|
light_color = LIGHT_COLOR_ORANGE
|
|
light_power = 0.5
|
|
var/inactive_drop_sound = 'sound/items/baton/stun_baton_inactive_drop.ogg'
|
|
var/inactive_pickup_sound = 'sound/items/baton/stun_baton_inactive_pickup.ogg'
|
|
var/active_drop_sound = 'sound/items/baton/stun_baton_active_drop.ogg'
|
|
var/active_pickup_sound = 'sound/items/baton/stun_baton_active_pickup.ogg'
|
|
drop_sound = 'sound/items/baton/stun_baton_inactive_drop.ogg'
|
|
pickup_sound = 'sound/items/baton/stun_baton_inactive_pickup.ogg'
|
|
sound_vary = TRUE
|
|
|
|
var/throw_stun_chance = 35
|
|
var/obj/item/stock_parts/power_store/cell
|
|
var/preload_cell_type //if not empty the baton starts with this type of cell
|
|
var/cell_hit_cost = STANDARD_CELL_CHARGE
|
|
var/can_remove_cell = TRUE
|
|
var/convertible = TRUE //if it can be converted with a conversion kit
|
|
///Whether or not our inhand changes when active.
|
|
var/active_changes_inhand = TRUE
|
|
///When set, inhand_icon_state defaults to this instead of base_icon_state
|
|
var/base_inhand_state = null
|
|
|
|
/datum/armor/baton_security
|
|
bomb = 50
|
|
fire = 80
|
|
acid = 80
|
|
|
|
/obj/item/melee/baton/security/Initialize(mapload)
|
|
. = ..()
|
|
if(preload_cell_type)
|
|
if(!ispath(preload_cell_type, /obj/item/stock_parts/power_store/cell))
|
|
log_mapping("[src] at [AREACOORD(src)] had an invalid preload_cell_type: [preload_cell_type].")
|
|
else
|
|
cell = new preload_cell_type(src)
|
|
RegisterSignal(src, COMSIG_ATOM_ATTACKBY, PROC_REF(convert))
|
|
update_appearance()
|
|
|
|
/obj/item/melee/baton/security/get_cell()
|
|
return cell
|
|
|
|
/obj/item/melee/baton/security/suicide_act(mob/living/user)
|
|
if(cell?.charge && active)
|
|
user.visible_message(span_suicide("[user] is putting the live [name] in [user.p_their()] mouth! It looks like [user.p_theyre()] trying to commit suicide!"))
|
|
finalize_baton_attack(user, user)
|
|
return FIRELOSS
|
|
else
|
|
user.visible_message(span_suicide("[user] is shoving \the [src] down their throat! It looks like [user.p_theyre()] trying to commit suicide!"))
|
|
return OXYLOSS
|
|
|
|
/obj/item/melee/baton/security/Destroy()
|
|
if(cell)
|
|
QDEL_NULL(cell)
|
|
UnregisterSignal(src, COMSIG_ATOM_ATTACKBY)
|
|
return ..()
|
|
|
|
/obj/item/melee/baton/security/proc/convert(datum/source, obj/item/item, mob/user)
|
|
SIGNAL_HANDLER
|
|
|
|
if(!istype(item, /obj/item/conversion_kit) || !convertible)
|
|
return
|
|
var/turf/source_turf = get_turf(src)
|
|
var/obj/item/melee/baton/baton = new (source_turf)
|
|
baton.alpha = 20
|
|
playsound(source_turf, 'sound/items/tools/drill_use.ogg', 80, TRUE, -1)
|
|
animate(src, alpha = 0, time = 1 SECONDS)
|
|
animate(baton, alpha = 255, time = 1 SECONDS)
|
|
qdel(item)
|
|
qdel(src)
|
|
|
|
/obj/item/melee/baton/security/on_saboteur(datum/source, disrupt_duration)
|
|
. = ..()
|
|
if(!active)
|
|
return
|
|
turn_off()
|
|
update_appearance()
|
|
return TRUE
|
|
|
|
/obj/item/melee/baton/security/Exited(atom/movable/mov_content)
|
|
. = ..()
|
|
if(mov_content == cell)
|
|
cell = null
|
|
turn_off()
|
|
update_appearance()
|
|
|
|
/obj/item/melee/baton/security/update_icon_state()
|
|
var/base_inhand = base_inhand_state || base_icon_state
|
|
if(active)
|
|
icon_state = "[base_icon_state]_active"
|
|
if(active_changes_inhand)
|
|
inhand_icon_state = "[base_inhand]_active"
|
|
return ..()
|
|
if(!cell)
|
|
icon_state = "[base_icon_state]_nocell"
|
|
inhand_icon_state = base_inhand
|
|
return ..()
|
|
icon_state = base_icon_state
|
|
inhand_icon_state = base_inhand
|
|
return ..()
|
|
|
|
/obj/item/melee/baton/security/examine(mob/user)
|
|
. = ..()
|
|
if(cell)
|
|
. += span_notice("\The [src] is [round(cell.percent())]% charged.")
|
|
else
|
|
. += span_warning("\The [src] does not have a power source installed.")
|
|
|
|
/obj/item/melee/baton/security/screwdriver_act(mob/living/user, obj/item/tool)
|
|
if(tryremovecell(user))
|
|
tool.play_tool_sound(src)
|
|
return TRUE
|
|
|
|
/obj/item/melee/baton/security/attackby(obj/item/item, mob/user, list/modifiers, list/attack_modifiers)
|
|
if(istype(item, /obj/item/stock_parts/power_store/cell))
|
|
var/obj/item/stock_parts/power_store/cell/active_cell = item
|
|
if(cell)
|
|
to_chat(user, span_warning("[src] already has a cell!"))
|
|
else
|
|
if(active_cell.maxcharge < cell_hit_cost)
|
|
to_chat(user, span_notice("[src] requires a higher capacity cell."))
|
|
return
|
|
if(!user.transferItemToLoc(item, src))
|
|
return
|
|
cell = item
|
|
to_chat(user, span_notice("You install a cell in [src]."))
|
|
update_appearance()
|
|
else
|
|
return ..()
|
|
|
|
/obj/item/melee/baton/security/proc/tryremovecell(mob/user)
|
|
if(cell && can_remove_cell)
|
|
cell.forceMove(drop_location())
|
|
to_chat(user, span_notice("You remove the cell from [src]."))
|
|
return TRUE
|
|
return FALSE
|
|
|
|
/obj/item/melee/baton/security/attack_self(mob/user)
|
|
if(cell?.charge >= cell_hit_cost && !active)
|
|
turn_on(user)
|
|
balloon_alert(user, "turned on")
|
|
else
|
|
turn_off()
|
|
if(!cell)
|
|
balloon_alert(user, "no power source!")
|
|
else if(cell?.charge < cell_hit_cost)
|
|
balloon_alert(user, "out of charge!")
|
|
else
|
|
balloon_alert(user, "turned off")
|
|
add_fingerprint(user)
|
|
|
|
/// Toggles the stun baton's light
|
|
/obj/item/melee/baton/security/proc/toggle_light()
|
|
set_light_on(!light_on)
|
|
|
|
/obj/item/melee/baton/security/proc/turn_on(mob/user)
|
|
active = TRUE
|
|
playsound(src, SFX_SPARKS, 75, TRUE, -1)
|
|
update_appearance()
|
|
toggle_light()
|
|
do_sparks(1, TRUE, src)
|
|
drop_sound = active_drop_sound
|
|
pickup_sound = active_pickup_sound
|
|
|
|
/obj/item/melee/baton/security/proc/turn_off()
|
|
active = FALSE
|
|
set_light_on(FALSE)
|
|
update_appearance()
|
|
playsound(src, SFX_SPARKS, 75, TRUE, -1)
|
|
drop_sound = inactive_drop_sound
|
|
pickup_sound = inactive_pickup_sound
|
|
|
|
/obj/item/melee/baton/security/proc/deductcharge(deducted_charge)
|
|
if(!cell)
|
|
return
|
|
//Note this value returned is significant, as it will determine
|
|
//if a stun is applied or not
|
|
. = cell.use(deducted_charge)
|
|
if(active && cell.charge < cell_hit_cost)
|
|
//we're below minimum, turn off
|
|
turn_off()
|
|
|
|
/obj/item/melee/baton/security/clumsy_check(mob/living/carbon/human/user)
|
|
. = ..()
|
|
if(.)
|
|
SEND_SIGNAL(user, COMSIG_LIVING_MINOR_SHOCK)
|
|
deductcharge(cell_hit_cost)
|
|
|
|
/obj/item/melee/baton/security/pre_attack(atom/target, mob/living/user, list/modifiers, list/attack_modifiers)
|
|
. = ..()
|
|
if(. || !isliving(target))
|
|
return .
|
|
|
|
if(!active && !user.combat_mode)
|
|
target.visible_message(
|
|
span_warning("[user] prods [target] with [src]. Luckily it was off."),
|
|
span_warning("[user] prods you with [src]. Luckily it was off."),
|
|
visible_message_flags = ALWAYS_SHOW_SELF_MESSAGE,
|
|
)
|
|
return TRUE
|
|
|
|
return .
|
|
|
|
/obj/item/melee/baton/security/baton_effect(mob/living/target, mob/living/user, modifiers, stun_override)
|
|
if(iscyborg(loc))
|
|
var/mob/living/silicon/robot/robot = loc
|
|
if(!robot || !robot.cell || !robot.cell.use(cell_hit_cost))
|
|
return FALSE
|
|
else if(!deductcharge(cell_hit_cost))
|
|
return FALSE
|
|
stun_override = 0 //Avoids knocking people down prematurely.
|
|
return ..()
|
|
|
|
/*
|
|
* After a target is hit, we apply some status effects.
|
|
* After a period of time, we then check to see what stun duration we give.
|
|
*/
|
|
/obj/item/melee/baton/security/additional_effects_non_cyborg(mob/living/target, mob/living/user)
|
|
target.set_jitter_if_lower(40 SECONDS)
|
|
target.set_confusion_if_lower(10 SECONDS)
|
|
target.set_stutter_if_lower(16 SECONDS)
|
|
|
|
SEND_SIGNAL(target, COMSIG_LIVING_MINOR_SHOCK)
|
|
addtimer(CALLBACK(src, PROC_REF(apply_stun_effect_end), target), 2 SECONDS)
|
|
|
|
/// After the initial stun period, we check to see if the target needs to have the stun applied.
|
|
/obj/item/melee/baton/security/proc/apply_stun_effect_end(mob/living/target)
|
|
var/trait_check = HAS_TRAIT(target, TRAIT_BATON_RESISTANCE) //var since we check it in out to_chat as well as determine stun duration
|
|
if(!target.IsKnockdown())
|
|
to_chat(target, span_warning("Your muscles seize, making you collapse[trait_check ? ", but your body quickly recovers..." : "!"]"))
|
|
|
|
if(!trait_check)
|
|
target.Knockdown(knockdown_time)
|
|
|
|
/obj/item/melee/baton/security/get_stun_description(mob/living/target, mob/living/user)
|
|
. = list()
|
|
|
|
.["visible"] = span_danger("[user] stuns [target] with [src]!")
|
|
.["local"] = span_userdanger("[user] stuns you with [src]!")
|
|
|
|
/obj/item/melee/baton/security/get_cyborg_stun_description(mob/living/target, mob/living/user)
|
|
. = ..()
|
|
if(!affect_cyborg)
|
|
.["visible"] = span_danger("[user] tries to stun [target] with [src], and predictably fails!")
|
|
.["local"] = span_userdanger("[user] tries to... stun you with [src]?")
|
|
|
|
/obj/item/melee/baton/security/throw_impact(atom/hit_atom, datum/thrownthing/throwingdatum)
|
|
. = ..()
|
|
if(!. && active && prob(throw_stun_chance) && hit_atom)
|
|
finalize_baton_attack(hit_atom, throwingdatum?.get_thrower())
|
|
|
|
/obj/item/melee/baton/security/emp_act(severity)
|
|
. = ..()
|
|
if (!cell)
|
|
return
|
|
if (!(. & EMP_PROTECT_SELF))
|
|
cell.emp_act(severity)
|
|
|
|
if (cell.charge >= cell_hit_cost)
|
|
var/scramble_time
|
|
scramble_mode()
|
|
for(var/loops in 1 to rand(6, 12))
|
|
scramble_time = rand(5, 15) / (1 SECONDS)
|
|
addtimer(CALLBACK(src, PROC_REF(scramble_mode)), scramble_time*loops * (1 SECONDS))
|
|
|
|
/obj/item/melee/baton/security/proc/scramble_mode()
|
|
if (!cell || cell.charge < cell_hit_cost)
|
|
return
|
|
active = !active
|
|
toggle_light()
|
|
do_sparks(1, TRUE, src)
|
|
playsound(src, SFX_SPARKS, 75, TRUE, -1)
|
|
update_appearance()
|
|
|
|
/obj/item/melee/baton/security/loaded //this one starts with a cell pre-installed.
|
|
preload_cell_type = /obj/item/stock_parts/power_store/cell/high
|
|
|
|
/obj/item/melee/baton/security/loaded/hos
|
|
preload_cell_type = /obj/item/stock_parts/power_store/cell/super
|
|
|
|
// Stunsword Skins
|
|
/datum/atom_skin/stunsword
|
|
abstract_type = /datum/atom_skin/stunsword
|
|
change_inhand_icon_state = TRUE
|
|
change_base_icon_state = TRUE
|
|
|
|
/datum/atom_skin/stunsword/default
|
|
preview_name = "Default"
|
|
new_icon_state = "stunsword"
|
|
|
|
/datum/atom_skin/stunsword/energy
|
|
preview_name = "Energy"
|
|
new_icon_state = "stunsword_energy"
|
|
|
|
///Stun Sword
|
|
/obj/item/melee/baton/security/stunsword
|
|
name = "\improper NT-20 'Excalibur' Stunsword"
|
|
desc = "It's a sword. It stuns. What more could you want?"
|
|
icon_state = "stunsword"
|
|
inhand_icon_state = "stunsword"
|
|
base_icon_state = "stunsword"
|
|
lefthand_file = 'icons/mob/inhands/64x64_lefthand.dmi'
|
|
righthand_file = 'icons/mob/inhands/64x64_righthand.dmi'
|
|
hitsound = 'sound/items/weapons/bladeslice.ogg'
|
|
attack_verb_continuous = list("attacks", "slashes", "slices", "tears", "lacerates", "rips", "dices", "cuts")
|
|
attack_verb_simple = list("attack", "slash", "slice", "tear", "lacerate", "rip", "dice", "cut")
|
|
inhand_x_dimension = 64
|
|
inhand_y_dimension = 64
|
|
w_class = WEIGHT_CLASS_HUGE
|
|
sharpness = SHARP_EDGED
|
|
force = 30
|
|
throwforce = 10
|
|
wound_bonus = 0
|
|
exposed_wound_bonus = 30
|
|
stun_armour_penetration = 40
|
|
throw_stun_chance = 60
|
|
convertible = FALSE
|
|
|
|
obj_flags = UNIQUE_RENAME
|
|
|
|
/obj/item/melee/baton/security/stunsword/Initialize(mapload)
|
|
. = ..()
|
|
AddComponent(/datum/component/reskinable_item, /datum/atom_skin/stunsword)
|
|
|
|
/obj/item/melee/baton/security/stunsword/add_deep_lore()
|
|
return
|
|
|
|
/obj/item/melee/baton/security/stunsword/loaded
|
|
preload_cell_type = /obj/item/stock_parts/power_store/cell/bluespace // 40% stun_armour_penetration
|
|
|
|
//Makeshift stun baton. Replacement for stun gloves.
|
|
/obj/item/melee/baton/security/cattleprod
|
|
name = "stunprod"
|
|
desc = "An improvised stun baton."
|
|
desc_controls = "Left click to stun, right click to harm."
|
|
icon = 'icons/obj/weapons/spear.dmi'
|
|
icon_state = "stunprod"
|
|
base_icon_state = "stunprod"
|
|
inhand_icon_state = "prod"
|
|
base_inhand_state = "prod"
|
|
worn_icon_state = null
|
|
icon_angle = -45
|
|
lefthand_file = 'icons/mob/inhands/weapons/melee_lefthand.dmi'
|
|
righthand_file = 'icons/mob/inhands/weapons/melee_righthand.dmi'
|
|
w_class = WEIGHT_CLASS_HUGE
|
|
force = 3
|
|
throwforce = 5
|
|
cell_hit_cost = STANDARD_CELL_CHARGE * 2
|
|
throw_stun_chance = 10
|
|
slot_flags = ITEM_SLOT_BACK
|
|
convertible = FALSE
|
|
active_changes_inhand = FALSE
|
|
custom_materials = list(/datum/material/iron = SHEET_MATERIAL_AMOUNT * 1.15, /datum/material/glass = SMALL_MATERIAL_AMOUNT * 2)
|
|
var/obj/item/assembly/igniter/sparkler
|
|
///Determines whether or not we can improve the cattleprod into a new type. Prevents turning the cattleprod subtypes into different subtypes, or wasting materials on making it....another version of itself.
|
|
var/can_upgrade = TRUE
|
|
|
|
/obj/item/melee/baton/security/cattleprod/Initialize(mapload)
|
|
. = ..()
|
|
sparkler = new (src)
|
|
|
|
/obj/item/melee/baton/security/cattleprod/add_deep_lore()
|
|
return
|
|
|
|
/obj/item/melee/baton/security/cattleprod/attackby(obj/item/item, mob/user, list/modifiers, list/attack_modifiers)//handles sticking a crystal onto a stunprod to make an improved cattleprod
|
|
if(!istype(item, /obj/item/stack))
|
|
return ..()
|
|
|
|
if(!can_upgrade)
|
|
user.visible_message(span_warning("This prod is already improved!"))
|
|
return ..()
|
|
|
|
if(cell)
|
|
user.visible_message(span_warning("You can't put the crystal onto the stunprod while it has a power cell installed!"))
|
|
return ..()
|
|
|
|
var/our_prod
|
|
if(istype(item, /obj/item/stack/ore/bluespace_crystal))
|
|
var/obj/item/stack/ore/bluespace_crystal/our_crystal = item
|
|
our_crystal.use(1)
|
|
our_prod = /obj/item/melee/baton/security/cattleprod/teleprod
|
|
|
|
else if(istype(item, /obj/item/stack/telecrystal))
|
|
var/obj/item/stack/telecrystal/our_crystal = item
|
|
our_crystal.use(1)
|
|
our_prod = /obj/item/melee/baton/security/cattleprod/telecrystalprod
|
|
else
|
|
to_chat(user, span_notice("You don't think \the [item] will do anything to improve \the [src]."))
|
|
return ..()
|
|
|
|
to_chat(user, span_notice("You place \the [item] firmly into \the [sparkler]."))
|
|
remove_item_from_storage(user)
|
|
qdel(src)
|
|
var/obj/item/melee/baton/security/cattleprod/brand_new_prod = new our_prod(user.loc)
|
|
user.put_in_hands(brand_new_prod)
|
|
|
|
/obj/item/melee/baton/security/cattleprod/can_baton(mob/living/target, mob/living/user)
|
|
if(!sparkler.activate())
|
|
return FALSE
|
|
return ..()
|
|
|
|
/obj/item/melee/baton/security/cattleprod/Destroy()
|
|
if(sparkler)
|
|
QDEL_NULL(sparkler)
|
|
return ..()
|
|
|
|
/obj/item/melee/baton/security/boomerang
|
|
name = "\improper OZtek Boomerang"
|
|
desc = "A device invented in 2486 for the great Space Emu War by the confederacy of Australicus, these high-tech boomerangs also work exceptionally well at stunning crewmembers. Just be careful to catch it when thrown!"
|
|
throw_speed = 1
|
|
icon = 'icons/obj/weapons/thrown.dmi'
|
|
icon_state = "boomerang"
|
|
base_icon_state = "boomerang"
|
|
inhand_icon_state = "boomerang"
|
|
force = 5
|
|
throwforce = 5
|
|
throw_range = 5
|
|
cell_hit_cost = STANDARD_CELL_CHARGE * 2
|
|
throw_stun_chance = 99 //Have you prayed today?
|
|
convertible = FALSE
|
|
active_changes_inhand = FALSE
|
|
custom_materials = list(/datum/material/iron = SHEET_MATERIAL_AMOUNT * 5, /datum/material/glass = SHEET_MATERIAL_AMOUNT*2, /datum/material/silver = SHEET_MATERIAL_AMOUNT*5, /datum/material/gold = SHEET_MATERIAL_AMOUNT)
|
|
|
|
/obj/item/melee/baton/security/boomerang/Initialize(mapload)
|
|
. = ..()
|
|
AddComponent(/datum/component/boomerang, throw_range + 2, TRUE)
|
|
|
|
/obj/item/melee/baton/security/boomerang/add_deep_lore()
|
|
return
|
|
|
|
/obj/item/melee/baton/security/boomerang/loaded //Same as above, comes with a cell.
|
|
preload_cell_type = /obj/item/stock_parts/power_store/cell/high
|
|
|
|
/obj/item/melee/baton/security/cattleprod/teleprod
|
|
name = "teleprod"
|
|
desc = "A prod with a bluespace crystal on the end. The crystal doesn't look too fun to touch."
|
|
w_class = WEIGHT_CLASS_NORMAL
|
|
icon_state = "teleprod"
|
|
base_icon_state = "teleprod"
|
|
inhand_icon_state = "teleprod"
|
|
slot_flags = null
|
|
can_upgrade = FALSE
|
|
custom_materials = list(/datum/material/iron = SHEET_MATERIAL_AMOUNT * 1.15, /datum/material/bluespace = SHEET_MATERIAL_AMOUNT, /datum/material/glass = SMALL_MATERIAL_AMOUNT * 2)
|
|
|
|
/obj/item/melee/baton/security/cattleprod/teleprod/clumsy_check(mob/living/carbon/human/user)
|
|
. = ..()
|
|
if(!.)
|
|
return
|
|
do_teleport(user, get_turf(user), 50, channel = TELEPORT_CHANNEL_BLUESPACE)
|
|
|
|
/obj/item/melee/baton/security/cattleprod/teleprod/baton_effect(mob/living/target, mob/living/user, modifiers, stun_override)
|
|
. = ..()
|
|
if(!. || target.move_resist >= MOVE_FORCE_OVERPOWERING)
|
|
return
|
|
do_teleport(target, get_turf(target), 15, channel = TELEPORT_CHANNEL_BLUESPACE)
|
|
|
|
/obj/item/melee/baton/security/cattleprod/telecrystalprod
|
|
name = "snatcherprod"
|
|
desc = "A prod with a telecrystal on the end. It sparks with a desire for theft and subversion."
|
|
w_class = WEIGHT_CLASS_NORMAL
|
|
icon_state = "telecrystalprod"
|
|
base_icon_state = "telecrystalprod"
|
|
inhand_icon_state = "telecrystalprod"
|
|
slot_flags = null
|
|
throw_stun_chance = 50 //I think it'd be funny
|
|
can_upgrade = FALSE
|
|
|
|
/obj/item/melee/baton/security/cattleprod/telecrystalprod/clumsy_check(mob/living/carbon/human/user)
|
|
. = ..()
|
|
if(!.)
|
|
return
|
|
do_teleport(src, get_turf(user), 50, channel = TELEPORT_CHANNEL_BLUESPACE) //Wait, where did it go?
|
|
|
|
/obj/item/melee/baton/security/cattleprod/telecrystalprod/baton_effect(mob/living/target, mob/living/user, modifiers, stun_override)
|
|
. = ..()
|
|
if(!.)
|
|
return
|
|
var/obj/item/stuff_in_hand = target.get_active_held_item()
|
|
if(!user || !stuff_in_hand || !target.temporarilyRemoveItemFromInventory(stuff_in_hand))
|
|
return
|
|
if(user.put_in_inactive_hand(stuff_in_hand))
|
|
stuff_in_hand.loc.visible_message(span_warning("[stuff_in_hand] suddenly appears in [user]'s hand!"))
|
|
else
|
|
stuff_in_hand.forceMove(user.drop_location())
|
|
stuff_in_hand.loc.visible_message(span_warning("[stuff_in_hand] suddenly appears!"))
|
|
|
|
|
|
/obj/item/melee/baton/nunchaku
|
|
name = "Syndie Fitness Nunchuks"
|
|
desc = "The most common fitness equipment in the entire syndicate, titanium rods weigh strictly 13 pounds"
|
|
desc_controls = "Left click to stun, right click to harm. Throw mode counterattack any melee/throwable attacks."
|
|
icon_state = "nunchaku"
|
|
lefthand_file = 'icons/mob/inhands/weapons/melee_lefthand.dmi'
|
|
righthand_file = 'icons/mob/inhands/weapons/melee_righthand.dmi'
|
|
inhand_icon_state = "nunchaku"
|
|
worn_icon_state = "nunchaku"
|
|
attack_verb_continuous = list("beats", "whips", "smashes", "punishes")
|
|
attack_verb_simple = list("beat", "whip", "smash", "punish")
|
|
hitsound = 'sound/items/weapons/chainhit.ogg'
|
|
block_sound = 'sound/items/weapons/block_shield.ogg'
|
|
slot_flags = ITEM_SLOT_BELT
|
|
cooldown = CLICK_CD_MELEE
|
|
knockdown_time = 0.25 SECONDS
|
|
demolition_mod = 1.5
|
|
stamina_damage = 30 // 4 hit stamcrit
|
|
stun_armour_penetration = 25 // bronze-silver telescopic
|
|
force = 16 // 7 hit crit
|
|
exposed_wound_bonus = 5
|
|
|
|
/obj/item/melee/baton/nunchaku/proc/randomize_state()
|
|
icon_state = pick(list("nunchaku", "nunchaku_x", "nunchaku_y"))
|
|
update_appearance()
|
|
|
|
/obj/item/melee/baton/nunchaku/after_throw(datum/callback/callback)
|
|
. = ..()
|
|
randomize_state()
|
|
|
|
/obj/item/melee/baton/nunchaku/afterattack(atom/target, mob/user, click_parameters)
|
|
. = ..()
|
|
randomize_state()
|
|
|
|
/obj/item/melee/baton/nunchaku/hit_reaction(mob/living/carbon/human/owner, atom/movable/hitby, attack_text, final_block_chance, damage, attack_type, damage_type)
|
|
if(attack_type == PROJECTILE_ATTACK || !owner.throw_mode)
|
|
return ..()
|
|
|
|
randomize_state()
|
|
|
|
// blocks any melee/throwable attacks
|
|
owner.adjust_stamina_loss(5)
|
|
final_block_chance = 100
|
|
|
|
// counterattack at melee
|
|
if(attack_type in list(MELEE_ATTACK, UNARMED_ATTACK, LEAP_ATTACK))
|
|
var/mob/living/attacker = GET_ASSAILANT(hitby)
|
|
playsound(src, pick(list('sound/items/weapons/cqchit2.ogg', 'sound/items/weapons/cqchit1.ogg')), 70, FALSE)
|
|
melee_attack_chain(owner, attacker, LEFT_CLICK)
|
|
|
|
return ..()
|
|
|
|
// Deep Lore //
|
|
|
|
/obj/item/melee/baton/security/add_deep_lore()
|
|
AddElement(/datum/element/examine_lore, \
|
|
lore_hint = span_notice("You can [EXAMINE_HINT("look closer")] to learn a little more about [src]."), \
|
|
lore = "The Secure Apprehension Device (sometimes referred to as the SAD in the officer training manuals) is \
|
|
the unholy union of a mace and a cattleprod. This nonlethal device was designed to put a stop to ruffians, \
|
|
scoundrels, ne'er-do-wells and criminals wherever they may rear their ugly heads.<br>\
|
|
<br>\
|
|
A symbol of Nanotrasen security forces, the stun baton is the primary tool officers employ against the \
|
|
unlawful scum and villainy of the Spinward and abroad. Trained to 'baton first, interrogate later', \
|
|
Nanotrasen security has long since earned itself a mixed reputation. Able to rapidly shut down the \
|
|
central nervous system of a criminal with only a few direct applications of the conductive striking head \
|
|
of the device, few would-be troublemakers want to find themselves on the wrong end of an officer brandishing \
|
|
this baton.<br>\
|
|
<br>\
|
|
TerraGov law enforcement has avoided the adoption of stun batons due to various ethical dilemmas posed by \
|
|
their usage, largely because of the longterm physical and mental ramifications of being struck by a human cattleprod. \
|
|
Citizens' rights advocacy groups protest against the proliferation of stun batons as a policing tool, \
|
|
arguing that they are 'inhumane' and 'authoritarian'. Nanotrasen, on the other hand, has had no such qualms \
|
|
when deploying stun batons as a compliance measure across all of their existing stations and facilities against \
|
|
unruly members of staff." \
|
|
)
|
|
|
|
// Contractor Baton
|
|
|
|
/obj/item/melee/baton/telescopic/contractor_baton/add_deep_lore()
|
|
AddElement(/datum/element/examine_lore, \
|
|
lore_hint = span_notice("You can [EXAMINE_HINT("look closer")] to learn a little more about [src]."), \
|
|
lore = "The Contract Acquisition Device (sometimes referred to as the CAD in encrypted correspondence) is \
|
|
one of the more frequently encountered examples of Cybersun Industries weaponry. Extremely similar to Nanotrasen's \
|
|
own Secure Apprehension Device (also simply known as the stun baton), the contractor baton is able to induce \
|
|
CNS disruption in a target to render them helpless. It is also capable of devastating blunt force trauma if \
|
|
used as a bludgeon. The contractor baton is also capable of telescopic deployment, allowing for discretion while \
|
|
making an approach towards a target.<br>\
|
|
<br>\
|
|
The contractor baton is famously associated with contractors, elite Cybersun field agents. While the standard \
|
|
agent would often be tasked with sabotage, terrorism, murder or theft, contractors have the critical task of \
|
|
kidnapping high value personnel. Anyone with the potential to possess classified or sensitive data about Nanotrasen \
|
|
security systems and devices could be a target for Cybersun. <br>\
|
|
<br>\
|
|
Extracting this information is most easily performed on living subjects. As such, the contractor baton was designed \
|
|
with nonlethal incapacitation in mind. However, Cybersun Industries has long since found workarounds for extracting \
|
|
data from the recently deceased, should the contractor find themselves with only a corpse left to send back. Death \
|
|
may not spare you from the machinations of Cybersun Industries if they deem you a valuable asset towards their goals.<br>\
|
|
<br>\
|
|
Nanotrasen utilizes a number of countermeasures to contractor insurgencies, such as employing selective memory wiping \
|
|
or falsified memory injection, the establishment of 'dummy' command staff through the artificial acceleration \
|
|
of otherwise incompetent but useful crewmembers (whose incompetence will often result in an acceptable degree \
|
|
of operational disruption), which provides convenient scapegoats in the event of a security breach as well as \
|
|
frequent staff turnover and reassignment." \
|
|
)
|