Skip to content

Commit

Permalink
[PORT] Add mantis blades (new traitor item) (#27594)
Browse files Browse the repository at this point in the history
* add mantis blades

* fix nuclear only

* fix .dme edit

* fix linter

* new attack chain

* maybe fix linter

* add NT mantis blade to syndicate 6

* newline

* add list

* fix nested types

* ability to pry open doors with two blades

* Update code/game/machinery/doors/airlock.dm

Co-authored-by: Burzah <[email protected]>
Signed-off-by: Mira <[email protected]>

* requested changes

* remove transform

* replace sleep with addtimer

* Update code/datums/uplink_items/uplink_general.dm

Co-authored-by: PopeDaveThe3th <[email protected]>
Signed-off-by: Mira <[email protected]>

* Update code/datums/uplink_items/uplink_general.dm

Co-authored-by: PopeDaveThe3th <[email protected]>
Signed-off-by: Mira <[email protected]>

* Update code/game/objects/items/weapons/storage/uplink_kits.dm

Co-authored-by: PopeDaveThe3th <[email protected]>
Signed-off-by: Mira <[email protected]>

* Update code/modules/research/designs/weapon_designs.dm

Co-authored-by: PopeDaveThe3th <[email protected]>
Signed-off-by: Mira <[email protected]>

* Update code/modules/research/designs/weapon_designs.dm

Co-authored-by: PopeDaveThe3th <[email protected]>
Signed-off-by: Mira <[email protected]>

* Update code/modules/surgery/organs/augments_arms.dm

Co-authored-by: PopeDaveThe3th <[email protected]>
Signed-off-by: Mira <[email protected]>

* Update code/modules/surgery/organs/augments_arms.dm

Co-authored-by: PopeDaveThe3th <[email protected]>
Signed-off-by: Mira <[email protected]>

* Update code/modules/surgery/organs/augments_arms.dm

Co-authored-by: PopeDaveThe3th <[email protected]>
Signed-off-by: Mira <[email protected]>

* Update code/modules/surgery/organs/augments_arms.dm

Co-authored-by: PopeDaveThe3th <[email protected]>
Signed-off-by: Mira <[email protected]>

* Update code/modules/surgery/organs/augments_arms.dm

Co-authored-by: PopeDaveThe3th <[email protected]>
Signed-off-by: Mira <[email protected]>

* Update code/modules/surgery/organs/augments_arms.dm

Co-authored-by: PopeDaveThe3th <[email protected]>
Signed-off-by: Mira <[email protected]>

* add safetys and some cleanup

* return parry sound

* snake case and replace CALLBACK with VARSET_CALLBACK

* move attacking logic and update item and uplink description

* cleanup

* first attempt

* fix conditional statement

* update paradise.dme

* edit whitespace

* signal interceptors

* improve some logic

* oops

* use COMSIG_INTERACTING

* return one whitespace

* subtype for mantis blades

* replace .GetComponent() with signal

* fix typo

* better naming

* attempt_cancel_message and some logic

* split logic

---------

Signed-off-by: Mira <[email protected]>
Co-authored-by: Burzah <[email protected]>
Co-authored-by: PopeDaveThe3th <[email protected]>
  • Loading branch information
3 people authored Jan 17, 2025
1 parent 6f77bf1 commit dac5700
Show file tree
Hide file tree
Showing 18 changed files with 265 additions and 37 deletions.
2 changes: 2 additions & 0 deletions code/__DEFINES/dcs/datum_signals.dm
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,8 @@
#define COMPONENT_TWOHANDED_BLOCK_WIELD (1<<0)
///from base of datum/component/two_handed/proc/unwield(mob/living/carbon/user): (/mob/user)
#define COMSIG_TWOHANDED_UNWIELD "twohanded_unwield"
///from base of /datum/component/forces_doors_open/proc/force_open_door(obj/item): (datum/source, mob/user, atom/target)
#define COMSIG_TWOHANDED_WIELDED_TRY_WIELD_INTERACT "twohanded_wielded_try_wield_interact"


// /datum/action
Expand Down
2 changes: 0 additions & 2 deletions code/__HELPERS/trait_helpers.dm
Original file line number Diff line number Diff line change
Expand Up @@ -280,8 +280,6 @@ Remember to update _globalvars/traits.dm if you're adding/removing/renaming trai
#define TRAIT_WIELDED "wielded"
/// Wires on this will have their titles randomized for those with SHOW_WIRES
#define TRAIT_OBSCURED_WIRES "obscured_wires"
/// Forces open doors after a delay specific to the item
#define TRAIT_FORCES_OPEN_DOORS_ITEM "forces_open_doors_item_varient"
/// Makes the item no longer spit out a visible message when thrown
#define TRAIT_NO_THROWN_MESSAGE "no_message_when_thrown"
/// Makes the item not display a message on storage insertion
Expand Down
1 change: 0 additions & 1 deletion code/_globalvars/traits.dm
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,6 @@ GLOBAL_LIST_INIT(traits_by_type, list(
"TRAIT_SUPERMATTER_IMMUNE" = TRAIT_SUPERMATTER_IMMUNE,
"TRAIT_BUTCHER_HUMANS" = TRAIT_BUTCHERS_HUMANS,
"TRAIT_CMAGGED" = TRAIT_CMAGGED,
"TRAIT_FORCES_OPEN_DOORS" = TRAIT_FORCES_OPEN_DOORS_ITEM,
"TRAIT_OBSCURED_WIRES" = TRAIT_OBSCURED_WIRES,
"TRAIT_XENO_INTERACTABLE" = TRAIT_XENO_INTERACTABLE,
"TRAIT_NO_THROWN_MESSAGE" = TRAIT_NO_THROWN_MESSAGE,
Expand Down
117 changes: 117 additions & 0 deletions code/datums/components/forces_doors_open.dm
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
/**
* /datum/component/forces_doors_open
*
* This component allows item to pry open doors.
*
*/

/datum/component/forces_doors_open
/// The time it takes to open the airlock when forced
var/time_to_open
/// Whether the airlock can be forced open while powered.
var/can_force_open_while_powered
/// Whether the airlock can be forced open while unpowered.
var/can_force_open_while_unpowered
/// Whether the firedoor can be opened.
var/can_open_firedoors
/// The sound played when the airlock is forced open.
var/open_sound
/// Indicates whether no sound should be played when opening.
var/no_sound

/datum/component/forces_doors_open/Initialize(
time_to_open = 5 SECONDS,
can_force_open_while_powered = TRUE,
can_force_open_while_unpowered = TRUE,
can_open_firedoors = TRUE,
open_sound = 'sound/machines/airlock_alien_prying.ogg',
no_sound = FALSE)
if(!isitem(parent))
return COMPONENT_INCOMPATIBLE

src.time_to_open = time_to_open
src.can_force_open_while_powered = can_force_open_while_powered
src.can_force_open_while_unpowered = can_force_open_while_unpowered
src.can_open_firedoors = can_open_firedoors
src.open_sound = open_sound
src.no_sound = no_sound

RegisterSignal(parent, COMSIG_INTERACTING, PROC_REF(on_interact))

/datum/component/forces_doors_open/proc/on_interact(datum/source, mob/user, atom/target)
SIGNAL_HANDLER // COMSIG_INTERACTING

if(check_intent(user))
return

if(try_to_open_firedoor(target))
return ITEM_INTERACT_COMPLETE

if(try_to_force_open_airlock(user, target))
return ITEM_INTERACT_COMPLETE

/// check is user in harm intent
/datum/component/forces_doors_open/proc/check_intent(mob/user)
if(user.a_intent == INTENT_HARM)
return TRUE

/// try to open firedoor
/datum/component/forces_doors_open/proc/try_to_open_firedoor(atom/target)
if(can_open_firedoors && istype(target, /obj/machinery/door/firedoor)) // open firedoor and dont open blastdoors and windowdoors
INVOKE_ASYNC(src, PROC_REF(open_unpowered_door), target)
return TRUE

/// try to force open airlock
/datum/component/forces_doors_open/proc/try_to_force_open_airlock(mob/user, obj/machinery/door/airlock/airlock)
if(!istype(airlock, /obj/machinery/door/airlock)) // only airlocks have arePowerSystemsOn()
return

if(SEND_SIGNAL(parent, COMSIG_TWOHANDED_WIELDED_TRY_WIELD_INTERACT) && airlock.arePowerSystemsOn())
to_chat(user, "<span class='warning'>You need to be wielding [parent] to do that!</span>")
return TRUE

if(!airlock.density)
return TRUE

// open unpowered
if(can_force_open_while_unpowered && !airlock.arePowerSystemsOn())
INVOKE_ASYNC(src, PROC_REF(open_unpowered_door), airlock)
return TRUE

// open powered
if(can_force_open_while_powered)
INVOKE_ASYNC(src, PROC_REF(open_powered_airlock), airlock, user)
return TRUE

/// open airlock with delay
/datum/component/forces_doors_open/proc/open_powered_airlock(obj/machinery/door/airlock/airlock, mob/user)
if(!no_sound)
playsound(parent, open_sound, 100, 1)

if(do_after_once(user, time_to_open, target = airlock, attempt_cancel_message = "You decide to stop prying [airlock] with [parent]."))
if(airlock.open(TRUE))
return // successfully opened

// opening failed
if(airlock.density)
to_chat(user, "<span class='warning'>Despite your attempts, [airlock] refuses to open.</span>")

/// open door without checks
/datum/component/forces_doors_open/proc/open_unpowered_door(obj/machinery/door/door)
door.open(TRUE)

/// subtype for mantis blades
/datum/component/forces_doors_open/mantis/on_interact(datum/source, mob/user, atom/target)
if(check_intent(user))
return

if(try_to_open_firedoor(target))
return ITEM_INTERACT_COMPLETE

var/obj/item/melee/mantis_blade/secondblade = user.get_inactive_hand()
if(!istype(secondblade, /obj/item/melee/mantis_blade))
to_chat(user, "<span class='warning'>You need a second [parent] to pry open doors!</span>")
return ITEM_INTERACT_COMPLETE

if(try_to_force_open_airlock(user, target))
return ITEM_INTERACT_COMPLETE
10 changes: 10 additions & 0 deletions code/datums/components/two_handed.dm
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,7 @@
RegisterSignal(parent, COMSIG_ITEM_SHARPEN_ACT, PROC_REF(on_sharpen))
RegisterSignal(parent, COMSIG_CARBON_UPDATE_HANDCUFFED, PROC_REF(on_handcuff_user))
RegisterSignal(parent, COMSIG_ATOM_ATTACK_HAND, PROC_REF(on_attack_hand))
RegisterSignal(parent, COMSIG_TWOHANDED_WIELDED_TRY_WIELD_INTERACT, PROC_REF(check_unwielded))

// Remove all siginals registered to the parent item
/datum/component/two_handed/UnregisterFromParent()
Expand Down Expand Up @@ -307,6 +308,15 @@
// Clear any old refrence to an item that should be gone now
offhand_item = null

/**
* Check if item is unwielded
*
* returns TRUE if unwielded
*/
/datum/component/two_handed/proc/check_unwielded()
SIGNAL_HANDLER // COMSIG_TWOHANDED_WIELDED_TRY_WIELD_INTERACT
return wielded ? FALSE : TRUE;

/**
* on_attack triggers on attack with the parent item
*/
Expand Down
9 changes: 9 additions & 0 deletions code/datums/uplink_items/uplink_general.dm
Original file line number Diff line number Diff line change
Expand Up @@ -949,6 +949,15 @@ GLOBAL_LIST_INIT(uplink_items, subtypesof(/datum/uplink_item))
item = /obj/item/autosurgeon/organ/syndicate/oneuse/scope_eyes
cost = 10

/datum/uplink_item/cyber_implants/mantis_kit
name = "'Naginata' Mantis Blades Kit"
desc = "A pair of devastating 'Naginata' concealable mantis blades, which retract into the arms of the user. \
Their monomolecular edges will easily tear through flesh and armor alike, and can even pry open airlocks when used together. \
When both blades are equipped, they enable the user to perform double attacks. \
Can be used to parry incoming melee attacks."
reference = "MBK"
item = /obj/item/storage/box/syndie_kit/syndie_mantis
cost = 60

////////////////////////////////////////
// MARK: POINTLESS BADASSERY
Expand Down
28 changes: 0 additions & 28 deletions code/game/machinery/doors/airlock.dm
Original file line number Diff line number Diff line change
Expand Up @@ -1190,9 +1190,6 @@ GLOBAL_LIST_EMPTY(airlock_emissive_underlays)
/obj/machinery/door/airlock/try_to_crowbar(mob/living/user, obj/item/I)
if(operating)
return
if(HAS_TRAIT(I, TRAIT_FORCES_OPEN_DOORS_ITEM))
force_open_with_item(user, I)
return
var/beingcrowbarred = FALSE
if(I.tool_behaviour == TOOL_CROWBAR && I.tool_use_check(user, 0))
beingcrowbarred = TRUE
Expand Down Expand Up @@ -1237,31 +1234,6 @@ GLOBAL_LIST_EMPTY(airlock_emissive_underlays)
if(density && !open(1))
to_chat(user, "<span class='warning'>Despite your attempts, [src] refuses to open.</span>")

/obj/machinery/door/airlock/proc/force_open_with_item(mob/living/user, obj/item/I)
/// Time it takes to open an airlock with an item with the TRAIT_FORCES_OPEN_DOORS_ITEM trait, 5 seconds for wielded items, 10 seconds for nonwielded items
var/time_to_open_airlock = 10 SECONDS
/// Can we open the airlock while unpowered? Wielded item's can't, but unwielded items can
var/can_force_open_while_unpowered = TRUE
if(I.GetComponent(/datum/component/two_handed))
can_force_open_while_unpowered = FALSE
time_to_open_airlock = 5 SECONDS
if(!HAS_TRAIT(I, TRAIT_WIELDED))
to_chat(user, "<span class='warning'>You need to be wielding [I] to do that!</span>")
return
if(!density || prying_so_hard)
return
playsound(src, 'sound/machines/airlock_alien_prying.ogg', 100, 1) //is it aliens or just the CE being a dick?
if(!arePowerSystemsOn() && can_force_open_while_unpowered)
open(TRUE)
return
prying_so_hard = TRUE //so you dont pry the door when you are already trying to pry it
var/result = do_after(user, time_to_open_airlock, target = src)
prying_so_hard = FALSE
if(result)
open(TRUE)
if(density && !open(TRUE))
to_chat(user, "<span class='warning'>Despite your attempts, [src] refuses to open.</span>")

/obj/machinery/door/airlock/open(forced=0)
if(operating || welded || locked || emagged)
return 0
Expand Down
3 changes: 0 additions & 3 deletions code/game/machinery/doors/door.dm
Original file line number Diff line number Diff line change
Expand Up @@ -260,9 +260,6 @@
if(HAS_TRAIT(src, TRAIT_CMAGGED) && I.can_clean()) //If the cmagged door is being hit with cleaning supplies, don't open it, it's being cleaned!
return

if(user.a_intent != INTENT_HARM && HAS_TRAIT(I, TRAIT_FORCES_OPEN_DOORS_ITEM))
try_to_crowbar(user, I)
return TRUE
else if(!(I.flags & NOBLUDGEON) && user.a_intent != INTENT_HARM)
try_to_activate_door(user)
return TRUE
Expand Down
9 changes: 9 additions & 0 deletions code/game/objects/items/weapons/storage/uplink_kits.dm
Original file line number Diff line number Diff line change
Expand Up @@ -579,3 +579,12 @@
/obj/item/storage/box/syndie_kit/forgers_kit/populate_contents()
new /obj/item/stamp/chameleon(src)
new /obj/item/pen/chameleon(src)

/obj/item/storage/box/syndie_kit/syndie_mantis
name = "\improper Mantis Blades kit"
desc = "A sleek box marked with a Cybersun logo. The label says it contains a pair of CX-12 'Naginata' mantis blades and accompanying autosurgeons."

/obj/item/storage/box/syndie_kit/syndie_mantis/populate_contents()
new /obj/item/autosurgeon/organ/syndicate/oneuse/syndie_mantis(src)
new /obj/item/autosurgeon/organ/syndicate/oneuse/syndie_mantis/l(src)

4 changes: 2 additions & 2 deletions code/game/objects/items/weapons/twohanded.dm
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@

/obj/item/fireaxe/Initialize(mapload)
. = ..()
ADD_TRAIT(src, TRAIT_FORCES_OPEN_DOORS_ITEM, ROUNDSTART_TRAIT)
AddComponent(/datum/component/forces_doors_open)
AddComponent(/datum/component/parry, _stamina_constant = 2, _stamina_coefficient = 0.7, _parryable_attack_types = MELEE_ATTACK, _parry_cooldown = (10 / 3) SECONDS, _requires_two_hands = TRUE) // 2.3333 seconds of cooldown for 30% uptime
AddComponent(/datum/component/two_handed, force_unwielded = force_unwielded, force_wielded = force_wielded, icon_wielded = "[base_icon_state]1")

Expand Down Expand Up @@ -1070,8 +1070,8 @@

/obj/item/supermatter_halberd/Initialize(mapload)
. = ..()
ADD_TRAIT(src, TRAIT_FORCES_OPEN_DOORS_ITEM, ROUNDSTART_TRAIT)
ADD_TRAIT(src, TRAIT_SUPERMATTER_IMMUNE, ROUNDSTART_TRAIT) //so it can't be dusted by the SM
AddComponent(/datum/component/forces_doors_open)
AddComponent(/datum/component/parry, _stamina_constant = 2, _stamina_coefficient = 0.25, _parryable_attack_types = ALL_ATTACK_TYPES, _parry_cooldown = (4 / 3) SECONDS, _requires_two_hands = TRUE) // 0.3333 seconds of cooldown for 75% uptime
AddComponent(/datum/component/two_handed, force_wielded = 40, force_unwielded = force, icon_wielded = "[base_icon_state]1")

Expand Down
2 changes: 1 addition & 1 deletion code/modules/antagonists/changeling/powers/mutations.dm
Original file line number Diff line number Diff line change
Expand Up @@ -149,7 +149,7 @@
/obj/item/melee/arm_blade/Initialize(mapload, silent, new_parent_action)
. = ..()
parent_action = new_parent_action
ADD_TRAIT(src, TRAIT_FORCES_OPEN_DOORS_ITEM, ROUNDSTART_TRAIT)
AddComponent(/datum/component/forces_doors_open, time_to_open = 10 SECONDS)

/obj/item/melee/arm_blade/Destroy()
if(parent_action)
Expand Down
12 changes: 12 additions & 0 deletions code/modules/research/designs/weapon_designs.dm
Original file line number Diff line number Diff line change
Expand Up @@ -399,3 +399,15 @@
reagents_list = list("fuel" = 30)
build_path = /obj/item/chemical_canister/pyrotechnics
category = list("Weapons")

/datum/design/nt_mantis
name = "'Scylla' mantis blade implant"
desc = "A reverse-engineered mantis blade implant. While the monomolecular edge was lost, they remain deadly weapons."
id = "mantis_blade_nt"
req_tech = list("materials" = 7, "engineering" = 6, "combat" = 7, "syndicate" = 6)
build_type = PROTOLATHE | MECHFAB
construction_time = 6 SECONDS
materials = list(MAT_METAL = 10000, MAT_SILVER = 2000, MAT_GOLD = 2000, MAT_TITANIUM = 3000, MAT_DIAMOND = 4000)
build_path = /obj/item/organ/internal/cyberimp/arm/nt_mantis
category = list("Medical", "Weapons")

96 changes: 96 additions & 0 deletions code/modules/surgery/organs/augments_arms.dm
Original file line number Diff line number Diff line change
Expand Up @@ -836,3 +836,99 @@
if(emp_proof)
return
muscle_implant.emp_act(severity, owner)

// Mantis blades

/obj/item/melee/mantis_blade
name = "mantis blade"
desc = "A blade designed to be hidden just beneath the skin. The brain is directly linked to this bad boy, allowing it to spring into action. \
When both blades are equipped, they enable the user to perform double attacks."
icon = 'icons/obj/weapons/melee.dmi'
lefthand_file = 'icons/mob/inhands/implants_lefthand.dmi'
righthand_file = 'icons/mob/inhands/implants_righthand.dmi'
hitsound = 'sound/weapons/bladeslice.ogg'
new_attack_chain = TRUE
var/double_attack = TRUE
var/double_attack_cd = 1.5 // seconds, so every second attack
sharp = TRUE
w_class = WEIGHT_CLASS_BULKY
attack_verb = list("attacked", "slashed", "stabbed", "sliced", "torn", "lacerated", "ripped", "diced", "cut")

/obj/item/melee/mantis_blade/equipped(mob/user, slot, initial)
. = ..()
if(slot == ITEM_SLOT_LEFT_HAND)
transform = matrix(-1, 0, 0, 0, 1, 0)
else
transform = null

// make double attack if blades in both hands and not on CD
/obj/item/melee/mantis_blade/attack(mob/living/target, mob/living/user, params)
var/obj/item/melee/mantis_blade/secondblade = user.get_inactive_hand()
if(!istype(secondblade, /obj/item/melee/mantis_blade) || !double_attack)
return ..()

double_attack(target, user, params, secondblade)
return FINISH_ATTACK

/obj/item/melee/mantis_blade/proc/double_attack(mob/living/target, mob/living/user, params, obj/item/melee/mantis_blade/secondblade)
// first attack
single_attack(target, user, params)
user.changeNext_move(CLICK_CD_MELEE)
// second attack
addtimer(CALLBACK(secondblade, PROC_REF(single_attack), target, user, params), 0.2 SECONDS) // not instant second attack

/obj/item/melee/mantis_blade/proc/single_attack(mob/living/target, mob/living/user, params)
if(QDELETED(src))
return
double_attack = FALSE
attack(target, user, params)
addtimer(VARSET_CALLBACK(src, double_attack, TRUE), double_attack_cd SECONDS)

/obj/item/melee/mantis_blade/Initialize(mapload)
. = ..()
AddComponent(/datum/component/forces_doors_open/mantis)

/obj/item/melee/mantis_blade/syndicate
name = "'Naginata' mantis blade"
icon_state = "syndie_mantis"
item_state = "syndie_mantis"
force = 20
armour_penetration_percentage = 30

/obj/item/melee/mantis_blade/syndicate/Initialize(mapload)
. = ..()
AddComponent(/datum/component/parry, _stamina_constant = 2, _stamina_coefficient = 0.35, _parryable_attack_types = NON_PROJECTILE_ATTACKS, _parry_cooldown = (4 / 3) SECONDS) // 0.3333 seconds of cooldown for 75% uptime, non projectile

/obj/item/melee/mantis_blade/nt
name = "'Scylla' mantis blade"
icon_state = "mantis"
item_state = "mantis"
force = 18

/obj/item/melee/mantis_blade/nt/Initialize(mapload)
. = ..()
AddComponent(/datum/component/parry, _stamina_constant = 2, _stamina_coefficient = 0.35, _parryable_attack_types = NON_PROJECTILE_ATTACKS, _parry_cooldown = (5 / 3) SECONDS) // 0.666667 seconds for 60% uptime, non projectile

// Mantis blades implants
/obj/item/organ/internal/cyberimp/arm/syndie_mantis
name = "'Naginata' mantis blade implants"
desc = "A powerful and concealable mantis blade with a monomolecular edge, produced by Cybersun Industries. Cuts through flesh and armor alike with ease."
origin_tech = "materials=5;combat=5;biotech=5;syndicate=4"
contents = newlist(/obj/item/melee/mantis_blade/syndicate)
icon_state = "syndie_mantis"
icon = 'icons/obj/weapons/melee.dmi'

/obj/item/organ/internal/cyberimp/arm/syndie_mantis/l
parent_organ = "l_arm"

/obj/item/organ/internal/cyberimp/arm/nt_mantis
name = "'Scylla' mantis blade implant"
desc = "A reverse-engineered mantis blade design produced by Nanotrasen. While still quite deadly, the loss of the monomolecular blade has drastically reduced its armor penetration capability."
origin_tech = "materials=5;combat=5;biotech=5;syndicate=4"
contents = newlist(/obj/item/melee/mantis_blade/nt)
icon_state = "mantis"
icon = 'icons/obj/weapons/melee.dmi'

/obj/item/organ/internal/cyberimp/arm/nt_mantis/l
parent_organ = "l_arm"

Loading

0 comments on commit dac5700

Please sign in to comment.