mirror of
https://github.com/Bubberstation/Bubberstation.git
synced 2026-07-15 01:54:52 +01:00
b942cec267
## About The Pull Request Fixes #94778 There are a bunch of places where we dismember a limb (or head) and then do something with it assuming that we actually dismembered it, but that isn't actually true. Many of these places then move your not-actually-dismembered head somewhere else. If you have an unremovable limb (such as if you have TRAIT_NODISMEMBER) this means that it actually gets removed anyway because it's physically moved somewhere else. In all of these cases, if we failed to dismember the limb we should just leave it alone. I left anything where after dismembering the limb it immediately deletes it in though because those are generally supposed to be invariably fatal. ## Changelog 🆑 fix: Chainsaws can't behead people with unremovable heads. fix: You can only put your own head on a spear or into a box if it is possible to remove your head. fix: Heretic rifts can only remove your arms if your arms can be removed. fix: Paperwork can only cut off your head if your head can be cut off. fix: Smite being reflected can only blow off your arm if your arm can be removed. /🆑
157 lines
5.8 KiB
Plaintext
157 lines
5.8 KiB
Plaintext
|
|
// CHAINSAW
|
|
/obj/item/chainsaw
|
|
name = "chainsaw"
|
|
desc = "A versatile power tool. Useful for limbing trees and delimbing humans."
|
|
icon = 'icons/obj/weapons/chainsaw.dmi'
|
|
icon_state = "chainsaw"
|
|
base_icon_state = "chainsaw"
|
|
icon_angle = 180
|
|
lefthand_file = 'icons/mob/inhands/weapons/chainsaw_lefthand.dmi'
|
|
righthand_file = 'icons/mob/inhands/weapons/chainsaw_righthand.dmi'
|
|
obj_flags = CONDUCTS_ELECTRICITY
|
|
force = 13
|
|
w_class = WEIGHT_CLASS_HUGE
|
|
throwforce = 13
|
|
throw_speed = 2
|
|
throw_range = 4
|
|
demolition_mod = 1.5
|
|
custom_materials = list(/datum/material/iron= SHEET_MATERIAL_AMOUNT * 6.5)
|
|
attack_verb_continuous = list("saws", "tears", "lacerates", "cuts", "chops", "dices")
|
|
attack_verb_simple = list("saw", "tear", "lacerate", "cut", "chop", "dice")
|
|
hitsound = SFX_SWING_HIT
|
|
sharpness = SHARP_EDGED
|
|
actions_types = list(/datum/action/item_action/startchainsaw)
|
|
tool_behaviour = TOOL_SAW
|
|
toolspeed = 1.5 //Turn it on first you dork
|
|
custom_materials = list(/datum/material/iron = SHEET_MATERIAL_AMOUNT * 5, /datum/material/alloy/plasteel = SHEET_MATERIAL_AMOUNT * 5, /datum/material/glass = SHEET_MATERIAL_AMOUNT * 3)
|
|
var/force_on = 24
|
|
/// The looping sound for our chainsaw when running
|
|
var/datum/looping_sound/chainsaw/chainsaw_loop
|
|
/// How long it takes to behead someone with this chainsaw.
|
|
var/behead_time = 15 SECONDS
|
|
|
|
/obj/item/chainsaw/Initialize(mapload)
|
|
. = ..()
|
|
chainsaw_loop = new(src)
|
|
AddComponent( \
|
|
/datum/component/transforming, \
|
|
force_on = force_on, \
|
|
throwforce_on = force_on, \
|
|
throw_speed_on = throw_speed, \
|
|
sharpness_on = SHARP_EDGED, \
|
|
hitsound_on = 'sound/items/weapons/chainsawhit.ogg', \
|
|
w_class_on = w_class, \
|
|
)
|
|
AddComponent(/datum/component/butchering, \
|
|
speed = 3 SECONDS, \
|
|
effectiveness = 100, \
|
|
bonus_modifier = 0, \
|
|
butcher_sound = 'sound/items/weapons/chainsawhit.ogg', \
|
|
disabled = TRUE, \
|
|
)
|
|
AddElement(/datum/element/prosthetic_icon, "mounted", 180, TRUE)
|
|
AddComponent(/datum/component/two_handed, require_twohands = TRUE)
|
|
RegisterSignal(src, COMSIG_TRANSFORMING_ON_TRANSFORM, PROC_REF(on_transform))
|
|
RegisterSignal(src, COMSIG_ITEM_PRE_USED_AS_PROSTHETIC, PROC_REF(disable_twohanded_comp))
|
|
RegisterSignal(src, COMSIG_ITEM_DROPPED_FROM_PROSTHETIC, PROC_REF(enable_twohanded_comp))
|
|
|
|
/obj/item/chainsaw/proc/on_transform(obj/item/source, mob/user, active)
|
|
SIGNAL_HANDLER
|
|
|
|
to_chat(user, span_notice("As you pull the starting cord dangling from [src], [active ? "it begins to whirr" : "the chain stops moving"]."))
|
|
var/datum/component/butchering/butchering = GetComponent(/datum/component/butchering)
|
|
butchering.butchering_enabled = active
|
|
if (active)
|
|
chainsaw_loop.start()
|
|
else
|
|
chainsaw_loop.stop()
|
|
|
|
toolspeed = active ? 0.5 : initial(toolspeed)
|
|
update_item_action_buttons()
|
|
|
|
return COMPONENT_NO_DEFAULT_MESSAGE
|
|
|
|
/obj/item/chainsaw/proc/disable_twohanded_comp()
|
|
SIGNAL_HANDLER
|
|
|
|
qdel(GetComponent(/datum/component/two_handed))
|
|
|
|
/obj/item/chainsaw/proc/enable_twohanded_comp()
|
|
SIGNAL_HANDLER
|
|
|
|
AddComponent(/datum/component/two_handed, require_twohands = TRUE)
|
|
|
|
/obj/item/chainsaw/get_demolition_modifier(obj/target)
|
|
return HAS_TRAIT(src, TRAIT_TRANSFORM_ACTIVE) ? demolition_mod : 0.8
|
|
|
|
/obj/item/chainsaw/suicide_act(mob/living/carbon/user)
|
|
if(!HAS_TRAIT(src, TRAIT_TRANSFORM_ACTIVE))
|
|
user.visible_message(span_suicide("[user] smashes [src] into [user.p_their()] neck, destroying [user.p_their()] esophagus! It looks like [user.p_theyre()] trying to commit suicide!"))
|
|
playsound(src, 'sound/items/weapons/genhit1.ogg', 100, TRUE)
|
|
return BRUTELOSS
|
|
|
|
user.visible_message(span_suicide("[user] begins to tear [user.p_their()] head off with [src]! It looks like [user.p_theyre()] trying to commit suicide!"))
|
|
var/obj/item/bodypart/head/myhead = user.get_bodypart(BODY_ZONE_HEAD)
|
|
if(!myhead)
|
|
visible_message(span_suicide("[user] realises that [user.p_they()] cannot cut off [user.p_their()] head because [user.p_they()] don't have one!"))
|
|
return SHAME
|
|
|
|
playsound(src, 'sound/items/weapons/chainsawhit.ogg', 100, TRUE)
|
|
if(myhead.dismember())
|
|
return BRUTELOSS
|
|
|
|
var/datum/wound/slash/crit_wound = new ()
|
|
crit_wound.apply_wound(myhead)
|
|
visible_message(span_suicide("[user] tries in vain to cut off [user.p_their()] head but perishes in the attempt!"))
|
|
return BRUTELOSS
|
|
|
|
/obj/item/chainsaw/attack(mob/living/target_mob, mob/living/user, list/modifiers, list/attack_modifiers)
|
|
if (target_mob.stat != DEAD)
|
|
return ..()
|
|
|
|
if (user.zone_selected != BODY_ZONE_HEAD)
|
|
return ..()
|
|
|
|
var/obj/item/bodypart/head = target_mob.get_bodypart(BODY_ZONE_HEAD)
|
|
if (!head?.can_dismember())
|
|
return ..()
|
|
|
|
playsound(user, 'sound/items/weapons/slice.ogg', vol = 80, vary = TRUE)
|
|
|
|
target_mob.balloon_alert(user, "cutting off head...")
|
|
if (!do_after(user, behead_time, target_mob, extra_checks = CALLBACK(src, PROC_REF(has_same_head), target_mob, head)))
|
|
return TRUE
|
|
|
|
if (head.dismember(silent = FALSE))
|
|
user.put_in_hands(head)
|
|
|
|
return TRUE
|
|
|
|
/obj/item/chainsaw/proc/has_same_head(mob/living/target_mob, obj/item/bodypart/head)
|
|
return target_mob.get_bodypart(BODY_ZONE_HEAD) == head
|
|
|
|
/**
|
|
* Handles adding components to the chainsaw. Added in Initialize()
|
|
*
|
|
* Applies components to the chainsaw. Added as a separate proc to allow for
|
|
* variance between subtypes
|
|
*/
|
|
|
|
/obj/item/chainsaw/doomslayer
|
|
name = "THE GREAT COMMUNICATOR"
|
|
desc = span_warning("VRRRRRRR!!!")
|
|
armour_penetration = 100
|
|
force_on = 30
|
|
behead_time = 2 SECONDS
|
|
|
|
/obj/item/chainsaw/doomslayer/hit_reaction(mob/living/carbon/human/owner, atom/movable/hitby, attack_text = "the attack", final_block_chance = 0, damage = 0, attack_type = MELEE_ATTACK, damage_type = BRUTE)
|
|
if(attack_type == PROJECTILE_ATTACK)
|
|
owner.visible_message(span_danger("Ranged attacks just make [owner] angrier!"))
|
|
playsound(src, SFX_BULLET_MISS, 75, TRUE)
|
|
return TRUE
|
|
return FALSE
|
|
|
|
/datum/action/item_action/startchainsaw
|
|
name = "Pull The Starting Cord"
|