mirror of
https://github.com/ParadiseSS13/Paradise.git
synced 2026-07-19 02:54:41 +01:00
Securiblade Redux (#30488)
* Securiblade Redux * It's back * Vars * LINTERS * Apply AP on burn damage * Fixes recharger bug * Slapper, Better code, cleanup, no damage on help intent while off or stun, sounds * Secblade now makes a sound when turning itself off
This commit is contained in:
@@ -70,6 +70,265 @@
|
||||
"<span class='suicide'>[user] is falling on [src]! It looks like [user.p_theyre()] trying to commit suicide!</span>"))
|
||||
return BRUTELOSS
|
||||
|
||||
#define SECSWORD_OFF 0
|
||||
#define SECSWORD_STUN 1
|
||||
#define SECSWORD_BURN 2
|
||||
|
||||
// MARK: SECURIBLADE
|
||||
/obj/item/melee/secsword
|
||||
name = "securiblade"
|
||||
desc = "A simple, practical blade developed by Shellguard munitions for ‘enhanced’ riot control."
|
||||
base_icon_state = "secsword0"
|
||||
flags = CONDUCT
|
||||
force = 15
|
||||
throwforce = 5
|
||||
w_class = WEIGHT_CLASS_BULKY
|
||||
origin_tech = "combat=4"
|
||||
attack_verb = list("stabbed", "slashed", "sliced")
|
||||
hitsound = 'sound/weapons/bladeslice.ogg'
|
||||
materials = list(MAT_METAL = 1000)
|
||||
new_attack_chain = TRUE
|
||||
/// The icon the sword has when turned off
|
||||
var/base_icon = "secsword"
|
||||
/// How much stamina damage the sword does in stamina mode
|
||||
var/stam_damage = 35 // 3 hits to stamcrit
|
||||
/// How much burn damage the sword does in burn mode
|
||||
var/burn_damage = 10
|
||||
/// How much power does it cost to stun someone
|
||||
var/stam_hitcost = 1000
|
||||
/// How much power does it cost to burn someone
|
||||
var/burn_hitcost = 1500
|
||||
/// the initial cooldown tracks the time between stamina damage. tracks the world.time when the baton is usable again.
|
||||
var/cooldown = 3.5 SECONDS
|
||||
/// The sword's power cell - starts high
|
||||
var/obj/item/stock_parts/cell/high/cell
|
||||
/// The sword's current mode. Defaults to off.
|
||||
var/state = SECSWORD_OFF
|
||||
/// Stun cooldown
|
||||
COOLDOWN_DECLARE(stun_cooldown)
|
||||
|
||||
/obj/item/melee/secsword/Initialize(mapload)
|
||||
. = ..()
|
||||
cell = new(src)
|
||||
AddComponent(/datum/component/parry, _stamina_constant = 2, _stamina_coefficient = 1, _parryable_attack_types = NON_PROJECTILE_ATTACKS)
|
||||
update_appearance(UPDATE_ICON_STATE)
|
||||
|
||||
/obj/item/melee/secsword/Destroy()
|
||||
QDEL_NULL(cell)
|
||||
return ..()
|
||||
|
||||
/obj/item/melee/secsword/examine(mob/user)
|
||||
. = ..()
|
||||
if(!cell)
|
||||
. += "<span class='notice'>The powercell has been removed!</span>"
|
||||
return
|
||||
. += "<span class='notice'>It is [round(cell.percent())]% charged.</span>"
|
||||
if(round(cell.percent() < 100))
|
||||
. += "<span class='notice'>Can be recharged with a recharger.</span>"
|
||||
|
||||
/obj/item/melee/secsword/examine_more(mob/user)
|
||||
. = ..()
|
||||
. += "A simple, practical blade developed by Shellguard munitions for ‘enhanced’ riot control."
|
||||
. += ""
|
||||
. += "The Securiblade is a simple blade of lightweight silver plasteel, augmented with an energy-emitting edge and with a simple \
|
||||
power pack built into the hilt. A multi-purpose option for the NT Officer with a flair for impracticality, the \
|
||||
Securiblade serves just as well as a regular sword, as it does a stun weapon or even an energized, heated blade."
|
||||
. += ""
|
||||
. += "While not the most popular option among the officers of Nanotrasen’s security forces, the Securiblade has still been valued for the multiple options it \
|
||||
presents in combat. Deactivated, it’s a simple sword, but powered, it can either be utilized as a useful stun weapon, or as a dangerous, heated blade \
|
||||
that can inflict grievous burn wounds on any suspects unfortunate enough to meet an officer using it. Rest assured, the Securiblade is a reliable tool in the hands of a skilled officer."
|
||||
|
||||
/obj/item/melee/secsword/update_icon_state()
|
||||
if(!cell)
|
||||
icon_state = "[base_icon]3"
|
||||
else
|
||||
icon_state = "[base_icon][state]"
|
||||
|
||||
/obj/item/melee/secsword/emp_act(severity)
|
||||
if(!cell)
|
||||
return
|
||||
cell.use(round(cell.charge / severity))
|
||||
update_icon()
|
||||
|
||||
/obj/item/melee/secsword/get_cell()
|
||||
return cell
|
||||
|
||||
/obj/item/melee/secsword/proc/clear_cell()
|
||||
SIGNAL_HANDLER // COMSIG_PARENT_QDELETING
|
||||
UnregisterSignal(cell, COMSIG_PARENT_QDELETING)
|
||||
cell = null
|
||||
update_icon()
|
||||
|
||||
/obj/item/melee/secsword/item_interaction(mob/living/user, obj/item/used, list/modifiers)
|
||||
. = ..()
|
||||
if(!istype(used, /obj/item/stock_parts/cell))
|
||||
return ITEM_INTERACT_COMPLETE
|
||||
var/obj/item/stock_parts/cell/C = used
|
||||
if(cell)
|
||||
to_chat(user, "<span class='warning'>[src] already has a cell!</span>")
|
||||
return ITEM_INTERACT_COMPLETE
|
||||
if(C.maxcharge < stam_hitcost)
|
||||
to_chat(user, "<span class='warning'>[src] requires a higher capacity cell!</span>")
|
||||
return ITEM_INTERACT_COMPLETE
|
||||
if(!user.unequip(used))
|
||||
return ITEM_INTERACT_COMPLETE
|
||||
used.forceMove(src)
|
||||
cell = used
|
||||
to_chat(user, "<span class='notice'>You install [used] into [src].</span>")
|
||||
update_icon()
|
||||
return ITEM_INTERACT_COMPLETE
|
||||
|
||||
/obj/item/melee/secsword/screwdriver_act(mob/living/user, obj/item/I)
|
||||
if(!cell)
|
||||
to_chat(user, "<span class='warning'>There's no cell installed!</span>")
|
||||
return
|
||||
if(!I.use_tool(src, user, volume = I.tool_volume))
|
||||
return
|
||||
|
||||
user.put_in_hands(cell)
|
||||
to_chat(user, "<span class='notice'>You remove [cell] from [src].</span>")
|
||||
cell.update_icon()
|
||||
clear_cell()
|
||||
|
||||
/obj/item/melee/secsword/activate_self(mob/user)
|
||||
if(..())
|
||||
return FINISH_ATTACK
|
||||
if(!cell)
|
||||
to_chat(user, "<span class='warning'>[src] does not have a power source!</span>")
|
||||
return FINISH_ATTACK
|
||||
|
||||
add_fingerprint(user)
|
||||
if(cell.charge < stam_hitcost || (SECSWORD_STUN && cell.charge < burn_hitcost))
|
||||
state = SECSWORD_OFF
|
||||
armor_penetration_percentage = 0
|
||||
to_chat(user, "<span class='notice'>[src] does not have enough charge!</span>")
|
||||
return FINISH_ATTACK
|
||||
switch(state)
|
||||
if(SECSWORD_OFF)
|
||||
state = SECSWORD_STUN
|
||||
armor_penetration_percentage = 30
|
||||
to_chat(user, "<span class='warning'>[src]'s edge is now set to stun.</span>")
|
||||
if(SECSWORD_STUN)
|
||||
state = SECSWORD_BURN
|
||||
armor_penetration_percentage = 60
|
||||
to_chat(user, "<span class='warning'>[src]'s edge is now set to burn.</span>")
|
||||
if(SECSWORD_BURN)
|
||||
state = SECSWORD_OFF
|
||||
armor_penetration_percentage = 0
|
||||
to_chat(user, "<span class='notice'>[src]'s edge is now turned off.</span>")
|
||||
update_icon()
|
||||
playsound(src, "sparks", 60, TRUE, -1)
|
||||
return FINISH_ATTACK
|
||||
|
||||
/obj/item/melee/secsword/attack(mob/living/M, mob/living/user, params)
|
||||
if(HAS_TRAIT(user, TRAIT_CLUMSY) && prob(50))
|
||||
if(state == SECSWORD_STUN && sword_stun(user, user, skip_cooldown = TRUE))
|
||||
user.visible_message("<span class='danger'>[user] accidentally hits [user.p_themselves()] with [src]!</span>",
|
||||
"<span class='userdanger'>You accidentally hit yourself with [src]!</span>")
|
||||
return FINISH_ATTACK | MELEE_COOLDOWN_PREATTACK
|
||||
if(user.mind?.martial_art?.no_baton && user.mind?.martial_art?.can_use(user)) // Just like the baton, no sword + judo.
|
||||
to_chat(user, "<span class='warning'>The sword feels off-balance in your hand due to your specific martial training!</span>")
|
||||
return FINISH_ATTACK | MELEE_COOLDOWN_PREATTACK
|
||||
|
||||
// Off
|
||||
if(!isliving(M) || state == SECSWORD_OFF)
|
||||
if(user.a_intent == INTENT_HELP)
|
||||
if(!COOLDOWN_FINISHED(src, stun_cooldown))
|
||||
return
|
||||
if(issilicon(M)) // Can't slap borgs and AIs
|
||||
user.do_attack_animation(M)
|
||||
M.visible_message(
|
||||
"<span class='warning'>[user] has slapped [M] harmlessly with [src].</span>",
|
||||
"<span class='danger'>[user] has slapped you harmlessly with [src].</span>"
|
||||
)
|
||||
return
|
||||
slap(M, user) // Just a little slap. No harm
|
||||
return
|
||||
return ..()
|
||||
|
||||
// Stun mode
|
||||
if(state == SECSWORD_STUN)
|
||||
if(issilicon(M) && user.a_intent != INTENT_HELP) // Can't stun borgs and AIs
|
||||
return ..()
|
||||
else if(issilicon(M))
|
||||
user.do_attack_animation(M)
|
||||
M.visible_message(
|
||||
"<span class='warning'>[user] has slapped [M] harmlessly with [src].</span>",
|
||||
"<span class='danger'>[user] has slapped you harmlessly with [src].</span>"
|
||||
)
|
||||
return
|
||||
if(sword_stun(M, user))
|
||||
user.do_attack_animation(M)
|
||||
if(user.a_intent != INTENT_HELP) // Hurt people only if not help
|
||||
return ..()
|
||||
return
|
||||
// Burn
|
||||
var/mob/living/L = M
|
||||
if(ishuman(L))
|
||||
var/mob/living/carbon/human/H = L
|
||||
var/obj/item/organ/external/targetlimb = H.get_organ(ran_zone(user.zone_selected))
|
||||
H.apply_damage(burn_damage, BURN, targetlimb, H.run_armor_check(targetlimb, MELEE, armor_penetration_percentage = armor_penetration_percentage))
|
||||
else
|
||||
L.apply_damage(burn_damage, BURN)
|
||||
deduct_charge(burn_hitcost)
|
||||
return ..()
|
||||
|
||||
/obj/item/melee/secsword/proc/slap(mob/living/carbon/human/target, mob/living/user)
|
||||
user.do_attack_animation(target, ATTACK_EFFECT_DISARM)
|
||||
playsound(loc, 'sound/effects/woodhit.ogg', 50, TRUE, -1)
|
||||
target.AdjustConfused(4 SECONDS, 0, 4 SECONDS)
|
||||
target.apply_damage(10, STAMINA)
|
||||
add_attack_logs(user, target, "Slapped by [src]", ATKLOG_ALL)
|
||||
COOLDOWN_START(src, stun_cooldown, cooldown) // Shares cooldown with stun to avoid comboing slap into stun
|
||||
|
||||
/obj/item/melee/secsword/proc/sword_stun(mob/living/L, mob/user, skip_cooldown = FALSE)
|
||||
if(!COOLDOWN_FINISHED(src, stun_cooldown) && !skip_cooldown)
|
||||
return FALSE
|
||||
|
||||
var/user_UID = user.UID()
|
||||
if(HAS_TRAIT_FROM(L, TRAIT_WAS_BATONNED, user_UID)) // Doesn't work in conjunction with stun batons.
|
||||
return FALSE
|
||||
|
||||
if(ishuman(L))
|
||||
var/mob/living/carbon/human/H = L
|
||||
if(H.check_shields(src, 0, "[user]'s [name]", MELEE_ATTACK)) // No message; check_shields() handles that
|
||||
playsound(L, 'sound/weapons/genhit.ogg', 50, TRUE)
|
||||
return TRUE
|
||||
// Weaker than a stun baton, less bad effects applied
|
||||
H.Jitter(6 SECONDS)
|
||||
H.AdjustConfused(4 SECONDS, 0, 4 SECONDS)
|
||||
H.SetStuttering(6 SECONDS)
|
||||
var/obj/item/organ/external/targetlimb = H.get_organ(ran_zone(user.zone_selected))
|
||||
H.apply_damage(stam_damage, STAMINA, targetlimb, H.run_armor_check(targetlimb, MELEE))
|
||||
deduct_charge(stam_hitcost)
|
||||
|
||||
ADD_TRAIT(L, TRAIT_WAS_BATONNED, user_UID) // So a person cannot hit the same person with a sword AND a baton, or two swords
|
||||
addtimer(CALLBACK(src, PROC_REF(stun_delay), L, user_UID), 2 SECONDS)
|
||||
SEND_SIGNAL(L, COMSIG_LIVING_MINOR_SHOCK, 33)
|
||||
playsound(src, 'sound/weapons/egloves.ogg', 50, TRUE, -1)
|
||||
COOLDOWN_START(src, stun_cooldown, cooldown)
|
||||
return TRUE
|
||||
|
||||
// Proc called to remove trait that prevents repeated stamina damage. Called on a 2 Second timer when hit in stun mode
|
||||
/obj/item/melee/secsword/proc/stun_delay(mob/living/target, user_UID)
|
||||
REMOVE_TRAIT(target, TRAIT_WAS_BATONNED, user_UID)
|
||||
|
||||
/obj/item/melee/secsword/proc/deduct_charge(amount)
|
||||
if(!cell)
|
||||
return
|
||||
if(cell.rigged)
|
||||
RegisterSignal(cell, COMSIG_PARENT_QDELETING, PROC_REF(clear_cell))
|
||||
cell.use(amount)
|
||||
if(cell.charge < amount) // If after the deduction the sword doesn't have enough charge for a hit it turns off.
|
||||
state = SECSWORD_OFF
|
||||
armor_penetration_percentage = 0
|
||||
playsound(src, "sparks", 60, TRUE, -1)
|
||||
update_icon()
|
||||
|
||||
#undef SECSWORD_OFF
|
||||
#undef SECSWORD_STUN
|
||||
#undef SECSWORD_BURN
|
||||
|
||||
// MARK: SNAKESFANG
|
||||
/obj/item/melee/snakesfang
|
||||
name = "snakesfang"
|
||||
|
||||
@@ -808,6 +808,16 @@
|
||||
new /obj/item/melee/saber(src)
|
||||
update_appearance(UPDATE_ICON_STATE)
|
||||
|
||||
/obj/item/storage/belt/sheath/secsword
|
||||
name = "securiblade scabbard"
|
||||
desc = "Can hold securiblades."
|
||||
base_icon_state = "secsheath"
|
||||
can_hold = list(/obj/item/melee/secsword)
|
||||
|
||||
/obj/item/storage/belt/sheath/secsword/populate_contents()
|
||||
new /obj/item/melee/secsword(src)
|
||||
update_appearance(UPDATE_ICON_STATE)
|
||||
|
||||
/obj/item/storage/belt/sheath/snakesfang
|
||||
name = "snakesfang scabbard"
|
||||
desc = "Can hold scimitars."
|
||||
|
||||
Reference in New Issue
Block a user