mirror of
https://github.com/Bubberstation/Bubberstation.git
synced 2026-08-22 12:41:09 +01:00
Adds the Ninja MODsuit (#67220)
Why It's Good For The Game Ninja code is pretty bad, I think it's best to move away into nice modular stuff instead. Changelog cl Fikou, PositiveEntropy, Nerevar, InfraRedBaron refactor: the ninja space suit is now a modsuit fix: fixes dash beams not working /cl
This commit is contained in:
@@ -216,6 +216,7 @@
|
||||
. += span_notice("You could remove [ai] with an <b>intellicard</b>.")
|
||||
else
|
||||
. += span_notice("You could install an AI with an <b>intellicard</b>.")
|
||||
. += span_notice("<i>You could examine it more thoroughly...</i>")
|
||||
|
||||
/obj/item/mod/control/examine_more(mob/user)
|
||||
. = ..()
|
||||
@@ -507,7 +508,7 @@
|
||||
return
|
||||
var/module_reference = display_names[pick]
|
||||
var/obj/item/mod/module/picked_module = locate(module_reference) in modules
|
||||
if(!istype(picked_module) || user.incapacitated())
|
||||
if(!istype(picked_module))
|
||||
return
|
||||
picked_module.on_select()
|
||||
|
||||
@@ -592,6 +593,9 @@
|
||||
/obj/item/mod/control/proc/subtract_charge(amount)
|
||||
return core?.subtract_charge(amount) || FALSE
|
||||
|
||||
/obj/item/mod/control/proc/check_charge(amount)
|
||||
return core?.check_charge(amount) || FALSE
|
||||
|
||||
/obj/item/mod/control/proc/update_charge_alert()
|
||||
if(!wearer)
|
||||
return
|
||||
|
||||
@@ -38,6 +38,9 @@
|
||||
/obj/item/mod/core/proc/subtract_charge(amount)
|
||||
return FALSE
|
||||
|
||||
/obj/item/mod/core/proc/check_charge(amount)
|
||||
return FALSE
|
||||
|
||||
/obj/item/mod/core/proc/update_charge_alert()
|
||||
mod.wearer.clear_alert(ALERT_MODSUIT_CHARGE)
|
||||
|
||||
@@ -62,6 +65,9 @@
|
||||
/obj/item/mod/core/infinite/subtract_charge(amount)
|
||||
return TRUE
|
||||
|
||||
/obj/item/mod/core/infinite/check_charge(amount)
|
||||
return TRUE
|
||||
|
||||
/obj/item/mod/core/standard
|
||||
name = "MOD standard core"
|
||||
icon_state = "mod-core-standard"
|
||||
@@ -120,6 +126,9 @@
|
||||
return FALSE
|
||||
return charge_source.use(amount, TRUE)
|
||||
|
||||
/obj/item/mod/core/standard/check_charge(amount)
|
||||
return charge_amount() >= amount
|
||||
|
||||
/obj/item/mod/core/standard/update_charge_alert()
|
||||
var/obj/item/stock_parts/cell/charge_source = charge_source()
|
||||
if(!charge_source)
|
||||
@@ -260,6 +269,9 @@
|
||||
charge_source.adjust_charge(-amount*charge_modifier)
|
||||
return TRUE
|
||||
|
||||
/obj/item/mod/core/ethereal/check_charge(amount)
|
||||
return charge_amount() >= amount*charge_modifier
|
||||
|
||||
/obj/item/mod/core/ethereal/update_charge_alert()
|
||||
var/obj/item/organ/internal/stomach/ethereal/charge_source = charge_source()
|
||||
if(charge_source)
|
||||
@@ -309,6 +321,9 @@
|
||||
charge = max(0, charge - amount)
|
||||
return TRUE
|
||||
|
||||
/obj/item/mod/core/plasma/check_charge(amount)
|
||||
return charge_amount() >= amount
|
||||
|
||||
/obj/item/mod/core/plasma/update_charge_alert()
|
||||
var/remaining_plasma = charge_amount() / max_charge_amount()
|
||||
switch(remaining_plasma)
|
||||
|
||||
@@ -1012,6 +1012,61 @@
|
||||
),
|
||||
)
|
||||
|
||||
/datum/mod_theme/ninja
|
||||
name = "ninja"
|
||||
desc = "A unique, vacuum-proof suit of nano-enhanced armor designed specifically for Spider Clan assassins."
|
||||
extended_desc = "A suit of nano-enhanced armor designed specifically for Spider Clan assassin-saboteurs. \
|
||||
This MODsuit employs the cutting edge of stealth and combat technology, built skin-tight but just as durable as \
|
||||
suits two or three times as thick. The nanomachines making up the outermost layer of armor \
|
||||
are capable of shifting their form into almost-microscopic radiating fins, rendering the suit itself \
|
||||
nigh-immune to even volcanic heat. It's entirely sealed against even the strongest acids, \
|
||||
and the myoelectric artifical muscles of the suit leave it light as a feather during movement."
|
||||
default_skin = "ninja"
|
||||
armor = list(MELEE = 40, BULLET = 30, LASER = 20, ENERGY = 30, BOMB = 30, BIO = 100, FIRE = 100, ACID = 100, WOUND = 10)
|
||||
resistance_flags = LAVA_PROOF|FIRE_PROOF|ACID_PROOF
|
||||
charge_drain = DEFAULT_CHARGE_DRAIN * 0.5
|
||||
siemens_coefficient = 0
|
||||
slowdown_inactive = 0.5
|
||||
slowdown_active = 0
|
||||
ui_theme = "hackerman"
|
||||
inbuilt_modules = list(/obj/item/mod/module/welding/camera_vision, /obj/item/mod/module/hacker, /obj/item/mod/module/weapon_recall, /obj/item/mod/module/adrenaline_boost, /obj/item/mod/module/energy_net)
|
||||
allowed_suit_storage = list(
|
||||
/obj/item/flashlight,
|
||||
/obj/item/tank/internals,
|
||||
/obj/item/gun,
|
||||
/obj/item/ammo_box,
|
||||
/obj/item/ammo_casing,
|
||||
/obj/item/melee/baton,
|
||||
/obj/item/restraints/handcuffs,
|
||||
)
|
||||
skins = list(
|
||||
"ninja" = list(
|
||||
HELMET_FLAGS = list(
|
||||
UNSEALED_LAYER = null,
|
||||
UNSEALED_CLOTHING = SNUG_FIT|THICKMATERIAL,
|
||||
SEALED_CLOTHING = STOPSPRESSUREDAMAGE,
|
||||
UNSEALED_INVISIBILITY = HIDEEARS|HIDEHAIR,
|
||||
SEALED_INVISIBILITY = HIDEFACIALHAIR|HIDEMASK|HIDEEYES|HIDEFACE|HIDESNOUT,
|
||||
SEALED_COVER = HEADCOVERSMOUTH|HEADCOVERSEYES|PEPPERPROOF,
|
||||
),
|
||||
CHESTPLATE_FLAGS = list(
|
||||
UNSEALED_CLOTHING = THICKMATERIAL,
|
||||
SEALED_CLOTHING = STOPSPRESSUREDAMAGE,
|
||||
SEALED_INVISIBILITY = HIDEJUMPSUIT,
|
||||
),
|
||||
GAUNTLETS_FLAGS = list(
|
||||
UNSEALED_CLOTHING = THICKMATERIAL,
|
||||
SEALED_CLOTHING = STOPSPRESSUREDAMAGE,
|
||||
CAN_OVERSLOT = TRUE,
|
||||
),
|
||||
BOOTS_FLAGS = list(
|
||||
UNSEALED_CLOTHING = THICKMATERIAL,
|
||||
SEALED_CLOTHING = STOPSPRESSUREDAMAGE,
|
||||
CAN_OVERSLOT = TRUE,
|
||||
),
|
||||
),
|
||||
)
|
||||
|
||||
/datum/mod_theme/prototype
|
||||
name = "prototype"
|
||||
desc = "A prototype modular suit powered by locomotives. While it is comfortable and has a big capacity, it remains very bulky and power-inefficient."
|
||||
|
||||
@@ -214,6 +214,18 @@
|
||||
/obj/item/mod/module/emp_shield/advanced,
|
||||
)
|
||||
|
||||
/obj/item/mod/control/pre_equipped/ninja
|
||||
theme = /datum/mod_theme/ninja
|
||||
applied_cell = /obj/item/stock_parts/cell/ninja
|
||||
initial_modules = list(
|
||||
/obj/item/mod/module/noslip,
|
||||
/obj/item/mod/module/stealth/ninja,
|
||||
/obj/item/mod/module/dispenser/ninja,
|
||||
/obj/item/mod/module/dna_lock/reinforced,
|
||||
/obj/item/mod/module/emp_shield/pulse,
|
||||
/obj/item/mod/module/status_readout,
|
||||
)
|
||||
|
||||
/obj/item/mod/control/pre_equipped/prototype
|
||||
theme = /datum/mod_theme/prototype
|
||||
req_access = list(ACCESS_AWAY_GENERAL)
|
||||
@@ -365,13 +377,18 @@
|
||||
)
|
||||
|
||||
//these exist for the prefs menu
|
||||
/obj/item/mod/control/pre_equipped/syndicate_empty
|
||||
/obj/item/mod/control/pre_equipped/empty
|
||||
|
||||
/obj/item/mod/control/pre_equipped/empty/syndicate
|
||||
theme = /datum/mod_theme/syndicate
|
||||
|
||||
/obj/item/mod/control/pre_equipped/syndicate_empty/honkerative
|
||||
/obj/item/mod/control/pre_equipped/empty/syndicate/honkerative
|
||||
applied_skin = "honkerative"
|
||||
|
||||
/obj/item/mod/control/pre_equipped/syndicate_empty/elite
|
||||
/obj/item/mod/control/pre_equipped/empty/elite
|
||||
theme = /datum/mod_theme/elite
|
||||
|
||||
INITIALIZE_IMMEDIATE(/obj/item/mod/control/pre_equipped/syndicate_empty)
|
||||
/obj/item/mod/control/pre_equipped/empty/ninja
|
||||
theme = /datum/mod_theme/ninja
|
||||
|
||||
INITIALIZE_IMMEDIATE(/obj/item/mod/control/pre_equipped/empty)
|
||||
|
||||
+14
-14
@@ -21,20 +21,20 @@
|
||||
data["modules"] = list()
|
||||
for(var/obj/item/mod/module/module as anything in modules)
|
||||
var/list/module_data = list(
|
||||
name = module.name,
|
||||
description = module.desc,
|
||||
module_type = module.module_type,
|
||||
active = module.active,
|
||||
pinned = module.pinned_to[user],
|
||||
idle_power = module.idle_power_cost,
|
||||
active_power = module.active_power_cost,
|
||||
use_power = module.use_power_cost,
|
||||
complexity = module.complexity,
|
||||
cooldown_time = module.cooldown_time,
|
||||
cooldown = round(COOLDOWN_TIMELEFT(module, cooldown_timer), 1 SECONDS),
|
||||
id = module.tgui_id,
|
||||
ref = REF(module),
|
||||
configuration_data = module.get_configuration()
|
||||
"module_name" = module.name,
|
||||
"description" = module.desc,
|
||||
"module_type" = module.module_type,
|
||||
"module_active" = module.active,
|
||||
"pinned" = module.pinned_to[user],
|
||||
"idle_power" = module.idle_power_cost,
|
||||
"active_power" = module.active_power_cost,
|
||||
"use_power" = module.use_power_cost,
|
||||
"module_complexity" = module.complexity,
|
||||
"cooldown_time" = module.cooldown_time,
|
||||
"cooldown" = round(COOLDOWN_TIMELEFT(module, cooldown_timer), 1 SECONDS),
|
||||
"id" = module.tgui_id,
|
||||
"ref" = REF(module),
|
||||
"configuration_data" = module.get_configuration()
|
||||
)
|
||||
module_data += module.add_ui_data()
|
||||
data["modules"] += list(module_data)
|
||||
|
||||
@@ -225,9 +225,7 @@
|
||||
|
||||
/// Checks if there is enough power in the suit
|
||||
/obj/item/mod/module/proc/check_power(amount)
|
||||
if(mod.get_charge() < amount)
|
||||
return FALSE
|
||||
return TRUE
|
||||
return mod.check_charge(amount)
|
||||
|
||||
/// Adds additional things to the MODsuit ui_data()
|
||||
/obj/item/mod/module/proc/add_ui_data()
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
immunity against extremities such as spot and arc welding, solar eclipses, and handheld flashlights."
|
||||
icon_state = "welding"
|
||||
complexity = 1
|
||||
incompatible_modules = list(/obj/item/mod/module/welding)
|
||||
incompatible_modules = list(/obj/item/mod/module/welding, /obj/item/mod/module/armor_booster)
|
||||
overlay_state_inactive = "module_welding"
|
||||
|
||||
/obj/item/mod/module/welding/on_suit_activation()
|
||||
@@ -168,9 +168,9 @@
|
||||
|
||||
/obj/item/mod/module/rad_protection/add_ui_data()
|
||||
. = ..()
|
||||
.["userradiated"] = mod.wearer ? HAS_TRAIT(mod.wearer, TRAIT_IRRADIATED) : 0
|
||||
.["usertoxins"] = mod.wearer ? mod.wearer.getToxLoss() : 0
|
||||
.["usermaxtoxins"] = mod.wearer ? mod.wearer.getMaxHealth() : 0
|
||||
.["userradiated"] = mod.wearer ? HAS_TRAIT(mod.wearer, TRAIT_IRRADIATED) : FALSE
|
||||
.["usertoxins"] = mod.wearer?.getToxLoss() || 0
|
||||
.["usermaxtoxins"] = mod.wearer?.getMaxHealth() || 0
|
||||
.["threatlevel"] = perceived_threat_level
|
||||
|
||||
/obj/item/mod/module/rad_protection/proc/on_pre_potential_irradiation(datum/source, datum/radiation_pulse_information/pulse_information, insulation_to_target)
|
||||
|
||||
@@ -178,7 +178,7 @@
|
||||
icon_state = "bloon"
|
||||
module_type = MODULE_USABLE
|
||||
complexity = 1
|
||||
use_power_cost = DEFAULT_CHARGE_DRAIN*0.5
|
||||
use_power_cost = DEFAULT_CHARGE_DRAIN * 0.5
|
||||
incompatible_modules = list(/obj/item/mod/module/balloon)
|
||||
cooldown_time = 15 SECONDS
|
||||
|
||||
|
||||
@@ -25,12 +25,12 @@
|
||||
|
||||
/obj/item/mod/module/health_analyzer/add_ui_data()
|
||||
. = ..()
|
||||
.["userhealth"] = mod.wearer ? mod.wearer.health : 0
|
||||
.["usermaxhealth"] = mod.wearer ? mod.wearer.getMaxHealth() : 0
|
||||
.["userbrute"] = mod.wearer ? mod.wearer.getBruteLoss() : 0
|
||||
.["userburn"] = mod.wearer ? mod.wearer.getFireLoss() : 0
|
||||
.["usertoxin"] = mod.wearer ? mod.wearer.getToxLoss() : 0
|
||||
.["useroxy"] = mod.wearer ? mod.wearer.getOxyLoss() : 0
|
||||
.["userhealth"] = mod.wearer?.health || 0
|
||||
.["usermaxhealth"] = mod.wearer?.getMaxHealth() || 0
|
||||
.["userbrute"] = mod.wearer?.getBruteLoss() || 0
|
||||
.["userburn"] = mod.wearer?.getFireLoss() || 0
|
||||
.["usertoxin"] = mod.wearer?.getToxLoss() || 0
|
||||
.["useroxy"] = mod.wearer?.getOxyLoss() || 0
|
||||
|
||||
/obj/item/mod/module/health_analyzer/on_select_use(atom/target)
|
||||
. = ..()
|
||||
|
||||
@@ -0,0 +1,444 @@
|
||||
//Ninja modules for MODsuits
|
||||
|
||||
///Cloaking - Lowers the user's visibility, can be interrupted by being touched or attacked.
|
||||
/obj/item/mod/module/stealth
|
||||
name = "MOD prototype cloaking module"
|
||||
desc = "A complete retrofitting of the suit, this is a form of visual concealment tech employing esoteric technology \
|
||||
to bend light around the user, as well as mimetic materials to make the surface of the suit match the \
|
||||
surroundings based off sensor data. For some reason, this tech is rarely seen."
|
||||
icon_state = "cloak"
|
||||
module_type = MODULE_TOGGLE
|
||||
complexity = 4
|
||||
active_power_cost = DEFAULT_CHARGE_DRAIN * 2
|
||||
use_power_cost = DEFAULT_CHARGE_DRAIN * 10
|
||||
incompatible_modules = list(/obj/item/mod/module/stealth)
|
||||
cooldown_time = 5 SECONDS
|
||||
/// Whether or not the cloak turns off on bumping.
|
||||
var/bumpoff = TRUE
|
||||
/// The alpha applied when the cloak is on.
|
||||
var/stealth_alpha = 50
|
||||
|
||||
/obj/item/mod/module/stealth/on_activation()
|
||||
. = ..()
|
||||
if(!.)
|
||||
return
|
||||
if(bumpoff)
|
||||
RegisterSignal(mod.wearer, COMSIG_LIVING_MOB_BUMP, .proc/unstealth)
|
||||
RegisterSignal(mod.wearer, COMSIG_HUMAN_MELEE_UNARMED_ATTACK, .proc/on_unarmed_attack)
|
||||
RegisterSignal(mod.wearer, COMSIG_ATOM_BULLET_ACT, .proc/on_bullet_act)
|
||||
RegisterSignal(mod.wearer, list(COMSIG_MOB_ITEM_ATTACK, COMSIG_PARENT_ATTACKBY, COMSIG_ATOM_ATTACK_HAND, COMSIG_ATOM_HITBY, COMSIG_ATOM_HULK_ATTACK, COMSIG_ATOM_ATTACK_PAW, COMSIG_CARBON_CUFF_ATTEMPTED), .proc/unstealth)
|
||||
animate(mod.wearer, alpha = stealth_alpha, time = 1.5 SECONDS)
|
||||
drain_power(use_power_cost)
|
||||
|
||||
/obj/item/mod/module/stealth/on_deactivation(display_message = TRUE, deleting = FALSE)
|
||||
. = ..()
|
||||
if(!.)
|
||||
return
|
||||
if(bumpoff)
|
||||
UnregisterSignal(mod.wearer, COMSIG_LIVING_MOB_BUMP)
|
||||
UnregisterSignal(mod.wearer, list(COMSIG_HUMAN_MELEE_UNARMED_ATTACK, COMSIG_MOB_ITEM_ATTACK, COMSIG_PARENT_ATTACKBY, COMSIG_ATOM_ATTACK_HAND, COMSIG_ATOM_BULLET_ACT, COMSIG_ATOM_HITBY, COMSIG_ATOM_HULK_ATTACK, COMSIG_ATOM_ATTACK_PAW, COMSIG_CARBON_CUFF_ATTEMPTED))
|
||||
animate(mod.wearer, alpha = 255, time = 1.5 SECONDS)
|
||||
|
||||
/obj/item/mod/module/stealth/proc/unstealth(datum/source)
|
||||
SIGNAL_HANDLER
|
||||
|
||||
to_chat(mod.wearer, span_warning("[src] gets discharged from contact!"))
|
||||
do_sparks(2, TRUE, src)
|
||||
drain_power(use_power_cost)
|
||||
on_deactivation(display_message = TRUE, deleting = FALSE)
|
||||
|
||||
/obj/item/mod/module/stealth/proc/on_unarmed_attack(datum/source, atom/target)
|
||||
SIGNAL_HANDLER
|
||||
|
||||
if(!isliving(target))
|
||||
return
|
||||
unstealth(source)
|
||||
|
||||
/obj/item/mod/module/stealth/proc/on_bullet_act(datum/source, obj/projectile/projectile)
|
||||
SIGNAL_HANDLER
|
||||
|
||||
if(projectile.nodamage)
|
||||
return
|
||||
unstealth(source)
|
||||
|
||||
//Advanced Cloaking - Doesn't turf off on bump, less power drain, more stealthy.
|
||||
/obj/item/mod/module/stealth/ninja
|
||||
name = "MOD advanced cloaking module"
|
||||
desc = "The latest in stealth technology, this module is a definite upgrade over previous versions. \
|
||||
The field has been tuned to be even more responsive and fast-acting, with enough stability to \
|
||||
continue operation of the field even if the user bumps into others. \
|
||||
The power draw has been reduced drastically, making this perfect for activities like \
|
||||
standing near sentry turrets for extended periods of time."
|
||||
icon_state = "cloak_ninja"
|
||||
bumpoff = FALSE
|
||||
stealth_alpha = 20
|
||||
active_power_cost = DEFAULT_CHARGE_DRAIN
|
||||
use_power_cost = DEFAULT_CHARGE_DRAIN * 5
|
||||
cooldown_time = 3 SECONDS
|
||||
|
||||
///Camera Vision - Prevents flashes, blocks tracking.
|
||||
/obj/item/mod/module/welding/camera_vision
|
||||
name = "MOD camera vision module"
|
||||
desc = "A module installed into the suit's helmet. This specialized piece of technology is built for subterfuge, \
|
||||
replacing the standard visor with a nanotech display; capable of displaying specialized imagery at \
|
||||
just the right frequency to jam all known forms of camera tracking and facial recognition, \
|
||||
as well as automatically dimming incoming flashes of light to protect the user's eyes. Become the unseen."
|
||||
icon_state = "welding_camera"
|
||||
removable = FALSE
|
||||
complexity = 0
|
||||
overlay_state_inactive = null
|
||||
|
||||
/obj/item/mod/module/welding/camera_vision/on_suit_activation()
|
||||
. = ..()
|
||||
RegisterSignal(mod.wearer, COMSIG_LIVING_CAN_TRACK, .proc/can_track)
|
||||
|
||||
/obj/item/mod/module/welding/camera_vision/on_suit_deactivation(deleting = FALSE)
|
||||
. = ..()
|
||||
UnregisterSignal(mod.wearer, COMSIG_LIVING_CAN_TRACK)
|
||||
|
||||
/obj/item/mod/module/welding/camera_vision/proc/can_track(datum/source, mob/user)
|
||||
SIGNAL_HANDLER
|
||||
|
||||
return COMPONENT_CANT_TRACK
|
||||
|
||||
//Ninja Star Dispenser - Dispenses ninja stars.
|
||||
/obj/item/mod/module/dispenser/ninja
|
||||
name = "MOD ninja star dispenser module"
|
||||
desc = "This piece of Spider Clan technology can exploit known energy-matter equivalence principles, \
|
||||
using the nanites already hosted in the wearer's suit to transmute into monomolecular shuriken. \
|
||||
While these lack the intense bleeding edge of conventional throwing stars, \
|
||||
they have been set to electrify fleeing targets; and branded with the Spider Clan symbol."
|
||||
dispense_type = /obj/item/throwing_star/stamina/ninja
|
||||
cooldown_time = 0.5 SECONDS
|
||||
|
||||
///Hacker - This module hooks onto your right-clicks with empty hands and causes ninja actions.
|
||||
/obj/item/mod/module/hacker
|
||||
name = "MOD hacker module"
|
||||
desc = "Built for one purpose, electronic warfare, this module is built into the hands. \
|
||||
Using near-field communication alongside precise electro-stimulation of the wires in machines, \
|
||||
this decker's dream is normally used to pass through doors like a phantom. \
|
||||
It's also capable of non-precise electro-stimulation of an assassin-saboteur's opponents on disarming attacks."
|
||||
icon_state = "hacker"
|
||||
removable = FALSE
|
||||
incompatible_modules = list(/obj/item/mod/module/hacker)
|
||||
/// Minimum amount of power we can drain in a single drain action
|
||||
var/mindrain = 200
|
||||
/// Maximum amount of power we can drain in a single drain action
|
||||
var/maxdrain = 400
|
||||
/// Whether or not the communication console hack was used to summon another antagonist.
|
||||
var/communication_console_hack_success = FALSE
|
||||
/// How many times the module has been used to force open doors.
|
||||
var/door_hack_counter = 0
|
||||
|
||||
/obj/item/mod/module/hacker/on_suit_activation()
|
||||
RegisterSignal(mod.wearer, COMSIG_HUMAN_EARLY_UNARMED_ATTACK, .proc/hack)
|
||||
|
||||
/obj/item/mod/module/hacker/on_suit_deactivation(deleting = FALSE)
|
||||
UnregisterSignal(mod.wearer, COMSIG_HUMAN_EARLY_UNARMED_ATTACK)
|
||||
|
||||
/obj/item/mod/module/hacker/proc/hack(mob/living/carbon/human/source, atom/target, proximity, modifiers)
|
||||
SIGNAL_HANDLER
|
||||
|
||||
if(!LAZYACCESS(modifiers, RIGHT_CLICK) || !proximity)
|
||||
return NONE
|
||||
target.add_fingerprint(mod.wearer)
|
||||
return target.ninjadrain_act(mod.wearer, src)
|
||||
|
||||
/obj/item/mod/module/hacker/proc/charge_message(atom/drained_atom, drain_amount)
|
||||
if(drain_amount)
|
||||
to_chat(mod.wearer, span_notice("Gained <B>[drain_amount]</B> units of energy from [drained_atom]."))
|
||||
else
|
||||
to_chat(mod.wearer, span_warning("[drained_atom] has run dry of energy, you must find another source!"))
|
||||
|
||||
///Weapon Recall - Teleports your katana to you, prevents gun use.
|
||||
/obj/item/mod/module/weapon_recall
|
||||
name = "MOD weapon recall module"
|
||||
desc = "The cornerstone of a clanmember's life as a blademaster, and a module symbolizing their eternal bond with their weapon. \
|
||||
This hooks to the micro bluespace drive inside an energy katana's handle, capable of recalling it to the user's \
|
||||
skilled hands wherever they are. However, those that make such a bond with their weapon are cursed to \
|
||||
fusing their existence with acts of combat, with a singular purpose; Cutting Down Their Opponent. \
|
||||
Their hand a hand that is cutting, their body a body that is cutting, their mind, a mind that is cutting. \
|
||||
Ranged weapons are forbidden."
|
||||
icon_state = "recall"
|
||||
removable = FALSE
|
||||
module_type = MODULE_USABLE
|
||||
use_power_cost = DEFAULT_CHARGE_DRAIN * 2
|
||||
incompatible_modules = list(/obj/item/mod/module/weapon_recall)
|
||||
cooldown_time = 0.5 SECONDS
|
||||
/// The item linked to the module that will get recalled.
|
||||
var/obj/item/linked_weapon
|
||||
/// The accepted typepath we can link to.
|
||||
var/accepted_type = /obj/item/energy_katana
|
||||
|
||||
/obj/item/mod/module/weapon_recall/on_suit_activation()
|
||||
ADD_TRAIT(mod.wearer, TRAIT_NOGUNS, MOD_TRAIT)
|
||||
|
||||
/obj/item/mod/module/weapon_recall/on_suit_deactivation(deleting = FALSE)
|
||||
REMOVE_TRAIT(mod.wearer, TRAIT_NOGUNS, MOD_TRAIT)
|
||||
|
||||
/obj/item/mod/module/weapon_recall/on_use()
|
||||
. = ..()
|
||||
if(!.)
|
||||
return
|
||||
if(!linked_weapon)
|
||||
var/obj/item/weapon_to_link = mod.wearer.is_holding_item_of_type(accepted_type)
|
||||
if(!weapon_to_link)
|
||||
balloon_alert(mod.wearer, "can't locate weapon!")
|
||||
return
|
||||
set_weapon(weapon_to_link)
|
||||
balloon_alert(mod.wearer, "[linked_weapon.name] linked")
|
||||
return
|
||||
if(linked_weapon in mod.wearer.get_all_contents())
|
||||
balloon_alert(mod.wearer, "already on self!")
|
||||
return
|
||||
var/distance = get_dist(mod.wearer, linked_weapon)
|
||||
var/in_view = (linked_weapon in view(mod.wearer))
|
||||
if(!in_view && !drain_power(use_power_cost * distance))
|
||||
balloon_alert(mod.wearer, "not enough charge!")
|
||||
return
|
||||
linked_weapon.forceMove(linked_weapon.drop_location())
|
||||
if(in_view)
|
||||
do_sparks(5, FALSE, linked_weapon)
|
||||
mod.wearer.visible_message(span_danger("[linked_weapon] flies towards [mod.wearer]!"),span_warning("You hold out your hand and [linked_weapon] flies towards you!"))
|
||||
linked_weapon.throw_at(mod.wearer, distance+1, linked_weapon.throw_speed, mod.wearer)
|
||||
else
|
||||
recall_weapon()
|
||||
|
||||
/obj/item/mod/module/weapon_recall/proc/set_weapon(obj/item/weapon)
|
||||
linked_weapon = weapon
|
||||
RegisterSignal(linked_weapon, COMSIG_MOVABLE_IMPACT, .proc/catch_weapon)
|
||||
RegisterSignal(linked_weapon, COMSIG_PARENT_QDELETING, .proc/deleted_weapon)
|
||||
|
||||
/obj/item/mod/module/weapon_recall/proc/recall_weapon(caught = FALSE)
|
||||
linked_weapon.forceMove(get_turf(src))
|
||||
var/alert = ""
|
||||
if(mod.wearer.put_in_hands(linked_weapon))
|
||||
alert = "[linked_weapon.name] teleports to your hand"
|
||||
else if(mod.wearer.equip_to_slot_if_possible(linked_weapon, ITEM_SLOT_BELT, disable_warning = TRUE))
|
||||
alert = "[linked_weapon.name] sheathes itself in your belt"
|
||||
else
|
||||
alert = "[linked_weapon.name] teleports under you"
|
||||
if(caught)
|
||||
if(mod.wearer.is_holding(linked_weapon))
|
||||
alert = "you catch [linked_weapon.name]"
|
||||
else
|
||||
alert = "[linked_weapon.name] lands under you"
|
||||
else
|
||||
do_sparks(5, FALSE, linked_weapon)
|
||||
if(alert)
|
||||
balloon_alert(mod.wearer, alert)
|
||||
|
||||
/obj/item/mod/module/weapon_recall/proc/catch_weapon(obj/item/source, atom/hit_atom, datum/thrownthing/thrownthing)
|
||||
SIGNAL_HANDLER
|
||||
|
||||
if(!mod)
|
||||
return
|
||||
if(hit_atom != mod.wearer)
|
||||
return
|
||||
INVOKE_ASYNC(src, .proc/recall_weapon, TRUE)
|
||||
return COMPONENT_MOVABLE_IMPACT_NEVERMIND
|
||||
|
||||
/obj/item/mod/module/weapon_recall/proc/deleted_weapon(obj/item/source)
|
||||
SIGNAL_HANDLER
|
||||
|
||||
linked_weapon = null
|
||||
|
||||
//Reinforced DNA Lock - Gibs if wrong DNA, emp-proof.
|
||||
/obj/item/mod/module/dna_lock/reinforced
|
||||
name = "MOD reinforced DNA lock module"
|
||||
desc = "A module which engages with the various locks and seals tied to the suit's systems, \
|
||||
enabling it to only be worn by someone corresponding with the user's exact DNA profile. \
|
||||
Due to utilizing a skintight dampening shield, this one is entirely sealed against electromagnetic interference; \
|
||||
it also dutifully protects the secrets of the Spider Clan from unknowing outsiders."
|
||||
icon_state = "dnalock_ninja"
|
||||
use_power_cost = DEFAULT_CHARGE_DRAIN * 0.5
|
||||
|
||||
/obj/item/mod/module/dna_lock/reinforced/on_mod_activation(datum/source, mob/user)
|
||||
. = ..()
|
||||
if(. != MOD_CANCEL_ACTIVATE || !isliving(user))
|
||||
return
|
||||
var/mob/living/living_user = user
|
||||
to_chat(living_user, span_danger("<B>fATaL EERRoR</B>: 382200-*#00CODE <B>RED</B>\nUNAUTHORIZED USE DETECteD\nCoMMENCING SUB-R0UTIN3 13...\nTERMInATING U-U-USER..."))
|
||||
living_user.gib()
|
||||
|
||||
/obj/item/mod/module/dna_lock/reinforced/on_emp(datum/source, severity)
|
||||
return
|
||||
|
||||
//EMP Pulse - In addition to normal shielding, can also launch an EMP itself.
|
||||
/obj/item/mod/module/emp_shield/pulse
|
||||
name = "MOD EMP pulse module"
|
||||
desc = "This module is normally set to activate on dramatic gestures, inverting and expanding the suit's \
|
||||
EMP dampening shield to cause an electromagnetic pulse of its own. While this won't interfere with the wearer, \
|
||||
it will piss off everyone around them."
|
||||
icon_state = "emp_pulse"
|
||||
module_type = MODULE_USABLE
|
||||
use_power_cost = DEFAULT_CHARGE_DRAIN * 10
|
||||
cooldown_time = 8 SECONDS
|
||||
|
||||
/obj/item/mod/module/emp_shield/pulse/on_use()
|
||||
. = ..()
|
||||
if(!.)
|
||||
return
|
||||
playsound(src, 'sound/effects/empulse.ogg', 60, TRUE)
|
||||
empulse(src, heavy_range = 4, light_range = 6)
|
||||
drain_power(use_power_cost)
|
||||
|
||||
///Status Readout - Puts a lot of information including health, nutrition, fingerprints, temperature to the suit TGUI.
|
||||
/obj/item/mod/module/status_readout
|
||||
name = "MOD status readout module"
|
||||
desc = "A once-common module, this technology went unfortunately out of fashion; \
|
||||
and right into the arachnid grip of the Spider Clan. This hooks into the suit's spine, \
|
||||
capable of capturing and displaying all possible biometric data of the wearer; sleep, nutrition, fitness, fingerprints, \
|
||||
and even useful information such as their overall health and wellness."
|
||||
icon_state = "status"
|
||||
complexity = 1
|
||||
use_power_cost = DEFAULT_CHARGE_DRAIN * 0.1
|
||||
incompatible_modules = list(/obj/item/mod/module/status_readout)
|
||||
tgui_id = "status_readout"
|
||||
|
||||
/obj/item/mod/module/status_readout/add_ui_data()
|
||||
. = ..()
|
||||
.["statustime"] = station_time_timestamp()
|
||||
.["statusid"] = GLOB.round_id
|
||||
.["statushealth"] = mod.wearer?.health || 0
|
||||
.["statusmaxhealth"] = mod.wearer?.getMaxHealth() || 0
|
||||
.["statusbrute"] = mod.wearer?.getBruteLoss() || 0
|
||||
.["statusburn"] = mod.wearer?.getFireLoss() || 0
|
||||
.["statustoxin"] = mod.wearer?.getToxLoss() || 0
|
||||
.["statusoxy"] = mod.wearer?.getOxyLoss() || 0
|
||||
.["statustemp"] = mod.wearer?.bodytemperature || 0
|
||||
.["statusnutrition"] = mod.wearer?.nutrition || 0
|
||||
.["statusfingerprints"] = mod.wearer ? md5(mod.wearer.dna.unique_identity) : null
|
||||
.["statusdna"] = mod.wearer?.dna.unique_enzymes
|
||||
.["statusviruses"] = null
|
||||
if(!length(mod.wearer?.diseases))
|
||||
return
|
||||
var/list/viruses = list()
|
||||
for(var/datum/disease/virus as anything in mod.wearer.diseases)
|
||||
var/list/virus_data = list()
|
||||
virus_data["name"] = virus.name
|
||||
virus_data["type"] = virus.spread_text
|
||||
virus_data["stage"] = virus.stage
|
||||
virus_data["maxstage"] = virus.max_stages
|
||||
virus_data["cure"] = virus.cure_text
|
||||
viruses += list(virus_data)
|
||||
.["statusviruses"] = viruses
|
||||
|
||||
///Energy Net - Ensnares enemies in a net that prevents movement.
|
||||
/obj/item/mod/module/energy_net
|
||||
name = "MOD energy net module"
|
||||
desc = "A custom-built net-thrower. While conventional implementations of this capturing device \
|
||||
tilize monomolecular fibers or cutting razorwire, this uses hardlight technology to deploy a \
|
||||
trapping field capable of immobilizing even the strongest opponents."
|
||||
icon_state = "energy_net"
|
||||
removable = FALSE
|
||||
module_type = MODULE_ACTIVE
|
||||
use_power_cost = DEFAULT_CHARGE_DRAIN * 6
|
||||
incompatible_modules = list(/obj/item/mod/module/energy_net)
|
||||
cooldown_time = 1.5 SECONDS
|
||||
|
||||
/obj/item/mod/module/energy_net/on_select_use(atom/target)
|
||||
. = ..()
|
||||
if(!.)
|
||||
return
|
||||
if(!isliving(target))
|
||||
balloon_alert(mod.wearer, "invalid target!")
|
||||
return
|
||||
var/mob/living/living_target = target
|
||||
if(locate(/obj/structure/energy_net) in get_turf(living_target))
|
||||
balloon_alert(mod.wearer, "already trapped!")
|
||||
return
|
||||
for(var/turf/between_turf as anything in get_line(get_turf(mod.wearer), get_turf(living_target)))
|
||||
if(between_turf.density)
|
||||
balloon_alert(mod.wearer, "not through obstacles!")
|
||||
return
|
||||
if(IS_SPACE_NINJA(mod.wearer))
|
||||
mod.wearer.say("Get over here!", forced = type)
|
||||
mod.wearer.Beam(living_target, "n_beam", time = 1.5 SECONDS)
|
||||
var/obj/structure/energy_net/net = new /obj/structure/energy_net(living_target.drop_location())
|
||||
net.affected_mob = living_target
|
||||
mod.wearer.visible_message(span_danger("[mod.wearer] caught [living_target] with an energy net!"), span_notice("You caught [living_target] with an energy net!"))
|
||||
if(living_target.buckled)
|
||||
living_target.buckled.unbuckle_mob(living_target, force = TRUE)
|
||||
net.buckle_mob(living_target, force = TRUE)
|
||||
drain_power(use_power_cost)
|
||||
|
||||
///Adrenaline Boost - Stops all stuns the ninja is affected with, increases his speed.
|
||||
/obj/item/mod/module/adrenaline_boost
|
||||
name = "MOD adrenaline boost module"
|
||||
desc = "The secrets of the Spider Clan are many. The exact specifications of their suits, \
|
||||
the techniques they use to make every singular cut make their enemies weep with admiration, \
|
||||
but one of their greatest mysteries is the chemical compound their assassin-saboteurs use in times of need. \
|
||||
It's capable of clearing any fatigue whatsoever from the user, any immobilizing effect, and can even \
|
||||
cure total paralysis. All that's known is that the fluid requires radiation to properly 'cook,' \
|
||||
so this module demands radium to be refilled with."
|
||||
icon_state = "adrenaline_boost"
|
||||
removable = FALSE
|
||||
module_type = MODULE_USABLE
|
||||
incompatible_modules = list(/obj/item/mod/module/adrenaline_boost)
|
||||
cooldown_time = 12 SECONDS
|
||||
/// What reagent we need to refill?
|
||||
var/reagent_required = /datum/reagent/uranium/radium
|
||||
/// How much of a reagent we need to refill the boost.
|
||||
var/reagent_required_amount = 20
|
||||
|
||||
/obj/item/mod/module/adrenaline_boost/Initialize(mapload)
|
||||
. = ..()
|
||||
create_reagents(reagent_required_amount)
|
||||
reagents.add_reagent(reagent_required, reagent_required_amount)
|
||||
|
||||
/obj/item/mod/module/adrenaline_boost/on_use()
|
||||
if(!reagents.has_reagent(reagent_required, reagent_required_amount))
|
||||
balloon_alert(mod.wearer, "no charge!")
|
||||
return
|
||||
. = ..()
|
||||
if(!.)
|
||||
return
|
||||
if(IS_SPACE_NINJA(mod.wearer))
|
||||
mod.wearer.say(pick_list_replacements(NINJA_FILE, "lines"), forced = type)
|
||||
to_chat(mod.wearer, span_notice("You have used the adrenaline boost."))
|
||||
mod.wearer.SetUnconscious(0)
|
||||
mod.wearer.SetStun(0)
|
||||
mod.wearer.SetKnockdown(0)
|
||||
mod.wearer.SetImmobilized(0)
|
||||
mod.wearer.SetParalyzed(0)
|
||||
mod.wearer.adjustStaminaLoss(-200)
|
||||
mod.wearer.remove_status_effect(/datum/status_effect/speech/stutter)
|
||||
mod.wearer.reagents.add_reagent(/datum/reagent/medicine/stimulants, 5)
|
||||
reagents.remove_reagent(reagent_required, reagents.total_volume * 0.75)
|
||||
addtimer(CALLBACK(src, .proc/boost_aftereffects, mod.wearer), 7 SECONDS)
|
||||
|
||||
/obj/item/mod/module/adrenaline_boost/on_install()
|
||||
RegisterSignal(mod, COMSIG_PARENT_ATTACKBY, .proc/on_attackby)
|
||||
|
||||
/obj/item/mod/module/adrenaline_boost/on_uninstall(deleting)
|
||||
UnregisterSignal(mod, COMSIG_PARENT_ATTACKBY)
|
||||
|
||||
/obj/item/mod/module/adrenaline_boost/attackby(obj/item/attacking_item, mob/user, params)
|
||||
if(charge_boost(attacking_item, user))
|
||||
return TRUE
|
||||
return ..()
|
||||
|
||||
/obj/item/mod/module/adrenaline_boost/proc/on_attackby(datum/source, obj/item/attacking_item, mob/user)
|
||||
SIGNAL_HANDLER
|
||||
|
||||
if(charge_boost(attacking_item, user))
|
||||
return COMPONENT_NO_AFTERATTACK
|
||||
return NONE
|
||||
|
||||
/obj/item/mod/module/adrenaline_boost/proc/charge_boost(obj/item/attacking_item, mob/user)
|
||||
if(!attacking_item.is_open_container())
|
||||
return FALSE
|
||||
if(reagents.has_reagent(reagent_required, reagent_required_amount))
|
||||
balloon_alert(mod.wearer, "already charged!")
|
||||
return FALSE
|
||||
if(!attacking_item.reagents.trans_id_to(src, reagent_required, reagent_required_amount))
|
||||
return FALSE
|
||||
balloon_alert(mod.wearer, "charge [reagents.has_reagent(reagent_required, reagent_required_amount) ? "fully" : "partially"] reloaded")
|
||||
return TRUE
|
||||
|
||||
/obj/item/mod/module/adrenaline_boost/proc/boost_aftereffects(mob/affected_mob)
|
||||
if(!affected_mob)
|
||||
return
|
||||
reagents.trans_to(affected_mob, reagents.total_volume)
|
||||
to_chat(affected_mob, span_danger("You are beginning to feel the after-effect of the injection."))
|
||||
@@ -1,80 +1,5 @@
|
||||
//Security modules for MODsuits
|
||||
|
||||
///Cloaking - Lowers the user's visibility, can be interrupted by being touched or attacked.
|
||||
/obj/item/mod/module/stealth
|
||||
name = "MOD prototype cloaking module"
|
||||
desc = "A complete retrofitting of the suit, this is a form of visual concealment tech employing esoteric technology \
|
||||
to bend light around the user, as well as mimetic materials to make the surface of the suit match the \
|
||||
surroundings based off sensor data. For some reason, this tech is rarely seen."
|
||||
icon_state = "cloak"
|
||||
module_type = MODULE_TOGGLE
|
||||
complexity = 4
|
||||
active_power_cost = DEFAULT_CHARGE_DRAIN * 2
|
||||
use_power_cost = DEFAULT_CHARGE_DRAIN * 10
|
||||
incompatible_modules = list(/obj/item/mod/module/stealth)
|
||||
cooldown_time = 5 SECONDS
|
||||
/// Whether or not the cloak turns off on bumping.
|
||||
var/bumpoff = TRUE
|
||||
/// The alpha applied when the cloak is on.
|
||||
var/stealth_alpha = 50
|
||||
|
||||
/obj/item/mod/module/stealth/on_activation()
|
||||
. = ..()
|
||||
if(!.)
|
||||
return
|
||||
if(bumpoff)
|
||||
RegisterSignal(mod.wearer, COMSIG_LIVING_MOB_BUMP, .proc/unstealth)
|
||||
RegisterSignal(mod.wearer, COMSIG_HUMAN_MELEE_UNARMED_ATTACK, .proc/on_unarmed_attack)
|
||||
RegisterSignal(mod.wearer, COMSIG_ATOM_BULLET_ACT, .proc/on_bullet_act)
|
||||
RegisterSignal(mod.wearer, list(COMSIG_ITEM_ATTACK, COMSIG_PARENT_ATTACKBY, COMSIG_ATOM_ATTACK_HAND, COMSIG_ATOM_HITBY, COMSIG_ATOM_HULK_ATTACK, COMSIG_ATOM_ATTACK_PAW, COMSIG_CARBON_CUFF_ATTEMPTED), .proc/unstealth)
|
||||
animate(mod.wearer, alpha = stealth_alpha, time = 1.5 SECONDS)
|
||||
drain_power(use_power_cost)
|
||||
|
||||
/obj/item/mod/module/stealth/on_deactivation(display_message = TRUE, deleting = FALSE)
|
||||
. = ..()
|
||||
if(!.)
|
||||
return
|
||||
if(bumpoff)
|
||||
UnregisterSignal(mod.wearer, COMSIG_LIVING_MOB_BUMP)
|
||||
UnregisterSignal(mod.wearer, list(COMSIG_HUMAN_MELEE_UNARMED_ATTACK, COMSIG_ITEM_ATTACK, COMSIG_PARENT_ATTACKBY, COMSIG_ATOM_ATTACK_HAND, COMSIG_ATOM_BULLET_ACT, COMSIG_ATOM_HITBY, COMSIG_ATOM_HULK_ATTACK, COMSIG_ATOM_ATTACK_PAW, COMSIG_CARBON_CUFF_ATTEMPTED))
|
||||
animate(mod.wearer, alpha = 255, time = 1.5 SECONDS)
|
||||
|
||||
/obj/item/mod/module/stealth/proc/unstealth(datum/source)
|
||||
SIGNAL_HANDLER
|
||||
|
||||
to_chat(mod.wearer, span_warning("[src] gets discharged from contact!"))
|
||||
do_sparks(2, TRUE, src)
|
||||
drain_power(use_power_cost)
|
||||
on_deactivation(display_message = TRUE, deleting = FALSE)
|
||||
|
||||
/obj/item/mod/module/stealth/proc/on_unarmed_attack(datum/source, atom/target)
|
||||
SIGNAL_HANDLER
|
||||
|
||||
if(!isliving(target))
|
||||
return
|
||||
unstealth(source)
|
||||
|
||||
/obj/item/mod/module/stealth/proc/on_bullet_act(datum/source, obj/projectile/projectile)
|
||||
SIGNAL_HANDLER
|
||||
|
||||
if(projectile.nodamage)
|
||||
return
|
||||
unstealth(source)
|
||||
|
||||
/obj/item/mod/module/stealth/ninja
|
||||
name = "MOD advanced cloaking module"
|
||||
desc = "The latest in stealth technology, this module is a definite upgrade over previous versions. \
|
||||
The field has been tuned to be even more responsive and fast-acting, with enough stability to \
|
||||
continue operation of the field even if the user bumps into others. \
|
||||
The power draw has been reduced drastically, making this perfect for activities like \
|
||||
standing near sentry turrets for extended periods of time."
|
||||
icon_state = "cloak_ninja"
|
||||
bumpoff = FALSE
|
||||
stealth_alpha = 20
|
||||
active_power_cost = DEFAULT_CHARGE_DRAIN
|
||||
use_power_cost = DEFAULT_CHARGE_DRAIN * 5
|
||||
cooldown_time = 3 SECONDS
|
||||
|
||||
///Magnetic Harness - Automatically puts guns in your suit storage when you drop them.
|
||||
/obj/item/mod/module/magnetic_harness
|
||||
name = "MOD magnetic harness module"
|
||||
|
||||
Reference in New Issue
Block a user