mirror of
https://github.com/Aurorastation/Aurora.3.git
synced 2026-08-27 06:54:18 +01:00
Hardsuit interface overhaul (#22403)
**Summary** Converts hardsuit NanoUI to TGUI and overhauls much of the associated UI and module code. The conversion alone is what necessitated quite a bit of cleanup of our 11-year-old hardsuit code, for which I leaned heavily upon tg's implementation of MODsuits. Therefore, this is a PARTIAL (???) port of both https://github.com/tgstation/tgstation/pull/59109 and https://github.com/tgstation/tgstation/pull/77022. While a lot of wonderful code and UI design was ported 1:1 (for which I am grateful!), our hardsuits are still NOT MODsuits. Most of our back-end remains the same. Fixes https://github.com/Aurorastation/Aurora.3/issues/22071 changes: - refactor: "Migrates Hardsuit NanoUI to TGUI." - refactor: "Updates Hardsuit module type definitions, configuration data, many misc other functions for the purpose of the UI refactor (general utility and readability improvements)." - balance: "Hardsuits now passively consume a small amount of energy while online, even when retracted." - balance: "Hardsuit boots can no longer be retracted without also retracting the chest piece first." - balance: "Mounted hardsuit storage module max space increased from 9 to 14." - balance: "Plasma cutter (standalone and mounted) damage increased and range decreased by 50% each." - soundadd: "Adds several new sounds for hardsuit use (attribution located w/ files)." - code_imp: "Makes power_wattage_readable() a global proc and adds power_joules_readable()." - code_imp: "Lots of misc DMdoc updates." - bugfix: "Synthetic Charging Stations now charge hardsuit power cells as intended." **Old UI** <img width="804" height="1321" alt="Screenshot 2026-05-04 135705" src="https://github.com/user-attachments/assets/f01957a0-7cec-4fcc-b862-c9dfde0dcc43" /> **New UI** <img width="998" height="782" alt="Screenshot 2026-05-04 174658" src="https://github.com/user-attachments/assets/ad402902-d489-435a-9c16-82150ed82618" /> ### Asset Licenses The following assets that **have not** been created by myself are included in this PR: | Path | Original Author | License | | --- | --- | --- | | icons/mob/rig_modules.dmi (mounted-plasmacutter)| [Ghostsheet](https://github.com/ghostsheet) | CC-BY-SA | --------- Signed-off-by: Batrachophreno <Batrochophreno@gmail.com> Co-authored-by: VMSolidus <evilexecutive@gmail.com>
This commit is contained in:
co-authored by
VMSolidus
parent
155944d1d0
commit
374e220be6
@@ -1,7 +0,0 @@
|
||||
#define MODULE_GENERAL 1
|
||||
#define MODULE_LIGHT_COMBAT 2
|
||||
#define MODULE_HEAVY_COMBAT 4
|
||||
#define MODULE_UTILITY 8
|
||||
#define MODULE_MEDICAL 16
|
||||
#define MODULE_SPECIAL 32
|
||||
#define MODULE_VAURCA 64
|
||||
@@ -20,7 +20,7 @@
|
||||
/obj/item/rig_module/grenade_launcher
|
||||
name = "mounted grenade launcher"
|
||||
desc = "A shoulder-mounted micro-explosive dispenser."
|
||||
selectable = TRUE
|
||||
module_type = MODULETYPE_USABLE_ACTIVE
|
||||
icon_state = "grenade"
|
||||
|
||||
interface_name = "integrated grenade launcher"
|
||||
@@ -78,7 +78,7 @@
|
||||
return FALSE
|
||||
|
||||
if(charge.charges <= 0)
|
||||
to_chat(user, SPAN_WARNING("Insufficient grenades!"))
|
||||
balloon_alert(user, "insufficient grenades!")
|
||||
return FALSE
|
||||
|
||||
charge.charges--
|
||||
@@ -91,7 +91,6 @@
|
||||
/obj/item/rig_module/grenade_launcher/frag
|
||||
name = "mounted frag grenade launcher"
|
||||
desc = "A shoulder-mounted fragmentation explosives dispenser."
|
||||
selectable = TRUE
|
||||
icon_state = "grenade"
|
||||
|
||||
interface_name = "integrated frag grenade launcher"
|
||||
@@ -114,8 +113,7 @@
|
||||
/obj/item/rig_module/mounted
|
||||
name = "mounted laser cannon"
|
||||
desc = "A shoulder-mounted battery-powered laser cannon mount."
|
||||
selectable = TRUE
|
||||
usable = TRUE
|
||||
module_type = MODULETYPE_USABLE_ACTIVE
|
||||
module_cooldown = 0
|
||||
icon_state = "lcannon"
|
||||
|
||||
@@ -160,6 +158,8 @@
|
||||
construction_cost= list(DEFAULT_WALL_MATERIAL = 7000, MATERIAL_GLASS = 2250, MATERIAL_URANIUM = 3250, MATERIAL_GOLD = 2500)
|
||||
construction_time = 300
|
||||
|
||||
suit_overlay_active = "mounted-lascannon"
|
||||
|
||||
interface_name = "mounted energy gun"
|
||||
interface_desc = "A forearm-mounted suit-powered energy gun."
|
||||
|
||||
@@ -174,10 +174,7 @@
|
||||
construction_cost = list(DEFAULT_WALL_MATERIAL = 7000, MATERIAL_GLASS = 5250)
|
||||
construction_time = 300
|
||||
|
||||
usable = FALSE
|
||||
|
||||
suit_overlay_active = "mounted-taser"
|
||||
suit_overlay_inactive = "mounted-taser"
|
||||
|
||||
interface_name = "mounted taser"
|
||||
interface_desc = "A shoulder-mounted cell-powered taser."
|
||||
@@ -191,6 +188,8 @@
|
||||
desc = "A shoulder-mounted battery-powered pulse rifle mount."
|
||||
icon_state = "pulse"
|
||||
|
||||
suit_overlay_active = "mounted-ion"
|
||||
|
||||
interface_name = "mounted pulse rifle"
|
||||
interface_desc = "A shoulder-mounted cell-powered pulse rifle."
|
||||
|
||||
@@ -212,6 +211,8 @@
|
||||
desc = "A forearm-mounted suit-powered ballistic submachine gun."
|
||||
icon_state = "smg"
|
||||
|
||||
suit_overlay_active = "mounted-ion"
|
||||
|
||||
interface_name = "mounted submachine gun"
|
||||
interface_desc = "A forearm-mounted suit-powered ballistic submachine gun."
|
||||
|
||||
@@ -222,6 +223,8 @@
|
||||
desc = "A forearm-mounted suit-powered xray laser gun."
|
||||
icon_state = "xray"
|
||||
|
||||
suit_overlay_active = "mounted-ion"
|
||||
|
||||
interface_name = "mounted xray laser gun"
|
||||
interface_desc = "A forearm-mounted suit-powered xray laser gun."
|
||||
|
||||
@@ -232,6 +235,8 @@
|
||||
desc = "A shoulder-mounted battery-powered ion rifle mount."
|
||||
icon_state = "ion"
|
||||
|
||||
suit_overlay_active = "mounted-ion"
|
||||
|
||||
interface_name = "mounted ion rifle"
|
||||
interface_desc = "A shoulder-mounted cell-powered ion rifle."
|
||||
|
||||
@@ -242,6 +247,8 @@
|
||||
desc = "A shoulder-mounted battery-powered tesla carbine mount."
|
||||
icon_state = "tesla"
|
||||
|
||||
suit_overlay_active = "mounted-ion"
|
||||
|
||||
interface_name = "mounted tesla carbine"
|
||||
interface_desc = "A shoulder-mounted cell-powered tesla carbine."
|
||||
|
||||
@@ -249,25 +256,44 @@
|
||||
|
||||
/obj/item/rig_module/mounted/plasmacutter
|
||||
name = "hardsuit plasma cutter"
|
||||
desc = "A forearm mounted kinetic accelerator"
|
||||
desc = "A forearm-mounted plasma arc cutter."
|
||||
icon_state = "plasmacutter"
|
||||
interface_name = "plasma cutter"
|
||||
interface_desc = "A self-sustaining plasma arc capable of cutting through walls."
|
||||
suit_overlay_active = "plasmacutter"
|
||||
suit_overlay_inactive = "plasmacutter"
|
||||
suit_overlay_active = "mounted-plasmacutter"
|
||||
construction_cost = list(MATERIAL_GLASS = 5250, DEFAULT_WALL_MATERIAL = 30000, MATERIAL_SILVER = 5250, MATERIAL_PHORON = 7250)
|
||||
activates_on_touch = TRUE
|
||||
construction_time = 300
|
||||
use_power_cost = 15
|
||||
|
||||
category = MODULE_UTILITY
|
||||
|
||||
gun_type = /obj/item/gun/energy/plasmacutter/mounted
|
||||
|
||||
/// Snowflake; this is a tool more than a gun, so it has special adjacency behaviors.
|
||||
/obj/item/rig_module/mounted/plasmacutter/engage(atom/target, mob/user)
|
||||
if(!check_can_use(user))
|
||||
return FALSE
|
||||
|
||||
if(!confined_use && !isturf(user.loc))
|
||||
to_chat(user, SPAN_DANGER("You cannot use the suit in a confined space."))
|
||||
return FALSE
|
||||
|
||||
if(target)
|
||||
// Don't prevent the player from trying to shoot someone who is up in their face if needs be.
|
||||
if(isliving(target) || !target.Adjacent(user))
|
||||
gun.Fire(target, user)
|
||||
else
|
||||
target.attackby(gun, user)
|
||||
return TRUE
|
||||
|
||||
/obj/item/rig_module/mounted/thermalldrill
|
||||
name = "hardsuit thermal drill"
|
||||
desc = "An incredibly lethal looking thermal drill."
|
||||
icon_state = "thermaldrill"
|
||||
interface_name = "thermal drill"
|
||||
interface_desc = "A potent drill that can pierce rock walls over long distances."
|
||||
use_power_cost = 20
|
||||
|
||||
gun_type = /obj/item/gun/energy/vaurca/thermaldrill/mounted
|
||||
|
||||
@@ -279,20 +305,18 @@
|
||||
icon_state = "eblade"
|
||||
|
||||
activate_string = "Project Blade"
|
||||
deactivate_string = "Cancel Blade"
|
||||
|
||||
interface_name = "spider fang blade"
|
||||
interface_desc = "A lethal energy projector that can shape a blade projected from the hand of the wearer or launch radioactive darts."
|
||||
|
||||
usable = FALSE
|
||||
selectable = TRUE
|
||||
toggleable = TRUE
|
||||
use_power_cost = 50
|
||||
active_power_cost = 10
|
||||
passive_power_cost = 0
|
||||
|
||||
gun_type = /obj/item/gun/energy/crossbow/ninja
|
||||
|
||||
var/blade_deployed = FALSE
|
||||
|
||||
category = MODULE_SPECIAL
|
||||
|
||||
/obj/item/rig_module/mounted/energy_blade/process()
|
||||
@@ -303,6 +327,18 @@
|
||||
|
||||
return ..()
|
||||
|
||||
/obj/item/rig_module/mounted/energy_blade/get_configuration()
|
||||
. = ..()
|
||||
.["deploy_blade"] = add_ui_configuration(activate_string, "bool", blade_deployed)
|
||||
|
||||
/obj/item/rig_module/mounted/energy_blade/configure_edit(key, value)
|
||||
switch(key)
|
||||
if("deploy_blade")
|
||||
if(!blade_deployed)
|
||||
activate(src, usr)
|
||||
else
|
||||
deactivate()
|
||||
|
||||
/obj/item/rig_module/mounted/energy_blade/activate(mob/user)
|
||||
..()
|
||||
|
||||
@@ -319,6 +355,7 @@
|
||||
var/obj/item/melee/energy/blade/blade = new(M)
|
||||
blade.creator = M
|
||||
M.put_in_hands(blade)
|
||||
blade_deployed = TRUE
|
||||
|
||||
/obj/item/rig_module/mounted/energy_blade/deactivate()
|
||||
..()
|
||||
@@ -330,12 +367,12 @@
|
||||
|
||||
for(var/obj/item/melee/energy/blade/blade in M.contents)
|
||||
qdel(blade)
|
||||
blade_deployed = FALSE
|
||||
|
||||
/obj/item/rig_module/fabricator
|
||||
name = "matter fabricator"
|
||||
desc = "A self-contained microfactory system for hardsuit integration."
|
||||
selectable = TRUE
|
||||
usable = TRUE
|
||||
module_type = MODULETYPE_USABLE_ACTIVE
|
||||
use_power_cost = 10
|
||||
icon_state = "enet"
|
||||
|
||||
@@ -356,7 +393,7 @@
|
||||
|
||||
var/mob/living/H = holder.wearer
|
||||
|
||||
if(target)
|
||||
if(target && target != H)
|
||||
var/obj/item/firing = new fabrication_type(get_turf(src))
|
||||
holder.wearer.visible_message(SPAN_DANGER("[user] launches \a [firing]!"))
|
||||
firing.throw_at(target, fire_force, fire_distance)
|
||||
@@ -388,14 +425,12 @@
|
||||
name = "mounted tesla coil"
|
||||
desc = "A mounted tesla coil that discharges a powerful lightning strike around the user."
|
||||
icon_state = "ewar"
|
||||
suit_overlay_active = "mounted-ion"
|
||||
interface_name = "mounted tesla coil"
|
||||
interface_desc ="Discharges a powerful lightning strike around the user."
|
||||
|
||||
module_type = MODULETYPE_USABLE
|
||||
use_power_cost = 30
|
||||
module_cooldown = 100
|
||||
|
||||
usable = TRUE
|
||||
|
||||
category = MODULE_LIGHT_COMBAT
|
||||
|
||||
/obj/item/rig_module/tesla_coil/engage(atom/target, mob/user)
|
||||
|
||||
@@ -23,7 +23,7 @@
|
||||
to_chat(usr, SPAN_WARNING("Your module is not installed in a hardsuit."))
|
||||
return
|
||||
|
||||
module.holder.ui_interact(usr, nano_state = GLOB.contained_state)
|
||||
module.holder.ui_interact(usr)
|
||||
|
||||
/mob
|
||||
var/get_rig_stats = 0
|
||||
@@ -32,9 +32,7 @@
|
||||
name = "IIS module"
|
||||
desc = "An integrated intelligence system module suitable for most hardsuits."
|
||||
icon_state = "IIS"
|
||||
toggleable = TRUE
|
||||
usable = TRUE
|
||||
disruptive = FALSE
|
||||
module_type = MODULETYPE_TOGGLE
|
||||
activates_on_touch = TRUE
|
||||
confined_use = TRUE
|
||||
|
||||
@@ -46,10 +44,12 @@
|
||||
deactivate_string = "Disable Dataspike"
|
||||
|
||||
interface_name = "integrated intelligence system"
|
||||
interface_desc = "A socket that supports a range of artificial intelligence systems."
|
||||
interface_desc = "A socket that supports a range of artificial intelligence systems. When active, you can click on any active AI (including traditional ship/station AIs, pAIs, and robot intelligence circuits) to attempt to integrate it into your suit systems."
|
||||
|
||||
var/mob/integrated_ai // Direct reference to the actual mob held in the suit.
|
||||
var/obj/item/ai_card // Reference to the MMI, posibrain, intellicard or pAI card previously holding the AI.
|
||||
/// Direct reference to the actual mob held in the suit.
|
||||
var/mob/integrated_ai
|
||||
/// Reference to the MMI, intellicard or pAI card previously holding the AI.
|
||||
var/obj/item/ai_card
|
||||
var/obj/item/ai_verbs/verb_holder
|
||||
|
||||
category = MODULE_GENERAL
|
||||
@@ -137,6 +137,18 @@
|
||||
|
||||
return FALSE
|
||||
|
||||
/obj/item/rig_module/ai_container/get_configuration()
|
||||
. = ..()
|
||||
var/button_label = "No AI Currently Installed"
|
||||
if(integrated_ai)
|
||||
button_label = integrated_ai.name
|
||||
.["eject"] = add_ui_configuration(engage_string, "button", button_label)
|
||||
|
||||
/obj/item/rig_module/ai_container/configure_edit(key, value, user)
|
||||
switch(key)
|
||||
if("eject")
|
||||
engage(null, user)
|
||||
|
||||
/obj/item/rig_module/ai_container/engage(atom/target, mob/user)
|
||||
if(!..())
|
||||
return FALSE
|
||||
@@ -227,10 +239,10 @@
|
||||
name = "datajack module"
|
||||
desc = "A simple induction datalink module."
|
||||
icon_state = "datajack"
|
||||
toggleable = TRUE
|
||||
activates_on_touch = TRUE
|
||||
usable = FALSE
|
||||
module_type = MODULETYPE_USABLE
|
||||
|
||||
engage_string = "Eject AI"
|
||||
activate_string = "Enable Datajack"
|
||||
deactivate_string = "Disable Datajack"
|
||||
|
||||
@@ -318,8 +330,7 @@
|
||||
name = "electrowarfare module"
|
||||
desc = "A bewilderingly complex bundle of fiber optics and chips."
|
||||
icon_state = "ewar"
|
||||
toggleable = TRUE
|
||||
usable = FALSE
|
||||
module_type = MODULETYPE_TOGGLE
|
||||
confined_use = TRUE
|
||||
|
||||
activate_string = "Enable Countermeasures"
|
||||
@@ -352,7 +363,7 @@
|
||||
name = "hardsuit power sink"
|
||||
desc = "An heavy-duty power sink."
|
||||
icon_state = "powersink"
|
||||
toggleable = TRUE
|
||||
module_type = MODULETYPE_TOGGLE
|
||||
activates_on_touch = TRUE
|
||||
disruptive = FALSE
|
||||
|
||||
|
||||
@@ -15,7 +15,9 @@
|
||||
icon_state = "generic"
|
||||
matter = list(DEFAULT_WALL_MATERIAL = 20000, MATERIAL_PLASTIC = 30000, MATERIAL_GLASS = 5000)
|
||||
|
||||
/// This is literally never read anywhere. All construction cost info lives within the /design. Due for removal.
|
||||
var/list/construction_cost = list(DEFAULT_WALL_MATERIAL=7000, MATERIAL_GLASS =7000)
|
||||
/// This is literally never read anywhere. All construction cost info lives within the /design. Due for removal.
|
||||
var/construction_time = 100
|
||||
|
||||
var/damage = 0
|
||||
@@ -24,42 +26,67 @@
|
||||
var/module_cooldown = 10
|
||||
var/next_use = 0
|
||||
|
||||
var/engage_on_activate = TRUE // Whether the rig should call engage() in its activate() proc
|
||||
var/toggleable // Set to 1 for the device to show up as an active effect.
|
||||
var/usable // Set to 1 for the device to have an on-use effect.
|
||||
var/selectable // Set to 1 to be able to assign the device as primary system.
|
||||
var/redundant // Set to 1 to ignore duplicate module checking when installing.
|
||||
var/permanent // If set, the module can't be removed.
|
||||
var/disruptive = 1 // Can disrupt by other effects.
|
||||
var/activates_on_touch // If set, unarmed attacks will call engage() on the target.
|
||||
var/confined_use = FALSE // If set, can be used inside mechs and other vehicles.
|
||||
/// The type of module this is.
|
||||
var/module_type
|
||||
/// Set TRUE to ignore duplicate module checking when installing.
|
||||
var/redundant
|
||||
/// If set, the module can't be removed.
|
||||
var/permanent
|
||||
/// Can disrupt by other effects.
|
||||
var/disruptive = 1
|
||||
/// If set, unarmed attacks will call engage() on the target.
|
||||
var/activates_on_touch
|
||||
/// If set, can be used inside mechs and other vehicles.
|
||||
var/confined_use = FALSE
|
||||
|
||||
var/active // Basic module status
|
||||
var/disruptable // Will deactivate if some other powers are used.
|
||||
var/attackdisrupts = 0 // Will deactivate if user attacks
|
||||
/// Basic module status
|
||||
var/active
|
||||
/// Will deactivate if some other powers are used.
|
||||
var/disruptable
|
||||
/// Will deactivate if user attacks
|
||||
var/attackdisrupts = 0
|
||||
|
||||
var/use_power_cost = 0 // Power used when single-use ability called.
|
||||
var/active_power_cost = 0 // Power used when turned on.
|
||||
var/passive_power_cost = 0 // Power used when turned off.
|
||||
/// Power used when single-use ability called.
|
||||
var/use_power_cost = 0
|
||||
/// Power used when turned on.
|
||||
var/active_power_cost = 0
|
||||
/// Power used when turned off.
|
||||
var/passive_power_cost = 0
|
||||
|
||||
var/list/charges // Associative list of charge types and remaining numbers.
|
||||
var/charge_selected // Currently selected option used for charge dispensing.
|
||||
/// Associative list of charge types and remaining numbers.
|
||||
var/list/charges
|
||||
/// Currently selected option used for charge dispensing.
|
||||
var/charge_selected
|
||||
|
||||
// Icons.
|
||||
var/suit_overlay
|
||||
var/suit_overlay_active // If set, drawn over icon and mob when effect is active.
|
||||
var/suit_overlay_inactive // As above, inactive.
|
||||
var/suit_overlay_used // As above, when engaged.
|
||||
/// If set, drawn over icon and mob when module is active OR selected.
|
||||
var/suit_overlay_active
|
||||
/// As above, when inactive.
|
||||
var/suit_overlay_inactive
|
||||
/// As above, when engaged. Not currently used, but in future should be a flick animation.
|
||||
var/suit_overlay_used
|
||||
|
||||
//Display fluff
|
||||
var/interface_name = "hardsuit upgrade"
|
||||
var/interface_desc = "A generic hardsuit upgrade."
|
||||
/// This is a string when a module with an active use is engaged, fire and forget-style. The UI will default to 'Engage' if this value is somehow nulled.
|
||||
var/engage_string = "Engage"
|
||||
/// This is when a module is toggled on. The UI will default to 'Activate' if this value is somehow nulled.
|
||||
var/activate_string = "Activate"
|
||||
/// This is when a module is toggled off. The UI will default to 'Deactivate' if this value is somehow nulled.
|
||||
var/deactivate_string = "Deactivate"
|
||||
|
||||
var/list/stat_rig_module/stat_modules = new()
|
||||
var/category // Use for restricting modules for specific suits, to specialize
|
||||
/// Use for restricting modules for specific suits, to specialize
|
||||
var/category
|
||||
|
||||
/// Sound played (to user only) when user changes a module configuration setting.
|
||||
var/sound_config = 'sound/machines/terminal/terminal_select.ogg'
|
||||
/// Sound played (to user only) when user activates a module.
|
||||
var/sound_activate = 'sound/machines/terminal/terminal_prompt_confirm.ogg'
|
||||
/// Sound played (to user only) when user deactivates a module.
|
||||
var/sound_deactivate = 'sound/machines/terminal/terminal_prompt_deny.ogg'
|
||||
|
||||
/obj/item/rig_module/get_examine_text(mob/user, distance, is_adjacent, infix, suffix)
|
||||
. = ..()
|
||||
@@ -160,22 +187,24 @@
|
||||
if(B)
|
||||
B.set_color_for(COLOR_RED, module_cooldown)
|
||||
|
||||
//Proc for one-use abilities like teleport.
|
||||
/obj/item/rig_module/proc/engage(atom/target, mob/user)
|
||||
/// Handles all usage checks for rig module use; both engage and activate use this.
|
||||
/obj/item/rig_module/proc/check_can_use(mob/user)
|
||||
if(damage >= 2)
|
||||
to_chat(user, SPAN_WARNING("\The [interface_name] is damaged beyond use!"))
|
||||
sound_to(user, 'sound/machines/terminal/terminal_error.ogg')
|
||||
balloon_alert(user, "[interface_name] is damaged!")
|
||||
return FALSE
|
||||
|
||||
if(world.time < next_use)
|
||||
to_chat(user, SPAN_WARNING("You cannot use \the [interface_name] again so soon."))
|
||||
sound_to(user, 'sound/machines/terminal/terminal_error.ogg')
|
||||
balloon_alert(user, "[interface_name] on cooldown!")
|
||||
return FALSE
|
||||
|
||||
if(!holder || holder.canremove)
|
||||
to_chat(user, SPAN_WARNING("The suit is not initialized."))
|
||||
sound_to(user, 'sound/machines/terminal/terminal_error.ogg')
|
||||
balloon_alert(user, "suit not initialized!")
|
||||
return FALSE
|
||||
|
||||
if(user.lying || user.stat || user.stunned || user.paralysis || user.weakened)
|
||||
to_chat(user, SPAN_WARNING("You cannot use the suit in this state."))
|
||||
if(use_check_and_message(user, USE_ALLOW_NON_ADJACENT))
|
||||
return FALSE
|
||||
|
||||
if(holder.wearer && holder.wearer.lying)
|
||||
@@ -183,26 +212,39 @@
|
||||
return FALSE
|
||||
|
||||
if(holder.security_check_enabled && holder.locked && !holder.check_suit_access(user))
|
||||
to_chat(user, SPAN_DANGER("Access denied."))
|
||||
// No sound or balloon alert here, because they live in check_suit_access()
|
||||
return FALSE
|
||||
|
||||
if(!holder.check_power_cost(user, use_power_cost, 0, src, (istype(user,/mob/living/silicon ? 1 : 0) ) ) )
|
||||
if(holder.sealing)
|
||||
sound_to(user, 'sound/machines/terminal/terminal_error.ogg')
|
||||
balloon_alert(user, "suit busy adjusting seals!")
|
||||
return FALSE
|
||||
|
||||
if(!confined_use && istype(user.loc, /mob/living/heavy_vehicle))
|
||||
to_chat(user, SPAN_DANGER("You cannot use the suit in the confined space."))
|
||||
var/is_user_silicon = issilicon(user)
|
||||
if(!holder.check_power_cost(user, use_power_cost, 0, src, is_user_silicon) || !holder.check_power_cost(user, active_power_cost, 0, src, is_user_silicon))
|
||||
sound_to(user, 'sound/effects/pop.ogg')
|
||||
balloon_alert(user, "insufficient power!")
|
||||
return FALSE
|
||||
|
||||
return TRUE
|
||||
|
||||
// Proc for toggling on active abilities.
|
||||
/// Proc for one-use abilities like teleport.
|
||||
/obj/item/rig_module/proc/engage(atom/target, mob/user)
|
||||
if(!check_can_use(user))
|
||||
return FALSE
|
||||
|
||||
if(!confined_use && !isturf(user.loc))
|
||||
to_chat(user, SPAN_DANGER("You cannot use the suit in a confined space."))
|
||||
return FALSE
|
||||
|
||||
return TRUE
|
||||
|
||||
/// Proc for toggling on active abilities.
|
||||
/obj/item/rig_module/proc/activate(mob/user)
|
||||
if(active)
|
||||
return FALSE
|
||||
if(engage_on_activate && !do_engage(null, user))
|
||||
return FALSE
|
||||
|
||||
if(use_check_and_message(user, USE_ALLOW_NON_ADJACENT))
|
||||
if(!check_can_use(user))
|
||||
return FALSE
|
||||
|
||||
active = TRUE
|
||||
@@ -211,7 +253,8 @@
|
||||
suit_overlay = suit_overlay_active
|
||||
else
|
||||
suit_overlay = null
|
||||
holder.update_icon()
|
||||
|
||||
holder?.update_icon(TRUE)
|
||||
|
||||
return TRUE
|
||||
|
||||
@@ -229,8 +272,8 @@
|
||||
suit_overlay = suit_overlay_inactive
|
||||
else
|
||||
suit_overlay = null
|
||||
if(holder)
|
||||
holder.update_icon()
|
||||
|
||||
holder?.update_icon(TRUE)
|
||||
|
||||
return TRUE
|
||||
|
||||
@@ -259,6 +302,19 @@
|
||||
to_chat(holder.wearer, wearer_text)
|
||||
return
|
||||
|
||||
/// Creates a list of configuring options for this module. Possible configs include number, bool, color, list, button.
|
||||
/obj/item/rig_module/proc/get_configuration(mob/user)
|
||||
return list()
|
||||
|
||||
/// Generates an element of the get_configuration list with a display name, type and value
|
||||
/obj/item/rig_module/proc/add_ui_configuration(display_name, type, value, list/values)
|
||||
return list("display_name" = display_name, "type" = type, "value" = value, "values" = values)
|
||||
|
||||
/// Receives configure edits from the TGUI and edits the vars
|
||||
/obj/item/rig_module/proc/configure_edit(key, value, mob/user)
|
||||
return
|
||||
|
||||
// Procs handling the statpanel 'Hardsuit Modules' tab, which is auto-populated by controls for all modules.
|
||||
/mob/living/carbon/human/get_actions_for_statpanel()
|
||||
var/list/data = ..()
|
||||
if(istype(back,/obj/item/rig))
|
||||
@@ -314,33 +370,33 @@
|
||||
..()
|
||||
name = module.activate_string
|
||||
if(module.active_power_cost)
|
||||
name += " ([module.active_power_cost*10]A)"
|
||||
name += " ([module.active_power_cost]A)"
|
||||
module_mode = "activate"
|
||||
|
||||
/stat_rig_module/activate/CanUse()
|
||||
return module.toggleable && !module.active
|
||||
return (module.module_type == MODULETYPE_TOGGLE) && !module.active
|
||||
|
||||
/stat_rig_module/deactivate/New(var/obj/item/rig_module/module)
|
||||
..()
|
||||
name = module.deactivate_string
|
||||
// Show cost despite being 0, if it means changing from an active cost.
|
||||
if(module.active_power_cost || module.passive_power_cost)
|
||||
name += " ([module.passive_power_cost*10]P)"
|
||||
name += " ([module.passive_power_cost]P)"
|
||||
|
||||
module_mode = "deactivate"
|
||||
|
||||
/stat_rig_module/deactivate/CanUse()
|
||||
return module.toggleable && module.active
|
||||
return (module.module_type == MODULETYPE_TOGGLE) && module.active
|
||||
|
||||
/stat_rig_module/engage/New(var/obj/item/rig_module/module)
|
||||
..()
|
||||
name = module.engage_string
|
||||
if(module.use_power_cost)
|
||||
name += " ([module.use_power_cost*10]E)"
|
||||
name += " ([module.use_power_cost]E)"
|
||||
module_mode = "engage"
|
||||
|
||||
/stat_rig_module/engage/CanUse()
|
||||
return module.usable
|
||||
return module.module_type == MODULETYPE_USABLE && !module.active
|
||||
|
||||
/stat_rig_module/select/New()
|
||||
..()
|
||||
@@ -348,7 +404,7 @@
|
||||
module_mode = "select"
|
||||
|
||||
/stat_rig_module/select/CanUse()
|
||||
if(module.selectable)
|
||||
if(module.module_type == MODULETYPE_USABLE_ACTIVE)
|
||||
name = module.holder.selected_module == module ? "Selected" : "Select"
|
||||
return TRUE
|
||||
return FALSE
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
desc = "A robust hardsuit-integrated stealth module."
|
||||
icon_state = "cloak"
|
||||
|
||||
toggleable = TRUE
|
||||
module_type = MODULETYPE_TOGGLE
|
||||
disruptable = TRUE
|
||||
disruptive = FALSE
|
||||
attackdisrupts = TRUE
|
||||
@@ -69,9 +69,8 @@
|
||||
desc = "A complex, sleek-looking, hardsuit-integrated teleportation module that exploits bluespace energy to phase from one location to another instantaneously."
|
||||
icon_state = "teleporter"
|
||||
use_power_cost = 40
|
||||
redundant = 1
|
||||
usable = TRUE
|
||||
selectable = 1
|
||||
redundant = TRUE
|
||||
module_type = MODULETYPE_USABLE_ACTIVE
|
||||
var/lastteleport
|
||||
var/phase_in_visual = /obj/effect/temp_visual/phase
|
||||
var/phase_out_visual = /obj/effect/temp_visual/phase/out
|
||||
@@ -186,8 +185,7 @@
|
||||
name = "self-destruct module"
|
||||
desc = "Oh my God, Captain. A bomb."
|
||||
icon_state = "deadman"
|
||||
usable = TRUE
|
||||
active = TRUE
|
||||
module_type = MODULETYPE_USABLE
|
||||
permanent = TRUE
|
||||
|
||||
engage_string = "Detonate"
|
||||
@@ -230,7 +228,7 @@
|
||||
name = "anti-theft system"
|
||||
desc = "An advanced anti-theft system that tracks the user's lifesigns."
|
||||
icon_state = "deadman"
|
||||
usable = FALSE
|
||||
module_type = MODULETYPE_PASSIVE
|
||||
active = FALSE
|
||||
permanent = FALSE
|
||||
|
||||
@@ -249,8 +247,7 @@
|
||||
name = "EMP dissipation module"
|
||||
desc = "A bewilderingly complex bundle of fiber optics and chips. Seems like it uses a good deal of power."
|
||||
active_power_cost = 10
|
||||
toggleable = TRUE
|
||||
usable = FALSE
|
||||
module_type = MODULETYPE_TOGGLE
|
||||
use_power_cost = 70
|
||||
module_cooldown = 30
|
||||
|
||||
@@ -279,8 +276,7 @@
|
||||
name = "emergency power generator"
|
||||
desc = "A high yield power generating device that takes a long time to recharge."
|
||||
active_power_cost = 0
|
||||
toggleable = FALSE
|
||||
usable = TRUE
|
||||
module_type = MODULETYPE_USABLE
|
||||
confined_use = TRUE
|
||||
var/cooldown = 0
|
||||
|
||||
@@ -337,10 +333,7 @@
|
||||
desc = "An advanced door hacking tool that sports a low power cost and incredibly quick door hacking time. The device also supports hacking several signals at once remotely, and the last 10 doors hacked can be instantly accessed."
|
||||
use_power_cost = 10
|
||||
module_cooldown = 5
|
||||
|
||||
usable = FALSE
|
||||
selectable = 0
|
||||
toggleable = TRUE
|
||||
module_type = MODULETYPE_TOGGLE
|
||||
|
||||
interface_name = "advanced door hacking tool"
|
||||
interface_desc = "An advanced door hacking tool that sports a low power cost and incredibly quick door hacking time. The device also supports hacking several signals at once remotely, and the last 10 doors hacked can be instantly accessed."
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
name = "mounted storage unit"
|
||||
interface_name = "mounted storage unit"
|
||||
interface_desc = "A storage unit for storing a precious few items in your hardsuit."
|
||||
module_type = MODULETYPE_PASSIVE
|
||||
icon_state = "paper"
|
||||
|
||||
origin_tech = list(TECH_MAGNET = 2, TECH_MATERIAL = 2, TECH_ENGINEERING = 3)
|
||||
@@ -10,7 +11,7 @@
|
||||
var/obj/item/storage/internal/hardsuit/pockets
|
||||
var/storage_slots = null
|
||||
var/storage_max_w_class = WEIGHT_CLASS_NORMAL
|
||||
var/storage_max_storage_space = 9
|
||||
var/storage_max_storage_space = DEFAULT_BOX_STORAGE
|
||||
|
||||
/obj/item/rig_module/storage/Initialize()
|
||||
. = ..()
|
||||
|
||||
@@ -19,17 +19,22 @@
|
||||
* /obj/item/rig_module/actuators/combat
|
||||
*/
|
||||
|
||||
/// Device-type modules create a contained /obj/item, which can then be used with middle-click.
|
||||
/obj/item/rig_module/device
|
||||
name = "mounted device"
|
||||
desc = "Some kind of hardsuit mount."
|
||||
usable = FALSE
|
||||
selectable = 1
|
||||
toggleable = FALSE
|
||||
module_type = MODULETYPE_USABLE_ACTIVE
|
||||
disruptive = FALSE
|
||||
use_power_cost = 5
|
||||
|
||||
var/device_type
|
||||
var/obj/item/device
|
||||
|
||||
/obj/item/rig_module/device/Initialize()
|
||||
. = ..()
|
||||
if(device_type)
|
||||
device = new device_type(src)
|
||||
|
||||
/obj/item/rig_module/device/Destroy()
|
||||
if(!ispath(src.device))
|
||||
QDEL_NULL(src.device)
|
||||
@@ -46,6 +51,8 @@
|
||||
construction_cost = list("$glass" = 5250, DEFAULT_WALL_MATERIAL = 2500)
|
||||
construction_time = 300
|
||||
|
||||
engage_string = "Run Self-Diagnostic"
|
||||
|
||||
device_type = /obj/item/healthanalyzer
|
||||
|
||||
category = MODULE_MEDICAL
|
||||
@@ -56,21 +63,17 @@
|
||||
interface_name = "vitals tracker"
|
||||
interface_desc = "Shows an informative health readout of the user."
|
||||
|
||||
usable = TRUE
|
||||
selectable = 0
|
||||
|
||||
category = MODULE_GENERAL
|
||||
|
||||
|
||||
/obj/item/rig_module/device/drill
|
||||
name = "hardsuit diamond drill mount"
|
||||
desc = "A very heavy diamond-tipped drill."
|
||||
icon_state = "drill"
|
||||
module_type = MODULETYPE_USABLE_ACTIVE
|
||||
interface_name = "mounted drill"
|
||||
interface_desc = "A diamond-tipped industrial drill."
|
||||
suit_overlay_active = "mounted-drill"
|
||||
suit_overlay_inactive = "mounted-drill"
|
||||
use_power_cost = 0.1
|
||||
use_power_cost = 0.2
|
||||
construction_cost = list(DEFAULT_WALL_MATERIAL = 55000, MATERIAL_GLASS = 2250, MATERIAL_SILVER = 5250, MATERIAL_DIAMOND = 3750)
|
||||
construction_time = 350
|
||||
|
||||
@@ -85,7 +88,6 @@
|
||||
interface_name = "mounted drill"
|
||||
interface_desc = "A basic industrial drill."
|
||||
suit_overlay_active = "mounted-drill"
|
||||
suit_overlay_inactive = "mounted-drill"
|
||||
use_power_cost = 0.1
|
||||
|
||||
device_type = /obj/item/pickaxe/drill
|
||||
@@ -99,8 +101,6 @@
|
||||
interface_name = "Alden-Saraspova counter"
|
||||
interface_desc = "An exotic particle detector commonly used by xenoarchaeologists."
|
||||
engage_string = "Begin Scan"
|
||||
usable = TRUE
|
||||
selectable = 0
|
||||
device_type = /obj/item/ano_scanner
|
||||
|
||||
category = MODULE_UTILITY
|
||||
@@ -112,8 +112,6 @@
|
||||
interface_name = "ore detector"
|
||||
interface_desc = "A sonar system for detecting large masses of ore."
|
||||
engage_string = "Begin Scan"
|
||||
usable = TRUE
|
||||
selectable = 0
|
||||
device_type = /obj/item/mining_scanner
|
||||
|
||||
category = MODULE_UTILITY
|
||||
@@ -122,17 +120,44 @@
|
||||
name = "RFD-C mount"
|
||||
desc = "A cell-powered rapid construction device for a hardsuit."
|
||||
icon_state = "rcd"
|
||||
suit_overlay_active = "mounted-rfd"
|
||||
interface_name = "mounted RFD-C"
|
||||
interface_desc = "A device for building or removing walls. Cell-powered."
|
||||
usable = TRUE
|
||||
module_type = MODULETYPE_USABLE_ACTIVE
|
||||
engage_string = "Configure RFD-C"
|
||||
construction_cost = list(DEFAULT_WALL_MATERIAL = 30000, MATERIAL_PHORON = 12500, MATERIAL_SILVER = 10000, MATERIAL_GOLD = 10000)
|
||||
construction_time = 1000
|
||||
|
||||
device_type = /obj/item/rfd/construction/mounted
|
||||
/// Name of the atom (or mode, if deconstructing) to display in the UI. Default for RFD-C is a wall.
|
||||
var/current_setting = "wall"
|
||||
|
||||
category = MODULE_UTILITY
|
||||
|
||||
/obj/item/rig_module/device/rfd_c/proc/get_current_setting()
|
||||
var/obj/item/rfd/construction/mounted/our_device = device
|
||||
switch(our_device?.mode)
|
||||
if(RFD_FLOORS_AND_WALL)
|
||||
return "Floors & Wall"
|
||||
if(RFD_WINDOW_AND_FRAME)
|
||||
return "Window & Frame"
|
||||
if(RFD_AIRLOCK)
|
||||
return "Airlock"
|
||||
if(RFD_DECONSTRUCT)
|
||||
return "Deconstruct"
|
||||
// How?
|
||||
return "ERROR - CONSULT MANUFACTURER"
|
||||
|
||||
/obj/item/rig_module/device/rfd_c/get_configuration()
|
||||
. = ..()
|
||||
.["rfd_settings"] = add_ui_configuration("Configure RFD-C Settings", "button", get_current_setting())
|
||||
|
||||
/obj/item/rig_module/device/rfd_c/configure_edit(key, value, mob/user)
|
||||
var/obj/item/rfd/construction/mounted/our_device = device
|
||||
switch(key)
|
||||
if("rfd_settings")
|
||||
our_device.attack_self(user)
|
||||
|
||||
/obj/item/rig_module/device/rfd_c/handle_device_engage(atom/target, mob/user)
|
||||
var/resolved = target.attackby(device, user)
|
||||
if(!resolved && device && target)
|
||||
@@ -142,17 +167,13 @@
|
||||
return FALSE
|
||||
return TRUE
|
||||
|
||||
/obj/item/rig_module/device/Initialize()
|
||||
. = ..()
|
||||
if(device_type)
|
||||
device = new device_type(src)
|
||||
|
||||
/obj/item/rig_module/device/engage(atom/target, mob/user)
|
||||
/obj/item/rig_module/device/rfd_c/engage(atom/target, mob/user)
|
||||
if(!..() || !device)
|
||||
return FALSE
|
||||
|
||||
var/obj/item/rfd/construction/mounted/our_device = device
|
||||
if(!target)
|
||||
device.attack_self(user)
|
||||
our_device.attack_self(user)
|
||||
return TRUE
|
||||
|
||||
var/turf/T = get_turf(target)
|
||||
@@ -174,11 +195,11 @@
|
||||
/obj/item/rig_module/chem_dispenser
|
||||
name = "mounted chemical dispenser"
|
||||
desc = "A complex web of tubing and needles suitable for hardsuit use."
|
||||
suit_overlay_active = "mounted-injector"
|
||||
interface_desc = "Dispenses loaded chemicals directly into the wearer's (or adjacent target's) bloodstream."
|
||||
icon_state = "injector"
|
||||
usable = TRUE
|
||||
selectable = FALSE
|
||||
toggleable = FALSE
|
||||
disruptive = FALSE
|
||||
module_type = MODULETYPE_USABLE_ACTIVE
|
||||
disruptive = TRUE
|
||||
confined_use = TRUE
|
||||
construction_cost = list(DEFAULT_WALL_MATERIAL=10000, MATERIAL_GLASS =9250, MATERIAL_GOLD =2500, MATERIAL_SILVER =4250,"phoron"=5500)
|
||||
construction_time = 400
|
||||
@@ -192,9 +213,9 @@
|
||||
list("tricordrazine", "tricordrazine", /singleton/reagent/tricordrazine, 80),
|
||||
list("mortaphenyl", "mortaphenyl", /singleton/reagent/mortaphenyl, 80),
|
||||
list("dexalin plus", "dexalinp", /singleton/reagent/dexalin/plus, 80),
|
||||
list("antibiotics", "thetamycin", /singleton/reagent/thetamycin, 80),
|
||||
list("antitoxins", "dylovene", /singleton/reagent/dylovene, 80),
|
||||
list("nutrients", "glucose", /singleton/reagent/nutriment/glucose, 80),
|
||||
list("thetamycin", "thetamycin", /singleton/reagent/thetamycin, 80),
|
||||
list("dylovene", "dylovene", /singleton/reagent/dylovene, 80),
|
||||
list("glucose", "glucose", /singleton/reagent/nutriment/glucose, 80),
|
||||
list("hyronalin", "hyronalin", /singleton/reagent/hyronalin, 80),
|
||||
list("synaptizine", "synaptizine", /singleton/reagent/synaptizine, 80),
|
||||
list("radium", "radium", /singleton/reagent/radium, 80)
|
||||
@@ -205,21 +226,21 @@
|
||||
category = MODULE_HEAVY_COMBAT
|
||||
|
||||
/obj/item/rig_module/chem_dispenser/ninja
|
||||
interface_desc = "Dispenses loaded chemicals directly into the wearer's bloodstream. This variant is made to be extremely light and flexible."
|
||||
interface_desc = "Dispenses loaded chemicals directly into the wearer's (or adjacent target's) bloodstream. This variant is made to be extremely light and flexible."
|
||||
|
||||
//just over a syringe worth of each. Want more? Go refill. Gives the ninja another reason to have to show their face.
|
||||
charges = list(
|
||||
list("tricordrazine", "tricordrazine", /singleton/reagent/tricordrazine, 20),
|
||||
list("mortaphenyl", "mortaphenyl", /singleton/reagent/mortaphenyl, 20),
|
||||
list("dexalin plus", "dexalinp", /singleton/reagent/dexalin/plus, 20),
|
||||
list("antibiotics", "thetamycin", /singleton/reagent/thetamycin, 20),
|
||||
list("antitoxins", "dylovene", /singleton/reagent/dylovene, 20),
|
||||
list("nutrients", "glucose", /singleton/reagent/nutriment/glucose, 80),
|
||||
list("thetamycin", "thetamycin", /singleton/reagent/thetamycin, 20),
|
||||
list("dylovene", "dylovene", /singleton/reagent/dylovene, 20),
|
||||
list("glucose", "glucose", /singleton/reagent/nutriment/glucose, 80),
|
||||
list("hyronalin", "hyronalin", /singleton/reagent/hyronalin, 20),
|
||||
list("synaptizine", "synaptizine", /singleton/reagent/synaptizine, 20),
|
||||
list("radium", "radium", /singleton/reagent/radium, 20)
|
||||
)
|
||||
|
||||
disruptive = FALSE
|
||||
category = MODULE_UTILITY
|
||||
|
||||
/obj/item/rig_module/chem_dispenser/accepts_item(var/obj/item/input_item, var/mob/living/user)
|
||||
@@ -261,7 +282,7 @@
|
||||
var/mob/living/carbon/human/H = holder.wearer
|
||||
|
||||
if(!charge_selected)
|
||||
to_chat(user, SPAN_WARNING("You have not selected a chemical type."))
|
||||
balloon_alert(user, "no chem selected!")
|
||||
return FALSE
|
||||
|
||||
var/datum/rig_charge/charge = charges[charge_selected]
|
||||
@@ -271,7 +292,7 @@
|
||||
|
||||
var/chems_to_use = 5
|
||||
if(charge.charges <= 0)
|
||||
to_chat(user, SPAN_WARNING("Insufficient chems!"))
|
||||
balloon_alert(user, "out of chem!")
|
||||
return FALSE
|
||||
else if(charge.charges < chems_to_use)
|
||||
chems_to_use = charge.charges
|
||||
@@ -300,6 +321,8 @@
|
||||
if(charge.charges < 0)
|
||||
charge.charges = 0
|
||||
|
||||
playsound(src,'sound/items/reagent_containers/liquid/plastic_bottle_liquid_slosh1.ogg',25,1)
|
||||
|
||||
return TRUE
|
||||
|
||||
/obj/item/rig_module/chem_dispenser/combat
|
||||
@@ -314,7 +337,6 @@
|
||||
)
|
||||
|
||||
interface_name = "combat chem dispenser"
|
||||
interface_desc = "Dispenses loaded chemicals directly into the bloodstream."
|
||||
|
||||
category = MODULE_LIGHT_COMBAT
|
||||
|
||||
@@ -331,7 +353,6 @@
|
||||
)
|
||||
|
||||
interface_name = "vaurca combat chem dispenser"
|
||||
interface_desc = "Dispenses loaded chemicals directly into the bloodstream."
|
||||
|
||||
category = MODULE_VAURCA
|
||||
|
||||
@@ -346,21 +367,18 @@
|
||||
)
|
||||
|
||||
interface_name = "chem dispenser"
|
||||
interface_desc = "Dispenses loaded chemicals directly into the bloodstream."
|
||||
|
||||
category = MODULE_GENERAL
|
||||
|
||||
/obj/item/rig_module/chem_dispenser/injector
|
||||
name = "mounted chemical injector"
|
||||
desc = "A complex web of tubing and a large needle suitable for hardsuit use."
|
||||
usable = FALSE
|
||||
selectable = 1
|
||||
disruptive = 1
|
||||
module_type = MODULETYPE_USABLE_ACTIVE
|
||||
construction_cost = list(DEFAULT_WALL_MATERIAL = 10000, MATERIAL_GLASS = 9250, MATERIAL_GOLD = 2500, MATERIAL_SILVER = 4250, MATERIAL_PHORON = 5500)
|
||||
construction_time = 400
|
||||
|
||||
interface_name = "mounted chem injector"
|
||||
interface_desc = "Dispenses loaded chemicals via an arm-mounted injector."
|
||||
interface_desc = "Dispenses loaded chemicals directly into the wearer's (or adjacent target's) bloodstream. This variant is made to be extremely light and flexible."
|
||||
|
||||
category = MODULE_MEDICAL
|
||||
|
||||
@@ -373,19 +391,15 @@
|
||||
)
|
||||
|
||||
/obj/item/rig_module/voice
|
||||
name = "hardsuit voice synthesiser"
|
||||
name = "hardsuit voice synthesizer"
|
||||
desc = "A speaker box and sound processor."
|
||||
icon_state = "megaphone"
|
||||
usable = TRUE
|
||||
selectable = 0
|
||||
toggleable = FALSE
|
||||
module_type = MODULETYPE_TOGGLE
|
||||
disruptive = FALSE
|
||||
confined_use = TRUE
|
||||
|
||||
engage_string = "Configure Synthesiser"
|
||||
|
||||
interface_name = "voice synthesiser"
|
||||
interface_desc = "A flexible and powerful voice modulator system."
|
||||
interface_name = "voice synthesizer"
|
||||
interface_desc = "A flexible and powerful voice modulator system. Can mimic both names and accents."
|
||||
|
||||
var/obj/item/voice_changer/voice_holder
|
||||
|
||||
@@ -406,30 +420,31 @@
|
||||
..()
|
||||
holder.speech = src
|
||||
|
||||
/obj/item/rig_module/voice/get_configuration()
|
||||
. = ..()
|
||||
.["configure"] = add_ui_configuration(engage_string, "button", "Name: [voice_holder?.name], Accent: [voice_holder?.current_accent]")
|
||||
|
||||
/obj/item/rig_module/voice/configure_edit(key, value, user)
|
||||
switch(key)
|
||||
if("configure")
|
||||
engage(null, user)
|
||||
|
||||
/obj/item/rig_module/voice/engage(atom/target, mob/user)
|
||||
if(!..())
|
||||
return FALSE
|
||||
|
||||
var/choice= tgui_input_list(user, "Would you like to toggle the synthesiser, set the name or set an accent?", "Synthesizer", list("Enable","Disable","Set Name", "Set Accent"))
|
||||
var/choice= tgui_input_list(user, "Would you like to set the name or accent for the synthesizer?", src, list("Set Name", "Set Accent"))
|
||||
|
||||
if(!choice)
|
||||
return FALSE
|
||||
|
||||
switch(choice)
|
||||
if("Enable")
|
||||
active = TRUE
|
||||
voice_holder.active = TRUE
|
||||
message_user(user, SPAN_NOTICE("You enable the speech synthesiser."), SPAN_NOTICE("\The [user] enables the speech synthesiser."))
|
||||
if("Disable")
|
||||
active = FALSE
|
||||
voice_holder.active = FALSE
|
||||
message_user(user, SPAN_NOTICE("You disable the speech synthesiser."), SPAN_NOTICE("\The [user] disables the speech synthesiser."))
|
||||
if("Set Name")
|
||||
var/raw_choice = sanitize(input(user, "Please enter a new name.") as text|null, MAX_NAME_LEN)
|
||||
if(!raw_choice)
|
||||
return FALSE
|
||||
voice_holder.voice = raw_choice
|
||||
message_user(user, SPAN_NOTICE("You set the synthesizer to mimic <b>[voice_holder.voice]</b>."), SPAN_NOTICE("\The [user] set the speech synthesizer to mimic <b>[voice_holder.voice]</b>."))
|
||||
message_user(user, SPAN_NOTICE("You set the synthesizer to mimic <b>[raw_choice]</b>."), SPAN_NOTICE("\The [user] set the speech synthesizer to mimic <b>[voice_holder.voice]</b>."))
|
||||
if("Set Accent")
|
||||
var/raw_choice = tgui_input_list(user, "Please choose an accent to mimick.", "Accent Mimicry", SSrecords.accents)
|
||||
if(!raw_choice)
|
||||
@@ -438,28 +453,39 @@
|
||||
message_user(user, SPAN_NOTICE("You set the synthesizer to mimic the [raw_choice] accent."), SPAN_NOTICE("\The [user] set the speech synthesizer the [raw_choice] accent."))
|
||||
return TRUE
|
||||
|
||||
/obj/item/rig_module/voice/activate(mob/user)
|
||||
if(!..())
|
||||
return
|
||||
voice_holder.active = TRUE
|
||||
message_user(user, SPAN_NOTICE("You enable the speech synthesizer. Name: [voice_holder?.name], Accent: [voice_holder?.current_accent]"), SPAN_NOTICE("\The [user] enables the speech synthesizer."))
|
||||
return TRUE
|
||||
|
||||
/obj/item/rig_module/voice/deactivate(mob/user)
|
||||
if(!..())
|
||||
return FALSE
|
||||
|
||||
voice_holder.active = FALSE
|
||||
message_user(user, SPAN_NOTICE("You disable the speech synthesizer."), SPAN_NOTICE("\The [user] disables the speech synthesizer."))
|
||||
return TRUE
|
||||
|
||||
/obj/item/rig_module/maneuvering_jets
|
||||
name = "hardsuit maneuvering jets"
|
||||
desc = "A compact gas thruster system for a hardsuit."
|
||||
icon_state = "thrusters"
|
||||
usable = TRUE
|
||||
toggleable = TRUE
|
||||
selectable = 0
|
||||
module_type = MODULETYPE_TOGGLE
|
||||
disruptive = FALSE
|
||||
construction_cost = list(DEFAULT_WALL_MATERIAL = 15000, MATERIAL_GLASS = 4250, MATERIAL_SILVER = 4250, MATERIAL_URANIUM = 5250)
|
||||
construction_time = 300
|
||||
|
||||
suit_overlay_active = "maneuvering_active"
|
||||
suit_overlay_inactive = null //"maneuvering_inactive"
|
||||
|
||||
engage_string = "Toggle Stabilizers"
|
||||
activate_string = "Activate Thrusters"
|
||||
deactivate_string = "Deactivate Thrusters"
|
||||
suit_overlay_inactive = "maneuvering_inactive"
|
||||
|
||||
interface_name = "maneuvering jets"
|
||||
interface_desc = "An inbuilt EVA maneuvering system that runs off the hardsuit air supply."
|
||||
|
||||
var/obj/item/tank/jetpack/rig/jets
|
||||
/// Do we have stabilizers? If yes the user won't move from inertia.
|
||||
var/stabilize = TRUE
|
||||
|
||||
category = MODULE_GENERAL
|
||||
|
||||
@@ -467,49 +493,35 @@
|
||||
QDEL_NULL(jets)
|
||||
. = ..()
|
||||
|
||||
/obj/item/rig_module/maneuvering_jets/engage(atom/target, mob/user)
|
||||
if(!..())
|
||||
return FALSE
|
||||
var/list/extra_mobs = list()
|
||||
if(user != holder.wearer)
|
||||
extra_mobs += holder.wearer
|
||||
jets.toggle_rockets_stabilization(user, extra_mobs)
|
||||
return TRUE
|
||||
/obj/item/rig_module/maneuvering_jets/get_configuration()
|
||||
. = ..()
|
||||
.["stabilizers"] = add_ui_configuration("Stabilizers", "bool", stabilize)
|
||||
|
||||
/obj/item/rig_module/maneuvering_jets/configure_edit(key, value, mob/user)
|
||||
switch(key)
|
||||
if("stabilizers")
|
||||
if(engage(src, user))
|
||||
jets.toggle_rockets_stabilization(user)
|
||||
|
||||
/obj/item/rig_module/maneuvering_jets/activate(mob/user)
|
||||
if(active)
|
||||
if(!..())
|
||||
return FALSE
|
||||
if(use_check_and_message(user))
|
||||
return FALSE
|
||||
|
||||
active = TRUE
|
||||
|
||||
if(suit_overlay_active)
|
||||
suit_overlay = suit_overlay_active
|
||||
else
|
||||
suit_overlay = null
|
||||
holder.update_icon()
|
||||
|
||||
if(!jets.on)
|
||||
var/list/extra_mobs = list()
|
||||
if(user != holder.wearer)
|
||||
extra_mobs += holder.wearer
|
||||
jets.toggle_jetpack(user, extra_mobs)
|
||||
jets.enable_jetpack(user)
|
||||
stabilize = jets.stabilization_on
|
||||
return TRUE
|
||||
|
||||
/obj/item/rig_module/maneuvering_jets/deactivate(mob/user)
|
||||
if(!..())
|
||||
return FALSE
|
||||
if(jets.on)
|
||||
var/list/extra_mobs = list()
|
||||
if(user != holder.wearer)
|
||||
extra_mobs += holder.wearer
|
||||
jets.toggle_jetpack(user, extra_mobs)
|
||||
jets.disable_jetpack(user)
|
||||
return TRUE
|
||||
|
||||
/obj/item/rig_module/maneuvering_jets/New()
|
||||
..()
|
||||
jets = new(src)
|
||||
stabilize = jets.stabilization_on
|
||||
|
||||
/obj/item/rig_module/maneuvering_jets/installed()
|
||||
..()
|
||||
@@ -526,8 +538,6 @@
|
||||
interface_name = "paper dispenser"
|
||||
interface_desc = "Dispenses warm, clean, and crisp sheets of paper."
|
||||
engage_string = "Dispense"
|
||||
usable = TRUE
|
||||
selectable = 0
|
||||
device_type = /obj/item/paper_bin
|
||||
|
||||
category = MODULE_GENERAL
|
||||
@@ -544,10 +554,10 @@
|
||||
name = "mounted pen"
|
||||
desc = "For mecha John Hancocks."
|
||||
icon_state = "pen"
|
||||
module_type = MODULETYPE_USABLE
|
||||
interface_name = "mounted pen"
|
||||
interface_desc = "Signatures with style(tm)."
|
||||
engage_string = "Change color"
|
||||
usable = TRUE
|
||||
device_type = /obj/item/pen/multi
|
||||
|
||||
category = MODULE_GENERAL
|
||||
@@ -555,11 +565,11 @@
|
||||
/obj/item/rig_module/device/stamp
|
||||
name = "mounted internal affairs stamp"
|
||||
desc = "DENIED."
|
||||
module_type = MODULETYPE_USABLE
|
||||
icon_state = "stamp"
|
||||
interface_name = "mounted stamp"
|
||||
interface_desc = "Leave your mark."
|
||||
engage_string = "Toggle stamp type"
|
||||
usable = TRUE
|
||||
var/iastamp
|
||||
var/deniedstamp
|
||||
|
||||
@@ -606,67 +616,51 @@
|
||||
name = "leg actuators"
|
||||
desc = "A set of electromechanical actuators, for safe traversal of multilevelled areas."
|
||||
icon_state = "actuators"
|
||||
module_type = MODULETYPE_USABLE_ACTIVE
|
||||
interface_name = "leg actuators"
|
||||
interface_desc = "Allows you to fall from heights and to jump up onto ledges."
|
||||
interface_desc = "Allows you to fall from heights and dash up to <b>4</b> tiles at once. To jump onto ledges, stand adjacent and facing a climbable wall (one with a walkable turf above it), then target your own turf to rapidly climb to the turf above!"
|
||||
|
||||
construction_cost = list(DEFAULT_WALL_MATERIAL=15000, MATERIAL_GLASS = 1250, MATERIAL_SILVER =5250)
|
||||
construction_time = 300
|
||||
|
||||
disruptive = FALSE
|
||||
|
||||
use_power_cost = 5
|
||||
active_power_cost = 1
|
||||
use_power_cost = 20
|
||||
module_cooldown = 25
|
||||
|
||||
/*
|
||||
* TOGGLE - dampens fall, on or off.
|
||||
* SELECTABLE - Jump forward or up!
|
||||
*/
|
||||
toggleable = TRUE
|
||||
selectable = TRUE
|
||||
usable = FALSE
|
||||
|
||||
engage_string = "Toggle Leg Actuators"
|
||||
activate_string = "Enable Leg Actuators"
|
||||
deactivate_string = "Disable Leg Actuators"
|
||||
|
||||
var/combatType = 0 // Determines whether or not the actuators can do special combat oriented tasks.
|
||||
// Such as leaping faster, or grappling targets.
|
||||
var/leapDistance = 4 // Determines how far the actuators allow you to leap (radius, inclusive).
|
||||
|
||||
/// Determines whether or not the actuators can do special combat oriented tasks,
|
||||
/// such as leaping faster, or grappling targets.
|
||||
var/combatType = 0
|
||||
/// Determines how far the actuators allow you to leap (radius, inclusive).
|
||||
var/leapDistance = 4
|
||||
category = MODULE_GENERAL
|
||||
|
||||
/obj/item/rig_module/actuators/combat
|
||||
name = "military grade leg actuators"
|
||||
desc = "A set of high-powered hydraulic actuators, for improved traversal of multilevelled areas."
|
||||
interface_name = "combat leg actuators"
|
||||
|
||||
interface_desc = "Allows you to fall from heights and dash up to <b>7</b> tiles at once. To jump onto ledges, stand adjacent and facing a climbable wall (one with a walkable turf above it), \
|
||||
then target your own turf to <b>instantly</b> leap to the turf above! These leg actuators also let you aggressively lunge and grap people by targeting them directly with your dash ability."
|
||||
combatType = 1
|
||||
leapDistance = 7
|
||||
|
||||
use_power_cost = 10
|
||||
use_power_cost = 50
|
||||
|
||||
category = MODULE_LIGHT_COMBAT
|
||||
|
||||
/obj/item/rig_module/actuators/proc/is_valid_turf(var/turf/T)
|
||||
if(!T || istype(T, /turf/space) || T.density || T.contains_dense_objects())
|
||||
return null
|
||||
if(isopenturf(T))
|
||||
var/obj/structure/lattice/L = locate() in T
|
||||
if(L)
|
||||
return L.name
|
||||
var/turf/leapBelow = GET_TURF_BELOW(T)
|
||||
if(leapBelow.density)
|
||||
return leapBelow.name
|
||||
else if(T.contains_dense_objects())
|
||||
return "structure"
|
||||
else
|
||||
return null
|
||||
return T.name
|
||||
/obj/item/rig_module/actuators/get_configuration()
|
||||
. = ..()
|
||||
.["fall_damping"] = add_ui_configuration("Fall Damping", "bool", active)
|
||||
|
||||
/obj/item/rig_module/actuators/configure_edit(key, value, mob/user)
|
||||
switch(key)
|
||||
if("fall_damping")
|
||||
active = !active
|
||||
balloon_alert(user, "fall damping [active ? "active" : "inactive"]!")
|
||||
|
||||
/obj/item/rig_module/actuators/engage(atom/target, mob/user)
|
||||
// This is for when you toggle it on or off. Why do they both run the same
|
||||
// proc chain ...? :l
|
||||
if (!target)
|
||||
if(!target)
|
||||
return TRUE
|
||||
|
||||
var/mob/living/carbon/human/H = holder.wearer
|
||||
@@ -765,10 +759,25 @@
|
||||
H.forceMove(leapEnd)
|
||||
return TRUE
|
||||
|
||||
/obj/item/rig_module/actuators/proc/is_valid_turf(var/turf/T)
|
||||
if(!T || istype(T, /turf/space) || T.density || T.contains_dense_objects())
|
||||
return null
|
||||
if(isopenturf(T))
|
||||
var/obj/structure/lattice/L = locate() in T
|
||||
if(L)
|
||||
return L.name
|
||||
var/turf/leapBelow = GET_TURF_BELOW(T)
|
||||
if(leapBelow.density)
|
||||
return leapBelow.name
|
||||
else if(T.contains_dense_objects())
|
||||
return "structure"
|
||||
else
|
||||
return null
|
||||
return T.name
|
||||
|
||||
/obj/item/rig_module/cooling_unit
|
||||
name = "mounted cooling unit"
|
||||
toggleable = TRUE
|
||||
module_type = MODULETYPE_TOGGLE
|
||||
origin_tech = list(TECH_MAGNET = 2, TECH_MATERIAL = 2, TECH_ENGINEERING = 3)
|
||||
interface_name = "mounted cooling unit"
|
||||
interface_desc = "A heat sink with liquid cooled radiator."
|
||||
@@ -819,14 +828,13 @@
|
||||
icon_state = "actuators"
|
||||
interface_name = "boring laser"
|
||||
interface_desc = "Allows you to burrow to the z-level below."
|
||||
module_type = MODULETYPE_USABLE
|
||||
|
||||
disruptive = 1
|
||||
|
||||
use_power_cost = 5
|
||||
module_cooldown = 25
|
||||
|
||||
usable = TRUE
|
||||
|
||||
category = MODULE_VAURCA
|
||||
|
||||
/obj/item/rig_module/boring/engage(atom/target, mob/user)
|
||||
@@ -850,10 +858,11 @@ GLOBAL_LIST_EMPTY(lattice_users)
|
||||
icon_state = "actuators"
|
||||
interface_name = "neural lattice"
|
||||
interface_desc = "Synchronize neural lattice to reduce pain."
|
||||
module_type = MODULETYPE_USABLE
|
||||
|
||||
disruptive = FALSE
|
||||
|
||||
toggleable = TRUE
|
||||
module_type = MODULETYPE_TOGGLE
|
||||
confined_use = TRUE
|
||||
|
||||
category = MODULE_VAURCA
|
||||
@@ -877,9 +886,11 @@ GLOBAL_LIST_EMPTY(lattice_users)
|
||||
/obj/item/rig_module/foam_sprayer
|
||||
name = "mounted foam sprayer"
|
||||
desc = "A shoulder-mounted metal foam sprayer."
|
||||
selectable = TRUE
|
||||
module_type = MODULETYPE_USABLE_ACTIVE
|
||||
icon_state = "actuators"
|
||||
|
||||
suit_overlay_active = "mounted-gun"
|
||||
|
||||
interface_name = "integrated foam sprayer"
|
||||
interface_desc = "Projects a line of metal foam where the user selects."
|
||||
|
||||
@@ -922,26 +933,27 @@ GLOBAL_LIST_EMPTY(lattice_users)
|
||||
/obj/item/rig_module/recharger
|
||||
name = "weapon recharge module"
|
||||
desc = "A specialised power cable designed to connect an energy weapon to a hardsuit's power supply."
|
||||
toggleable = TRUE
|
||||
module_type = MODULETYPE_TOGGLE
|
||||
icon_state = "powersink"
|
||||
interface_name = "integrated weapon recharger"
|
||||
interface_desc = "Can connect to an energy weapon, recharging it off the hardsuit's power supply. Drag the weapon onto the hardsuit control module to connect it."
|
||||
category = MODULE_LIGHT_COMBAT
|
||||
usable = FALSE
|
||||
disruptive = FALSE
|
||||
confined_use = TRUE
|
||||
///The gun charging off our hardsuit
|
||||
/// The gun charging off our hardsuit
|
||||
var/obj/item/gun/energy/connected
|
||||
|
||||
/obj/item/rig_module/recharger/activate(mob/user)
|
||||
/obj/item/rig_module/recharger/engage(atom/target, mob/user)
|
||||
if (!..())
|
||||
return FALSE
|
||||
|
||||
|
||||
if(!connected)
|
||||
to_chat(user, SPAN_NOTICE("\The [src] does not have a connected energy weapon to charge!"))
|
||||
return FALSE
|
||||
|
||||
if(!active)
|
||||
balloon_alert(user, "module inactive!")
|
||||
return FALSE
|
||||
|
||||
to_chat(user, SPAN_NOTICE("\The [connected] is now connected to your hardsuit power supply. Deactivate this module to disconnect it."))
|
||||
return TRUE
|
||||
@@ -949,9 +961,8 @@ GLOBAL_LIST_EMPTY(lattice_users)
|
||||
/obj/item/rig_module/recharger/deactivate(mob/user)
|
||||
if (!..())
|
||||
return FALSE
|
||||
|
||||
|
||||
if(connected)
|
||||
balloon_alert(user, "[connected] disconnected!")
|
||||
connected.disconnect()
|
||||
|
||||
|
||||
|
||||
@@ -53,13 +53,10 @@
|
||||
name = "hardsuit visor"
|
||||
desc = "A layered, translucent visor system for a hardsuit."
|
||||
icon_state = "optics"
|
||||
|
||||
module_type = MODULETYPE_TOGGLE
|
||||
interface_name = "optical scanners"
|
||||
interface_desc = "An integrated multi-mode vision system."
|
||||
|
||||
engage_on_activate = FALSE
|
||||
usable = TRUE
|
||||
toggleable = TRUE
|
||||
disruptive = FALSE
|
||||
confined_use = TRUE
|
||||
|
||||
@@ -67,7 +64,9 @@
|
||||
activate_string = "Enable Visor"
|
||||
deactivate_string = "Disable Visor"
|
||||
|
||||
var/datum/rig_vision/vision
|
||||
active_power_cost = 2
|
||||
|
||||
var/datum/rig_vision/vision_mode
|
||||
var/list/vision_modes = list(
|
||||
/datum/rig_vision/nvg,
|
||||
/datum/rig_vision/thermal
|
||||
@@ -77,11 +76,77 @@
|
||||
|
||||
category = MODULE_GENERAL
|
||||
|
||||
/// There should only ever be one vision module installed in a suit.
|
||||
/obj/item/rig_module/vision/installed()
|
||||
..()
|
||||
holder.visor = src
|
||||
|
||||
/obj/item/rig_module/vision/New()
|
||||
..()
|
||||
|
||||
if(!vision_modes)
|
||||
return
|
||||
|
||||
var/list/processed_vision = list()
|
||||
for(var/new_vision_mode in vision_modes)
|
||||
var/datum/rig_vision/vision_datum = new new_vision_mode
|
||||
processed_vision += vision_datum
|
||||
|
||||
vision_modes = processed_vision
|
||||
|
||||
vision_index = 1
|
||||
vision_mode = length(vision_modes) ? vision_modes[vision_index] : null
|
||||
|
||||
/obj/item/rig_module/vision/get_configuration(mob/user)
|
||||
. = ..()
|
||||
if(!vision_modes || length(vision_modes) <= 1)
|
||||
return .
|
||||
|
||||
var/list/modes = list()
|
||||
for(var/datum/rig_vision/added_mode in vision_modes)
|
||||
modes += added_mode.mode
|
||||
|
||||
.["vision_mode"] = add_ui_configuration("Visor mode", "list", vision_mode.mode, modes)
|
||||
|
||||
/obj/item/rig_module/vision/configure_edit(key, value, mob/user)
|
||||
switch(key)
|
||||
if("vision_mode")
|
||||
set_vision_mode(user, value)
|
||||
|
||||
/obj/item/rig_module/vision/proc/set_vision_mode(mob/user, var/new_mode)
|
||||
if(!new_mode || new_mode == "")
|
||||
return FALSE
|
||||
|
||||
if(!active)
|
||||
to_chat(user, SPAN_WARNING("\The [src] isn't activated!"))
|
||||
return FALSE
|
||||
|
||||
var/i = 1
|
||||
for(var/datum/rig_vision/V in vision_modes)
|
||||
if(V.mode == new_mode)
|
||||
vision_index = i
|
||||
vision_mode = V
|
||||
sound_to(user, 'sound/machines/terminal/terminal_select.ogg')
|
||||
return TRUE
|
||||
i++
|
||||
|
||||
return FALSE
|
||||
|
||||
/obj/item/rig_module/vision/activate(mob/user)
|
||||
. = ..()
|
||||
sound_to(user, 'sound/items/goggles_charge.ogg')
|
||||
|
||||
/obj/item/rig_module/vision/deactivate(mob/user)
|
||||
. = ..()
|
||||
sound_to(user, 'sound/effects/pop.ogg')
|
||||
|
||||
/obj/item/rig_module/vision/multi
|
||||
name = "hardsuit optical package"
|
||||
desc = "A complete visor system of optical scanners and vision modes."
|
||||
icon_state = "fulloptics"
|
||||
|
||||
active_power_cost = 3
|
||||
|
||||
interface_name = "multi optical visor"
|
||||
interface_desc = "An integrated multi-mode vision system."
|
||||
|
||||
@@ -100,11 +165,11 @@
|
||||
desc = "A layered, translucent visor system for a hardsuit."
|
||||
icon_state = "meson"
|
||||
|
||||
usable = FALSE
|
||||
|
||||
construction_cost = list(DEFAULT_WALL_MATERIAL = 1500, MATERIAL_GLASS = 5000)
|
||||
construction_time = 300
|
||||
|
||||
active_power_cost = 2
|
||||
|
||||
interface_name = "meson/material scanner"
|
||||
interface_desc = "An integrated meson/material scanner."
|
||||
|
||||
@@ -118,7 +183,7 @@
|
||||
desc = "A layered, translucent visor system for a hardsuit."
|
||||
icon_state = "thermal"
|
||||
|
||||
usable = FALSE
|
||||
active_power_cost = 2
|
||||
|
||||
interface_name = "thermal scanner"
|
||||
interface_desc = "An integrated thermal scanner."
|
||||
@@ -132,11 +197,11 @@
|
||||
desc = "A multi input night vision system for a hardsuit."
|
||||
icon_state = "night"
|
||||
|
||||
usable = FALSE
|
||||
|
||||
construction_cost = list(DEFAULT_WALL_MATERIAL = 1500, MATERIAL_GLASS = 5000, MATERIAL_URANIUM = 5000)
|
||||
construction_time = 300
|
||||
|
||||
active_power_cost = 2
|
||||
|
||||
interface_name = "night vision interface"
|
||||
interface_desc = "An integrated night vision system."
|
||||
|
||||
@@ -149,8 +214,6 @@
|
||||
desc = "A simple tactical information system for a hardsuit."
|
||||
icon_state = "securityhud"
|
||||
|
||||
usable = FALSE
|
||||
|
||||
construction_cost = list(DEFAULT_WALL_MATERIAL = 1500, MATERIAL_GLASS = 5000)
|
||||
construction_time = 300
|
||||
|
||||
@@ -166,8 +229,6 @@
|
||||
desc = "A simple medical status indicator for a hardsuit."
|
||||
icon_state = "healthhud"
|
||||
|
||||
usable = FALSE
|
||||
|
||||
construction_cost = list(DEFAULT_WALL_MATERIAL = 1500, MATERIAL_GLASS = 5000)
|
||||
construction_time = 300
|
||||
|
||||
@@ -177,42 +238,3 @@
|
||||
vision_modes = list(/datum/rig_vision/medhud)
|
||||
|
||||
category = MODULE_MEDICAL
|
||||
|
||||
// There should only ever be one vision module installed in a suit.
|
||||
/obj/item/rig_module/vision/installed()
|
||||
..()
|
||||
holder.visor = src
|
||||
|
||||
/obj/item/rig_module/vision/engage(atom/target, mob/user)
|
||||
if(!..() || !vision_modes)
|
||||
return FALSE
|
||||
if(!active)
|
||||
to_chat(user, SPAN_WARNING("\The [src] isn't activated!"))
|
||||
return FALSE
|
||||
|
||||
if(vision_modes.len > 1)
|
||||
vision_index++
|
||||
if(vision_index > vision_modes.len)
|
||||
vision_index = 1
|
||||
vision = vision_modes[vision_index]
|
||||
|
||||
message_user(user, SPAN_NOTICE("You cycle \the [src] to <b>[vision.mode]</b> mode."), SPAN_NOTICE("\The [user] cycles \the [src] to <b>[vision.mode]</b> mode."))
|
||||
else
|
||||
to_chat(user, SPAN_WARNING("\The [src] only has one mode."))
|
||||
return TRUE
|
||||
|
||||
/obj/item/rig_module/vision/New()
|
||||
..()
|
||||
|
||||
if(!vision_modes)
|
||||
return
|
||||
|
||||
vision_index = 1
|
||||
var/list/processed_vision = list()
|
||||
|
||||
for(var/vision_mode in vision_modes)
|
||||
var/datum/rig_vision/vision_datum = new vision_mode
|
||||
if(!vision) vision = vision_datum
|
||||
processed_vision += vision_datum
|
||||
|
||||
vision_modes = processed_vision
|
||||
|
||||
@@ -1,7 +1,3 @@
|
||||
#define ONLY_DEPLOY 1
|
||||
#define ONLY_RETRACT 2
|
||||
#define SEAL_DELAY 30
|
||||
|
||||
/*
|
||||
* Defines the behavior of hardsuits/rigs/power armor.
|
||||
*/
|
||||
@@ -36,17 +32,18 @@
|
||||
unacidable = 1
|
||||
slowdown = 0.5 // All rigs by default should have slowdown.
|
||||
|
||||
action_button_name = "Open Hardsuit Interface"
|
||||
|
||||
var/has_sealed_state = FALSE
|
||||
var/has_hidden_jumpsuit = FALSE
|
||||
|
||||
var/interface_path = "hardsuit.tmpl"
|
||||
var/ai_interface_path = "hardsuit.tmpl"
|
||||
var/interface_title = "Hardsuit Controller"
|
||||
var/wearer_move_delay //Used for AI moving.
|
||||
/// Used for AI moving.
|
||||
var/wearer_move_delay
|
||||
var/ai_controlled_move_delay = 10
|
||||
var/last_remote_message // when did a mounted pAI or AI use a module? used to prevent admin msg spam
|
||||
/// When did a mounted pAI or AI use a module? used to prevent admin msg spam
|
||||
var/last_remote_message
|
||||
|
||||
// Keeps track of what this rig should spawn with.
|
||||
/// Keeps track of what this rig should spawn with.
|
||||
var/suit_type = "hardsuit"
|
||||
var/list/initial_modules
|
||||
var/chest_type = /obj/item/clothing/suit/space/rig
|
||||
@@ -57,51 +54,82 @@
|
||||
var/air_type = /obj/item/tank/oxygen
|
||||
|
||||
//Component/device holders.
|
||||
var/obj/item/tank/air_supply // Air tank, if any.
|
||||
var/obj/item/clothing/shoes/boots = null // Deployable boots, if any.
|
||||
var/obj/item/clothing/suit/space/rig/chest // Deployable chestpiece, if any.
|
||||
var/obj/item/clothing/head/helmet/space/rig/helmet = null // Deployable helmet, if any.
|
||||
var/obj/item/clothing/gloves/rig/gloves = null // Deployable gauntlets, if any.
|
||||
var/obj/item/cell/cell // Power supply, if any.
|
||||
var/obj/item/rig_module/selected_module = null // Primary system (used with middle-click)
|
||||
var/obj/item/rig_module/vision/visor // Kinda shitty to have a var for a module, but saves time.
|
||||
var/obj/item/rig_module/voice/speech // As above.
|
||||
var/mob/living/carbon/human/wearer // The person currently wearing the rig.
|
||||
var/image/mob_icon // Holder for on-mob icon.
|
||||
var/list/installed_modules = list() // Power consumption/use bookkeeping.
|
||||
/// Air tank, if any.
|
||||
var/obj/item/tank/air_supply
|
||||
/// Deployable boots, if any.
|
||||
var/obj/item/clothing/shoes/boots = null
|
||||
/// Deployable chestpiece, if any.
|
||||
var/obj/item/clothing/suit/space/rig/chest
|
||||
/// Deployable helmet, if any.
|
||||
var/obj/item/clothing/head/helmet/space/rig/helmet = null
|
||||
/// Deployable gauntlets, if any.
|
||||
var/obj/item/clothing/gloves/rig/gloves = null
|
||||
/// Power supply, if any.
|
||||
var/obj/item/cell/cell
|
||||
/// Primary system (used with middle-click)
|
||||
var/obj/item/rig_module/selected_module = null
|
||||
/// Kinda shitty to have a var for a module, but saves time.
|
||||
var/obj/item/rig_module/vision/visor
|
||||
/// As above.
|
||||
var/obj/item/rig_module/voice/speech
|
||||
/// The person currently wearing the rig.
|
||||
var/mob/living/carbon/human/wearer
|
||||
/// Holder for on-mob icon.
|
||||
var/image/mob_icon
|
||||
/// Power consumption/use bookkeeping.
|
||||
var/list/installed_modules = list()
|
||||
|
||||
// Rig status vars.
|
||||
var/open = 0 // Access panel status.
|
||||
var/locked = 1 // Lock status.
|
||||
var/dnaLock // To whom do we belong?
|
||||
var/crushing = FALSE // Are we crushing the occupant to death?
|
||||
/// Access panel status.
|
||||
var/open = FALSE
|
||||
/// Lock status.
|
||||
var/locked = TRUE
|
||||
/// To whom do we belong?
|
||||
var/dnaLock
|
||||
/// Are we crushing the occupant to death?
|
||||
var/crushing = FALSE
|
||||
var/subverted = 0
|
||||
var/interface_locked = 0
|
||||
var/control_overridden = 0
|
||||
var/ai_override_enabled = 0
|
||||
var/security_check_enabled = 1
|
||||
/// Interfaces get locked when the corresponding rig wire is pulsed.
|
||||
var/interface_locked = FALSE
|
||||
/// Whether or not the AI is currently overriding control of the suit.
|
||||
var/control_overridden = FALSE
|
||||
/// Whether or not the AI is capable of overriding control of the suit.
|
||||
var/ai_override_enabled = FALSE
|
||||
/// Access req status.
|
||||
var/security_check_enabled = TRUE
|
||||
var/malfunctioning = 0
|
||||
var/malfunction_delay = 0
|
||||
var/electrified = 0
|
||||
var/locked_down = 0
|
||||
|
||||
/// Rate at which the suit cell will passively use power when online.
|
||||
var/cell_draw_rate = CHARGE_DRAIN_DEFAULT
|
||||
|
||||
var/seal_delay = SEAL_DELAY
|
||||
var/sealing // Keeps track of seal status independantly of canremove.
|
||||
var/offline = 1 // Should we be applying suit maluses?
|
||||
var/offline_slowdown = 1.5 // If the suit is deployed and unpowered, it sets slowdown to this.
|
||||
/// Keeps track of seal status independantly of canremove.
|
||||
var/sealing
|
||||
/// Should we be applying suit maluses? Note that this is tristate: 0 = online; 1 = offline, modules still active; 2 = offline, inc. modules
|
||||
/// Generally speaking, a suit is 0 when on, 1 when just turned off, and 2 after it has run process(), which deactivates all modules if offline == 1
|
||||
var/offline = 0
|
||||
/// If the suit is deployed and unpowered, it sets slowdown to this.
|
||||
var/offline_slowdown = 1.5
|
||||
var/vision_restriction = TINT_NONE
|
||||
var/offline_vision_restriction = TINT_HEAVY
|
||||
var/airtight = 1 //If set, will adjust the ITEM_FLAG_AIRTIGHT flag on components. Otherwise it should leave them untouched.
|
||||
///If set, will adjust the ITEM_FLAG_AIRTIGHT flag on components. Otherwise it should leave them untouched.
|
||||
var/airtight = TRUE
|
||||
|
||||
var/emp_protection = 0
|
||||
|
||||
// Wiring! How exciting.]
|
||||
// Wiring! How exciting.
|
||||
var/datum/wires/rig/wires
|
||||
var/datum/effect_system/sparks/spark_system
|
||||
|
||||
var/allowed_module_types = MODULE_GENERAL // All rigs by default should have access to general
|
||||
/// All rigs by default should have access to general
|
||||
var/allowed_module_types = MODULE_GENERAL
|
||||
var/list/species_restricted = list(BODYTYPE_HUMAN,BODYTYPE_TAJARA,BODYTYPE_UNATHI, BODYTYPE_SKRELL, BODYTYPE_IPC, BODYTYPE_IPC_BISHOP, BODYTYPE_IPC_ZENGHU)
|
||||
var/anomaly_protection = FALSE //If TRUE, this rig will protect against anomalies. Currently only used for AMI hardsuit.
|
||||
///If TRUE, this rig will protect against anomalies. Currently only used for AMI hardsuit.
|
||||
var/anomaly_protection = FALSE
|
||||
|
||||
var/ui_configure_ref
|
||||
|
||||
/obj/item/rig/get_examine_text(mob/user, distance, is_adjacent, infix, suffix)
|
||||
. = ..()
|
||||
@@ -122,7 +150,7 @@
|
||||
wires = new(src)
|
||||
|
||||
if(!LAZYLEN(req_access) && !LAZYLEN(req_one_access))
|
||||
locked = 0
|
||||
locked = FALSE
|
||||
|
||||
spark_system = bind_spark(src, 5)
|
||||
|
||||
@@ -220,6 +248,7 @@
|
||||
return 0
|
||||
return 1
|
||||
|
||||
/// Not currently used.
|
||||
/obj/item/rig/proc/reset()
|
||||
offline = 2
|
||||
canremove = 1
|
||||
@@ -335,7 +364,7 @@
|
||||
var/datum/component/armor/armor_component = piece.GetComponent(/datum/component/armor)
|
||||
if(istype(armor_component))
|
||||
armor_component.sealed = !seal_target
|
||||
playsound(src, "[!seal_target ? 'sound/machines/rig/rig_deploy.ogg' : 'sound/machines/rig/rig_retract.ogg']", 20, FALSE)
|
||||
playsound(src, "[!seal_target ? 'sound/machines/rig/rig_deploy.ogg' : 'sound/machines/rig/rig_retract.ogg']", 30, FALSE)
|
||||
|
||||
else
|
||||
failed_to_seal = 1
|
||||
@@ -361,7 +390,7 @@
|
||||
// Success!
|
||||
canremove = seal_target
|
||||
to_chat(wearer, SPAN_NOTICE("<b>Your entire suit [canremove ? "loosens as the components relax" : "tightens around you as the components lock into place"].</b>"))
|
||||
playsound(src, 'sound/items/rped.ogg', 20, FALSE)
|
||||
playsound(src, 'sound/items/rped.ogg', 30, FALSE)
|
||||
if (has_sealed_state)
|
||||
icon_state = canremove ? initial(icon_state) : "[initial(icon_state)]_sealed"
|
||||
if(dnaLock && !offline)
|
||||
@@ -411,15 +440,18 @@
|
||||
piece.forceMove(src)
|
||||
|
||||
var/previous_offline_status = offline
|
||||
// Consume energy per tick while active. If you don't have a cell... Weird, but we'll deal with that shortly.
|
||||
var/power_usage_this_tick = ((!offline && cell) ? cell_draw_rate : 0.0)
|
||||
|
||||
if(!istype(wearer) || loc != wearer || wearer.back != src || canremove || !cell || cell.charge <= 0)
|
||||
if(!cell || cell.charge <= 0)
|
||||
if(electrified > 0)
|
||||
electrified = 0
|
||||
if(!offline)
|
||||
if(istype(wearer))
|
||||
playsound(src, 'sound/machines/rig/rig_shutdown.ogg', 20, FALSE)
|
||||
playsound(src, 'sound/machines/rig/rig_shutdown.ogg', 35, FALSE)
|
||||
if(!canremove)
|
||||
if (offline_slowdown < 3)
|
||||
if(offline_slowdown < 3)
|
||||
to_chat(wearer, SPAN_DANGER("Your suit beeps stridently, and suddenly goes dead."))
|
||||
else
|
||||
to_chat(wearer, SPAN_DANGER("Your suit beeps stridently, and suddenly you're wearing a leaden mass of metal and plastic composites instead of a powered suit."))
|
||||
@@ -442,6 +474,16 @@
|
||||
update_icon(TRUE)
|
||||
|
||||
set_vision(!offline)
|
||||
|
||||
if(cell && cell.charge > 0 && electrified > 0)
|
||||
electrified--
|
||||
|
||||
if(crushing)
|
||||
wearer.apply_damage(10) // Applies 10 brute damage to a random extremity each process
|
||||
if(wearer.stat == DEAD)
|
||||
crushing = FALSE
|
||||
visible_message(SPAN_DANGER("A squelching sound comes from within the sealed hardsuit..")) // this denotes that the user inside has died.
|
||||
|
||||
if(offline)
|
||||
crushing = FALSE
|
||||
if(offline == 1)
|
||||
@@ -453,15 +495,6 @@
|
||||
wearer?.update_equipment_speed_mods()
|
||||
return
|
||||
|
||||
if(crushing)
|
||||
wearer.apply_damage(10) // Applies 10 brute damage to a random extremity each process
|
||||
if(wearer.stat == DEAD)
|
||||
crushing = FALSE
|
||||
visible_message(SPAN_DANGER("A squelching sound comes from within the sealed hardsuit..")) // this denotes that the user inside has died.
|
||||
|
||||
if(cell && cell.charge > 0 && electrified > 0)
|
||||
electrified--
|
||||
|
||||
if(malfunction_delay > 0)
|
||||
malfunction_delay--
|
||||
else if(malfunctioning)
|
||||
@@ -469,12 +502,15 @@
|
||||
malfunction()
|
||||
|
||||
for(var/obj/item/rig_module/module in installed_modules)
|
||||
cell.use(module.process()*10)
|
||||
power_usage_this_tick += module.process()
|
||||
|
||||
if(power_usage_this_tick)
|
||||
cell.use(power_usage_this_tick)
|
||||
|
||||
/obj/item/rig/proc/check_power_cost(var/mob/living/user, var/cost, var/use_unconcious, var/obj/item/rig_module/mod, var/user_is_ai)
|
||||
|
||||
if(!istype(user))
|
||||
return 0
|
||||
return FALSE
|
||||
|
||||
var/fail_msg
|
||||
|
||||
@@ -490,13 +526,15 @@
|
||||
fail_msg = SPAN_WARNING("You are in no fit state to do that.")
|
||||
else if(!cell)
|
||||
fail_msg = SPAN_WARNING("There is no cell installed in the suit.")
|
||||
else if(cost && cell.charge < cost * 10) //TODO: Cellrate?
|
||||
else if(cost && cell?.charge < cost) //TODO: Cellrate?
|
||||
fail_msg = SPAN_WARNING("Not enough stored power.")
|
||||
|
||||
if(fail_msg)
|
||||
to_chat(user, "[fail_msg]")
|
||||
// If a module has been passed to this proc, then the module will handle its own error messages.
|
||||
if(!mod)
|
||||
to_chat(user, "[fail_msg]")
|
||||
playsound(src, 'sound/items/rfd_empty.ogg', 20, FALSE)
|
||||
return 0
|
||||
return FALSE
|
||||
|
||||
// This is largely for cancelling stealth and whatever.
|
||||
if(mod && mod.disruptive)
|
||||
@@ -504,86 +542,10 @@
|
||||
if(module.active && module.disruptable)
|
||||
module.deactivate()
|
||||
|
||||
cell.use(cost*10)
|
||||
return 1
|
||||
|
||||
/obj/item/rig/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1, var/nano_state = GLOB.inventory_state)
|
||||
if(!user)
|
||||
return
|
||||
|
||||
var/list/data = list()
|
||||
|
||||
if(selected_module)
|
||||
data["primarysystem"] = "[selected_module.interface_name]"
|
||||
|
||||
if(src.loc != user)
|
||||
data["ai"] = 1
|
||||
|
||||
data["seals"] = "[src.canremove]"
|
||||
data["sealing"] = "[src.sealing]"
|
||||
data["helmet"] = (helmet ? "[helmet.name]" : "None.")
|
||||
data["gauntlets"] = (gloves ? "[gloves.name]" : "None.")
|
||||
data["boots"] = (boots ? "[boots.name]" : "None.")
|
||||
data[BP_CHEST] = (chest ? "[chest.name]" : "None.")
|
||||
|
||||
data["charge"] = cell ? round(cell.charge,1) : 0
|
||||
data["maxcharge"] = cell ? cell.maxcharge : 0
|
||||
data["chargestatus"] = cell ? FLOOR((cell.charge/cell.maxcharge)*50, 1) : 0
|
||||
|
||||
data["emagged"] = subverted
|
||||
data["coverlock"] = locked
|
||||
data["interfacelock"] = interface_locked
|
||||
data["aicontrol"] = control_overridden
|
||||
data["aioverride"] = ai_override_enabled
|
||||
data["securitycheck"] = security_check_enabled
|
||||
data["malf"] = malfunction_delay
|
||||
|
||||
|
||||
var/list/module_list = list()
|
||||
var/i = 1
|
||||
for(var/obj/item/rig_module/module in installed_modules)
|
||||
var/list/module_data = list(
|
||||
"index" = i,
|
||||
"name" = "[module.interface_name]",
|
||||
"desc" = "[module.interface_desc]",
|
||||
"can_use" = "[module.usable]",
|
||||
"can_select" = "[module.selectable]",
|
||||
"can_toggle" = "[module.toggleable]",
|
||||
"is_active" = "[module.active]",
|
||||
"engagecost" = module.use_power_cost*10,
|
||||
"activecost" = module.active_power_cost*10,
|
||||
"passivecost" = module.passive_power_cost*10,
|
||||
"engagestring" = module.engage_string,
|
||||
"activatestring" = module.activate_string,
|
||||
"deactivatestring" = module.deactivate_string,
|
||||
"damage" = module.damage
|
||||
)
|
||||
|
||||
if(module.charges && module.charges.len)
|
||||
|
||||
module_data["charges"] = list()
|
||||
var/datum/rig_charge/selected = module.charges[module.charge_selected]
|
||||
module_data["chargetype"] = selected ? "[selected.display_name]" : "none"
|
||||
|
||||
for(var/chargetype in module.charges)
|
||||
var/datum/rig_charge/charge = module.charges[chargetype]
|
||||
module_data["charges"] += list(list("caption" = "[chargetype] ([charge.charges])", "index" = "[chargetype]"))
|
||||
|
||||
module_list += list(module_data)
|
||||
i++
|
||||
|
||||
if(module_list.len)
|
||||
data["modules"] = module_list
|
||||
|
||||
ui = SSnanoui.try_update_ui(user, src, ui_key, ui, data, force_open)
|
||||
if (!ui)
|
||||
ui = new(user, src, ui_key, ((src.loc != user) ? ai_interface_path : interface_path), interface_title, 480, 550, state = nano_state)
|
||||
ui.set_initial_data(data)
|
||||
ui.open()
|
||||
ui.set_auto_update(1)
|
||||
cell.use(cost)
|
||||
return TRUE
|
||||
|
||||
/obj/item/rig/update_icon(var/update_mob_icon)
|
||||
|
||||
//TODO: Maybe consider a cache for this (use mob_icon as blank canvas, use suit icon overlay).
|
||||
ClearOverlays()
|
||||
if(!mob_icon || update_mob_icon)
|
||||
@@ -594,7 +556,7 @@
|
||||
species_icon = sprite_sheets[wearer.species.get_bodytype()]
|
||||
mob_icon = image("icon" = species_icon, "icon_state" = "[icon_state]")
|
||||
|
||||
if(installed_modules.len)
|
||||
if(length(installed_modules))
|
||||
for(var/obj/item/rig_module/module in installed_modules)
|
||||
if(module.suit_overlay)
|
||||
chest.AddOverlays(image("icon" = 'icons/mob/rig_modules.dmi', "icon_state" = "[module.suit_overlay]", "dir" = SOUTH))
|
||||
@@ -607,6 +569,15 @@
|
||||
wearer.update_inv_back()
|
||||
return
|
||||
|
||||
/obj/item/rig/get_mob_overlay(var/mob/living/carbon/human/H, var/mob_icon, var/mob_state, var/slot)
|
||||
var/image/I = ..()
|
||||
if(length(installed_modules))
|
||||
if((chest_type && (chest && wearer?.wear_suit == chest)))
|
||||
for(var/obj/item/rig_module/module in installed_modules)
|
||||
if(module.suit_overlay)
|
||||
I.AddOverlays(image('icons/mob/rig_modules.dmi', null, module.suit_overlay))
|
||||
return I
|
||||
|
||||
/obj/item/rig/get_cell()
|
||||
if(cell)
|
||||
return cell
|
||||
@@ -621,80 +592,234 @@
|
||||
return FALSE
|
||||
|
||||
/obj/item/rig/proc/check_suit_access(var/mob/living/user)
|
||||
|
||||
if(!security_check_enabled || !locked)
|
||||
return 1
|
||||
return TRUE
|
||||
|
||||
if(is_integrated_rig_ai(user))
|
||||
return 1
|
||||
return TRUE
|
||||
|
||||
if(ishuman(user))
|
||||
var/mob/living/carbon/human/H = user
|
||||
if(malfunction_check(H))
|
||||
return 0
|
||||
return FALSE
|
||||
if(H.back != src)
|
||||
return 0
|
||||
return FALSE
|
||||
else if(!src.allowed(H))
|
||||
to_chat(H, SPAN_DANGER("Unauthorized user. Access denied."))
|
||||
return 0
|
||||
sound_to(H, 'sound/machines/terminal/terminal_error.ogg')
|
||||
balloon_alert(H, "access denied!")
|
||||
return FALSE
|
||||
|
||||
else if(!ai_override_enabled)
|
||||
to_chat(user, SPAN_DANGER("Synthetic access disabled. Please consult hardware provider."))
|
||||
return 0
|
||||
return FALSE
|
||||
|
||||
return 1
|
||||
return TRUE
|
||||
|
||||
//TODO: Fix Topic vulnerabilities for malfunction and AI override.
|
||||
/obj/item/rig/Topic(href,href_list)
|
||||
if(href_list["examine_armor"])
|
||||
var/list/armor_details = list()
|
||||
for(var/armor_type in armor)
|
||||
armor_details[armor_type] = armor[armor_type]
|
||||
var/datum/tgui_module/armor_values/AV = new /datum/tgui_module/armor_values(usr, capitalize_first_letters(name), armor_details)
|
||||
AV.ui_interact(usr)
|
||||
if(href_list["examine_fluff"])
|
||||
examine(usr, show_extended = TRUE)
|
||||
if(ismob(href))
|
||||
do_rig_thing(href, href_list)
|
||||
/obj/item/rig/ui_interact(mob/user, datum/tgui/ui)
|
||||
if(!user)
|
||||
return
|
||||
do_rig_thing(usr, href_list)
|
||||
|
||||
/obj/item/rig/proc/do_rig_thing(mob/user, var/list/href_list)
|
||||
ui = SStgui.try_update_ui(user, src, ui)
|
||||
if(!ui)
|
||||
ui = new(user, src, "Hardsuit", src, 480, 550)
|
||||
ui.open()
|
||||
ui.set_autoupdate(TRUE)
|
||||
|
||||
/obj/item/rig/ui_data(mob/user)
|
||||
var/list/data = list()
|
||||
|
||||
if(selected_module)
|
||||
data["primarysystem"] = selected_module.interface_name
|
||||
data["primarysystem_ref"] = REF(selected_module)
|
||||
// Needs to be explicitly nulled when de-selected, otherwise the old data persists in the UI.
|
||||
else
|
||||
data["primarysystem"] = null
|
||||
data["primarysystem_ref"] = null
|
||||
|
||||
data["ai"] = (src.loc != user)
|
||||
|
||||
data["seals"] = canremove
|
||||
data["sealing"] = sealing
|
||||
|
||||
data["helmet"] = helmet ? helmet.name : "None."
|
||||
data["gauntlets"] = gloves ? gloves.name : "None."
|
||||
data["boots"] = boots ? boots.name : "None."
|
||||
data["chest"] = chest ? chest.name : "None."
|
||||
|
||||
var/data_charge = cell ? round(cell.charge, 1) : 0
|
||||
var/data_maxcharge = cell ? cell.maxcharge : 1
|
||||
data["charge"] = data_charge
|
||||
data["maxcharge"] = data_maxcharge
|
||||
data["chargedisplay"] = "[power_joules_readable(data_charge)] / [power_joules_readable(data_maxcharge)]"
|
||||
data["chargestatus"] = cell ? FLOOR((cell.charge / cell.maxcharge) * 50, 1) : 0
|
||||
|
||||
data["emagged"] = subverted
|
||||
data["coverlock"] = locked
|
||||
data["interfacelock"] = interface_locked
|
||||
data["aicontrol"] = control_overridden
|
||||
data["aioverride"] = ai_override_enabled
|
||||
data["id_lock"] = security_check_enabled
|
||||
data["malf"] = malfunction_delay
|
||||
|
||||
var/list/module_list = list()
|
||||
var/i = 1
|
||||
for(var/obj/item/rig_module/module in installed_modules)
|
||||
var/list/module_data = list(
|
||||
"index" = i,
|
||||
"module_name" = module.interface_name,
|
||||
"desc" = module.interface_desc,
|
||||
"module_type" = module.module_type,
|
||||
"module_active" = module.active,
|
||||
"module_selected" = selected_module == module ? TRUE : FALSE,
|
||||
"engagecost" = module.use_power_cost,
|
||||
"activecost" = module.active_power_cost,
|
||||
"passivecost" = module.passive_power_cost,
|
||||
"engagestring" = module.engage_string,
|
||||
"activatestring" = module.activate_string,
|
||||
"deactivatestring" = module.deactivate_string,
|
||||
"damage" = module.damage,
|
||||
"ref" = REF(module),
|
||||
"configuration_data" = module.get_configuration(user)
|
||||
)
|
||||
|
||||
if(module.charges && module.charges.len)
|
||||
module_data["charges"] = list()
|
||||
|
||||
var/datum/rig_charge/selected = module.charges[module.charge_selected]
|
||||
module_data["charge_selected"] = "[module.charge_selected]"
|
||||
module_data["chargetype"] = selected ? selected.display_name : "none"
|
||||
|
||||
for(var/chargetype in module.charges)
|
||||
var/datum/rig_charge/charge = module.charges[chargetype]
|
||||
module_data["charges"] += list(list(
|
||||
"chargetype" = "[chargetype]",
|
||||
"charges" = "[charge.charges]",
|
||||
"index" = "[chargetype]"
|
||||
))
|
||||
|
||||
module_list += list(module_data)
|
||||
i++
|
||||
|
||||
if(module_list.len)
|
||||
data["modules"] = module_list
|
||||
|
||||
return data
|
||||
|
||||
/obj/item/rig/ui_act(action, params)
|
||||
. = ..()
|
||||
if(.)
|
||||
return TRUE
|
||||
|
||||
var/mob/user = usr
|
||||
if(!user)
|
||||
return TRUE
|
||||
// Just handles the UI's examine buttons. Doesn't need to check for access.
|
||||
switch(action)
|
||||
// Returns the Armor Values UI.
|
||||
if("examine_armor")
|
||||
var/list/armor_details = list()
|
||||
for(var/armor_type in armor)
|
||||
armor_details[armor_type] = armor[armor_type]
|
||||
var/datum/tgui_module/armor_values/AV = new /datum/tgui_module/armor_values(user, capitalize_first_letters(name), armor_details)
|
||||
AV.ui_interact(user)
|
||||
return TRUE
|
||||
if("examine_fluff")
|
||||
examine(user, show_extended = TRUE)
|
||||
return TRUE
|
||||
|
||||
if(!check_suit_access(user))
|
||||
return 0
|
||||
return FALSE
|
||||
|
||||
if(href_list["toggle_piece"])
|
||||
if(ishuman(user) && (user.stat || user.stunned || user.lying))
|
||||
return FALSE
|
||||
toggle_piece(href_list["toggle_piece"], user)
|
||||
else if(href_list["toggle_seals"])
|
||||
toggle_seals(user)
|
||||
else if(href_list["interact_module"])
|
||||
// Suit access-gated actions.
|
||||
switch(action)
|
||||
// Toggles a 'clothing' piece on or off.
|
||||
if("toggle_piece")
|
||||
var/piece = "[params["piece"]]"
|
||||
if(!piece)
|
||||
return TRUE
|
||||
|
||||
var/module_index = text2num(href_list["interact_module"])
|
||||
if(ishuman(user) && (user.stat || user.stunned || user.lying))
|
||||
return TRUE
|
||||
|
||||
if(module_index > 0 && module_index <= installed_modules.len)
|
||||
var/obj/item/rig_module/module = installed_modules[module_index]
|
||||
switch(href_list["module_mode"])
|
||||
if("activate")
|
||||
module.activate(user)
|
||||
if("deactivate")
|
||||
module.deactivate(user)
|
||||
if("engage")
|
||||
module.do_engage(null, user)
|
||||
if("select")
|
||||
selected_module = module
|
||||
if("select_charge_type")
|
||||
module.charge_selected = href_list["charge_type"]
|
||||
else if(href_list["toggle_ai_control"])
|
||||
ai_override_enabled = !ai_override_enabled
|
||||
notify_ai("Synthetic suit control has been [ai_override_enabled ? "enabled" : "disabled"].")
|
||||
else if(href_list["toggle_suit_lock"])
|
||||
locked = !locked
|
||||
toggle_piece(piece, user)
|
||||
|
||||
// Deploys all pieces.
|
||||
if("toggle_seals")
|
||||
toggle_seals(user)
|
||||
|
||||
// Module interactions.
|
||||
if("interact_module")
|
||||
var/module_index = text2num(params["index"])
|
||||
if(!module_index)
|
||||
return TRUE
|
||||
|
||||
if(module_index > 0 && module_index <= installed_modules.len)
|
||||
var/obj/item/rig_module/module = installed_modules[module_index]
|
||||
var/mode = "[params["mode"]]"
|
||||
switch(mode)
|
||||
if("activate")
|
||||
module.activate(user)
|
||||
sound_to(usr, module?.sound_activate)
|
||||
if("deactivate")
|
||||
module.deactivate(user)
|
||||
sound_to(usr, module?.sound_deactivate)
|
||||
if("engage")
|
||||
module.do_engage(null, user)
|
||||
if("select")
|
||||
if(selected_module != module)
|
||||
// Clear the currently selected module's overlay.
|
||||
if(selected_module)
|
||||
selected_module.suit_overlay = null
|
||||
selected_module = module
|
||||
// Set the new selected module's suit overlay.
|
||||
if(selected_module.suit_overlay_active)
|
||||
selected_module.suit_overlay = selected_module.suit_overlay_active
|
||||
sound_to(usr, module?.sound_activate)
|
||||
else
|
||||
sound_to(usr, selected_module?.sound_deactivate)
|
||||
selected_module.suit_overlay = null
|
||||
selected_module = null
|
||||
update_icon(TRUE)
|
||||
playsound(src.loc, 'sound/items/rfd_dispense.ogg', 25, FALSE)
|
||||
if("select_charge_type")
|
||||
module.charge_selected = "[params["charge_type"]]"
|
||||
sound_to(usr, module.sound_config)
|
||||
|
||||
if("toggle_ai_control")
|
||||
ai_override_enabled = !ai_override_enabled
|
||||
notify_ai("Synthetic suit control has been [ai_override_enabled ? "enabled" : "disabled"].")
|
||||
sound_to(usr, 'sound/machines/terminal/terminal_prompt_deny.ogg')
|
||||
|
||||
// Cover panel locked or unlocked (by access ID).
|
||||
if("toggle_suit_lock")
|
||||
locked = !locked
|
||||
sound_to(usr, 'sound/machines/terminal/terminal_prompt_deny.ogg')
|
||||
// Toggles whether access locks are enabled.
|
||||
if("toggle_id_lock")
|
||||
// Only those people who have access rights in the first place should be able to toggle access on or off.
|
||||
if(!src.allowed(user))
|
||||
sound_to(user, 'sound/machines/terminal/terminal_error.ogg')
|
||||
balloon_alert(user, "access denied!")
|
||||
else
|
||||
security_check_enabled = !security_check_enabled
|
||||
sound_to(usr, 'sound/machines/terminal/terminal_prompt_deny.ogg')
|
||||
|
||||
if("configure")
|
||||
var/obj/item/rig_module/module = locate(params["ref"]) in installed_modules
|
||||
if(!module)
|
||||
return
|
||||
module.configure_edit(params["key"], params["value"], user)
|
||||
sound_to(usr, module.sound_config)
|
||||
|
||||
user.set_machine(src)
|
||||
src.add_fingerprint(user)
|
||||
return FALSE
|
||||
|
||||
return TRUE
|
||||
|
||||
// Makes sure the UI is only available if you're wearing it, unless you're an AI.
|
||||
/obj/item/rig/ui_state(mob/user)
|
||||
if(!issilicon(user))
|
||||
return GLOB.inventory_state
|
||||
|
||||
/obj/item/rig/proc/notify_ai(var/message)
|
||||
for(var/obj/item/rig_module/ai_container/module in installed_modules)
|
||||
@@ -712,7 +837,7 @@
|
||||
M.visible_message(SPAN_NOTICE("<b>[M] struggles into \the [src].</b>"), SPAN_NOTICE("<b>You struggle into \the [src].</b>"))
|
||||
wearer = M
|
||||
wearer.wearing_rig = src
|
||||
update_icon()
|
||||
update_icon(TRUE)
|
||||
return TRUE
|
||||
return TRUE
|
||||
|
||||
@@ -753,25 +878,43 @@
|
||||
check_slot = wearer.wear_suit
|
||||
|
||||
if(use_obj)
|
||||
// Handle retracting the piece, if possible.
|
||||
if(check_slot == use_obj && deploy_mode != ONLY_DEPLOY)
|
||||
|
||||
var/mob/living/carbon/human/holder
|
||||
holder = use_obj.loc
|
||||
if(istype(holder))
|
||||
// Special code for boots. This is to prevent boots from being retracted while the chest piece is deployed.
|
||||
// Otherwise, it is an easy exploit to make any hardsuit stealthy by wearing everything EXCEPT the boots.
|
||||
var/obj/item/chest_slot = holder.wear_suit
|
||||
var/obj/item/chest_obj = chest
|
||||
if(use_obj == boots && chest_slot == chest_obj)
|
||||
to_chat(wearer, SPAN_WARNING("The chest piece of the hardsuit must be retracted before you can retract your boots!"))
|
||||
sound_to(wearer, 'sound/machines/terminal/terminal_error.ogg')
|
||||
return
|
||||
|
||||
if(use_obj)
|
||||
holder = use_obj.loc
|
||||
if(istype(holder))
|
||||
if(use_obj && check_slot == use_obj)
|
||||
to_chat(wearer, "<font color='blue'><b>Your [use_obj.name] [use_obj.gender == PLURAL ? "retract" : "retracts"] swiftly.</b></font>")
|
||||
playsound(src, 'sound/machines/rig/rig_retract.ogg', 20, FALSE)
|
||||
use_obj.canremove = 1
|
||||
holder.drop_from_inventory(use_obj,get_turf(src)) //TODO: TEST THIS CODE!
|
||||
use_obj.dropped(wearer)
|
||||
use_obj.canremove = 0
|
||||
use_obj.forceMove(src)
|
||||
if(check_slot == use_obj)
|
||||
to_chat(wearer, "<font color='blue'><b>Your [use_obj.name] [use_obj.gender == PLURAL ? "retract" : "retracts"] swiftly.</b></font>")
|
||||
playsound(src, 'sound/machines/rig/rig_retract.ogg', 30, FALSE)
|
||||
use_obj.canremove = 1
|
||||
holder.drop_from_inventory(use_obj,get_turf(src)) //TODO: TEST THIS CODE!
|
||||
use_obj.dropped(wearer)
|
||||
use_obj.canremove = 0
|
||||
use_obj.forceMove(src)
|
||||
|
||||
// Handle deploying the piece, if possible.
|
||||
else if (deploy_mode != ONLY_RETRACT)
|
||||
if(check_slot && check_slot == use_obj)
|
||||
return
|
||||
return TRUE
|
||||
if(!do_after(wearer, 8))
|
||||
if(wearer)
|
||||
to_chat(wearer, SPAN_WARNING("You must remain still while the suit deploys its parts."))
|
||||
return FALSE
|
||||
// If we're deploying the chest, we also try to deploy boots. If we can't also deploy boots, the entire thing fails.
|
||||
if(use_obj == chest)
|
||||
if(!toggle_piece("boots", initiator, ONLY_DEPLOY))
|
||||
to_chat(initiator, SPAN_DANGER("You are unable to deploy \the [piece] as the boots were unable to also deploy!"))
|
||||
playsound(src, 'sound/items/rfd_empty.ogg', 20, FALSE)
|
||||
return FALSE
|
||||
use_obj.forceMove(wearer)
|
||||
if(src.color)
|
||||
use_obj.color = src.color
|
||||
@@ -780,14 +923,18 @@
|
||||
if(check_slot)
|
||||
to_chat(initiator, SPAN_DANGER("You are unable to deploy \the [piece] as \the [check_slot] [check_slot.gender == PLURAL ? "are" : "is"] in the way."))
|
||||
playsound(src, 'sound/items/rfd_empty.ogg', 20, FALSE)
|
||||
return
|
||||
return FALSE
|
||||
else
|
||||
to_chat(wearer, SPAN_NOTICE("Your [use_obj.name] [use_obj.gender == PLURAL ? "deploy" : "deploys"] swiftly."))
|
||||
playsound(src, 'sound/machines/rig/rig_deploy.ogg', 20, FALSE)
|
||||
playsound(src, 'sound/machines/rig/rig_deploy.ogg', 30, FALSE)
|
||||
|
||||
if(piece == "helmet" && helmet)
|
||||
helmet.update_light(wearer)
|
||||
|
||||
update_icon(TRUE)
|
||||
|
||||
return TRUE
|
||||
|
||||
/obj/item/rig/proc/deploy(mob/M,var/sealed)
|
||||
|
||||
var/mob/living/carbon/human/H = M
|
||||
@@ -864,16 +1011,18 @@
|
||||
//possibly damage some modules
|
||||
take_hit((100/severity), "electrical pulse", 1)
|
||||
|
||||
/// Handles running electrocute_mob() on the passed user. If the user is wearing the suit, it picks between head, chest, and groin for contact_zone.
|
||||
/// If not wearing the suit (i.e. tampering with the wires), contact_zone is assumed to be the passed user's hands.
|
||||
/obj/item/rig/proc/shock(mob/user)
|
||||
var/touchy = pick(BP_CHEST,BP_HEAD,BP_GROIN)
|
||||
if(!wearer)
|
||||
touchy = "hand"
|
||||
|
||||
if (electrocute_mob(user, cell, src, contact_zone = touchy)) //electrocute_mob() handles removing charge from the cell, no need to do that here.
|
||||
if(electrocute_mob(user, cell, src, contact_zone = touchy)) //electrocute_mob() handles removing charge from the cell, no need to do that here.
|
||||
spark_system.queue()
|
||||
if(user.stunned)
|
||||
return 1
|
||||
return 0
|
||||
return TRUE
|
||||
return FALSE
|
||||
|
||||
/obj/item/rig/proc/take_hit(damage, source, is_emp=0)
|
||||
|
||||
@@ -956,7 +1105,7 @@
|
||||
to_chat(user, SPAN_WARNING("Your host module is unable to interface with the suit."))
|
||||
return 0
|
||||
|
||||
if(offline || !cell || !cell.charge || locked_down)
|
||||
if(offline || !cell || !cell.charge)
|
||||
if(user) to_chat(user, SPAN_WARNING("Your host rig is unpowered and unresponsive."))
|
||||
return 0
|
||||
if(!wearer || wearer.back != src)
|
||||
@@ -1100,7 +1249,3 @@
|
||||
air_supply.remove_air(air_supply.air_contents.total_moles)
|
||||
else
|
||||
air_supply = null
|
||||
|
||||
#undef ONLY_DEPLOY
|
||||
#undef ONLY_RETRACT
|
||||
#undef SEAL_DELAY
|
||||
|
||||
@@ -83,20 +83,20 @@
|
||||
var/mob/living/carbon/human/H = src.loc
|
||||
if(H.back == src)
|
||||
to_chat(user, SPAN_DANGER("You can't install a hardsuit module while the suit is being worn."))
|
||||
return 1
|
||||
return TRUE
|
||||
|
||||
if(!installed_modules) installed_modules = list()
|
||||
|
||||
if(!(module.category & allowed_module_types))
|
||||
var/mod_name = get_module_category(module.category)
|
||||
to_chat(user, SPAN_WARNING("\The [src] does not support [mod_name] modules!"))
|
||||
return 0
|
||||
return FALSE
|
||||
|
||||
if(installed_modules.len)
|
||||
for(var/obj/item/rig_module/installed_mod in installed_modules)
|
||||
if(!installed_mod.redundant && istype(installed_mod, attacking_item))
|
||||
to_chat(user, SPAN_NOTICE("The hardsuit already has a module of that class installed."))
|
||||
return 1
|
||||
return TRUE
|
||||
|
||||
var/obj/item/rig_module/mod = attacking_item
|
||||
to_chat(user, SPAN_NOTICE("You begin installing \the [mod] into \the [src]."))
|
||||
@@ -113,7 +113,7 @@
|
||||
mod.forceMove(src)
|
||||
mod.installed(src)
|
||||
update_icon()
|
||||
return 1
|
||||
return TRUE
|
||||
|
||||
else if(!cell && istype(attacking_item,/obj/item/cell))
|
||||
|
||||
@@ -222,6 +222,10 @@
|
||||
return
|
||||
..()
|
||||
|
||||
/obj/item/rig/attack_self(var/mob/user)
|
||||
if(wearer && wearer.back == src)
|
||||
ui_interact(usr)
|
||||
|
||||
/obj/item/rig/emag_act(var/remaining_charges, var/mob/user)
|
||||
if(!subverted)
|
||||
req_access.Cut()
|
||||
@@ -229,7 +233,7 @@
|
||||
locked = FALSE
|
||||
subverted = 1
|
||||
to_chat(user, SPAN_DANGER("You short out the access protocol for the suit."))
|
||||
return 1
|
||||
return TRUE
|
||||
|
||||
/obj/item/rig/proc/get_module_category(var/category)
|
||||
switch(category)
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
/obj/item/rig/verb/hardsuit_interface()
|
||||
set name = "Open Hardsuit Interface"
|
||||
set desc = "Open the hardsuit system interface."
|
||||
set category = "Hardsuit"
|
||||
set category = "Hardsuit.Core Functions"
|
||||
set src = usr.contents
|
||||
|
||||
if(wearer && wearer.back == src)
|
||||
@@ -11,7 +11,7 @@
|
||||
/obj/item/rig/verb/toggle_vision()
|
||||
set name = "Toggle Visor"
|
||||
set desc = "Turns your rig visor off or on."
|
||||
set category = "Hardsuit"
|
||||
set category = "Hardsuit.Module Control"
|
||||
set src = usr.contents
|
||||
|
||||
if(!istype(wearer) || !wearer.back == src)
|
||||
@@ -40,7 +40,7 @@
|
||||
/obj/item/rig/proc/toggle_helmet()
|
||||
set name = "Toggle Helmet"
|
||||
set desc = "Deploys or retracts your helmet."
|
||||
set category = "Hardsuit"
|
||||
set category = "Hardsuit.Part Toggles"
|
||||
set src = usr.contents
|
||||
|
||||
if(!istype(wearer) || !wearer.back == src)
|
||||
@@ -58,7 +58,7 @@
|
||||
/obj/item/rig/proc/toggle_chest()
|
||||
set name = "Toggle Chestpiece"
|
||||
set desc = "Deploys or retracts your chestpiece."
|
||||
set category = "Hardsuit"
|
||||
set category = "Hardsuit.Part Toggles"
|
||||
set src = usr.contents
|
||||
|
||||
if(!istype(wearer) || !wearer.back == src)
|
||||
@@ -76,7 +76,7 @@
|
||||
/obj/item/rig/proc/toggle_gauntlets()
|
||||
set name = "Toggle Gauntlets"
|
||||
set desc = "Deploys or retracts your gauntlets."
|
||||
set category = "Hardsuit"
|
||||
set category = "Hardsuit.Part Toggles"
|
||||
set src = usr.contents
|
||||
|
||||
if(!istype(wearer) || !wearer.back == src)
|
||||
@@ -94,7 +94,7 @@
|
||||
/obj/item/rig/proc/toggle_boots()
|
||||
set name = "Toggle Boots"
|
||||
set desc = "Deploys or retracts your boots."
|
||||
set category = "Hardsuit"
|
||||
set category = "Hardsuit.Part Toggles"
|
||||
set src = usr.contents
|
||||
|
||||
if(!istype(wearer) || !wearer.back == src)
|
||||
@@ -110,9 +110,9 @@
|
||||
toggle_piece("boots",wearer)
|
||||
|
||||
/obj/item/rig/verb/deploy_suit()
|
||||
set name = "Deploy Hardsuit"
|
||||
set name = "Deploy All Hardsuit Parts"
|
||||
set desc = "Deploys helmet, gloves and boots."
|
||||
set category = "Hardsuit"
|
||||
set category = "Hardsuit.Core Functions"
|
||||
set src = usr.contents
|
||||
|
||||
if(!istype(wearer) || !wearer.back == src)
|
||||
@@ -131,9 +131,9 @@
|
||||
deploy(wearer)
|
||||
|
||||
/obj/item/rig/verb/toggle_seals_verb()
|
||||
set name = "Toggle Hardsuit"
|
||||
set desc = "Activates or deactivates your rig."
|
||||
set category = "Hardsuit"
|
||||
set name = "Engage/Disengage Hardsuit"
|
||||
set desc = "Activates or deactivates your hardsuit."
|
||||
set category = "Hardsuit.Core Functions"
|
||||
set src = usr.contents
|
||||
|
||||
if(!istype(wearer) || !wearer.back == src)
|
||||
@@ -151,7 +151,7 @@
|
||||
/obj/item/rig/verb/switch_vision_mode()
|
||||
set name = "Switch Vision Mode"
|
||||
set desc = "Switches between available vision modes."
|
||||
set category = "Hardsuit"
|
||||
set category = "Hardsuit.Module Control"
|
||||
set src = usr.contents
|
||||
|
||||
if(malfunction_check(usr))
|
||||
@@ -180,7 +180,7 @@
|
||||
/obj/item/rig/verb/alter_voice()
|
||||
set name = "Configure Voice Synthesiser"
|
||||
set desc = "Toggles or configures your voice synthesizer."
|
||||
set category = "Hardsuit"
|
||||
set category = "Hardsuit.Module Control"
|
||||
set src = usr.contents
|
||||
|
||||
if(malfunction_check(usr))
|
||||
@@ -203,7 +203,7 @@
|
||||
/obj/item/rig/verb/select_module()
|
||||
set name = "Select Module"
|
||||
set desc = "Selects a module as your primary system."
|
||||
set category = "Hardsuit"
|
||||
set category = "Hardsuit.Module Control"
|
||||
set src = usr.contents
|
||||
|
||||
if(malfunction_check(usr))
|
||||
@@ -222,7 +222,7 @@
|
||||
|
||||
var/list/selectable = list()
|
||||
for(var/obj/item/rig_module/module in installed_modules)
|
||||
if(module.selectable)
|
||||
if(module.module_type == MODULETYPE_USABLE_ACTIVE)
|
||||
selectable |= module
|
||||
|
||||
var/obj/item/rig_module/module = tgui_input_list(usr, "Which module do you wish to select?", "Select Module", selectable)
|
||||
@@ -238,7 +238,7 @@
|
||||
/obj/item/rig/verb/toggle_module()
|
||||
set name = "Toggle Module"
|
||||
set desc = "Toggle a system module."
|
||||
set category = "Hardsuit"
|
||||
set category = "Hardsuit.Module Control"
|
||||
set src = usr.contents
|
||||
|
||||
if(malfunction_check(usr))
|
||||
@@ -257,7 +257,7 @@
|
||||
|
||||
var/list/selectable = list()
|
||||
for(var/obj/item/rig_module/module in installed_modules)
|
||||
if(module.toggleable)
|
||||
if(module.module_type == MODULETYPE_TOGGLE)
|
||||
selectable |= module
|
||||
|
||||
var/obj/item/rig_module/module = tgui_input_list(usr, "Which module do you wish to toggle?", "Toggle Module", selectable)
|
||||
@@ -275,7 +275,7 @@
|
||||
/obj/item/rig/verb/engage_module()
|
||||
set name = "Engage Module"
|
||||
set desc = "Engages a system module."
|
||||
set category = "Hardsuit"
|
||||
set category = "Hardsuit.Module Control"
|
||||
set src = usr.contents
|
||||
|
||||
if(malfunction_check(usr))
|
||||
@@ -294,7 +294,7 @@
|
||||
|
||||
var/list/selectable = list()
|
||||
for(var/obj/item/rig_module/module in installed_modules)
|
||||
if(module.usable)
|
||||
if(module.module_type == MODULETYPE_USABLE)
|
||||
selectable |= module
|
||||
|
||||
var/obj/item/rig_module/module = tgui_input_list(usr, "Which module do you wish to engage?", "Engage Module", selectable)
|
||||
|
||||
@@ -51,7 +51,7 @@
|
||||
|
||||
req_access = list(ACCESS_SYNDICATE)
|
||||
|
||||
airtight = 0
|
||||
airtight = FALSE
|
||||
seal_delay = 5 //not being vaccum-proof has an upside I guess
|
||||
|
||||
helm_type = /obj/item/clothing/head/lightrig/hacker
|
||||
@@ -215,7 +215,7 @@
|
||||
RAD = ARMOR_RAD_MINOR
|
||||
)
|
||||
slowdown = 0
|
||||
airtight = 0
|
||||
airtight = FALSE
|
||||
seal_delay = 5
|
||||
helm_type = /obj/item/clothing/head/lightrig/offworlder
|
||||
chest_type = /obj/item/clothing/suit/lightrig/offworlder
|
||||
@@ -262,7 +262,7 @@
|
||||
)
|
||||
slowdown = -0.3
|
||||
offline_slowdown = 0
|
||||
airtight = 1
|
||||
airtight = TRUE
|
||||
offline_vision_restriction = TINT_HEAVY
|
||||
siemens_coefficient = 0.2
|
||||
icon_supported_species_tags = null
|
||||
|
||||
@@ -93,8 +93,8 @@
|
||||
G.process_hud(src)
|
||||
|
||||
/mob/living/carbon/human/proc/process_rig(var/obj/item/rig/O)
|
||||
if(O.visor && O.visor.active && O.visor.vision && O.visor.vision.glasses && (!O.helmet || (head && O.helmet == head)))
|
||||
process_glasses(O.visor.vision.glasses)
|
||||
if(O.visor && O.visor.active && O.visor.vision_mode && O.visor.vision_mode.glasses && (!O.helmet || (head && O.helmet == head)))
|
||||
process_glasses(O.visor.vision_mode.glasses)
|
||||
|
||||
/// Applies organ/markings prefs to this mob.
|
||||
/mob/living/carbon/human/proc/sync_organ_prefs_to_mob(datum/preferences/prefs, apply_prosthetics = TRUE, apply_markings = TRUE)
|
||||
|
||||
+53
-22
@@ -24,10 +24,13 @@
|
||||
///////////////////////////////
|
||||
// General procedures
|
||||
//////////////////////////////
|
||||
// Proc: power_wattage_readable()
|
||||
// Parameters: 1 (amount - Power in Watts to be converted to W, kW or MW)
|
||||
// Description: Helper proc that converts reading in Watts to kW or MW (returns string version of amount parameter)
|
||||
/obj/machinery/proc/power_wattage_readable(var/amount = 0)
|
||||
/**
|
||||
* Proc: power_wattage_readable()
|
||||
* Parameters: 1 (amount - Power in Watts to be converted to W, kW or MW)
|
||||
* Description: Helper proc that converts reading in Watts to kW or MW (returns string version of amount parameter)
|
||||
* NOTE: This needs to be replaced by a common SIUnits proc once energy is normalized (watts, volts, joules, etc.)
|
||||
*/
|
||||
/proc/power_wattage_readable(var/amount = 0)
|
||||
var/units = ""
|
||||
// 10kW and less - Watts
|
||||
if(amount < 10000)
|
||||
@@ -45,10 +48,35 @@
|
||||
else
|
||||
return "[amount] [units]"
|
||||
|
||||
/obj/machinery/power/proc/disconnect_terminal() // machines without a terminal will just return, no harm no fowl.
|
||||
/**
|
||||
* Proc: power_joules_readable()
|
||||
* Parameters: 1 (amount - Power in Joules to be converted to J, kJ or MJ)
|
||||
* Description: Helper proc that converts reading in Joules to kJ or MJ (returns string version of amount parameter)
|
||||
* NOTE: This needs to be replaced by a common SIUnits proc once energy is normalized (watts, volts, joules, etc.)
|
||||
*/
|
||||
/proc/power_joules_readable(var/amount = 0)
|
||||
var/units = ""
|
||||
// 10kW and less - Watts
|
||||
if(amount < 10000)
|
||||
units = "W"
|
||||
// 10MW and less - KiloWatts
|
||||
else if(amount < 10000000)
|
||||
units = "kJ"
|
||||
amount = (round(amount/100) / 10)
|
||||
// More than 10MW - MegaWatts
|
||||
else
|
||||
units = "MJ"
|
||||
amount = (round(amount/10000) / 100)
|
||||
if (units == "J")
|
||||
return "[amount] J"
|
||||
else
|
||||
return "[amount] [units]"
|
||||
|
||||
/// Machines without a terminal will just return, no harm no fowl.
|
||||
/obj/machinery/power/proc/disconnect_terminal()
|
||||
return
|
||||
|
||||
// connect the machine to a powernet if a node cable is present on the turf
|
||||
/// Connect the machine to a powernet if a node cable is present on the turf
|
||||
/obj/machinery/power/proc/connect_to_network()
|
||||
var/turf/T = src.loc
|
||||
if(!T || !istype(T))
|
||||
@@ -61,15 +89,17 @@
|
||||
C.powernet.add_machine(src)
|
||||
return 1
|
||||
|
||||
// remove and disconnect the machine from its current powernet
|
||||
/// Remove and disconnect the machine from its current powernet.
|
||||
/obj/machinery/power/proc/disconnect_from_network()
|
||||
if(!powernet)
|
||||
return 0
|
||||
powernet.remove_machine(src)
|
||||
return 1
|
||||
|
||||
// attach a wire to a power machine - leads from the turf you are standing on
|
||||
//almost never called, overwritten by all power machines but terminal and generator
|
||||
/**
|
||||
* Attach a wire to a power machine - leads from the turf you are standing on
|
||||
* almost never called, overwritten by all power machines but terminal and generator
|
||||
*/
|
||||
/obj/machinery/power/attackby(obj/item/attacking_item, mob/user)
|
||||
|
||||
if(attacking_item.tool_behaviour == TOOL_CABLECOIL)
|
||||
@@ -94,8 +124,8 @@
|
||||
// Powernet handling helpers
|
||||
//////////////////////////////////////////
|
||||
|
||||
//returns all the cables WITHOUT a powernet in neighbors turfs,
|
||||
//pointing towards the turf the machine is located at
|
||||
/// Returns all the cables WITHOUT a powernet in neighbors turfs,
|
||||
/// pointing towards the turf the machine is located at.
|
||||
/obj/machinery/power/proc/get_connections()
|
||||
|
||||
. = list()
|
||||
@@ -113,8 +143,8 @@
|
||||
. += C
|
||||
return .
|
||||
|
||||
//returns all the cables in neighbors turfs,
|
||||
//pointing towards the turf the machine is located at
|
||||
/// Returns all the cables in neighbors turfs,
|
||||
/// pointing towards the turf the machine is located at
|
||||
/obj/machinery/power/proc/get_marked_connections()
|
||||
|
||||
. = list()
|
||||
@@ -131,7 +161,7 @@
|
||||
. += C
|
||||
return .
|
||||
|
||||
//returns all the NODES (O-X) cables WITHOUT a powernet in the turf the machine is located at
|
||||
/// Returns all the NODES (O-X) cables WITHOUT a powernet in the turf the machine is located at
|
||||
/obj/machinery/power/proc/get_indirect_connections()
|
||||
. = list()
|
||||
for(var/obj/structure/cable/C in loc)
|
||||
@@ -144,10 +174,11 @@
|
||||
// GLOBAL PROCS for powernets handling
|
||||
//////////////////////////////////////////
|
||||
|
||||
|
||||
// returns a list of all power-related objects (nodes, cable, junctions) in turf,
|
||||
// excluding source, that match the direction d
|
||||
// if unmarked==1, only return those with no powernet
|
||||
/**
|
||||
* Returns a list of all power-related objects (nodes, cable, junctions) in turf,
|
||||
* excluding source, that match the direction d.
|
||||
* If unmarked==1, only return those with no powernet
|
||||
*/
|
||||
/proc/power_list(var/turf/T, var/source, var/d, var/unmarked=0, var/cable_only = 0)
|
||||
. = list()
|
||||
var/fdir = (!d)? 0 : turn(d, 180) // the opposite direction to d (or 0 if d==0)
|
||||
@@ -183,7 +214,7 @@
|
||||
. += C
|
||||
return .
|
||||
|
||||
//remove the old powernet and replace it with a new one throughout the network.
|
||||
/// Remove the old powernet and replace it with a new one throughout the network.
|
||||
/proc/propagate_network(var/obj/O, var/datum/powernet/PN)
|
||||
//world.log << "propagating new network"
|
||||
var/list/worklist = list()
|
||||
@@ -216,7 +247,7 @@
|
||||
PM.disconnect_from_network() //... so disconnect if already on a powernet
|
||||
|
||||
|
||||
//Merge two powernets, the bigger (in cable length term) absorbing the other
|
||||
/// Merge two powernets, the bigger (in cable length term) absorbing the other
|
||||
/proc/merge_powernets(var/datum/powernet/net1, var/datum/powernet/net2)
|
||||
if(!net1 || !net2) //if one of the powernet doesn't exist, return
|
||||
return
|
||||
@@ -280,10 +311,10 @@
|
||||
if (apc.terminal)
|
||||
PN = apc.terminal.powernet
|
||||
else if (!power_source)
|
||||
return 0
|
||||
return FALSE
|
||||
else
|
||||
log_admin("ERROR: /proc/electrocute_mob([victim], [power_source], [source]): wrong power_source")
|
||||
return 0
|
||||
return FALSE
|
||||
//Triggers powernet warning, but only for 5 ticks (if applicable)
|
||||
//If following checks determine user is protected we won't alarm for long.
|
||||
if(PN)
|
||||
|
||||
@@ -69,13 +69,14 @@
|
||||
/obj/projectile/beam/plasmacutter
|
||||
name = "plasma arc"
|
||||
icon_state = "omnilaser"
|
||||
damage = 20
|
||||
damage = 32
|
||||
damage_type = DAMAGE_BURN
|
||||
check_armor = LASER
|
||||
range = 5
|
||||
range = 3
|
||||
pass_flags = PASSTABLE|PASSRAILING
|
||||
|
||||
var/mineral_passes = 2 // amount of mineral turfs it passes through before ending
|
||||
/// Number of mineral turfs it passes through before ending.
|
||||
var/mineral_passes = 2
|
||||
|
||||
muzzle_type = /obj/effect/projectile/muzzle/plasma_cutter
|
||||
tracer_type = /obj/effect/projectile/tracer/plasma_cutter
|
||||
|
||||
Reference in New Issue
Block a user