mirror of
https://github.com/Aurorastation/Aurora.3.git
synced 2026-07-18 11:30:35 +01:00
Shell May Cry: A comprehensive rework of synthetics. (#20721)
https://www.youtube.com/watch?v=9mPvZ96pHJI A pull request commissioned by the Synthetic Lore Team to comprehensively rework synthetics (read: IPCs) and how they work in Aurora. The objective is to make IPCs as unique as possible from humans, upgrading the robotic feel and atmosphere, while also preserving a good sense of balance in-game. Key features: - A comprehensive expansion of synthetic organs, all of which now fulfill a purpose: hydraulics, cooling units, power systems, actuators, diagnostics units. - Customizable organs with benefits and drawbacks, such as with cooling units and power systems. - Unique ways to repair the organs and more involved steps. - Unique damage mechanics - every organ has wiring and electronics which affect its functioning, and they are defended by plating which provides natural armour. - Improved and immersive diagnostics. - Unique features, benefits, and drawbacks for every IPC frame. - A rework of the positronic brain, which can be either destroyed or shut down, alongside effects caused by low integrity. - A rework of how EMPs affect IPC organs. - Non-binary damage states for each organ. To-do: - [x] Finish the unique features for each frame. - [x] Look into if mechanical synthskin is possible. - [x] Power system. - [x] Posibrain mechanics. - [ ] Passive cooling expansion. - [x] EMP mechanics. - [x] Repair mechanics. - [x] Mob weight mechanics. - [ ] Gurney for heavy mobs. - [x] New augments. - [ ] IPC tag scanning and flashing. --------- Signed-off-by: Werner <1331699+Arrow768@users.noreply.github.com> Co-authored-by: Matt Atlas <liermattia@gmail.com> Co-authored-by: Geeves <22774890+Geevies@users.noreply.github.com> Co-authored-by: Werner <1331699+Arrow768@users.noreply.github.com>
This commit is contained in:
+36
-1
@@ -187,6 +187,7 @@
|
||||
#include "code\__DEFINES\dcs\signals\signals_atom\signals_atom_movement.dm"
|
||||
#include "code\__DEFINES\dcs\signals\signals_atom\signals_atom_x_act.dm"
|
||||
#include "code\__DEFINES\dcs\signals\signals_atom\signals_power_cell.dm"
|
||||
#include "code\__DEFINES\dcs\signals\signals_mob\signals_mob_human.dm"
|
||||
#include "code\__DEFINES\dcs\signals\signals_mob\signals_mob_living.dm"
|
||||
#include "code\__DEFINES\dcs\signals\signals_mob\signals_mob_main.dm"
|
||||
#include "code\__DEFINES\dcs\signals\signals_object\signals_object.dm"
|
||||
@@ -476,7 +477,8 @@
|
||||
#include "code\datums\components\local_network.dm"
|
||||
#include "code\datums\components\orbiter.dm"
|
||||
#include "code\datums\components\overlay_lighting.dm"
|
||||
#include "code\datums\components\armor\armor.dm"
|
||||
#include "code\datums\components\armor\_armor.dm"
|
||||
#include "code\datums\components\armor\synthetic_armor.dm"
|
||||
#include "code\datums\components\base_name\base_name.dm"
|
||||
#include "code\datums\components\eye\_eye.dm"
|
||||
#include "code\datums\components\eye\base_planner.dm"
|
||||
@@ -487,6 +489,7 @@
|
||||
#include "code\datums\components\multitool\circuitboards\circuitboards.dm"
|
||||
#include "code\datums\components\overhead_emote\overhead_emote_datum.dm"
|
||||
#include "code\datums\components\overhead_emote\overhead_emote_singleton.dm"
|
||||
#include "code\datums\components\synthetic_endoskeleton\synthetic_endoskeleton.dm"
|
||||
#include "code\datums\components\turf_click\turf_hand.dm"
|
||||
#include "code\datums\elements\_element.dm"
|
||||
#include "code\datums\elements\connect_loc.dm"
|
||||
@@ -505,6 +508,7 @@
|
||||
#include "code\datums\langchat\langchat.dm"
|
||||
#include "code\datums\looping_sounds\_looping_sound.dm"
|
||||
#include "code\datums\looping_sounds\machinery_sounds.dm"
|
||||
#include "code\datums\looping_sounds\mobs.dm"
|
||||
#include "code\datums\looping_sounds\revenant_rift.dm"
|
||||
#include "code\datums\looping_sounds\thermal_drill.dm"
|
||||
#include "code\datums\observation\_debug.dm"
|
||||
@@ -573,6 +577,10 @@
|
||||
#include "code\datums\scenarios\scenario.dm"
|
||||
#include "code\datums\state_machine\state.dm"
|
||||
#include "code\datums\state_machine\transition.dm"
|
||||
#include "code\datums\synthetic_internals\_synthetic_internals.dm"
|
||||
#include "code\datums\synthetic_internals\electronics.dm"
|
||||
#include "code\datums\synthetic_internals\plating.dm"
|
||||
#include "code\datums\synthetic_internals\wiring.dm"
|
||||
#include "code\datums\tips\tips.dm"
|
||||
#include "code\datums\trading\_trading_defines.dm"
|
||||
#include "code\datums\trading\ai.dm"
|
||||
@@ -3008,6 +3016,7 @@
|
||||
#include "code\modules\modular_computers\file_system\programs\research\ai_restorer.dm"
|
||||
#include "code\modules\modular_computers\file_system\programs\research\chemistry_codex.dm"
|
||||
#include "code\modules\modular_computers\file_system\programs\research\ntmonitor.dm"
|
||||
#include "code\modules\modular_computers\file_system\programs\research\robotics.dm"
|
||||
#include "code\modules\modular_computers\file_system\programs\security\camera.dm"
|
||||
#include "code\modules\modular_computers\file_system\programs\security\digitalwarrant.dm"
|
||||
#include "code\modules\modular_computers\file_system\programs\security\guntracker.dm"
|
||||
@@ -3017,6 +3026,7 @@
|
||||
#include "code\modules\modular_computers\file_system\programs\system\configurator.dm"
|
||||
#include "code\modules\modular_computers\file_system\programs\system\file_browser.dm"
|
||||
#include "code\modules\modular_computers\file_system\programs\system\ntdownloader.dm"
|
||||
#include "code\modules\modular_computers\hardware\access_cable_dongle.dm"
|
||||
#include "code\modules\modular_computers\hardware\ai_slot.dm"
|
||||
#include "code\modules\modular_computers\hardware\battery_module.dm"
|
||||
#include "code\modules\modular_computers\hardware\card_slot.dm"
|
||||
@@ -3029,6 +3039,7 @@
|
||||
#include "code\modules\modular_computers\hardware\portable_hard_drive_presets.dm"
|
||||
#include "code\modules\modular_computers\hardware\processor_unit.dm"
|
||||
#include "code\modules\modular_computers\hardware\tesla_link.dm"
|
||||
#include "code\modules\modular_computers\hardware\universal_port.dm"
|
||||
#include "code\modules\modular_computers\items\paper_scanner.dm"
|
||||
#include "code\modules\modular_computers\NTNet\NTNet.dm"
|
||||
#include "code\modules\modular_computers\NTNet\NTNet_relay.dm"
|
||||
@@ -3040,6 +3051,7 @@
|
||||
#include "code\modules\movespeed\modifiers\mobs.dm"
|
||||
#include "code\modules\movespeed\modifiers\reagents.dm"
|
||||
#include "code\modules\movespeed\modifiers\spells.dm"
|
||||
#include "code\modules\movespeed\modifiers\synthetics.dm"
|
||||
#include "code\modules\multiz\_stubs.dm"
|
||||
#include "code\modules\multiz\basic.dm"
|
||||
#include "code\modules\multiz\hoist.dm"
|
||||
@@ -3083,6 +3095,26 @@
|
||||
#include "code\modules\organs\internal\species\tajara.dm"
|
||||
#include "code\modules\organs\internal\species\unathi.dm"
|
||||
#include "code\modules\organs\internal\species\vaurca.dm"
|
||||
#include "code\modules\organs\internal\species\machine\_generic.dm"
|
||||
#include "code\modules\organs\internal\species\machine\_presets.dm"
|
||||
#include "code\modules\organs\internal\species\machine\access_port.dm"
|
||||
#include "code\modules\organs\internal\species\machine\actuators.dm"
|
||||
#include "code\modules\organs\internal\species\machine\cooling_unit.dm"
|
||||
#include "code\modules\organs\internal\species\machine\cooling_unit_presets.dm"
|
||||
#include "code\modules\organs\internal\species\machine\data_core.dm"
|
||||
#include "code\modules\organs\internal\species\machine\hydraulics.dm"
|
||||
#include "code\modules\organs\internal\species\machine\internal_diagnostics.dm"
|
||||
#include "code\modules\organs\internal\species\machine\internal_storage.dm"
|
||||
#include "code\modules\organs\internal\species\machine\ipc_tag.dm"
|
||||
#include "code\modules\organs\internal\species\machine\optical_sensor.dm"
|
||||
#include "code\modules\organs\internal\species\machine\posibrain.dm"
|
||||
#include "code\modules\organs\internal\species\machine\power_core.dm"
|
||||
#include "code\modules\organs\internal\species\machine\reactor.dm"
|
||||
#include "code\modules\organs\internal\species\machine\reactor_presets.dm"
|
||||
#include "code\modules\organs\internal\species\machine\surge_protector.dm"
|
||||
#include "code\modules\organs\internal\species\machine\targeting_core.dm"
|
||||
#include "code\modules\organs\internal\species\machine\voice_synthesizer.dm"
|
||||
#include "code\modules\organs\internal\species\machine\wireless_access.dm"
|
||||
#include "code\modules\organs\subtypes\autakh.dm"
|
||||
#include "code\modules\organs\subtypes\diona.dm"
|
||||
#include "code\modules\organs\subtypes\industrial.dm"
|
||||
@@ -3600,6 +3632,7 @@
|
||||
#include "code\modules\research\designs\mechfab\prosthetics\internal.dm"
|
||||
#include "code\modules\research\designs\mechfab\robot\robot.dm"
|
||||
#include "code\modules\research\designs\mechfab\robot\robot_upgrades.dm"
|
||||
#include "code\modules\research\designs\mechfab\synthetic\synthetic_organ_parts.dm"
|
||||
#include "code\modules\research\designs\protolathe\deployable_kits.dm"
|
||||
#include "code\modules\research\designs\protolathe\disk_designs.dm"
|
||||
#include "code\modules\research\designs\protolathe\hud_glasses_designs.dm"
|
||||
@@ -3799,6 +3832,8 @@
|
||||
#include "code\modules\tgui\modules\armor_values.dm"
|
||||
#include "code\modules\tgui\modules\flavor_text.dm"
|
||||
#include "code\modules\tgui\modules\hivenet_manifest.dm"
|
||||
#include "code\modules\tgui\modules\ipc_diagnostic.dm"
|
||||
#include "code\modules\tgui\modules\neural_configuration.dm"
|
||||
#include "code\modules\tgui\states\admin.dm"
|
||||
#include "code\modules\tgui\states\always.dm"
|
||||
#include "code\modules\tgui\states\conscious.dm"
|
||||
|
||||
@@ -66,6 +66,8 @@
|
||||
#define COMSIG_ITEM_UPDATE_STATE "update_state"
|
||||
/// updates sprites
|
||||
#define COMSIG_ITEM_ICON_UPDATE "icon_update"
|
||||
/// when a gun mag is emptied
|
||||
#define COMSIG_EMPTIED_MAGAZINE "emptied_magazine"
|
||||
|
||||
// tgui signals
|
||||
#define COMSIG_TGUI_CLOSE "tgui_close"
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
///from datum/species/machine/handle_sprint_cost()
|
||||
#define COMSIG_IPC_HAS_SPRINTED "ipc_sprinted"
|
||||
@@ -141,6 +141,23 @@
|
||||
#define BP_CELL "cell"
|
||||
#define BP_OPTICS "optics"
|
||||
#define BP_IPCTAG "ipc tag"
|
||||
#define BP_REACTOR "reactor"
|
||||
#define BP_VOICE_SYNTHESIZER "voice synthesizer"
|
||||
#define BP_DIAGNOSTICS_SUITE "internal diagnostics suite"
|
||||
#define BP_HYDRAULICS "hydraulics system"
|
||||
#define BP_COOLING_UNIT "cooling unit"
|
||||
#define BP_ACCESS_PORT "universal access port"
|
||||
#define BP_ACTUATORS_LEFT "left arm actuators"
|
||||
#define BP_ACTUATORS_RIGHT "right arm actuators"
|
||||
#define BP_SURGE_PROTECTOR "surge"
|
||||
#define BP_DATACORE "data core"
|
||||
#define BP_TARGETING_CORE "targeting core"
|
||||
|
||||
// Bishop frame only.
|
||||
#define BP_WIRELESS_ACCESS "wireless access point"
|
||||
|
||||
// G2 frame only.
|
||||
#define BP_INTERNAL_STORAGE "internal storage system"
|
||||
|
||||
// Parasite organs
|
||||
#define BP_ZOMBIE_PARASITE "black tumour"
|
||||
@@ -303,6 +320,24 @@
|
||||
#define MOB_TINY 4
|
||||
#define MOB_MINISCULE 1
|
||||
|
||||
// Mob weight, separate from mob size. Affects how easy a mob is to lift.
|
||||
/// Light mobs, can be lifted by anyone.
|
||||
#define MOB_WEIGHT_LIGHT 1
|
||||
/// Medium weight mobs, the default for humanoids. Can be lifted by medium+.
|
||||
#define MOB_WEIGHT_MEDIUM 2
|
||||
/// Heavy mobs. They need speecial equipment or a heavy+ mob to lift.
|
||||
#define MOB_WEIGHT_HEAVY 3
|
||||
/// Superheavy mobs. Gonna need a lot of help with those.
|
||||
#define MOB_WEIGHT_SUPERHEAVY 4
|
||||
|
||||
// Mob strength. This allows us to represent stronger mobs with a bit more granularity. Robots should be stronger than normal people. A bonus to the checks on lifting/throwing mobs, essentially.
|
||||
/// A normal mob, basically. Does not get us any buffs.
|
||||
#define MOB_STRENGTH_NORMAL 0
|
||||
/// A strong mob. Small bonus.
|
||||
#define MOB_STRENGTH_STRONG 1
|
||||
/// A very strong mob. Big bonus.
|
||||
#define MOB_STRENGTH_VERY_STRONG 2
|
||||
|
||||
#define BASE_MAX_NUTRITION 600
|
||||
#define HUNGER_FACTOR 0.04 // Factor of how fast mob nutrition decreases over time.
|
||||
|
||||
@@ -573,3 +608,25 @@
|
||||
#define DO_MISSING_TARGET (-2)
|
||||
#define DO_INCAPACITATED (-3)
|
||||
#define DO_EXTRA_CHECKS (-4)
|
||||
|
||||
// Threshold defines for integrity damage. Used for when you want to check for a specific threshold to do damage effects.
|
||||
|
||||
#define IPC_INTEGRITY_THRESHOLD_LOW 75
|
||||
#define IPC_INTEGRITY_THRESHOLD_MEDIUM 50
|
||||
#define IPC_INTEGRITY_THRESHOLD_HIGH 25
|
||||
#define IPC_INTEGRITY_THRESHOLD_VERY_HIGH 10
|
||||
|
||||
// These are the power supply organ defines.
|
||||
// They are bitflags because it should be technically possible to have a power supply do multiple things at once if you wish.
|
||||
// Just be wary of balancing issues.
|
||||
|
||||
/// The default functioning of a power reactor. Externally powered only. Allows recharging from APCs. Has a multiplier for faster recharging from power stations.
|
||||
#define POWER_SUPPLY_ELECTRIC 1
|
||||
/// Recharges by walking/running. Far slower at charging from external sources.
|
||||
#define POWER_SUPPLY_KINETIC 2
|
||||
/// Recharges through consuming nutrients/food. Slower at recharging from external sources.
|
||||
#define POWER_SUPPLY_BIOLOGICAL 4
|
||||
/// Recharges from external lighting. Slower at recharging from external sources.
|
||||
#define POWER_SUPPLY_SOLAR 8
|
||||
|
||||
|
||||
|
||||
@@ -48,3 +48,18 @@
|
||||
* Set the canceled variable to true in order to negate said weakness.
|
||||
*/
|
||||
#define COMSIG_GRAVITY_WEAKNESS_EVENT "gravity_weakness_event"
|
||||
|
||||
/// Raised external organ (a limb) takes damage. Used for the synthetic endoskeleton at the moment. Must supply damage.
|
||||
#define COMSIG_EXTERNAL_ORGAN_DAMAGE "machine_internal_damage"
|
||||
|
||||
/// Sent when the burst damage is cleared by the posibrain.
|
||||
#define COMSIG_SYNTH_EMP_DAMAGE_CLEARED "emp_damage_cleared"
|
||||
|
||||
/// Sent when the synthetic enters self-preservation mode. Must supply a TRUE/FALSE state.
|
||||
#define COMSIG_SYNTH_SET_SELF_PRESERVATION "synth_self_preservation_set"
|
||||
|
||||
/// Sent when endoskeleton repair is done. Must supply a number of damage healed.
|
||||
#define COMSIG_SYNTH_ENDOSKELETON_REPAIR "synth_endoskeleton_repair"
|
||||
|
||||
/// Sent when a full endoskeleton repair is done. Unlike the normal one, also restores max_damage to initial state. No extra arguments.
|
||||
#define COMSIG_SYNTH_ENDOSKELETON_FULL_REPAIR "synth_endoskeleton_full_repair"
|
||||
|
||||
@@ -35,3 +35,19 @@
|
||||
/// Internal organ. Removed, used for appendixes.
|
||||
#define ORGAN_PREF_REMOVED "removed"
|
||||
/// Note that a "normal" limb or organ has no pref, so there's no define for it.
|
||||
|
||||
/// Air cooling. Technically not used, but we need this for the linked lists in cooling_unit.dm.
|
||||
#define ORGAN_PREF_AIRCOOLED "air"
|
||||
/// Liquid cooling. For IPC cooling units. Default is air cooling.
|
||||
#define ORGAN_PREF_LIQUIDCOOLED "liquid"
|
||||
/// Passive cooling. For IPC cooling units. Default is air cooling.
|
||||
#define ORGAN_PREF_PASSIVECOOLED "passive"
|
||||
|
||||
/// Externally powered only. Technically not used, but we need this for the linked lists in reactor.dm.
|
||||
#define ORGAN_PREF_ELECTRICPOWER "electric"
|
||||
/// Biological power reactor. Nutrients, food, etc.
|
||||
#define ORGAN_PREF_BIOPOWER "biological"
|
||||
/// Kinetic power reactor. Walking, running.
|
||||
#define ORGAN_PREF_KINETICPOWER "kinetic"
|
||||
/// Solar powered. Stand in the sun. Or LED lights. It's the future, fuck you.
|
||||
#define ORGAN_PREF_SOLARPOWER "solar"
|
||||
|
||||
@@ -25,6 +25,10 @@
|
||||
#define SPAN_CAUTION(str) ("<span class='caution'>" + str + "</span>")
|
||||
#define SPAN_STORYTELLER(str) ("<span class='storyteller'>" + str + "</span>")
|
||||
|
||||
#define SPAN_MACHINE_WARNING(str) ("<span class='machine-warning'>" + str + "</span>")
|
||||
#define SPAN_MACHINE_DANGER(str) ("<span class='machine-danger'>" + str + "</span>")
|
||||
#define SPAN_MACHINE_VISION(str) ("<span class='machine-vision'>" + str + "</span>")
|
||||
|
||||
#define SPAN_RED(str) "<span style='color:[COLOR_RED]'>[str]</span>"
|
||||
#define SPAN_YELLOW(str) "<span style='color:[COLOR_YELLOW]'>[str]</span>"
|
||||
#define SPAN_GREEN(str) "<span style='color:[COLOR_GREEN]'>[str]</span>"
|
||||
|
||||
@@ -140,5 +140,3 @@
|
||||
SPECIES_IPC_UNBRANDED, SPECIES_IPC_UNBRANDED_REMOTE, SPECIES_IPC_XION, SPECIES_IPC_ZENGHU, \
|
||||
SPECIES_IPC_SHELL_ROGUE, SPECIES_IPC_XION_REMOTE, SPECIES_IPC_PURPOSE_HK, \
|
||||
)
|
||||
|
||||
|
||||
|
||||
@@ -1 +1,2 @@
|
||||
GLOBAL_LIST_EMPTY(mob_config_movespeed_type_lookup)
|
||||
GLOBAL_LIST_INIT(low_integrity_messages, world.file2list("config/synthetic_messages/low_integrity_messages.txt"))
|
||||
|
||||
@@ -114,6 +114,10 @@
|
||||
icon_state = "brutedamageoverlay6"
|
||||
alpha = 0
|
||||
|
||||
/atom/movable/screen/fullscreen/robot_pain
|
||||
icon = 'icons/mob/screen/robot_pain.dmi'
|
||||
alpha = 255
|
||||
|
||||
/atom/movable/screen/fullscreen/flash
|
||||
icon = 'icons/mob/screen/effects.dmi'
|
||||
screen_loc = "WEST,SOUTH to EAST,NORTH"
|
||||
|
||||
@@ -324,6 +324,10 @@
|
||||
mymob.up_hint.screen_loc = ui_up_hint
|
||||
hud_elements |= mymob.up_hint
|
||||
|
||||
if(hud_data.has_robot_pain)
|
||||
mymob.robot_pain = new /atom/movable/screen/fullscreen/robot_pain()
|
||||
hud_elements |= mymob.robot_pain
|
||||
|
||||
mymob.pain = new /atom/movable/screen/fullscreen/pain(null)
|
||||
hud_elements |= mymob.pain
|
||||
|
||||
|
||||
@@ -109,6 +109,11 @@
|
||||
key = RAD
|
||||
return key
|
||||
|
||||
// Used for natural armor for species.
|
||||
/datum/component/armor/natural
|
||||
full_block_message = "Your natural armor blocks the blow!"
|
||||
partial_block_message = "Your natural armor softens the blow!"
|
||||
|
||||
/datum/component/armor/toggle
|
||||
var/active = TRUE
|
||||
|
||||
@@ -0,0 +1,61 @@
|
||||
// An edit of ablative armor, taken from Baystation12.
|
||||
/datum/component/armor/synthetic
|
||||
full_block_message = "Your external plating absorbs the blow!"
|
||||
partial_block_message = "Your external plating dulls the blow!"
|
||||
|
||||
/// Maximum armor values.
|
||||
var/list/max_armor_values
|
||||
/// How fast armor degrades with blocked damage, with armor value reduced by [coef * damage taken]
|
||||
var/armor_degradation_coef = 0.8
|
||||
/// Wearer feedback.
|
||||
var/list/last_reported_damage
|
||||
|
||||
/datum/component/armor/synthetic/Initialize(list/armor, armor_type, _armor_degradation_speed)
|
||||
. = ..()
|
||||
max_armor_values = armor_values.Copy()
|
||||
if(!isnull(_armor_degradation_speed))
|
||||
armor_degradation_coef = _armor_degradation_speed
|
||||
|
||||
/datum/component/armor/synthetic/on_blocking(damage, damage_type, damage_flags, armor_pen, blocked)
|
||||
if (!(damage_type == DAMAGE_BRUTE || damage_type == DAMAGE_BURN))
|
||||
return
|
||||
if(armor_degradation_coef)
|
||||
var/key = get_armor_key(damage_type, damage_flags)
|
||||
var/damage_taken
|
||||
if(blocked)
|
||||
damage_taken = round(damage * blocked)
|
||||
else
|
||||
damage_taken = damage
|
||||
var/new_armor = max(0, get_value(key) - armor_degradation_coef * damage_taken)
|
||||
set_value(key, new_armor)
|
||||
var/mob/M = parent
|
||||
if(istype(M))
|
||||
var/list/visible = get_visible_damage()
|
||||
for(var/k in visible)
|
||||
if(LAZYACCESS(last_reported_damage, k) != visible[k])
|
||||
LAZYSET(last_reported_damage, k, visible[k])
|
||||
to_chat(M, SPAN_WARNING("Your external plating has suffered [visible[k]] damage!"))
|
||||
playsound(M, 'sound/effects/synth_armor_break.ogg', 50)
|
||||
|
||||
/datum/component/armor/synthetic/proc/get_damage()
|
||||
for(var/key in armor_values)
|
||||
var/damage = max_armor_values[key] - armor_values[key]
|
||||
if(damage > 0)
|
||||
LAZYSET(., key, damage)
|
||||
|
||||
/datum/component/armor/synthetic/proc/get_visible_damage()
|
||||
var/list/damages = get_damage()
|
||||
if(!LAZYLEN(damages))
|
||||
return
|
||||
var/result = list()
|
||||
for(var/key in damages)
|
||||
switch(round(100 * damages[key]/max_armor_values[key]))
|
||||
if(5 to 10)
|
||||
result[key] = "minor"
|
||||
if(11 to 25)
|
||||
result[key] = "moderate"
|
||||
if(26 to 50)
|
||||
result[key] = "serious"
|
||||
if(51 to 100)
|
||||
result[key] = "catastrophic"
|
||||
return result
|
||||
@@ -0,0 +1,120 @@
|
||||
/datum/component/synthetic_endoskeleton
|
||||
/// The synthetic that owns this component. Equivalent to `parent`, we just use this for ease of use.
|
||||
var/mob/living/carbon/human/owner
|
||||
/**
|
||||
* The synthetic endoskeleton is our answer to the eternal problem of IPCs being unable to be brainmed complaint because
|
||||
* of a lack of mechanics to represent pain, organ breaking, or bleeding/respiration, which is how humans in brainmed are
|
||||
* taken down nonlethally, or before they die.
|
||||
*/
|
||||
var/damage = 0
|
||||
/// The maximum damage the endoskeleton can take before triggering the safety shutdown.
|
||||
var/max_damage = 200
|
||||
|
||||
/// Time until next message.
|
||||
var/message_cooldown = 10 SECONDS
|
||||
/// World.time of last message sent.
|
||||
var/last_sent_message = 0
|
||||
|
||||
/datum/component/synthetic_endoskeleton/Initialize(...)
|
||||
. = ..()
|
||||
if(isipc(parent))
|
||||
owner = parent
|
||||
else
|
||||
log_debug("Synthetic endoskeleton component spawned on non-IPC. Deleting.")
|
||||
qdel_self()
|
||||
|
||||
RegisterSignal(owner, COMSIG_EXTERNAL_ORGAN_DAMAGE, PROC_REF(receive_damage))
|
||||
RegisterSignal(owner, COMSIG_SYNTH_ENDOSKELETON_REPAIR, PROC_REF(heal_damage))
|
||||
RegisterSignal(owner, COMSIG_SYNTH_ENDOSKELETON_FULL_REPAIR, PROC_REF(full_repair))
|
||||
|
||||
/datum/component/synthetic_endoskeleton/Destroy(force)
|
||||
owner = null
|
||||
return ..()
|
||||
|
||||
/**
|
||||
* Signal handler called when an external synthetic limb receives damage.
|
||||
*/
|
||||
/datum/component/synthetic_endoskeleton/proc/receive_damage(atom/source, amount)
|
||||
SIGNAL_HANDLER
|
||||
damage = min(damage + amount, max_damage)
|
||||
handle_exoskeleton_damage()
|
||||
|
||||
/**
|
||||
* Signal handler called when the endoskeleton is repaired.
|
||||
*/
|
||||
/datum/component/synthetic_endoskeleton/proc/heal_damage(atom/source, amount)
|
||||
SIGNAL_HANDLER
|
||||
damage = max(damage - amount, 0)
|
||||
var/damage_ratio = damage / max_damage
|
||||
switch(damage_ratio)
|
||||
if(0 to 0.3)
|
||||
owner.remove_movespeed_modifier(/datum/movespeed_modifier/endoskeleton)
|
||||
if(0.3 to 0.5)
|
||||
owner.add_or_update_variable_movespeed_modifier(/datum/movespeed_modifier/endoskeleton, multiplicative_slowdown = 1)
|
||||
if(0.5 to 0.75)
|
||||
owner.add_or_update_variable_movespeed_modifier(/datum/movespeed_modifier/endoskeleton, multiplicative_slowdown = 2)
|
||||
if(0.75 to 1)
|
||||
owner.add_or_update_variable_movespeed_modifier(/datum/movespeed_modifier/endoskeleton, multiplicative_slowdown = 3)
|
||||
if(!damage)
|
||||
STOP_PROCESSING(SSprocessing, src)
|
||||
|
||||
/**
|
||||
* Does a full repair of the endoskeleton, also restoring max_damage to initial state.
|
||||
*/
|
||||
/datum/component/synthetic_endoskeleton/proc/full_repair(atom/source)
|
||||
max_damage = initial(max_damage)
|
||||
heal_damage(source, max_damage)
|
||||
|
||||
/**
|
||||
* The function that handles exoskeleton damage effects.
|
||||
*/
|
||||
/datum/component/synthetic_endoskeleton/proc/handle_exoskeleton_damage()
|
||||
if(damage)
|
||||
START_PROCESSING(SSprocessing, src)
|
||||
var/damage_ratio = damage / max_damage
|
||||
switch(damage_ratio)
|
||||
if(0.3 to 0.5)
|
||||
notify_owner(owner, SPAN_WARNING("Your self-preservation warning system notifies you of moderate damage to your endoskeleton's supports!"))
|
||||
owner.add_or_update_variable_movespeed_modifier(/datum/movespeed_modifier/endoskeleton, multiplicative_slowdown = 1)
|
||||
if(0.5 to 0.75)
|
||||
notify_owner(owner, SPAN_WARNING("Your self-preservation warning system notifies you of major damage to your endoskeleton!"))
|
||||
spark(owner, 2, GLOB.alldirs)
|
||||
owner.add_or_update_variable_movespeed_modifier(/datum/movespeed_modifier/endoskeleton, multiplicative_slowdown = 2)
|
||||
if(0.75 to 0.99)
|
||||
notify_owner(owner, SPAN_DANGER("Your self-preservation routines are starting to kick in! Your endoskeleton is falling apart!"))
|
||||
spark(owner, 3, GLOB.alldirs)
|
||||
owner.add_or_update_variable_movespeed_modifier(/datum/movespeed_modifier/endoskeleton, multiplicative_slowdown = 3)
|
||||
if(1 to INFINITY)
|
||||
SEND_SIGNAL(owner, COMSIG_SYNTH_SET_SELF_PRESERVATION, TRUE)
|
||||
|
||||
/datum/component/synthetic_endoskeleton/process()
|
||||
if(owner.stat)
|
||||
return
|
||||
|
||||
var/damage_ratio = damage / max_damage
|
||||
switch(damage_ratio)
|
||||
if(0.3 to 0.5)
|
||||
if(prob(5))
|
||||
notify_owner(owner, SPAN_MACHINE_WARNING("Warning: Endoskeleton integrity at [100 - (damage_ratio * 100)]%."))
|
||||
if(0.5 to 0.75)
|
||||
if(prob(10))
|
||||
notify_owner(owner, SPAN_MACHINE_WARNING("WARNING: Endoskeleton integrity at [100 - (damage_ratio * 100)]%!"))
|
||||
notify_owner(owner, SPAN_WARNING("The mangled and exposed wires in your endoskeleton spark!"))
|
||||
spark(owner, 3, GLOB.alldirs)
|
||||
owner.bodytemperature += 10
|
||||
if(0.75 to 1)
|
||||
if(prob(15))
|
||||
notify_owner(owner, SPAN_MACHINE_DANGER(FONT_LARGE("ENDOSKELETON INTEGRITY CRITICAL. Your self preservation blares at you to return to safety!")))
|
||||
notify_owner(owner, SPAN_DANGER("Your frame creaks and groans, threatening to break apart at the metallic seams!"))
|
||||
spark(owner, 4, GLOB.alldirs)
|
||||
owner.bodytemperature += 20
|
||||
|
||||
/**
|
||||
* Wrapper to_chat proc with a stat check.
|
||||
*/
|
||||
/datum/component/synthetic_endoskeleton/proc/notify_owner(mob/living/carbon/human/user, message)
|
||||
if(user.is_asystole() || (last_sent_message + message_cooldown > world.time))
|
||||
return
|
||||
|
||||
to_chat(user, message)
|
||||
last_sent_message = world.time
|
||||
@@ -118,3 +118,14 @@
|
||||
mid_sounds = list('sound/machines/clanking.ogg' = 1)
|
||||
mid_length = 5 SECONDS
|
||||
volume = 75
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/datum/looping_sound/synth_fab
|
||||
start_sound = 'sound/machines/synthfab/synthfab_start.ogg'
|
||||
start_length = 1 SECOND
|
||||
start_volume = 100
|
||||
mid_sounds = list('sound/machines/synthfab/synthfab_running.ogg' = 1)
|
||||
mid_length = 3 SECONDS
|
||||
end_sound = 'sound/machines/synthfab/synthfab_end.ogg'
|
||||
volume = 75
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
/datum/looping_sound/ipc_sizzling
|
||||
mid_sounds = list('sound/species/synthetic/sizzling_mid.ogg' = 1)
|
||||
end_sound = 'sound/species/synthetic/sizzling_end.ogg'
|
||||
mid_length = 30
|
||||
volume = 50
|
||||
extra_range = SHORT_RANGE_SOUND_EXTRARANGE
|
||||
@@ -42,7 +42,7 @@
|
||||
U.hidden_uplink.bluecrystals = round(uplink_uses / 2)
|
||||
U.hidden_uplink.tgui_menu = 1
|
||||
if(isipc(H))
|
||||
var/obj/item/organ/internal/ipc_tag/tag = H.internal_organs_by_name[BP_IPCTAG]
|
||||
var/obj/item/organ/internal/machine/ipc_tag/tag = H.internal_organs_by_name[BP_IPCTAG]
|
||||
if(istype(tag))
|
||||
tag.modify_tag_data(TRUE)
|
||||
|
||||
|
||||
@@ -59,7 +59,7 @@ GLOBAL_DATUM_INIT(crew_repository, /datum/repository/crew, new())
|
||||
crewmemberData["pulse"] = H.get_pulse(GETPULSE_TOOL)
|
||||
else
|
||||
if(isipc(H) && H.internal_organs_by_name[BP_IPCTAG]) // Don't make untagged IPCs obvious
|
||||
var/obj/item/organ/internal/cell/cell = H.internal_organs_by_name[BP_CELL]
|
||||
var/obj/item/organ/internal/machine/power_core/cell = H.internal_organs_by_name[BP_CELL]
|
||||
if(cell)
|
||||
crewmemberData["cellCharge"] = cell.percent()
|
||||
|
||||
|
||||
@@ -0,0 +1,70 @@
|
||||
// Synthetic internals represent things that are not physically modelled as an organ, but are rather part of the organ.
|
||||
// That means wiring, plating, and electronics. Damaging organs has adverse effects on these components.
|
||||
// The goal is to emulate damaging effects similar to arterial bleeding, infections, etc. on organics.
|
||||
|
||||
// The specific effects of each synthetic internal can vary organ by organ. They all have different health measurements as well.
|
||||
// These measurements can change depending on the organ they are attached to.
|
||||
|
||||
/datum/synthetic_internal
|
||||
/// The name of the internal component. Shows up in analysis tools.
|
||||
var/name = "default synthetic internal"
|
||||
/// The description. Shows up in analysis tools.
|
||||
var/desc = "A default synthetic internal component."
|
||||
/// The organ this synthetic internal belongs to.
|
||||
var/obj/item/organ/internal/machine/organ
|
||||
|
||||
/datum/synthetic_internal/New(obj/item/organ/internal/machine/attached_organ)
|
||||
. = ..()
|
||||
if(istype(attached_organ))
|
||||
organ = attached_organ
|
||||
else
|
||||
LOG_DEBUG("Synthetic internal [type] generated on invalid organ [attached_organ]. Aborting.")
|
||||
qdel(src)
|
||||
|
||||
/datum/synthetic_internal/Destroy(force)
|
||||
organ = null
|
||||
return ..()
|
||||
|
||||
/**
|
||||
* The proc that handles taking damage. As some components take damage differently,
|
||||
* this is overridden by them.
|
||||
*/
|
||||
/datum/synthetic_internal/proc/take_damage(amount)
|
||||
return
|
||||
|
||||
/**
|
||||
* The proc that handles restoring damage. As some components restore damage differently,
|
||||
* this is overridden by them.
|
||||
*/
|
||||
/datum/synthetic_internal/proc/heal_damage(amount)
|
||||
return
|
||||
|
||||
/**
|
||||
* This proc returns the status of this synthetic internal as a percentage.
|
||||
* It will return 100 if the component is 100% healthy, a value between 0 and 100 if not, and 0 if broken.
|
||||
* This logic can be overridden for custom behaviour.
|
||||
*/
|
||||
/datum/synthetic_internal/proc/get_status()
|
||||
return
|
||||
|
||||
/**
|
||||
* This proc returns the status of this internal component, but imprecisely.
|
||||
* Basically what could be obvious at an eye-glance.
|
||||
*/
|
||||
/datum/synthetic_internal/proc/analyse_integrity_imprecise()
|
||||
return
|
||||
|
||||
/**
|
||||
* This proc returns the status of this internal component, but precisely.
|
||||
* Basically the results of an in-depth analysis with an appropriate tool.
|
||||
*/
|
||||
/datum/synthetic_internal/proc/analyze_integrity_precise()
|
||||
return
|
||||
|
||||
/**
|
||||
* Replaces the health by setting a new max health and setting the health to the new max_health value.
|
||||
* Needs to be overridden on every subtype.
|
||||
*/
|
||||
/datum/synthetic_internal/proc/replace_health(new_max_health)
|
||||
SHOULD_CALL_PARENT(FALSE)
|
||||
CRASH("Not implemented!")
|
||||
@@ -0,0 +1,19 @@
|
||||
// The synthetic's electronics. Represents both the hardware and software component.
|
||||
// The integrity of electronics only goes from 0% to 100%. It does not vary, unlike other components.
|
||||
|
||||
/datum/synthetic_internal/electronics
|
||||
name = "internal electronics"
|
||||
desc = "The electronics and the code responsible for many internal functions."
|
||||
/// The maximum integrity percentage of the internals. Represents code coherence and physical damage.
|
||||
var/max_integrity = 30
|
||||
/// The integrity of the internals in percentage. Represents code coherence and physical damage.
|
||||
var/integrity = 30
|
||||
|
||||
/datum/synthetic_internal/electronics/get_status()
|
||||
return (integrity / max_integrity) * 100
|
||||
|
||||
/datum/synthetic_internal/electronics/take_damage(amount)
|
||||
integrity = max(integrity - amount, 0)
|
||||
|
||||
/datum/synthetic_internal/electronics/heal_damage(amount)
|
||||
integrity = min(integrity + amount, max_integrity)
|
||||
@@ -0,0 +1,39 @@
|
||||
// The synthetic organ's plating. Represents its natural armour, which will degrade as it's damaged.
|
||||
|
||||
/datum/synthetic_internal/plating
|
||||
name = "internal steel plating"
|
||||
desc = "The steel plating that keeps internal components safe and sound from the exterior."
|
||||
/// The maximum health of the organ's plating. Represents... you know, the plating.
|
||||
var/max_health = 50
|
||||
/// The health of the organ's plating. Represents... you know, the plating.
|
||||
var/health = 50
|
||||
|
||||
/datum/synthetic_internal/plating/take_damage(amount)
|
||||
var/old_health = health
|
||||
health = max(health - amount, 0)
|
||||
return max(amount - old_health, 0)
|
||||
|
||||
/datum/synthetic_internal/plating/heal_damage(amount)
|
||||
health = min(health + amount, max_health)
|
||||
|
||||
/datum/synthetic_internal/plating/get_status()
|
||||
return (health / max_health) * 100
|
||||
|
||||
/datum/synthetic_internal/plating/replace_health(new_max_health)
|
||||
max_health = new_max_health
|
||||
health = new_max_health
|
||||
|
||||
/obj/item/synth_plating
|
||||
name = "synthetic steel plating"
|
||||
desc = "These steel plates are replacements for the steel plating lining a synthetic's internal components. They are welded to the chassis in order to safeguard the component in question."
|
||||
icon = 'icons/obj/ipc_utilities.dmi'
|
||||
icon_state = "ipc_repair_plates"
|
||||
matter = list(MATERIAL_STEEL = 40000)
|
||||
surgerysound = 'sound/weapons/saw/drillhit1.ogg'
|
||||
item_flags = ITEM_FLAG_SURGERY
|
||||
|
||||
/obj/item/synth_plating/mechanics_hints()
|
||||
. = ..()
|
||||
. += list("These plates are used to replace broken internal plating around a synthetic's organ. \
|
||||
While normally you can repair it with normal steel plates, in the case that it is broken, \
|
||||
you'll need to substitute the plating entirely with this item.")
|
||||
@@ -0,0 +1,18 @@
|
||||
// The synthetic's wiring. Represents the fragile connections between organs and limbs.
|
||||
|
||||
/datum/synthetic_internal/wiring
|
||||
name = "internal wiring"
|
||||
desc = "The wiring that connects components together and allows them to talk to eachother."
|
||||
/// The maximum wires on this organ. Wires represent physical connections between components. They are less plentiful than plating, but they are worse to lose.
|
||||
var/max_wires = 15
|
||||
/// The wires left on this organ. Wires represent physical connections between components. They are less plentiful than plating, but they are worse to lose.
|
||||
var/wires = 15
|
||||
|
||||
/datum/synthetic_internal/wiring/get_status()
|
||||
return (wires / max_wires) * 100
|
||||
|
||||
/datum/synthetic_internal/wiring/take_damage(amount)
|
||||
wires = max(wires - round(amount, 1), 0)
|
||||
|
||||
/datum/synthetic_internal/wiring/heal_damage(amount)
|
||||
wires = min(wires + amount, max_wires)
|
||||
@@ -142,7 +142,7 @@
|
||||
if(user.isSynthetic() && ishuman(user)) // Let's do something with it, if we're a robot.
|
||||
var/mob/living/carbon/human/H = user
|
||||
charge_to_give = charge_to_give - (core.max_energy - core.energy)
|
||||
var/obj/item/organ/internal/cell/C = H.internal_organs_by_name[BP_CELL]
|
||||
var/obj/item/organ/internal/machine/power_core/C = H.internal_organs_by_name[BP_CELL]
|
||||
var/obj/item/cell/potato = C.get_cell()
|
||||
potato.give(charge_to_give)
|
||||
to_chat(user, SPAN_NOTICE("Redirected energy to internal microcell."))
|
||||
|
||||
@@ -99,7 +99,7 @@
|
||||
minimal_player_age = 7
|
||||
outfit = /obj/outfit/job/warden
|
||||
|
||||
blacklisted_species = list(SPECIES_IPC_G1, SPECIES_IPC_G2, SPECIES_IPC_XION, SPECIES_IPC_XION_REMOTE, SPECIES_VAURCA_BULWARK, SPECIES_DIONA_COEUS, SPECIES_VAURCA_BREEDER)
|
||||
blacklisted_species = list(SPECIES_IPC_XION_REMOTE, SPECIES_VAURCA_BULWARK, SPECIES_DIONA_COEUS, SPECIES_VAURCA_BREEDER)
|
||||
|
||||
/obj/outfit/job/warden
|
||||
name = "Warden"
|
||||
@@ -163,7 +163,7 @@
|
||||
)
|
||||
minimal_player_age = 3
|
||||
outfit = /obj/outfit/job/forensics
|
||||
blacklisted_species = list(SPECIES_IPC_G1, SPECIES_IPC_G2, SPECIES_IPC_XION, SPECIES_IPC_XION_REMOTE, SPECIES_VAURCA_BULWARK, SPECIES_VAURCA_BREEDER)
|
||||
blacklisted_species = list(SPECIES_IPC_XION_REMOTE, SPECIES_VAURCA_BULWARK, SPECIES_VAURCA_BREEDER)
|
||||
|
||||
/obj/outfit/job/forensics
|
||||
name = "Investigator"
|
||||
@@ -222,7 +222,7 @@
|
||||
minimal_player_age = 7
|
||||
outfit = /obj/outfit/job/officer
|
||||
|
||||
blacklisted_species = list(SPECIES_IPC_G1, SPECIES_IPC_G2, SPECIES_IPC_XION, SPECIES_IPC_XION_REMOTE, SPECIES_VAURCA_BULWARK, SPECIES_DIONA_COEUS, SPECIES_VAURCA_BREEDER)
|
||||
blacklisted_species = list(SPECIES_IPC_XION_REMOTE, SPECIES_VAURCA_BULWARK, SPECIES_DIONA_COEUS, SPECIES_VAURCA_BREEDER)
|
||||
|
||||
/obj/outfit/job/officer
|
||||
name = "Security Officer"
|
||||
@@ -289,7 +289,7 @@
|
||||
SPECIES_SKRELL_AXIORI = 50
|
||||
)
|
||||
|
||||
blacklisted_species = list(SPECIES_IPC_G1, SPECIES_IPC_G2, SPECIES_IPC_XION, SPECIES_IPC_XION_REMOTE, SPECIES_VAURCA_BULWARK, SPECIES_DIONA_COEUS, SPECIES_VAURCA_BREEDER)
|
||||
blacklisted_species = list(SPECIES_IPC_XION_REMOTE, SPECIES_VAURCA_BULWARK, SPECIES_DIONA_COEUS, SPECIES_VAURCA_BREEDER)
|
||||
|
||||
/obj/outfit/job/intern_sec
|
||||
name = "Security Cadet"
|
||||
|
||||
@@ -26,6 +26,9 @@
|
||||
///The connected surgery computer
|
||||
var/obj/machinery/computer/operating/computer = null
|
||||
|
||||
/// If the patient must be lying on this surgery table for it to set the patient as occupant.
|
||||
var/occupant_must_be_lying = TRUE
|
||||
|
||||
/obj/machinery/optable/mechanics_hints(mob/user, distance, is_adjacent)
|
||||
. += ..()
|
||||
. += "Click your target with Grab intent, then click on the table with an empty hand, to place them on it."
|
||||
@@ -154,6 +157,7 @@
|
||||
if((user.a_intent != I_HELP) && buckled)
|
||||
user_unbuckle(user)
|
||||
return
|
||||
|
||||
if(user != occupant_resolved && !use_check_and_message(user)) // Skip checks if you're doing it to yourself or turning it off, this is an anti-griefing mechanic more than anything.
|
||||
user.visible_message(SPAN_WARNING("\The [user] begins switching [suppressing ? "off" : "on"] \the [src]'s neural suppressor."))
|
||||
if(!do_after(user, 3 SECONDS, src, DO_UNIQUE))
|
||||
@@ -201,10 +205,11 @@
|
||||
//does not mean it's suppressed, just that it's occupying the table
|
||||
var/mob/living/carbon/human/new_occupant = locate() in loc
|
||||
if(istype(new_occupant))
|
||||
if(new_occupant.lying)
|
||||
//Set the occupant weakref and get his view
|
||||
occupant = WEAKREF(new_occupant)
|
||||
acquire_view(new_occupant)
|
||||
if(occupant_must_be_lying && !new_occupant.lying)
|
||||
return FALSE
|
||||
//Set the occupant weakref and get his view
|
||||
occupant = WEAKREF(new_occupant)
|
||||
acquire_view(new_occupant)
|
||||
|
||||
//We have a patient, and it's not synthetic
|
||||
else if(!occupant_resolved.isSynthetic())
|
||||
@@ -257,11 +262,17 @@
|
||||
add_fingerprint(patient)
|
||||
add_fibers(patient)
|
||||
|
||||
patient.resting = TRUE
|
||||
patient.forceMove(loc)
|
||||
move_patient_to_table(patient, giver)
|
||||
|
||||
return TRUE
|
||||
|
||||
/**
|
||||
* Actually moves a patient to the table.
|
||||
*/
|
||||
/obj/machinery/optable/proc/move_patient_to_table(mob/living/carbon/patient, mob/living/carbon/giver)
|
||||
patient.resting = TRUE
|
||||
patient.forceMove(loc)
|
||||
|
||||
/obj/machinery/optable/mouse_drop_receive(atom/dropped, mob/user, params)
|
||||
//If the user is a ghost, stop.
|
||||
if(isghost(user))
|
||||
@@ -333,3 +344,28 @@
|
||||
return TRUE
|
||||
if(default_part_replacement(user, attacking_item))
|
||||
return TRUE
|
||||
|
||||
/obj/machinery/optable/robotics
|
||||
name = "machinery chair"
|
||||
desc = "Some sort of hybrid between an operating table and a chair, typically used by machinists and roboticists to strap synthetics to while they work on them. \
|
||||
It comes with an access cable for easy access to a synthetic's diagnostics unit."
|
||||
icon_state = "machinist_or_table"
|
||||
density = FALSE
|
||||
occupant_must_be_lying = FALSE
|
||||
can_buckle = list(/mob/living/carbon/human)
|
||||
|
||||
/obj/machinery/optable/robotics/mechanics_hints(mob/user, distance, is_adjacent)
|
||||
. = ..()
|
||||
. += list("Use a <b>non-help</b> intent to unbuckle.")
|
||||
|
||||
/obj/machinery/optable/robotics/refresh_icon_state()
|
||||
return
|
||||
|
||||
/obj/machinery/optable/robotics/move_patient_to_table(mob/living/carbon/patient, mob/living/carbon/giver)
|
||||
buckle(patient, giver)
|
||||
visible_message(SPAN_NOTICE("[giver] buckles [patient] to \the [src]."))
|
||||
|
||||
/obj/machinery/optable/robotics/buckle(atom/movable/buckling_atom, mob/user)
|
||||
. = ..()
|
||||
if(.)
|
||||
playsound(src, 'sound/effects/metal_close.ogg', 20)
|
||||
|
||||
@@ -29,6 +29,9 @@
|
||||
/// The zlevel that this computer is spawned on.
|
||||
var/starting_z_level = null
|
||||
|
||||
/// The access cable inserted into this computer, if any.
|
||||
var/obj/item/access_cable/inserted_cable
|
||||
|
||||
/obj/machinery/computer/Initialize()
|
||||
. = ..()
|
||||
overlay_layer = layer
|
||||
@@ -36,6 +39,12 @@
|
||||
power_change()
|
||||
update_icon()
|
||||
|
||||
/obj/machinery/computer/Destroy()
|
||||
if(inserted_cable)
|
||||
inserted_cable.retract()
|
||||
inserted_cable = null
|
||||
return ..()
|
||||
|
||||
/obj/machinery/computer/ui_interact(mob/user, ui_key = "main", datum/nanoui/ui = null, force_open = TRUE)
|
||||
if(!operable() || !is_station_level(z) || user.stat)
|
||||
user.unset_machine()
|
||||
@@ -47,7 +56,6 @@
|
||||
if(prob(20/severity))
|
||||
set_broken()
|
||||
|
||||
|
||||
/obj/machinery/computer/ex_act(severity)
|
||||
switch(severity)
|
||||
if(1.0)
|
||||
@@ -194,6 +202,15 @@
|
||||
update_icon()
|
||||
return TRUE
|
||||
else
|
||||
if(istype(attacking_item, /obj/item/access_cable))
|
||||
var/obj/item/access_cable/access_cable = attacking_item
|
||||
if(inserted_cable)
|
||||
to_chat(user, SPAN_WARNING("There's already a cable in the universal port!"))
|
||||
return
|
||||
|
||||
if(do_after(user, 1 SECONDS))
|
||||
visible_message(SPAN_NOTICE("[user] slots \the [access_cable] into \the [src]."))
|
||||
insert_cable(access_cable, user)
|
||||
return ..()
|
||||
|
||||
/obj/machinery/computer/CanPass(atom/movable/mover, turf/target, height=0, air_group=0)
|
||||
@@ -218,6 +235,19 @@
|
||||
to_chat(user, SPAN_WARNING("\The [src]'s non-stick surface prevents you from attaching a sticker to it!"))
|
||||
return FALSE
|
||||
|
||||
/obj/machinery/computer/insert_cable(obj/item/access_cable/cable, mob/user)
|
||||
. = ..()
|
||||
inserted_cable = cable
|
||||
cable.create_cable(src)
|
||||
|
||||
/obj/machinery/computer/cable_interact(obj/item/access_cable/cable, mob/user)
|
||||
. = ..()
|
||||
attack_hand(user)
|
||||
|
||||
/obj/machinery/computer/remove_cable(obj/item/access_cable/cable)
|
||||
..()
|
||||
inserted_cable = null
|
||||
|
||||
/obj/machinery/computer/terminal
|
||||
name = "terminal"
|
||||
icon = 'icons/obj/machinery/modular_terminal.dmi'
|
||||
|
||||
@@ -554,7 +554,7 @@
|
||||
var/choice = alert(M, "Would you like to save your tag data?", "Tag Persistence", "Yes", "No")
|
||||
if(choice == "Yes")
|
||||
var/mob/living/carbon/human/H = M
|
||||
var/obj/item/organ/internal/ipc_tag/tag = H.internal_organs_by_name[BP_IPCTAG]
|
||||
var/obj/item/organ/internal/machine/ipc_tag/tag = H.internal_organs_by_name[BP_IPCTAG]
|
||||
if(tag)
|
||||
M.client.prefs.machine_ownership_status = tag.ownership_info
|
||||
M.client.prefs.machine_serial_number = tag.serial_number
|
||||
|
||||
@@ -297,7 +297,7 @@ Class Procs:
|
||||
|
||||
update_icon()
|
||||
|
||||
/obj/machinery/CanUseTopic(var/mob/user)
|
||||
/obj/machinery/CanUseTopic(mob/user)
|
||||
if(stat & BROKEN)
|
||||
return STATUS_CLOSE
|
||||
|
||||
@@ -306,18 +306,18 @@ Class Procs:
|
||||
|
||||
return ..()
|
||||
|
||||
/obj/machinery/CouldUseTopic(var/mob/user)
|
||||
/obj/machinery/CouldUseTopic(mob/user)
|
||||
..()
|
||||
if(clicksound && iscarbon(user))
|
||||
playsound(src, clicksound, clickvol)
|
||||
user.set_machine(src)
|
||||
|
||||
/obj/machinery/CouldNotUseTopic(var/mob/user)
|
||||
/obj/machinery/CouldNotUseTopic(mob/user)
|
||||
user.unset_machine()
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/obj/machinery/attack_ai(mob/user as mob)
|
||||
/obj/machinery/attack_ai(mob/user)
|
||||
if(!ai_can_interact(user))
|
||||
return
|
||||
if(isrobot(user))
|
||||
@@ -328,33 +328,27 @@ Class Procs:
|
||||
else
|
||||
return src.attack_hand(user)
|
||||
|
||||
/obj/machinery/attack_hand(mob/user as mob)
|
||||
/obj/machinery/attack_hand(mob/user)
|
||||
if(!operable(MAINT))
|
||||
return 1
|
||||
return TRUE
|
||||
if(user.lying || user.stat)
|
||||
return 1
|
||||
if ( ! (istype(usr, /mob/living/carbon/human) || \
|
||||
istype(usr, /mob/living/silicon)))
|
||||
return TRUE
|
||||
if (!istype(usr, /mob/living/carbon/human) && !istype(usr, /mob/living/silicon))
|
||||
to_chat(usr, SPAN_WARNING("You don't have the dexterity to do this!"))
|
||||
return 1
|
||||
/*
|
||||
//distance checks are made by atom/proc/DblClick
|
||||
if ((get_dist(src, user) > 1 || !istype(src.loc, /turf)) && !istype(user, /mob/living/silicon))
|
||||
return 1
|
||||
*/
|
||||
if (ishuman(user))
|
||||
var/mob/living/carbon/human/H = user
|
||||
if(H.getBrainLoss() >= 60)
|
||||
visible_message(SPAN_WARNING("[H] stares cluelessly at [src] and drools."))
|
||||
return 1
|
||||
else if(prob(H.getBrainLoss()))
|
||||
to_chat(user, SPAN_WARNING("You momentarily forget how to use [src]."))
|
||||
return 1
|
||||
return TRUE
|
||||
|
||||
src.add_fingerprint(user)
|
||||
|
||||
return ..()
|
||||
|
||||
/obj/machinery/attack_ranged(mob/user, params)
|
||||
. = ..()
|
||||
if(isipc(user))
|
||||
var/mob/living/carbon/human/robot = user
|
||||
var/obj/item/organ/internal/machine/wireless_access/wireless_access_point = robot.internal_organs_by_name[BP_WIRELESS_ACCESS]
|
||||
if(wireless_access_point?.access_terminal(src))
|
||||
attack_hand(user)
|
||||
|
||||
/obj/machinery/attackby(obj/item/attacking_item, mob/user)
|
||||
if(obj_flags & OBJ_FLAG_SIGNALER)
|
||||
if(issignaler(attacking_item))
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/obj/machinery/mecha_part_fabricator
|
||||
name = "mechatronic fabricator"
|
||||
desc = "A general purpose fabricator that can be used to fabricate robotic equipment."
|
||||
name = "synthetic fabricator"
|
||||
desc = "A general purpose fabricator that can be used to fabricate equipment for synthetics or exosuits."
|
||||
icon = 'icons/obj/machinery/robotics_fabricator.dmi'
|
||||
icon_state = "fab"
|
||||
density = TRUE
|
||||
@@ -15,6 +15,7 @@
|
||||
/obj/item/stock_parts/micro_laser,
|
||||
/obj/item/stock_parts/console_screen
|
||||
)
|
||||
manufacturer = "hephaestus"
|
||||
|
||||
/**
|
||||
* A `/list` of enqueued `/datum/design` to be printed, processed in the queue
|
||||
@@ -36,6 +37,9 @@
|
||||
|
||||
var/datum/research/files
|
||||
|
||||
/// The looping sound for production.
|
||||
var/datum/looping_sound/synth_fab/fab_loop
|
||||
|
||||
var/list/categories = list()
|
||||
var/category = null
|
||||
var/sync_message = ""
|
||||
@@ -57,11 +61,13 @@
|
||||
. = ..()
|
||||
|
||||
files = new /datum/research(src) //Setup the research data holder.
|
||||
fab_loop = new(src)
|
||||
limb_manufacturer = GLOB.basic_robolimb.company
|
||||
update_categories()
|
||||
|
||||
/obj/machinery/mecha_part_fabricator/update_icon()
|
||||
ClearOverlays()
|
||||
update_fab_audio()
|
||||
if(panel_open)
|
||||
AddOverlays("[icon_state]_panel")
|
||||
if(!(stat & (NOPOWER|BROKEN)))
|
||||
@@ -72,9 +78,19 @@
|
||||
AddOverlays(emissive_appearance(icon, "[icon_state]_lights_working"))
|
||||
AddOverlays("[icon_state]_lights_working")
|
||||
|
||||
/// Starts and stops the necessary audio.
|
||||
/obj/machinery/mecha_part_fabricator/proc/update_fab_audio()
|
||||
if(!fab_loop)
|
||||
return
|
||||
|
||||
if(build_callback_timer)
|
||||
fab_loop.start()
|
||||
else
|
||||
fab_loop.stop()
|
||||
|
||||
/obj/machinery/mecha_part_fabricator/dismantle()
|
||||
for(var/f in materials)
|
||||
eject_materials(f, -1)
|
||||
eject_materials(f, materials[f])
|
||||
|
||||
//Stop the queue building if you're dismantling
|
||||
deltimer(build_callback_timer)
|
||||
@@ -106,27 +122,36 @@
|
||||
do_hair_pull(user)
|
||||
ui_interact(user)
|
||||
|
||||
/obj/machinery/mecha_part_fabricator/ui_interact(var/mob/user, var/ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1)
|
||||
var/data[0]
|
||||
/obj/machinery/mecha_part_fabricator/ui_interact(mob/user, datum/tgui/ui)
|
||||
. = ..()
|
||||
ui = SStgui.try_update_ui(user, src, ui)
|
||||
if(!ui)
|
||||
ui = new(user, src, "SyntheticFabricator", "Synthetic Fabricator", 900, 700)
|
||||
ui.open()
|
||||
|
||||
/obj/machinery/mecha_part_fabricator/ui_data(mob/user)
|
||||
var/list/data = list()
|
||||
data["manufacturer"] = manufacturer
|
||||
var/datum/design/current = queue.len ? queue[1] : null
|
||||
if(current)
|
||||
data["current"] = current.name
|
||||
data["queue"] = get_queue_names()
|
||||
data["buildable"] = get_build_options()
|
||||
data["category"] = category
|
||||
data["categories"] = categories
|
||||
data["available_categories"] = list()
|
||||
for(var/possible_category in categories)
|
||||
data["available_categories"] += list(list("name" = possible_category))
|
||||
|
||||
if(GLOB.fabricator_robolimbs)
|
||||
var/list/T = list()
|
||||
for(var/A in GLOB.fabricator_robolimbs)
|
||||
var/datum/robolimb/R = GLOB.fabricator_robolimbs[A]
|
||||
T += list(list("id" = A, "company" = R.company))
|
||||
T += list(list("name" = R.company, "type" = A))
|
||||
data["manufacturers"] = T
|
||||
data["manufacturer"] = limb_manufacturer
|
||||
data["selected_manufacturer"] = limb_manufacturer
|
||||
|
||||
data["materials"] = get_materials()
|
||||
data["maxres"] = res_max_amount
|
||||
data["maximum_resource_amount"] = res_max_amount
|
||||
data["sync"] = sync_message
|
||||
|
||||
//If we have something in the queue that we're trying to build, show the time left if the build is undergoing, otherwise null
|
||||
@@ -136,42 +161,46 @@
|
||||
data["timeleft"] = round(timeleft(build_callback_timer))
|
||||
else
|
||||
data["timeleft"] = null
|
||||
return data
|
||||
|
||||
ui = SSnanoui.try_update_ui(user, src, ui_key, ui, data, force_open)
|
||||
if(!ui)
|
||||
ui = new(user, src, ui_key, "mechfab.tmpl", "Exosuit Fabricator UI", 800, 600)
|
||||
ui.set_initial_data(data)
|
||||
ui.open()
|
||||
ui.set_auto_update(1)
|
||||
|
||||
/obj/machinery/mecha_part_fabricator/Topic(href, href_list)
|
||||
if(..())
|
||||
/obj/machinery/mecha_part_fabricator/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state)
|
||||
. = ..()
|
||||
if(.)
|
||||
return
|
||||
|
||||
if(href_list["build"])
|
||||
var/path = text2path(href_list["build"])
|
||||
add_to_queue(path)
|
||||
switch(action)
|
||||
if("build")
|
||||
var/path = text2path(params["build"])
|
||||
add_to_queue(path)
|
||||
. = TRUE
|
||||
|
||||
if(href_list["remove"])
|
||||
remove_from_queue(text2num(href_list["remove"]))
|
||||
if("remove")
|
||||
remove_from_queue(text2num(params["remove"]))
|
||||
. = TRUE
|
||||
|
||||
if(href_list["category"])
|
||||
if(href_list["category"] in categories)
|
||||
category = href_list["category"]
|
||||
if("category")
|
||||
if(params["category"] in categories)
|
||||
category = params["category"]
|
||||
. = TRUE
|
||||
|
||||
if(href_list["manufacturer"])
|
||||
if(href_list["manufacturer"] in GLOB.fabricator_robolimbs)
|
||||
limb_manufacturer = href_list["manufacturer"]
|
||||
if("manufacturer")
|
||||
if(params["manufacturer"] in GLOB.fabricator_robolimbs)
|
||||
limb_manufacturer = params["manufacturer"]
|
||||
. = TRUE
|
||||
|
||||
if(href_list["eject"])
|
||||
eject_materials(href_list["eject"], text2num(href_list["amount"]))
|
||||
if("eject")
|
||||
eject_materials(params["eject"], text2num(params["amount"]))
|
||||
. = TRUE
|
||||
|
||||
if(href_list["sync"])
|
||||
sync()
|
||||
else
|
||||
sync_message = ""
|
||||
if("sync")
|
||||
sync()
|
||||
. = TRUE
|
||||
else
|
||||
sync_message = ""
|
||||
|
||||
return 1
|
||||
if(.)
|
||||
playsound(src, 'sound/machines/synthfab/synthfab_button.ogg', 50)
|
||||
|
||||
/obj/machinery/mecha_part_fabricator/attackby(obj/item/attacking_item, mob/user)
|
||||
if(build_callback_timer)
|
||||
@@ -195,7 +224,7 @@
|
||||
return TRUE
|
||||
|
||||
var/sname = "[M.name]"
|
||||
if(materials[M.material.name] + M.perunit <= res_max_amount)
|
||||
if(materials[M.material.name] + SHEET_MATERIAL_AMOUNT <= res_max_amount)
|
||||
if(M.amount >= 1)
|
||||
var/count = 0
|
||||
var/mutable_appearance/MA = mutable_appearance(icon, "material_insertion")
|
||||
@@ -206,7 +235,7 @@
|
||||
//now play the progress bar animation
|
||||
flick_overlay_view(mutable_appearance(icon, "fab_progress"), 1 SECONDS)
|
||||
|
||||
while(materials[M.material.name] + M.perunit <= res_max_amount && M.amount >= 1)
|
||||
while(materials[M.material.name] + SHEET_MATERIAL_AMOUNT <= res_max_amount && M.amount >= 1)
|
||||
materials[M.material.name] += M.perunit
|
||||
M.use(1)
|
||||
count++
|
||||
@@ -344,6 +373,7 @@
|
||||
|
||||
else
|
||||
visible_message(SPAN_NOTICE("[icon2html(src, viewers(get_turf(src)))] \The [src] flashes: Insufficient materials to complete build: [D.name]."))
|
||||
remove_from_queue(1)
|
||||
|
||||
update_icon()
|
||||
|
||||
@@ -383,17 +413,17 @@
|
||||
|
||||
/obj/machinery/mecha_part_fabricator/proc/get_queue_names()
|
||||
. = list()
|
||||
for(var/i = 2 to queue.len)
|
||||
for(var/i = 1 to queue.len)
|
||||
var/datum/design/D = queue[i]
|
||||
. += D.name
|
||||
. += list(list("name" = D.name, "time" = get_design_time(D), "index" = i))
|
||||
|
||||
/obj/machinery/mecha_part_fabricator/proc/get_build_options()
|
||||
. = list()
|
||||
for(var/path in files.known_designs)
|
||||
var/datum/design/D = files.known_designs[path]
|
||||
if(!D.build_path || !(D.build_type & MECHFAB) || !D.category)
|
||||
if(!D.build_path || !(D.build_type & MECHFAB) || !D.category || (D.category != category))
|
||||
continue
|
||||
. += list(list("name" = D.name, "id" = D.type, "category" = D.category, "resourses" = get_design_resourses(D), "time" = get_design_time(D)))
|
||||
. += list(list("name" = D.name, "desc" = D.desc, "type" = D.type, "category" = D.category, "resources" = get_design_resourses(D), "time" = get_design_time(D)))
|
||||
|
||||
/obj/machinery/mecha_part_fabricator/proc/get_design_resourses(var/datum/design/D)
|
||||
var/list/F = list()
|
||||
@@ -417,25 +447,19 @@
|
||||
/obj/machinery/mecha_part_fabricator/proc/get_materials()
|
||||
. = list()
|
||||
for(var/T in materials)
|
||||
. += list(list("mat" = capitalize(T), "amt" = materials[T]))
|
||||
. += list(list("name" = capitalize(T), "amount" = materials[T]))
|
||||
|
||||
/obj/machinery/mecha_part_fabricator/proc/eject_materials(var/material, var/amount) // 0 amount = 0 means ejecting a full stack; -1 means eject everything
|
||||
var/recursive = amount == -1 ? 1 : 0
|
||||
/obj/machinery/mecha_part_fabricator/proc/eject_materials(var/material, var/amount)
|
||||
if(!amount)
|
||||
return
|
||||
material = lowertext(material)
|
||||
var/material/mattype = SSmaterials.get_material_by_name(material)
|
||||
var/stack_type = mattype.stack_type
|
||||
|
||||
var/obj/item/stack/material/S = new stack_type(loc)
|
||||
if(amount <= 0)
|
||||
amount = S.max_amount
|
||||
var/ejected = min(round(materials[material] / S.perunit), amount)
|
||||
S.amount = min(ejected, amount)
|
||||
if(S.amount <= 0)
|
||||
qdel(S)
|
||||
return
|
||||
materials[material] -= ejected * S.perunit
|
||||
if(recursive && materials[material] >= S.perunit)
|
||||
eject_materials(material, -1)
|
||||
var/real_amount = round(amount / SHEET_MATERIAL_AMOUNT)
|
||||
var/obj/item/stack/material/S = new stack_type(loc, real_amount)
|
||||
S.update_icon()
|
||||
materials[material] -= amount
|
||||
|
||||
/obj/machinery/mecha_part_fabricator/proc/sync()
|
||||
sync_message = "Error: no console found."
|
||||
|
||||
@@ -117,6 +117,9 @@
|
||||
return
|
||||
|
||||
var/obj/item/cell/target
|
||||
|
||||
// We use the reactor variable to see if this is an IPC that's charging.
|
||||
var/obj/item/organ/internal/machine/reactor/reactor
|
||||
if(isrobot(occupant))
|
||||
var/mob/living/silicon/robot/R = occupant
|
||||
|
||||
@@ -132,9 +135,15 @@
|
||||
|
||||
if(ishuman(occupant))
|
||||
var/mob/living/carbon/human/H = occupant
|
||||
var/obj/item/organ/internal/cell/IC = H.internal_organs_by_name[BP_CELL]
|
||||
if(IC)
|
||||
var/obj/item/organ/internal/machine/power_core/IC = H.internal_organs_by_name[BP_CELL]
|
||||
if(istype(IC))
|
||||
target = IC.cell
|
||||
|
||||
// Different reactor types have different external recharge speeds.
|
||||
reactor = H.internal_organs_by_name[BP_REACTOR]
|
||||
if(!istype(reactor))
|
||||
return
|
||||
|
||||
if((!target || target.percent() > 95) && istype(H.back, /obj/item/rig))
|
||||
var/obj/item/rig/R = H.back
|
||||
if(R.cell && !R.cell.fully_charged())
|
||||
@@ -143,7 +152,11 @@
|
||||
if(target && !target.fully_charged())
|
||||
var/diff = min(target.maxcharge - target.charge, charging_power * CELLRATE * seconds_per_tick) // Capped by charging_power / tick
|
||||
var/charge_used = cell.use(diff)
|
||||
target.give(charge_used*charging_efficiency)
|
||||
|
||||
if(!reactor) // not an IPC
|
||||
target.give(charge_used * charging_efficiency)
|
||||
else
|
||||
reactor.generate_power(charge_used * charging_efficiency * reactor.external_charge_multiplier)
|
||||
|
||||
if(isDrone(occupant))
|
||||
var/mob/living/silicon/robot/drone/D = occupant
|
||||
@@ -172,6 +185,13 @@
|
||||
if(cell)
|
||||
cell.emp_act(severity)
|
||||
|
||||
/obj/machinery/recharge_station/attack_hand(mob/user)
|
||||
. = ..()
|
||||
if(occupant && (user != occupant))
|
||||
if(do_after(user, 1 SECOND, src))
|
||||
user.visible_message(SPAN_NOTICE("[user] lowers the manual release lever on \the [src]."), SPAN_NOTICE("You lower the manual release lever on \the [src]."))
|
||||
go_out()
|
||||
|
||||
/obj/machinery/recharge_station/attackby(obj/item/attacking_item, mob/user)
|
||||
if(!occupant)
|
||||
if(default_deconstruction_screwdriver(user, attacking_item))
|
||||
|
||||
@@ -180,7 +180,7 @@
|
||||
if(!emagged)
|
||||
playsound(src.loc, 'sound/effects/sparks4.ogg', 75, 1)
|
||||
emagged = 1
|
||||
to_chat(user, SPAN_NOTICE("You you disable the security protocols"))
|
||||
to_chat(user, SPAN_NOTICE("You disable the security protocols."))
|
||||
src.updateUsrDialog()
|
||||
return 1
|
||||
|
||||
|
||||
@@ -157,6 +157,6 @@
|
||||
if(!emagged)
|
||||
playsound(src.loc, 'sound/effects/sparks4.ogg', 75, 1)
|
||||
emagged = 1
|
||||
to_chat(user, SPAN_NOTICE("You you disable the security protocols"))
|
||||
to_chat(user, SPAN_NOTICE("You disable the security protocols."))
|
||||
src.updateUsrDialog()
|
||||
return 1
|
||||
|
||||
@@ -234,6 +234,6 @@
|
||||
if(!emagged)
|
||||
playsound(src.loc, 'sound/effects/sparks4.ogg', 75, 1)
|
||||
emagged = 1
|
||||
to_chat(user, SPAN_NOTICE("You you disable the security protocols"))
|
||||
to_chat(user, SPAN_NOTICE("You disable the security protocols."))
|
||||
src.updateUsrDialog()
|
||||
return 1
|
||||
|
||||
@@ -420,7 +420,7 @@
|
||||
make_announcement("pings, \"Resuscitation successful.\"", "notice")
|
||||
playsound(get_turf(src), 'sound/machines/defib_success.ogg', 50, 0)
|
||||
H.resuscitate()
|
||||
var/obj/item/organ/internal/cell/potato = H.internal_organs_by_name[BP_CELL]
|
||||
var/obj/item/organ/internal/machine/power_core/potato = H.internal_organs_by_name[BP_CELL]
|
||||
if(istype(potato) && potato.cell)
|
||||
var/obj/item/cell/C = potato.cell
|
||||
C.give(chargecost)
|
||||
|
||||
@@ -23,7 +23,7 @@
|
||||
var/on = 0 //is it turned on?
|
||||
var/cover_open = 0 //is the cover open?
|
||||
var/obj/item/cell/cell
|
||||
var/max_cooling = 12 //in degrees per second - probably don't need to mess with heat capacity here
|
||||
var/max_cooling = 24 //in degrees per second - probably don't need to mess with heat capacity here
|
||||
var/charge_consumption = 8.3 //charge per second at max_cooling
|
||||
var/thermostat = T20C
|
||||
|
||||
@@ -95,7 +95,7 @@
|
||||
|
||||
var/charge_usage = (temp_adj/max_cooling)*charge_consumption
|
||||
|
||||
H.bodytemperature -= temp_adj*efficiency
|
||||
H.bodytemperature = max(T0C, H.bodytemperature - temp_adj*efficiency)
|
||||
|
||||
cell.use(charge_usage)
|
||||
|
||||
|
||||
@@ -83,6 +83,25 @@
|
||||
var/obj/item/organ/external/S = H.get_organ(target_zone)
|
||||
|
||||
if (S && (S.status & ORGAN_ASSISTED))
|
||||
var/datum/component/synthetic_endoskeleton/endoskeleton = H.GetComponent(/datum/component/synthetic_endoskeleton)
|
||||
if(istype(endoskeleton) && endoskeleton.damage)
|
||||
if(target_mob == user)
|
||||
if(endoskeleton.damage >= endoskeleton.max_damage * 0.5)
|
||||
to_chat(user, SPAN_WARNING("Your control over your limbs is too damaged to apply the nanopaste precisely!"))
|
||||
return
|
||||
application_time *= application_multiplier // It takes longer to apply nanopaste to yourself than to someone else.
|
||||
|
||||
if (application_in_progress == FALSE)
|
||||
application_in_progress = TRUE
|
||||
user.visible_message(SPAN_NOTICE("\The [user] begins to apply nanite past to the broken support systems of [user != target_mob ? " \the [target_mob]'s" : "\the [user]'s"] endoskeleton..."), \
|
||||
SPAN_NOTICE("You begin to apply nanite paste to the broken support systems of [user != target_mob ? " \the [target_mob]'s" : "your"] [endoskeleton]..."))
|
||||
if(do_mob(user, target_mob, application_time))
|
||||
SEND_SIGNAL(target_mob, COMSIG_SYNTH_ENDOSKELETON_REPAIR, rand(15, 30))
|
||||
user.visible_message(SPAN_NOTICE("\The [user] mends the broken links in [user != target_mob ? " \the [target_mob]'s" : "\the [user]'s"] endoskeleton with \the [src]."),\
|
||||
SPAN_NOTICE("You successfully mend the broken links in[user == target_mob ? "your" : "[target_mob]'s"] endoskeleton with \the [src]."))
|
||||
use(1)
|
||||
application_in_progress = FALSE
|
||||
|
||||
if(S.get_damage())
|
||||
user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN)
|
||||
|
||||
@@ -144,7 +163,7 @@
|
||||
return FALSE
|
||||
|
||||
if (isipc(M))
|
||||
var/obj/item/organ/internal/surge/s = M.internal_organs_by_name["surge"]
|
||||
var/obj/item/organ/internal/machine/surge/s = M.internal_organs_by_name[BP_SURGE_PROTECTOR]
|
||||
if(isnull(s))
|
||||
user.visible_message(
|
||||
SPAN_NOTICE("[user] is trying to apply [src] to [(M == user) ? ("itself") : (M)]!"),
|
||||
@@ -154,9 +173,9 @@
|
||||
if (!do_mob(user, M, 2))
|
||||
return FALSE
|
||||
|
||||
s = new /obj/item/organ/internal/surge()
|
||||
s = new /obj/item/organ/internal/machine/surge()
|
||||
M.internal_organs += s
|
||||
M.internal_organs_by_name["surge"] = s
|
||||
M.internal_organs_by_name[BP_SURGE_PROTECTOR] = s
|
||||
user.visible_message(
|
||||
SPAN_NOTICE("[user] applies some nanite paste to [(M == user) ? ("itself") : (M)]!"),
|
||||
SPAN_NOTICE("You apply [src] to [(M == user) ? ("youself") : (M)].")
|
||||
|
||||
@@ -68,11 +68,11 @@
|
||||
/obj/item/implanter/ipc_tag
|
||||
name = "IPC tag implanter"
|
||||
desc = "A special implanter used for implanting synthetics with a special tag."
|
||||
var/obj/item/organ/internal/ipc_tag/ipc_tag
|
||||
var/obj/item/organ/internal/machine/ipc_tag/ipc_tag
|
||||
|
||||
/obj/item/implanter/ipc_tag/Initialize()
|
||||
. = ..()
|
||||
ipc_tag = new /obj/item/organ/internal/ipc_tag(src)
|
||||
ipc_tag = new /obj/item/organ/internal/machine/ipc_tag(src)
|
||||
update_icon()
|
||||
|
||||
/obj/item/implanter/ipc_tag/update_icon()
|
||||
@@ -121,7 +121,7 @@
|
||||
ipc_tag = null
|
||||
update_icon()
|
||||
return
|
||||
if(istype(attacking_item, /obj/item/organ/internal/ipc_tag))
|
||||
if(istype(attacking_item, /obj/item/organ/internal/machine/ipc_tag))
|
||||
if(ipc_tag)
|
||||
to_chat(user, SPAN_WARNING("\The [src] already has an IPC tag loaded."))
|
||||
return
|
||||
|
||||
@@ -40,7 +40,7 @@
|
||||
to_chat(user, SPAN_WARNING("You analyze \the [target_mob], but find that they're not an IPC at all!"))
|
||||
return
|
||||
var/mob/living/carbon/human/IPC = target_mob
|
||||
var/obj/item/organ/internal/ipc_tag/tag = IPC.internal_organs_by_name[BP_IPCTAG]
|
||||
var/obj/item/organ/internal/machine/ipc_tag/tag = IPC.internal_organs_by_name[BP_IPCTAG]
|
||||
if(isnull(tag) || !tag)
|
||||
to_chat(user, SPAN_WARNING("Error: Serial Identification Missing."))
|
||||
return
|
||||
|
||||
@@ -11,16 +11,17 @@
|
||||
throw_speed = 3
|
||||
throw_range = 5
|
||||
w_class = WEIGHT_CLASS_NORMAL
|
||||
matter = list(DEFAULT_WALL_MATERIAL = 700, MATERIAL_GLASS = 50)
|
||||
recyclable = TRUE
|
||||
|
||||
/// Note %age converted to actual charge in New()
|
||||
var/charge = 0
|
||||
var/maxcharge = 2500
|
||||
/// Maximum cell charge.
|
||||
var/maxcharge = 1000
|
||||
/// True if rigged to explode
|
||||
var/rigged = FALSE
|
||||
/// If not 100% reliable, it will build up faults.
|
||||
var/minor_fault = 0
|
||||
matter = list(DEFAULT_WALL_MATERIAL = 700, MATERIAL_GLASS = 50)
|
||||
recyclable = TRUE
|
||||
|
||||
/// Percentage of maxcharge to recharge per minute, though it will trickle charge every process tick (every ~2 seconds), leave null for no self-recharge
|
||||
var/self_charge_percentage
|
||||
|
||||
@@ -126,10 +127,10 @@
|
||||
matter = list(DEFAULT_WALL_MATERIAL = 700, MATERIAL_GLASS = 80)
|
||||
|
||||
/obj/item/cell/infinite/check_charge()
|
||||
return 1
|
||||
return 1
|
||||
|
||||
/obj/item/cell/infinite/use()
|
||||
return 1
|
||||
return 1
|
||||
|
||||
/obj/item/cell/potato
|
||||
name = "potato battery"
|
||||
@@ -139,8 +140,6 @@
|
||||
icon_state = "potato_cell" //"potato_battery"
|
||||
charge = 100
|
||||
maxcharge = 300
|
||||
minor_fault = 1
|
||||
|
||||
|
||||
/obj/item/cell/slime
|
||||
name = "charged slime core"
|
||||
|
||||
@@ -355,6 +355,30 @@
|
||||
/obj/proc/do_signaler()
|
||||
return
|
||||
|
||||
|
||||
/**
|
||||
* Called when an access cable - from an IPC or from a roboticist tool - is inserted into an object.
|
||||
*/
|
||||
/obj/proc/insert_cable(obj/item/access_cable/cable, mob/user)
|
||||
user.drop_from_inventory(cable)
|
||||
cable.forceMove(src)
|
||||
cable.target = src
|
||||
|
||||
/**
|
||||
* Called when an access cable is removed from something, forcibly or not.
|
||||
* Override as needed to clear variables up.
|
||||
*/
|
||||
/obj/proc/remove_cable(obj/item/access_cable/cable)
|
||||
SHOULD_CALL_PARENT(TRUE)
|
||||
cable.target = null
|
||||
|
||||
/**
|
||||
* Called when an access cable - from an IPC or from a roboticist tool - is used on an object to interact with it.
|
||||
* For example, brings up diagnostics for an access port if it's hooked into one.
|
||||
*/
|
||||
/obj/proc/cable_interact(obj/item/access_cable/cable, mob/user)
|
||||
return
|
||||
|
||||
/*#############################################
|
||||
PERSISTENT
|
||||
#############################################*/
|
||||
|
||||
@@ -73,6 +73,7 @@
|
||||
new /obj/item/storage/belt/utility(src)
|
||||
new /obj/item/storage/belt/utility/alt(src)
|
||||
new /obj/item/storage/toolbox/mechanical(src)
|
||||
new /obj/item/modular_computer/laptop/preset/supply/robotics(src)
|
||||
|
||||
// Miner
|
||||
/obj/structure/closet/secure_closet/miner
|
||||
|
||||
@@ -49,6 +49,7 @@
|
||||
new /obj/item/device/taperecorder(src)
|
||||
new /obj/item/sampler(src)
|
||||
new /obj/item/storage/box/shells/tranquilizer(src)
|
||||
new /obj/item/modular_computer/laptop/preset/supply/robotics(src)
|
||||
|
||||
/// Used for when we want to populate the contents of this locker ourself. Good for away sites
|
||||
/obj/structure/closet/secure_closet/RD/empty
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
<br>
|
||||
BRUTE:<a href='byond://?_src_=vars;mobToDamage=[REF(src)];adjustDamage=brute'>[getBruteLoss()]</a>
|
||||
FIRE:<a href='byond://?_src_=vars;mobToDamage=[REF(src)];adjustDamage=fire'>[getFireLoss()]</a>
|
||||
TOXIN:<a href='byond://?_src_=vars;mobToDamage=[REF(src)];adjustDamage=toxin'>[getToxLoss()]</a>
|
||||
ORGAN:<a href='byond://?_src_=vars;mobToDamage=[REF(src)];adjustDamage=toxin'>[getToxLoss()]</a>
|
||||
OXY:<a href='byond://?_src_=vars;mobToDamage=[REF(src)];adjustDamage=oxygen'>[getOxyLoss()]</a>
|
||||
CLONE:<a href='byond://?_src_=vars;mobToDamage=[REF(src)];adjustDamage=clone'>[getCloneLoss()]</a>
|
||||
BRAIN:<a href='byond://?_src_=vars;mobToDamage=[REF(src)];adjustDamage=brain'>[getBrainLoss()]</a>
|
||||
|
||||
@@ -243,6 +243,11 @@ GLOBAL_LIST_INIT(valid_bloodtypes, list(
|
||||
out += "Limbs: <a href='byond://?src=[REF(src)];limbs=1'>Adjust</a><br>"
|
||||
if(length(mob_species.alterable_internal_organs))
|
||||
out += "Internal Organs: <a href='byond://?src=[REF(src)];organs=1'>Adjust</a><br>"
|
||||
for(var/organ in pref.organ_data)
|
||||
var/output_pref = pref.organ_data[organ]
|
||||
if(!pref.organ_data[organ])
|
||||
output_pref = "Default"
|
||||
out += "- <b>[capitalize_first_letters(organ)]</b>: [capitalize(output_pref)] <br>"
|
||||
out += "Prosthesis/Amputations: <a href='byond://?src=[REF(src)];reset_organs=1'>Reset</a><br>"
|
||||
|
||||
//display limbs below
|
||||
@@ -890,6 +895,22 @@ GLOBAL_LIST_INIT(valid_bloodtypes, list(
|
||||
if("Removed")
|
||||
pref.organ_data[organ_name] = ORGAN_PREF_REMOVED
|
||||
|
||||
// IPC cooling unit options.
|
||||
if("Air Cooling")
|
||||
pref.organ_data[organ_name] = null
|
||||
if("Liquid Cooling")
|
||||
pref.organ_data[organ_name] = ORGAN_PREF_LIQUIDCOOLED
|
||||
if("Passive Cooling")
|
||||
pref.organ_data[organ_name] = ORGAN_PREF_PASSIVECOOLED
|
||||
|
||||
// IPC reactor options.
|
||||
if("Electric")
|
||||
pref.organ_data[organ_name] = null
|
||||
if("Biological")
|
||||
pref.organ_data[organ_name] = ORGAN_PREF_BIOPOWER
|
||||
if("Solar")
|
||||
pref.organ_data[organ_name] = ORGAN_PREF_SOLARPOWER
|
||||
|
||||
return TOPIC_REFRESH_UPDATE_PREVIEW
|
||||
|
||||
else if(href_list["reset_organs"])
|
||||
|
||||
@@ -774,7 +774,7 @@
|
||||
interface_desc = "A heat sink with liquid cooled radiator."
|
||||
icon_state = "suitcooler"
|
||||
var/charge_consumption = 1
|
||||
var/max_cooling = 12
|
||||
var/max_cooling = 24
|
||||
var/thermostat = T20C
|
||||
|
||||
category = MODULE_GENERAL
|
||||
@@ -785,15 +785,34 @@
|
||||
|
||||
var/mob/living/carbon/human/H = holder.wearer
|
||||
|
||||
var/temp_adj = min(H.bodytemperature - thermostat, max_cooling)
|
||||
var/env_temp = get_environment_temperature()
|
||||
var/temp_adj = min(H.bodytemperature - max(thermostat, env_temp), max_cooling)
|
||||
|
||||
if (temp_adj < 0.5)
|
||||
return passive_power_cost
|
||||
|
||||
H.bodytemperature -= temp_adj
|
||||
H.bodytemperature = max(T0C, H.bodytemperature - temp_adj)
|
||||
active_power_cost = round((temp_adj/max_cooling)*charge_consumption)
|
||||
|
||||
return active_power_cost
|
||||
|
||||
/obj/item/rig_module/cooling_unit/proc/get_environment_temperature()
|
||||
if(ishuman(loc))
|
||||
var/mob/living/carbon/human/H = loc
|
||||
if(istype(H.loc, /obj/machinery/atmospherics/unary/cryo_cell))
|
||||
var/obj/machinery/atmospherics/unary/cryo_cell/C = H.loc
|
||||
return C.air_contents.temperature
|
||||
|
||||
var/turf/T = get_turf(src)
|
||||
if(istype(T, /turf/space) || !isturf(T))
|
||||
return FALSE //space has no temperature, this just makes sure the cooling unit works in space
|
||||
|
||||
var/datum/gas_mixture/environment = T.return_air()
|
||||
if(!environment)
|
||||
return FALSE
|
||||
|
||||
return environment.temperature
|
||||
|
||||
/obj/item/rig_module/boring
|
||||
name = "burrowing lasers"
|
||||
desc = "A set of precise boring lasers designed to carve a hole beneath the user."
|
||||
|
||||
@@ -1985,6 +1985,7 @@ All custom items with worn sprites must follow the contained sprite system: http
|
||||
// adding the hand to the child here means only the arm has to be added to the DB
|
||||
// since the hand will be attached automatically
|
||||
LAZYADD(children, new /obj/item/organ/external/hand/fluff/gracia_autakh(src))
|
||||
internal_organs += new /obj/item/organ/internal/machine/actuators/left(src)
|
||||
|
||||
/obj/item/organ/external/hand/fluff/gracia_autakh // gracia's aut'akh left hand - Gracia Hiza - cometblaze
|
||||
robotize_type = PROSTHETIC_AUTAKH
|
||||
|
||||
@@ -34,6 +34,15 @@
|
||||
for(var/obj/machinery/power/apc/valid_apc in SSmachinery.apc_units)
|
||||
if((valid_apc.z in affecting_z) && !valid_apc.is_critical)
|
||||
valid_apcs += valid_apc
|
||||
for(var/mob/living/carbon/human/victim_ipc in GLOB.human_mob_list)
|
||||
if(!isipc(victim_ipc))
|
||||
continue
|
||||
if(!(victim_ipc.z in affecting_z))
|
||||
continue
|
||||
var/obj/item/organ/internal/machine/posibrain/brain = victim_ipc.internal_organs_by_name[BP_BRAIN]
|
||||
if(istype(brain))
|
||||
to_chat(victim_ipc, SPAN_MACHINE_WARNING("A jolt of ambient electricity rumbles through your circuitry! Your processors go to work putting the bits back together..."))
|
||||
brain.brain_scrambling += rand(severity * 35, severity * 45)
|
||||
endWhen = (severity * 35) + startWhen
|
||||
|
||||
/datum/event/electrical_storm/end(faked)
|
||||
|
||||
@@ -27,7 +27,7 @@
|
||||
return
|
||||
switch(href_list["info"])
|
||||
if("actuator")
|
||||
to_chat(usr, SPAN_NOTICE("An actuator can be created at a mechatronic fabricator."))
|
||||
to_chat(usr, SPAN_NOTICE("An actuator can be created at a synthetic fabricator."))
|
||||
|
||||
/obj/item/mech_component/manipulators/return_diagnostics(mob/user)
|
||||
..()
|
||||
|
||||
@@ -79,11 +79,11 @@
|
||||
return
|
||||
switch(href_list["info"])
|
||||
if("cell")
|
||||
to_chat(usr, SPAN_NOTICE("A power core can be created at a mechatronic fabricator."))
|
||||
to_chat(usr, SPAN_NOTICE("A power core can be created at a synthetic fabricator."))
|
||||
if("diagnostics")
|
||||
to_chat(usr, SPAN_NOTICE("A diagnostics unit can be created at a mechatronic fabricator."))
|
||||
to_chat(usr, SPAN_NOTICE("A diagnostics unit can be created at a synthetic fabricator."))
|
||||
if("armor")
|
||||
to_chat(usr, SPAN_NOTICE("Armor plating can be created at a mechatronic fabricator."))
|
||||
to_chat(usr, SPAN_NOTICE("Armor plating can be created at a synthetic fabricator."))
|
||||
|
||||
/obj/item/mech_component/chassis/return_diagnostics(mob/user)
|
||||
..()
|
||||
|
||||
@@ -66,13 +66,13 @@
|
||||
return
|
||||
switch(href_list["info"])
|
||||
if("manipulators")
|
||||
to_chat(usr, SPAN_NOTICE("Manipulators, the arms of the exosuit, can be created at a mechatronic fabricator."))
|
||||
to_chat(usr, SPAN_NOTICE("Manipulators, the arms of the exosuit, can be created at a synthetic fabricator."))
|
||||
if("propulsion")
|
||||
to_chat(usr, SPAN_NOTICE("Propulsion, the legs of the exosuit, can be created at a mechatronic fabricator."))
|
||||
to_chat(usr, SPAN_NOTICE("Propulsion, the legs of the exosuit, can be created at a synthetic fabricator."))
|
||||
if("sensors")
|
||||
to_chat(usr, SPAN_NOTICE("Sensors, the head of the exosuit, can be created at a mechatronic fabricator."))
|
||||
to_chat(usr, SPAN_NOTICE("Sensors, the head of the exosuit, can be created at a synthetic fabricator."))
|
||||
if("chassis")
|
||||
to_chat(usr, SPAN_NOTICE("A chassis, the body of the exosuit, can be created at a mechatronic fabricator."))
|
||||
to_chat(usr, SPAN_NOTICE("A chassis, the body of the exosuit, can be created at a synthetic fabricator."))
|
||||
if("wire")
|
||||
if(!is_wired)
|
||||
to_chat(usr, SPAN_NOTICE("The frame requires wiring between its components. This can be added with cable coil."))
|
||||
|
||||
@@ -37,11 +37,11 @@
|
||||
return
|
||||
switch(href_list["info"])
|
||||
if("radio")
|
||||
to_chat(usr, SPAN_NOTICE("A radio can be created at a mechatronic fabricator."))
|
||||
to_chat(usr, SPAN_NOTICE("A radio can be created at a synthetic fabricator."))
|
||||
if("camera")
|
||||
to_chat(usr, SPAN_NOTICE("A camera can be created at a mechatronic fabricator."))
|
||||
to_chat(usr, SPAN_NOTICE("A camera can be created at a synthetic fabricator."))
|
||||
if("module")
|
||||
to_chat(usr, SPAN_NOTICE("An exosuit control module can be created at a mechatronic fabricator, while the software chips it uses can be printed at the circuit imprinter."))
|
||||
to_chat(usr, SPAN_NOTICE("An exosuit control module can be created at a synthetic fabricator, while the software chips it uses can be printed at the circuit imprinter."))
|
||||
|
||||
/obj/item/mech_component/sensors/return_diagnostics(mob/user)
|
||||
..()
|
||||
|
||||
@@ -26,7 +26,7 @@
|
||||
return
|
||||
switch(href_list["info"])
|
||||
if("actuator")
|
||||
to_chat(usr, SPAN_NOTICE("An actuator can be created at a mechatronic fabricator."))
|
||||
to_chat(usr, SPAN_NOTICE("An actuator can be created at a synthetic fabricator."))
|
||||
|
||||
/obj/item/mech_component/propulsion/return_diagnostics(mob/user)
|
||||
..()
|
||||
|
||||
@@ -64,6 +64,18 @@
|
||||
style_open = "<span class='langchat' style=font-size:16pt;text-align:center valign='top'>"
|
||||
style_close = "</span>"
|
||||
|
||||
/atom/movable/screen/text/screen_text/low_integrity_message
|
||||
maptext_height = 64
|
||||
maptext_width = 480
|
||||
maptext_x = 0
|
||||
maptext_y = 0
|
||||
screen_loc = "LEFT,TOP-3"
|
||||
|
||||
letters_per_update = 1
|
||||
fade_out_delay = 6 SECONDS
|
||||
style_open = "<span class='langchat' style=font-size:20pt;text-align:center valign='top'>"
|
||||
style_close = "</span>"
|
||||
|
||||
///proc for actually playing this screen_text on a mob.
|
||||
/atom/movable/screen/text/screen_text/proc/play_to_client()
|
||||
player?.add_to_screen(src)
|
||||
|
||||
@@ -30,7 +30,7 @@
|
||||
cell.maxcharge = 10000
|
||||
cell.charge = 10000
|
||||
|
||||
mmi = /obj/item/organ/internal/mmi_holder/circuit
|
||||
mmi = /obj/item/organ/internal/machine/posibrain/circuit
|
||||
|
||||
// Allows mining drones to pull ore boxes, might be useful for supporting miners
|
||||
pull_list |= /obj/structure/ore_box
|
||||
|
||||
@@ -421,6 +421,10 @@ GLOBAL_LIST_INIT(slot_equipment_priority, list(
|
||||
item = G.throw_held() //throw the person instead of the grab
|
||||
if(ismob(item) && G.state >= GRAB_NECK)
|
||||
var/mob/M = item
|
||||
if(M.mob_weight > get_mob_strength())
|
||||
to_chat(src, SPAN_WARNING("[M] is far too heavy for you to throw around!"))
|
||||
return
|
||||
|
||||
throw_range = round(throw_range * (src.mob_size/M.mob_size))
|
||||
itemsize = round(M.mob_size/4)
|
||||
var/turf/start_T = get_turf(loc) //Get the start and target tile for the descriptors
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
set_species(new_species)
|
||||
reset_hair()
|
||||
if(isipc(src))
|
||||
var/obj/item/organ/internal/ipc_tag/tag = internal_organs_by_name[BP_IPCTAG]
|
||||
var/obj/item/organ/internal/machine/ipc_tag/tag = internal_organs_by_name[BP_IPCTAG]
|
||||
if(istype(tag))
|
||||
tag.modify_tag_data(TRUE)
|
||||
return 1
|
||||
|
||||
@@ -188,6 +188,15 @@
|
||||
var/obj/item/organ/internal/stomach/stomach = internal_organs_by_name[BP_STOMACH]
|
||||
if(stomach)
|
||||
return stomach.ingested
|
||||
|
||||
if(should_have_organ(BP_REACTOR))
|
||||
var/obj/item/organ/internal/machine/reactor/reactor = internal_organs_by_name[BP_REACTOR]
|
||||
if(!reactor)
|
||||
return
|
||||
if(reactor.is_broken())
|
||||
return FALSE
|
||||
if(reactor.power_supply_type & POWER_SUPPLY_BIOLOGICAL)
|
||||
return reactor.bio_reagents
|
||||
return touching
|
||||
|
||||
/mob/living/carbon/human/proc/metabolize_ingested_reagents()
|
||||
@@ -239,9 +248,16 @@
|
||||
. += "Tank Pressure: [internal.air_contents.return_pressure()]"
|
||||
. += "Distribution Pressure: [internal.distribute_pressure]"
|
||||
|
||||
var/obj/item/organ/internal/cell/IC = internal_organs_by_name[BP_CELL]
|
||||
var/obj/item/organ/internal/machine/power_core/IC = internal_organs_by_name[BP_CELL]
|
||||
if(IC && IC.cell)
|
||||
. += "Battery charge: [IC.get_charge()]/[IC.cell.maxcharge]"
|
||||
. += "Battery Charge: [IC.get_charge()]/[IC.cell.maxcharge]"
|
||||
|
||||
var/obj/item/organ/internal/machine/internal_diagnostics/diagnostics = internal_organs_by_name[BP_DIAGNOSTICS_SUITE]
|
||||
if(diagnostics)
|
||||
if((diagnostics.get_integrity() < IPC_INTEGRITY_THRESHOLD_HIGH) || !diagnostics.is_broken())
|
||||
. += "Temperature: [round(bodytemperature - T0C, 1)]°C"
|
||||
else
|
||||
. += "Temperature: E#RR"
|
||||
|
||||
if(mind)
|
||||
var/datum/vampire/vampire = mind.antag_datums[MODE_VAMPIRE]
|
||||
@@ -970,6 +986,13 @@
|
||||
return
|
||||
|
||||
/mob/living/carbon/human/proc/check_has_mouth()
|
||||
// Look, it's not really a mouth, but you gotta do what you gotta do.
|
||||
// Imagine the Bender shit from Futurama where he opens his stomach hatch and drops shit in there.
|
||||
if(should_have_organ(BP_REACTOR))
|
||||
var/obj/item/organ/internal/machine/reactor/reactor = internal_organs_by_name[BP_REACTOR]
|
||||
if(reactor && (reactor.power_supply_type & POWER_SUPPLY_BIOLOGICAL))
|
||||
return TRUE
|
||||
|
||||
// Todo, check stomach organ when implemented.
|
||||
var/obj/item/organ/external/E = get_organ(BP_HEAD)
|
||||
if(E && !E.is_stump())
|
||||
@@ -1888,6 +1911,10 @@
|
||||
return 0
|
||||
|
||||
/mob/living/carbon/human/proc/can_drink(var/obj/item/I)
|
||||
if(should_have_organ(BP_REACTOR))
|
||||
var/obj/item/organ/internal/machine/reactor/reactor = internal_organs_by_name[BP_REACTOR]
|
||||
if(reactor && (reactor.power_supply_type & POWER_SUPPLY_BIOLOGICAL))
|
||||
return TRUE
|
||||
if(!check_has_mouth())
|
||||
to_chat(src, SPAN_NOTICE("Where do you intend to put \the [I]? You don't have a mouth!"))
|
||||
return FALSE
|
||||
@@ -2070,8 +2097,8 @@
|
||||
|
||||
// Check if we should die.
|
||||
/mob/living/carbon/human/proc/handle_death_check()
|
||||
if(should_have_organ(BP_BRAIN) && !is_mechanical()) //robots don't die via brain damage
|
||||
var/obj/item/organ/internal/brain/brain = internal_organs_by_name[BP_BRAIN]
|
||||
if(should_have_organ(BP_BRAIN))
|
||||
var/obj/item/organ/internal/brain = internal_organs_by_name[BP_BRAIN]
|
||||
if(!brain || (brain.status & ORGAN_DEAD))
|
||||
return TRUE
|
||||
return species.handle_death_check(src)
|
||||
|
||||
@@ -306,7 +306,7 @@
|
||||
return FALSE
|
||||
|
||||
var/disarm_cost
|
||||
var/obj/item/organ/internal/cell/cell = M.internal_organs_by_name[BP_CELL]
|
||||
var/obj/item/organ/internal/machine/power_core/cell = M.internal_organs_by_name[BP_CELL]
|
||||
var/obj/item/cell/potato
|
||||
if(cell)
|
||||
potato = cell.cell
|
||||
|
||||
@@ -404,7 +404,7 @@ This function restores the subjects blood to max.
|
||||
This function restores all organs.
|
||||
*/
|
||||
/mob/living/carbon/human/restore_all_organs()
|
||||
for(var/obj/item/organ/external/current_organ in organs)
|
||||
for(var/obj/item/organ/current_organ in organs)
|
||||
current_organ.rejuvenate()
|
||||
|
||||
/mob/living/carbon/human/proc/HealDamage(zone, brute, burn)
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
return 1
|
||||
if(feedback)
|
||||
if(status[1] == HUMAN_EATING_NO_MOUTH)
|
||||
to_chat(src, "Where do you intend to put \the [food]? You don't have a mouth!")
|
||||
to_chat(src, SPAN_NOTICE("Where do you intend to put \the [food]? You don't have a mouth!"))
|
||||
else if(status[1] == HUMAN_EATING_BLOCKED_MOUTH)
|
||||
to_chat(src, SPAN_WARNING("\The [status[2]] is in the way!"))
|
||||
return 0
|
||||
@@ -133,16 +133,24 @@
|
||||
else
|
||||
var/obj/item/organ/I = internal_organs_by_name[name]
|
||||
if(I)
|
||||
switch (status)
|
||||
if (ORGAN_PREF_ASSISTED)
|
||||
I.mechassist()
|
||||
if (ORGAN_PREF_MECHANICAL)
|
||||
if (rlimb_data[name])
|
||||
I.robotize(rlimb_data[name])
|
||||
else
|
||||
I.robotize()
|
||||
if (ORGAN_PREF_REMOVED)
|
||||
qdel(I)
|
||||
if(istype(I, /obj/item/organ/internal/machine))
|
||||
var/obj/item/organ/internal/machine/machine_organ = I
|
||||
if(length(machine_organ.possible_modifications))
|
||||
machine_organ.get_preset_from_pref(status)
|
||||
// If you add any more presets here, make sure to update the presets on the organ as well.
|
||||
// Remember also that the default pref, but "default pref" is actually "the absence of any pref".
|
||||
// We check for unique prefs and if we don't find a unique organ pref, then we default to the base type.
|
||||
else
|
||||
switch (status)
|
||||
if (ORGAN_PREF_ASSISTED)
|
||||
I.mechassist()
|
||||
if (ORGAN_PREF_MECHANICAL)
|
||||
if (rlimb_data[name])
|
||||
I.robotize(rlimb_data[name])
|
||||
else
|
||||
I.robotize()
|
||||
if (ORGAN_PREF_REMOVED)
|
||||
qdel(I)
|
||||
|
||||
if (apply_markings)
|
||||
for(var/N in organs_by_name)
|
||||
@@ -363,7 +371,7 @@
|
||||
return FALSE
|
||||
|
||||
/mob/living/carbon/human/get_cell()
|
||||
var/obj/item/organ/internal/cell/C = internal_organs_by_name[BP_CELL]
|
||||
var/obj/item/organ/internal/machine/power_core/C = internal_organs_by_name[BP_CELL]
|
||||
if(C)
|
||||
return C.cell
|
||||
|
||||
|
||||
@@ -55,6 +55,11 @@
|
||||
var/obj/item/P = pulling
|
||||
tally += P.slowdown
|
||||
|
||||
var/obj/item/grab/grab = get_type_in_hands(/obj/item/grab)
|
||||
if(istype(grab) && ishuman(grab.affecting))
|
||||
if(grab.affecting.mob_weight > get_mob_strength())
|
||||
tally += grab.affecting.mob_weight - get_mob_strength()
|
||||
|
||||
var/turf/T = get_turf(src)
|
||||
if(T) // changelings don't get movement costs
|
||||
var/datum/changeling/changeling
|
||||
@@ -188,4 +193,4 @@
|
||||
var/mob/living/carbon/human/H = pulling
|
||||
if(H.species.slowdown > species.slowdown)
|
||||
. += H.species.slowdown - species.slowdown
|
||||
// . += H.ClothesSlowdown()
|
||||
|
||||
|
||||
@@ -37,6 +37,9 @@
|
||||
internal_organs -= I
|
||||
continue
|
||||
|
||||
if(I.status & ORGAN_DEAD)
|
||||
continue
|
||||
|
||||
I.process(seconds_per_tick)
|
||||
|
||||
handle_stance()
|
||||
@@ -192,10 +195,13 @@
|
||||
|
||||
/mob/living/carbon/human/is_asystole()
|
||||
if(isSynthetic())
|
||||
var/obj/item/organ/internal/cell/C = internal_organs_by_name[BP_CELL]
|
||||
var/obj/item/organ/internal/machine/power_core/C = internal_organs_by_name[BP_CELL]
|
||||
if(istype(C) && C.is_usable() && C.percent())
|
||||
return FALSE
|
||||
var/obj/item/organ/internal/machine/posibrain/posi = internal_organs_by_name[BP_BRAIN]
|
||||
if(istype(posi) && !posi.self_preservation_activated)
|
||||
return FALSE
|
||||
return TRUE
|
||||
|
||||
else if(should_have_organ(BP_HEART))
|
||||
var/obj/item/organ/internal/heart/heart = internal_organs_by_name[BP_HEART]
|
||||
if(!istype(heart) || !heart.is_working())
|
||||
|
||||
@@ -1066,9 +1066,6 @@
|
||||
|
||||
drop_from_inventory(O)
|
||||
O.replaced(src)
|
||||
update_body()
|
||||
updatehealth()
|
||||
UpdateDamageIcon()
|
||||
|
||||
update_body()
|
||||
updatehealth()
|
||||
@@ -1077,45 +1074,6 @@
|
||||
visible_message(SPAN_NOTICE("\The [src] attaches \the [O] to [get_pronoun("his")] body!"),
|
||||
SPAN_NOTICE("You attach \the [O] to your body!"))
|
||||
|
||||
/mob/living/carbon/human/proc/self_diagnostics()
|
||||
set name = "Self-Diagnostics"
|
||||
set desc = "Run an internal self-diagnostic to check for damage."
|
||||
set category = "Abilities"
|
||||
|
||||
if(stat == DEAD) return
|
||||
|
||||
to_chat(src, SPAN_NOTICE("Performing self-diagnostic, please wait..."))
|
||||
if (do_after(src, 10))
|
||||
var/output = SPAN_NOTICE("Self-Diagnostic Results:\n")
|
||||
|
||||
output += "Internal Temperature: [convert_k2c(bodytemperature)] Degrees Celsius\n"
|
||||
|
||||
var/obj/item/organ/internal/cell/C = internal_organs_by_name[BP_CELL]
|
||||
if(!C || !C.cell)
|
||||
output += SPAN_DANGER("ERROR: NO BATTERY DETECTED")
|
||||
else
|
||||
output += "Current Charge Level: [C.percent()]\n"
|
||||
|
||||
var/toxDam = getToxLoss()
|
||||
if(toxDam)
|
||||
output += "Blood Toxicity: <span class='warning'>[toxDam > 25 ? "Severe" : "Moderate"]</span>. Seek medical facilities for cleanup.\n"
|
||||
else
|
||||
output += "Blood Toxicity: <span style='color:green;'>OK</span>\n"
|
||||
|
||||
for(var/obj/item/organ/external/EO in organs)
|
||||
if(EO.brute_dam || EO.burn_dam)
|
||||
output += "[EO.name] - <span class='warning'>[EO.burn_dam + EO.brute_dam > ROBOLIMB_SELF_REPAIR_CAP ? "Heavy Damage" : "Light Damage"]</span>\n"
|
||||
else
|
||||
output += "[EO.name] - <span style='color:green;'>OK</span>\n"
|
||||
|
||||
for(var/obj/item/organ/IO in internal_organs)
|
||||
if(IO.damage)
|
||||
output += "[IO.name] - <span class='warning'>[IO.damage > 10 ? "Heavy Damage" : "Light Damage"]</span>\n"
|
||||
else
|
||||
output += "[IO.name] - <span style='color:green;'>OK</span>\n"
|
||||
|
||||
to_chat(src, output)
|
||||
|
||||
/mob/living/carbon/human/proc/check_tag()
|
||||
set name = "Check Tag"
|
||||
set desc = "Run diagnostics on your tag to display its information."
|
||||
@@ -1124,7 +1082,7 @@
|
||||
if(use_check_and_message(usr))
|
||||
return
|
||||
|
||||
var/obj/item/organ/internal/ipc_tag/tag = internal_organs_by_name[BP_IPCTAG]
|
||||
var/obj/item/organ/internal/machine/ipc_tag/tag = internal_organs_by_name[BP_IPCTAG]
|
||||
if(isnull(tag) || !tag)
|
||||
to_chat(src, SPAN_WARNING("Error: No Tag Found."))
|
||||
return
|
||||
|
||||
@@ -439,7 +439,8 @@
|
||||
|
||||
/mob/living/carbon/human/proc/stabilize_body_temperature()
|
||||
if (species.passive_temp_gain) // We produce heat naturally.
|
||||
bodytemperature += species.passive_temp_gain
|
||||
species.handle_temperature_regulation(src)
|
||||
|
||||
if (species.body_temperature == null)
|
||||
return //this species doesn't have metabolic thermoregulation
|
||||
|
||||
@@ -1015,7 +1016,7 @@
|
||||
nut_icon = 2
|
||||
else if (nut_factor >= CREW_NUTRITION_HUNGRY)
|
||||
nut_icon = 3
|
||||
else if (nut_factor >= CREW_NUTRITION_VERYHUNGRY )
|
||||
else if (nut_factor >= CREW_NUTRITION_VERYHUNGRY)
|
||||
nut_icon = 4
|
||||
var/new_val = "[isSynthetic() ? "charge" : "nutrition"][nut_icon]"
|
||||
if (nutrition_icon.icon_state != new_val)
|
||||
@@ -1039,7 +1040,7 @@
|
||||
hydration_icon.icon_state = new_val
|
||||
|
||||
if(isSynthetic())
|
||||
var/obj/item/organ/internal/cell/IC = internal_organs_by_name[BP_CELL]
|
||||
var/obj/item/organ/internal/machine/power_core/IC = internal_organs_by_name[BP_CELL]
|
||||
if(istype(IC) && IC.is_usable())
|
||||
var/chargeNum = clamp(Ceiling(IC.percent()/25), 0, 4) //0-100 maps to 0-4, but give it a paranoid clamp just in case.
|
||||
cells.icon_state = "charge[chargeNum]"
|
||||
|
||||
@@ -65,6 +65,12 @@
|
||||
|
||||
return ..()
|
||||
|
||||
/mob/living/carbon/human/say(message, datum/language/speaking, verb, alt_name, ghost_hearing, whisper, skip_edit)
|
||||
// Messaging the user is handled by the species proc.
|
||||
if(!species.can_speak(src, speaking, message))
|
||||
return FALSE
|
||||
. = ..()
|
||||
|
||||
/mob/living/carbon/human/GetVoice()
|
||||
var/voice_sub
|
||||
if(istype(back,/obj/item/rig))
|
||||
|
||||
@@ -94,6 +94,10 @@
|
||||
/// Used for mob icon generation for non-32x32 species.
|
||||
var/icon/icon_template
|
||||
var/mob_size = MOB_MEDIUM
|
||||
/// The weight of the mob. Affects if the mob can be easily lifted or not. Separate from size, as some mobs may be big but not particularly heavy.
|
||||
var/mob_weight = MOB_WEIGHT_MEDIUM
|
||||
/// The strength of the mob. A bonus to the checks on lifting/throwing other mobs.
|
||||
var/mob_strength = MOB_STRENGTH_NORMAL
|
||||
var/show_ssd = "in a deep slumber"
|
||||
var/short_sighted
|
||||
var/bald = 0
|
||||
@@ -389,6 +393,7 @@
|
||||
BP_R_FOOT = list("path" = /obj/item/organ/external/foot/right)
|
||||
)
|
||||
|
||||
var/natural_armor_type = /datum/component/armor/natural
|
||||
var/list/natural_armor
|
||||
|
||||
// Bump vars
|
||||
@@ -545,7 +550,7 @@
|
||||
if(H.bad_external_organs) H.bad_external_organs.Cut()
|
||||
if(H.bad_internal_organs) H.bad_internal_organs.Cut()
|
||||
|
||||
var/datum/component/armor/armor_component = H.GetComponent(/datum/component/armor)
|
||||
var/datum/component/armor/armor_component = H.GetComponent(natural_armor_type)
|
||||
if(armor_component)
|
||||
qdel(armor_component)
|
||||
|
||||
@@ -584,7 +589,7 @@
|
||||
I.status |= ORGAN_ADV_ROBOT
|
||||
|
||||
if(natural_armor)
|
||||
H.AddComponent(/datum/component/armor, natural_armor)
|
||||
H.AddComponent(natural_armor_type, natural_armor)
|
||||
|
||||
/datum/species/proc/tap(var/mob/living/carbon/human/H,var/mob/living/target)
|
||||
if(H.on_fire)
|
||||
@@ -620,13 +625,16 @@
|
||||
|
||||
return
|
||||
|
||||
/datum/species/proc/handle_post_spawn(var/mob/living/carbon/human/H,var/kpg = 0) //Handles anything not already covered by basic species assignment. Keepgene value should only be used by genetics.
|
||||
/// Handles anything not already covered by basic species assignment. Keepgene (kpg) value should only be used by genetics.
|
||||
/datum/species/proc/handle_post_spawn(mob/living/carbon/human/H, kpg = 0)
|
||||
add_inherent_verbs(H)
|
||||
H.mob_bump_flag = bump_flag
|
||||
H.mob_swap_flags = swap_flags
|
||||
H.mob_push_flags = push_flags
|
||||
H.pass_flags = pass_flags
|
||||
H.mob_size = mob_size
|
||||
H.mob_weight = mob_weight
|
||||
H.mob_strength = mob_strength
|
||||
H.eat_types = allowed_eat_types
|
||||
if(!kpg)
|
||||
if(islesserform(H))
|
||||
@@ -1057,3 +1065,18 @@
|
||||
*/
|
||||
/datum/species/proc/sleep_examine_msg(var/mob/M)
|
||||
return SPAN_NOTICE("[M.get_pronoun("He")] appears to be fast asleep.\n")
|
||||
|
||||
/**
|
||||
* This proc is used to override speech checks for human mobs.
|
||||
* If it returns FALSE, the mob will not be able to speak.
|
||||
* Make sure to give the user the relevant error message in the override.
|
||||
*/
|
||||
/datum/species/proc/can_speak(mob/living/carbon/human/speaker, datum/language/speaking, message)
|
||||
return TRUE
|
||||
|
||||
/**
|
||||
* This proc handles the species temperature regulation. By default, it just adds `passive_temp_gain` to the human's bodytemperature.
|
||||
* Can be overridden for more complex calculations.
|
||||
*/
|
||||
/datum/species/proc/handle_temperature_regulation(mob/living/carbon/human/human)
|
||||
human.bodytemperature += passive_temp_gain
|
||||
|
||||
@@ -1,24 +1,42 @@
|
||||
/datum/hud_data
|
||||
var/icon // If set, overrides ui_style.
|
||||
var/has_a_intent = TRUE // Set to draw intent box.
|
||||
var/has_m_intent = TRUE // Set to draw move intent box.
|
||||
var/has_warnings = TRUE // Set to draw environment warnings.
|
||||
var/has_pressure = TRUE // Draw the pressure indicator.
|
||||
var/has_nutrition = TRUE // Draw the nutrition indicator.
|
||||
var/has_hydration = TRUE // Draw the hydration indicator.
|
||||
var/has_bodytemp = TRUE // Draw the bodytemp indicator.
|
||||
var/has_hands = TRUE // Set to draw hands.
|
||||
var/has_drop = TRUE // Set to draw drop button.
|
||||
var/has_throw = TRUE // Set to draw throw button.
|
||||
var/has_resist = TRUE // Set to draw resist button.
|
||||
var/has_internals = TRUE // Set to draw the internals toggle button.
|
||||
var/has_up_hint = TRUE // Set to draw the "look-up" hint icon.
|
||||
var/has_cell = FALSE //Set if the species has a cell.
|
||||
/// If set, overrides ui_style.
|
||||
var/icon
|
||||
/// Set to draw intent box.
|
||||
var/has_a_intent = TRUE
|
||||
/// Set to draw move intent box.
|
||||
var/has_m_intent = TRUE
|
||||
/// Set to draw environment warnings.
|
||||
var/has_warnings = TRUE
|
||||
/// Draw the pressure indicator.
|
||||
var/has_pressure = TRUE
|
||||
/// Draw the nutrition indicator.
|
||||
var/has_nutrition = TRUE
|
||||
/// Draw the hydration indicator.
|
||||
var/has_hydration = TRUE
|
||||
/// Draw the bodytemp indicator.
|
||||
var/has_bodytemp = TRUE
|
||||
/// Set to draw hands.
|
||||
var/has_hands = TRUE
|
||||
/// Set to draw drop button.
|
||||
var/has_drop = TRUE
|
||||
/// Set to draw throw button.
|
||||
var/has_throw = TRUE
|
||||
/// Set to draw resist button.
|
||||
var/has_resist = TRUE
|
||||
/// Set to draw the internals toggle button.
|
||||
var/has_internals = TRUE
|
||||
/// Set to draw the "look-up" hint icon.
|
||||
var/has_up_hint = TRUE
|
||||
/// Set if the species has a cell.
|
||||
var/has_cell = FALSE
|
||||
/// If the mob in question uses robot pain textures.
|
||||
var/has_robot_pain = FALSE
|
||||
var/list/equip_slots = list() // Checked by mob_can_equip().
|
||||
|
||||
// Contains information on the position and tag for all inventory slots
|
||||
// to be drawn for the mob. This is fairly delicate, try to avoid messing with it
|
||||
// unless you know exactly what it does.
|
||||
/** Contains information on the position and tag for all inventory slots
|
||||
* to be drawn for the mob. This is fairly delicate, try to avoid messing with it
|
||||
* unless you know exactly what it does.
|
||||
*/
|
||||
var/list/gear = list(
|
||||
"i_clothing" = list("loc" = ui_iclothing, "name" = "uniform", "slot" = slot_w_uniform, "state" = "center", "toggle" = 1),
|
||||
"o_clothing" = list("loc" = ui_oclothing, "name" = "suit", "slot" = slot_wear_suit, "state" = "suit", "toggle" = 1),
|
||||
@@ -98,6 +116,7 @@
|
||||
has_hydration = FALSE
|
||||
has_nutrition = FALSE
|
||||
has_cell = TRUE
|
||||
has_robot_pain = TRUE
|
||||
|
||||
/datum/hud_data/construct
|
||||
has_hydration = FALSE
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
economic_modifier = 6
|
||||
default_genders = list(NEUTER)
|
||||
selectable_pronouns = list(NEUTER, PLURAL)
|
||||
mob_weight = MOB_WEIGHT_HEAVY
|
||||
|
||||
blurb = "IPCs are, quite simply, \"Integrated Positronic Chassis.\" In this scenario, 'positronic' implies that the chassis possesses a positronic processing core (or positronic brain), meaning that an IPC must be positronic to be considered an IPC. The Baseline model is more of a category - the long of the short is that they represent all unbound synthetic units. Baseline models cover anything that is not an Industrial chassis or a Shell chassis. They can be custom made or assembly made. The most common feature of the Baseline model is a simple design, skeletal or semi-humanoid, and ordinary atmospheric diffusion cooling systems."
|
||||
|
||||
@@ -43,7 +44,7 @@
|
||||
|
||||
hud_type = /datum/hud_data/ipc
|
||||
|
||||
brute_mod = 1.0
|
||||
brute_mod = 1
|
||||
burn_mod = 1.2
|
||||
|
||||
grab_mod = 1.1 // Smooth, no real edges to grab onto
|
||||
@@ -71,10 +72,9 @@
|
||||
heat_level_3 = 2400
|
||||
|
||||
body_temperature = null
|
||||
passive_temp_gain = 10 // This should cause IPCs to stabilize at ~80 C in a 20 C environment.
|
||||
passive_temp_gain = 10
|
||||
|
||||
inherent_verbs = list(
|
||||
/mob/living/carbon/human/proc/self_diagnostics,
|
||||
/mob/living/carbon/human/proc/change_monitor,
|
||||
/mob/living/carbon/human/proc/check_tag
|
||||
)
|
||||
@@ -88,11 +88,21 @@
|
||||
flesh_color = "#575757"
|
||||
reagent_tag = IS_MACHINE
|
||||
|
||||
// If you add a new organ to IPCs, remember that a lot of the normal subspecies have overrides because of custom subtype organs.
|
||||
// You'll need to add the new organ there too.
|
||||
has_organ = list(
|
||||
BP_BRAIN = /obj/item/organ/internal/mmi_holder/posibrain,
|
||||
BP_CELL = /obj/item/organ/internal/cell,
|
||||
BP_BRAIN = /obj/item/organ/internal/machine/posibrain,
|
||||
BP_VOICE_SYNTHESIZER = /obj/item/organ/internal/machine/voice_synthesizer,
|
||||
BP_DIAGNOSTICS_SUITE = /obj/item/organ/internal/machine/internal_diagnostics,
|
||||
BP_HYDRAULICS = /obj/item/organ/internal/machine/hydraulics,
|
||||
BP_ACTUATORS_LEFT = /obj/item/organ/internal/machine/actuators/left,
|
||||
BP_ACTUATORS_RIGHT = /obj/item/organ/internal/machine/actuators/right,
|
||||
BP_COOLING_UNIT = /obj/item/organ/internal/machine/cooling_unit,
|
||||
BP_REACTOR = /obj/item/organ/internal/machine/reactor,
|
||||
BP_ACCESS_PORT = /obj/item/organ/internal/machine/access_port,
|
||||
BP_CELL = /obj/item/organ/internal/machine/power_core,
|
||||
BP_EYES = /obj/item/organ/internal/eyes/optical_sensor,
|
||||
BP_IPCTAG = /obj/item/organ/internal/ipc_tag
|
||||
BP_IPCTAG = /obj/item/organ/internal/machine/ipc_tag
|
||||
)
|
||||
|
||||
vision_organ = BP_EYES
|
||||
@@ -114,7 +124,10 @@
|
||||
|
||||
heat_discomfort_level = 500 //This will be 100 below the first heat level
|
||||
heat_discomfort_strings = list(
|
||||
"Your CPU temperature probes warn you that you are approaching critical heat levels!"
|
||||
"Your positronic's temperature probes warn you that you are approaching critical heat levels!",
|
||||
"Your cooling systems are struggling to keep your positronic's temperature down!",
|
||||
"Your positronic is approaching dangerous temperature levels! Immediate cooling required!",
|
||||
"Critical temperature levels approaching!"
|
||||
)
|
||||
stamina = -1 // Machines use power and generate heat, stamina is not a thing
|
||||
sprint_speed_factor = 1 // About as capable of speed as a human
|
||||
@@ -135,13 +148,8 @@
|
||||
/singleton/origin_item/culture/scrapper
|
||||
)
|
||||
|
||||
alterable_internal_organs = list()
|
||||
alterable_internal_organs = list(BP_COOLING_UNIT, BP_REACTOR)
|
||||
possible_speech_bubble_types = list("robot", "default")
|
||||
|
||||
// Special snowflake machine vars.
|
||||
var/sprint_temperature_factor = 1.15
|
||||
var/move_charge_factor = 1
|
||||
|
||||
use_alt_hair_layer = TRUE
|
||||
psi_deaf = TRUE
|
||||
|
||||
@@ -149,23 +157,99 @@
|
||||
snores = FALSE
|
||||
indefinite_sleep = TRUE
|
||||
|
||||
natural_armor_type = /datum/component/armor/synthetic
|
||||
natural_armor = list(
|
||||
ballistic = ARMOR_BALLISTIC_MINOR,
|
||||
melee = ARMOR_MELEE_KNIVES
|
||||
)
|
||||
|
||||
// Special snowflake machine vars.
|
||||
var/sprint_temperature_factor = 1.05
|
||||
/// Species-based multiplier to movement power costs in the power core.
|
||||
var/move_charge_factor = 1.2
|
||||
/// The theme of the IPC's personal UIs, if not broken.
|
||||
var/machine_ui_theme = "hackerman"
|
||||
|
||||
|
||||
/datum/species/machine/handle_temperature_regulation(mob/living/carbon/human/human)
|
||||
// No cooling unit = you're cooking. Broken cooling unit effects are handled by the organ itself.
|
||||
// Here we just want to check if it's been removed.
|
||||
// 500K is about 226 degrees. Spicy!
|
||||
var/base_heat_gain = passive_temp_gain
|
||||
var/obj/item/organ/internal/machine/cooling_unit/cooling = human.internal_organs_by_name[BP_COOLING_UNIT]
|
||||
if(!cooling || (cooling?.status & ORGAN_DEAD))
|
||||
base_heat_gain *= 4 //uh oh
|
||||
human.bodytemperature += base_heat_gain
|
||||
|
||||
/datum/species/machine/handle_stance_damage(mob/living/carbon/human/H, damage_only)
|
||||
var/stance_damage = 0
|
||||
var/obj/item/organ/internal/machine/hydraulics/hydraulics = H.internal_organs_by_name[BP_HYDRAULICS]
|
||||
if(!hydraulics)
|
||||
return 6 //no hydraulics, no party
|
||||
|
||||
if(hydraulics.status & ORGAN_DEAD)
|
||||
return 5
|
||||
|
||||
switch(hydraulics.get_integrity())
|
||||
if(0 to IPC_INTEGRITY_THRESHOLD_VERY_HIGH)
|
||||
to_chat(H, SPAN_MACHINE_WARNING("Your hydraulics are on the verge of breaking completely!"))
|
||||
spark(H, rand(3, 4), GLOB.alldirs)
|
||||
stance_damage += 4
|
||||
if(IPC_INTEGRITY_THRESHOLD_VERY_HIGH to IPC_INTEGRITY_THRESHOLD_HIGH)
|
||||
to_chat(H, SPAN_MACHINE_WARNING("Your hydraulics spark and whine!"))
|
||||
spark(H, rand(1, 3), GLOB.alldirs)
|
||||
stance_damage += 2
|
||||
|
||||
var/datum/component/synthetic_endoskeleton/endoskeleton = H.GetComponent(/datum/component/synthetic_endoskeleton)
|
||||
if(!endoskeleton)
|
||||
return 6 //how?
|
||||
|
||||
var/damage_ratio = endoskeleton.damage / endoskeleton.max_damage
|
||||
switch(damage_ratio)
|
||||
if(0.3 to 0.5)
|
||||
stance_damage += 1
|
||||
if(0.5 to 0.75)
|
||||
stance_damage += 2
|
||||
if(0.75 to INFINITY)
|
||||
stance_damage += 3
|
||||
|
||||
return stance_damage
|
||||
|
||||
/datum/species/machine/handle_post_spawn(var/mob/living/carbon/human/H)
|
||||
. = ..()
|
||||
H.AddComponent(/datum/component/synthetic_endoskeleton)
|
||||
check_tag(H, H.client)
|
||||
var/obj/item/organ/internal/cell/C = H.internal_organs_by_name[BP_CELL]
|
||||
var/obj/item/organ/internal/machine/power_core/C = H.internal_organs_by_name[BP_CELL]
|
||||
if(C)
|
||||
C.move_charge_factor = move_charge_factor
|
||||
|
||||
/datum/species/machine/handle_sprint_cost(var/mob/living/carbon/human/H, var/cost, var/pre_move)
|
||||
if(!pre_move && H.stat == CONSCIOUS)
|
||||
H.bodytemperature += cost * sprint_temperature_factor
|
||||
var/obj/item/organ/internal/cell/C = H.internal_organs_by_name[BP_CELL]
|
||||
if(C)
|
||||
var/obj/item/organ/internal/machine/hydraulics/hydraulics = H.internal_organs_by_name[BP_HYDRAULICS]
|
||||
if(istype(hydraulics))
|
||||
var/hydraulics_integrity = hydraulics.get_integrity()
|
||||
if(hydraulics_integrity < 75)
|
||||
var/damage_mod = 2
|
||||
if(hydraulics.is_bruised())
|
||||
damage_mod = 3
|
||||
if(hydraulics.is_broken())
|
||||
damage_mod = 5
|
||||
|
||||
// x = x * (2 + 100 - y ) / 100
|
||||
// x = x * (2 + 100 - 75) / 100 -> x = x * (2 + (25 / 100)) --> x = x * 2.25
|
||||
// increases depending on integrity
|
||||
|
||||
cost *= damage_mod + ((100 - hydraulics_integrity) / 100)
|
||||
|
||||
var/obj/item/organ/internal/machine/power_core/C = H.internal_organs_by_name[BP_CELL]
|
||||
if(istype(C))
|
||||
C.use(cost * sprint_cost_factor)
|
||||
SEND_SIGNAL(H, COMSIG_IPC_HAS_SPRINTED)
|
||||
return TRUE
|
||||
|
||||
/datum/species/machine/handle_emp_act(mob/living/carbon/human/hit_mob, severity)
|
||||
var/obj/item/organ/internal/surge/S = hit_mob.internal_organs_by_name["surge"]
|
||||
var/obj/item/organ/internal/machine/surge/S = hit_mob.internal_organs_by_name[BP_SURGE_PROTECTOR]
|
||||
if(!isnull(S))
|
||||
if(S.surge_left >= 1)
|
||||
playsound(hit_mob.loc, 'sound/magic/LightningShock.ogg', 25, 1)
|
||||
@@ -189,16 +273,22 @@
|
||||
/datum/species/machine/sanitize_name(var/new_name)
|
||||
return sanitizeName(new_name, allow_numbers = 1)
|
||||
|
||||
/datum/species/machine/bypass_food_fullness(mob/living/carbon/human/H)
|
||||
var/obj/item/organ/internal/machine/reactor/reactor = H.internal_organs_by_name[BP_REACTOR]
|
||||
if(reactor && (reactor.power_supply_type & POWER_SUPPLY_BIOLOGICAL))
|
||||
return TRUE
|
||||
return FALSE
|
||||
|
||||
/datum/species/machine/proc/check_tag(var/mob/living/carbon/human/new_machine, var/client/player)
|
||||
if(!new_machine || !player)
|
||||
var/obj/item/organ/internal/ipc_tag/tag = new_machine.internal_organs_by_name[BP_IPCTAG]
|
||||
var/obj/item/organ/internal/machine/ipc_tag/tag = new_machine.internal_organs_by_name[BP_IPCTAG]
|
||||
if(tag)
|
||||
tag.serial_number = uppertext(dd_limittext(md5(new_machine.real_name), 12))
|
||||
tag.ownership_info = IPC_OWNERSHIP_COMPANY
|
||||
tag.citizenship_info = CITIZENSHIP_BIESEL
|
||||
return
|
||||
|
||||
var/obj/item/organ/internal/ipc_tag/tag = new_machine.internal_organs_by_name[BP_IPCTAG]
|
||||
var/obj/item/organ/internal/machine/ipc_tag/tag = new_machine.internal_organs_by_name[BP_IPCTAG]
|
||||
|
||||
if(player.prefs.machine_tag_status)
|
||||
tag.serial_number = player.prefs.machine_serial_number
|
||||
@@ -381,19 +471,14 @@
|
||||
. = ..()
|
||||
check_tag(H, H.client)
|
||||
|
||||
/datum/species/machine/handle_death_check(var/mob/living/carbon/human/H)
|
||||
if(H.get_total_health() <= GLOB.config.health_threshold_dead)
|
||||
return TRUE
|
||||
return FALSE
|
||||
|
||||
/datum/species/machine/has_stamina_for_pushup(var/mob/living/carbon/human/human)
|
||||
var/obj/item/organ/internal/cell/C = human.internal_organs_by_name[BP_CELL]
|
||||
var/obj/item/organ/internal/machine/power_core/C = human.internal_organs_by_name[BP_CELL]
|
||||
if(!C.cell)
|
||||
return FALSE
|
||||
return C.cell.charge > (C.cell.maxcharge / 10)
|
||||
|
||||
/datum/species/machine/drain_stamina(var/mob/living/carbon/human/human, var/stamina_cost)
|
||||
var/obj/item/organ/internal/cell/C = human.internal_organs_by_name[BP_CELL]
|
||||
var/obj/item/organ/internal/machine/power_core/C = human.internal_organs_by_name[BP_CELL]
|
||||
if(C)
|
||||
C.use(stamina_cost * 8)
|
||||
|
||||
@@ -403,3 +488,19 @@
|
||||
|
||||
/datum/species/machine/sleep_examine_msg(var/mob/M)
|
||||
return SPAN_NOTICE("[M.get_pronoun("He")] appears to be in standby.\n")
|
||||
|
||||
/datum/species/machine/can_speak(mob/living/carbon/human/speaker, datum/language/speaking, message)
|
||||
var/obj/item/organ/internal/machine/voice_synthesizer/voice_synth = speaker.internal_organs_by_name[BP_VOICE_SYNTHESIZER]
|
||||
if(istype(voice_synth))
|
||||
return TRUE
|
||||
else
|
||||
to_chat(speaker, SPAN_WARNING("You cannot synthesize a voice without your [BP_VOICE_SYNTHESIZER]!"))
|
||||
return FALSE
|
||||
|
||||
/datum/species/machine/handle_speech_problems(mob/living/carbon/human/H, message, say_verb, message_mode, message_range)
|
||||
var/obj/item/organ/internal/machine/voice_synthesizer/voice_synth = H.internal_organs_by_name[BP_VOICE_SYNTHESIZER]
|
||||
if(istype(voice_synth))
|
||||
if(voice_synth.is_bruised())
|
||||
// at most, 30 * 2 + 10 = 70, which is the maximum value we can use for Gibberish
|
||||
message = Gibberish(message, voice_synth.damage * 2 + (voice_synth.is_broken() ? 10 : 0))
|
||||
return list(HSP_MSG = message, HSP_VERB = pick(list("crackles", "buzzes")))
|
||||
|
||||
@@ -9,10 +9,11 @@
|
||||
height_max = 230
|
||||
default_genders = list(MALE, FEMALE)
|
||||
selectable_pronouns = list(MALE, FEMALE, PLURAL, NEUTER)
|
||||
mob_weight = MOB_WEIGHT_MEDIUM // Would be really easy to find untagged shells otherwise.
|
||||
|
||||
alterable_internal_organs = list(BP_EYES)
|
||||
alterable_internal_organs = list(BP_EYES, BP_COOLING_UNIT, BP_REACTOR)
|
||||
|
||||
burn_mod = 1.2
|
||||
burn_mod = 1.3
|
||||
grab_mod = 1
|
||||
|
||||
blurb = "IPCs with humanlike properties. Their focus is on service, civilian, and medical, but there are no \
|
||||
@@ -67,11 +68,10 @@
|
||||
|
||||
character_color_presets = list("Dark" = "#000000", "Warm" = "#250302", "Cold" = "#1e1e29", "Rubber" = "#000f36")
|
||||
|
||||
sprint_temperature_factor = 1.3
|
||||
move_charge_factor = 0.85
|
||||
sprint_temperature_factor = 1.15
|
||||
move_charge_factor = 1.1
|
||||
|
||||
inherent_verbs = list(
|
||||
/mob/living/carbon/human/proc/self_diagnostics,
|
||||
/mob/living/carbon/human/proc/check_tag,
|
||||
/mob/living/carbon/human/proc/tie_hair)
|
||||
|
||||
@@ -101,10 +101,19 @@
|
||||
break_cuffs = TRUE
|
||||
|
||||
has_organ = list(
|
||||
BP_BRAIN = /obj/item/organ/internal/mmi_holder/posibrain,
|
||||
BP_CELL = /obj/item/organ/internal/cell,
|
||||
BP_BRAIN = /obj/item/organ/internal/machine/posibrain,
|
||||
BP_VOICE_SYNTHESIZER = /obj/item/organ/internal/machine/voice_synthesizer,
|
||||
BP_DIAGNOSTICS_SUITE = /obj/item/organ/internal/machine/internal_diagnostics,
|
||||
BP_HYDRAULICS = /obj/item/organ/internal/machine/hydraulics,
|
||||
BP_ACTUATORS_LEFT = /obj/item/organ/internal/machine/actuators/left,
|
||||
BP_ACTUATORS_RIGHT = /obj/item/organ/internal/machine/actuators/right,
|
||||
BP_COOLING_UNIT = /obj/item/organ/internal/machine/cooling_unit,
|
||||
BP_REACTOR = /obj/item/organ/internal/machine/reactor,
|
||||
BP_ACCESS_PORT = /obj/item/organ/internal/machine/access_port,
|
||||
BP_CELL = /obj/item/organ/internal/machine/power_core,
|
||||
BP_EYES = /obj/item/organ/internal/eyes/optical_sensor,
|
||||
"surge" = /obj/item/organ/internal/surge/advanced
|
||||
BP_SURGE_PROTECTOR = /obj/item/organ/internal/machine/surge/advanced,
|
||||
BP_TARGETING_CORE = /obj/item/organ/internal/machine/targeting_core
|
||||
)
|
||||
|
||||
unarmed_types = list(
|
||||
@@ -113,10 +122,6 @@
|
||||
/datum/unarmed_attack/terminator,
|
||||
/datum/unarmed_attack/bite/strong)
|
||||
|
||||
inherent_verbs = list(
|
||||
/mob/living/carbon/human/proc/self_diagnostics
|
||||
)
|
||||
|
||||
/datum/species/machine/shell/rogue/check_tag(var/mob/living/carbon/human/new_machine, var/client/player)
|
||||
return
|
||||
|
||||
@@ -138,7 +143,7 @@
|
||||
grab_mod = 0.8 // Big, easy to grab onto
|
||||
resist_mod = 10 // Good luck wrestling against this powerhouse.
|
||||
|
||||
slowdown = 4
|
||||
slowdown = 3
|
||||
|
||||
blurb = "The first commercialized attempt Hephaestus Industries made at an industrial-type IPC. Designed for extra durability and increased weight loads, the first generation Industrial was considered a success, though it possessed some issues. A limited power cell and actuators designed for heavy lifting and not locomotion resulted in a slow and frequently charging machine. A special addition to the chassis makes up for these drawbacks - the ability to simply slot a suit cooling unit onto the model's back and make use of its built-in heat transferal conduits, allowing the Industrial to perform EVA without any extra peripherals such as a voidsuit."
|
||||
|
||||
@@ -178,12 +183,28 @@
|
||||
|
||||
sprint_speed_factor = 1.4
|
||||
sprint_temperature_factor = 0.9
|
||||
move_charge_factor = 1.1
|
||||
move_charge_factor = 1.5
|
||||
|
||||
inherent_verbs = list(
|
||||
/mob/living/carbon/human/proc/self_diagnostics,
|
||||
/mob/living/carbon/human/proc/check_tag
|
||||
)
|
||||
has_organ = list(
|
||||
BP_BRAIN = /obj/item/organ/internal/machine/posibrain,
|
||||
BP_VOICE_SYNTHESIZER = /obj/item/organ/internal/machine/voice_synthesizer,
|
||||
BP_DIAGNOSTICS_SUITE = /obj/item/organ/internal/machine/internal_diagnostics,
|
||||
BP_HYDRAULICS = /obj/item/organ/internal/machine/hydraulics,
|
||||
BP_ACTUATORS_LEFT = /obj/item/organ/internal/machine/actuators/left,
|
||||
BP_ACTUATORS_RIGHT = /obj/item/organ/internal/machine/actuators/right,
|
||||
BP_COOLING_UNIT = /obj/item/organ/internal/machine/cooling_unit,
|
||||
BP_REACTOR = /obj/item/organ/internal/machine/reactor,
|
||||
BP_ACCESS_PORT = /obj/item/organ/internal/machine/access_port,
|
||||
BP_CELL = /obj/item/organ/internal/machine/power_core,
|
||||
BP_EYES = /obj/item/organ/internal/eyes/optical_sensor,
|
||||
BP_IPCTAG = /obj/item/organ/internal/machine/ipc_tag,
|
||||
BP_INTERNAL_STORAGE = /obj/item/organ/internal/machine/internal_storage,
|
||||
)
|
||||
|
||||
machine_ui_theme = "hephaestus"
|
||||
|
||||
/datum/species/machine/industrial/get_light_color()
|
||||
return LIGHT_COLOR_TUNGSTEN
|
||||
@@ -238,7 +259,6 @@
|
||||
heat_level_3 = 5000
|
||||
|
||||
body_temperature = null
|
||||
passive_temp_gain = 0
|
||||
|
||||
flags = IS_IPC | ACCEPTS_COOLER
|
||||
spawn_flags = IS_RESTRICTED
|
||||
@@ -250,16 +270,24 @@
|
||||
inherent_verbs = list(
|
||||
/mob/living/carbon/human/proc/self_destruct,
|
||||
/mob/living/carbon/human/proc/detonate_flechettes,
|
||||
/mob/living/carbon/human/proc/state_laws,
|
||||
/mob/living/carbon/human/proc/self_diagnostics
|
||||
/mob/living/carbon/human/proc/state_laws
|
||||
)
|
||||
|
||||
has_organ = list(
|
||||
BP_BRAIN = /obj/item/organ/internal/mmi_holder/posibrain/terminator,
|
||||
BP_CELL = /obj/item/organ/internal/cell/terminator,
|
||||
BP_EYES = /obj/item/organ/internal/eyes/optical_sensor/terminator,
|
||||
"data core" = /obj/item/organ/internal/data,
|
||||
"surge" = /obj/item/organ/internal/surge/advanced
|
||||
BP_BRAIN = /obj/item/organ/internal/machine/posibrain,
|
||||
BP_VOICE_SYNTHESIZER = /obj/item/organ/internal/machine/voice_synthesizer,
|
||||
BP_DIAGNOSTICS_SUITE = /obj/item/organ/internal/machine/internal_diagnostics,
|
||||
BP_HYDRAULICS = /obj/item/organ/internal/machine/hydraulics,
|
||||
BP_ACTUATORS_LEFT = /obj/item/organ/internal/machine/actuators/left,
|
||||
BP_ACTUATORS_RIGHT = /obj/item/organ/internal/machine/actuators/right,
|
||||
BP_COOLING_UNIT = /obj/item/organ/internal/machine/cooling_unit,
|
||||
BP_REACTOR = /obj/item/organ/internal/machine/reactor,
|
||||
BP_ACCESS_PORT = /obj/item/organ/internal/machine/access_port,
|
||||
BP_CELL = /obj/item/organ/internal/machine/power_core,
|
||||
BP_EYES = /obj/item/organ/internal/eyes/optical_sensor,
|
||||
BP_DATACORE = /obj/item/organ/internal/machine/data,
|
||||
BP_SURGE_PROTECTOR = /obj/item/organ/internal/machine/surge/advanced,
|
||||
BP_TARGETING_CORE = /obj/item/organ/internal/machine/targeting_core
|
||||
)
|
||||
|
||||
has_limbs = list(
|
||||
@@ -289,6 +317,8 @@
|
||||
sprint_temperature_factor = 0.6
|
||||
move_charge_factor = 0.3
|
||||
|
||||
machine_ui_theme = "syndicate"
|
||||
|
||||
/datum/species/machine/hunter_killer/get_light_color()
|
||||
return
|
||||
|
||||
@@ -314,8 +344,8 @@
|
||||
|
||||
unarmed_types = list(/datum/unarmed_attack/industrial/heavy, /datum/unarmed_attack/palm/industrial)
|
||||
|
||||
slowdown = 6
|
||||
brute_mod = 0.7
|
||||
slowdown = 2
|
||||
brute_mod = 0.9
|
||||
grab_mod = 0.7 // Bulkier and bigger than the G1
|
||||
resist_mod = 12 // Overall stronger than G1
|
||||
|
||||
@@ -326,8 +356,9 @@
|
||||
heat_discomfort_level = 900
|
||||
|
||||
inherent_verbs = list(
|
||||
/mob/living/carbon/human/proc/self_diagnostics,
|
||||
/mob/living/carbon/human/proc/check_tag
|
||||
/mob/living/carbon/human/proc/check_tag,
|
||||
/mob/living/carbon/human/proc/discard_limb,
|
||||
/mob/living/carbon/human/proc/attach_hephaestus_limb
|
||||
)
|
||||
|
||||
examine_color = "#688359"
|
||||
@@ -348,8 +379,100 @@
|
||||
BP_R_FOOT = list("path" = /obj/item/organ/external/foot/right/ipc/industrial/hephaestus)
|
||||
)
|
||||
|
||||
|
||||
has_organ = list(
|
||||
BP_BRAIN = /obj/item/organ/internal/machine/posibrain,
|
||||
BP_VOICE_SYNTHESIZER = /obj/item/organ/internal/machine/voice_synthesizer,
|
||||
BP_DIAGNOSTICS_SUITE = /obj/item/organ/internal/machine/internal_diagnostics,
|
||||
BP_HYDRAULICS = /obj/item/organ/internal/machine/hydraulics,
|
||||
BP_ACTUATORS_LEFT = /obj/item/organ/internal/machine/actuators/left,
|
||||
BP_ACTUATORS_RIGHT = /obj/item/organ/internal/machine/actuators/right,
|
||||
BP_COOLING_UNIT = /obj/item/organ/internal/machine/cooling_unit,
|
||||
BP_REACTOR = /obj/item/organ/internal/machine/reactor,
|
||||
BP_ACCESS_PORT = /obj/item/organ/internal/machine/access_port,
|
||||
BP_CELL = /obj/item/organ/internal/machine/power_core,
|
||||
BP_EYES = /obj/item/organ/internal/eyes/optical_sensor,
|
||||
BP_IPCTAG = /obj/item/organ/internal/machine/ipc_tag
|
||||
)
|
||||
|
||||
flags = IS_IPC | ACCEPTS_COOLER | NO_EQUIP_SPEEDMODS
|
||||
|
||||
move_charge_factor = 1.7
|
||||
|
||||
machine_ui_theme = "hephaestus"
|
||||
|
||||
natural_armor = list(
|
||||
ballistic = ARMOR_BALLISTIC_PISTOL,
|
||||
melee = ARMOR_MELEE_KEVLAR
|
||||
)
|
||||
|
||||
/mob/living/carbon/human/proc/discard_limb()
|
||||
set name = "Discard Limb"
|
||||
set category = "Object"
|
||||
|
||||
if(incapacitated(INCAPACITATION_DEFAULT))
|
||||
return
|
||||
|
||||
if(get_active_hand())
|
||||
to_chat(src, SPAN_WARNING("You need your hand to be free!"))
|
||||
return
|
||||
|
||||
var/limb_list = list()
|
||||
for(var/obj/item/organ/external/limb in organs)
|
||||
if(limb.limb_name in list(BP_CHEST, BP_GROIN, BP_HEAD))
|
||||
continue
|
||||
|
||||
if(limb.robotize_type == PROSTHETIC_HI)
|
||||
limb_list[capitalize_first_letters(limb.name)] = limb
|
||||
|
||||
var/chosen_limb = tgui_input_list(src, "Choose a limb to discard.", "Discard Limb", limb_list)
|
||||
if(!chosen_limb)
|
||||
return
|
||||
|
||||
var/obj/item/organ/external/oopsie = limb_list[chosen_limb]
|
||||
visible_message(SPAN_DANGER("[src] ejects [get_pronoun("his")] [oopsie] with a hiss!"))
|
||||
oopsie.droplimb(TRUE, DROPLIMB_EDGE)
|
||||
|
||||
/mob/living/carbon/human/proc/attach_hephaestus_limb()
|
||||
set name = "Attach Limb"
|
||||
set category = "Object"
|
||||
|
||||
if(incapacitated(INCAPACITATION_DEFAULT))
|
||||
return
|
||||
|
||||
var/obj/item/organ/external/limb = get_active_hand()
|
||||
if(!istype(limb))
|
||||
to_chat(src, SPAN_WARNING("You need to be holding a compatible Hephaestus Industries limb!"))
|
||||
return
|
||||
|
||||
if(!limb.robotic)
|
||||
to_chat(src, SPAN_WARNING("That is not a compatible Hephaestus Industries limb!"))
|
||||
return
|
||||
|
||||
if(limb.robotize_type != PROSTHETIC_HI)
|
||||
to_chat(src,SPAN_WARNING("That prosthetic does not have the right ports for your joint!"))
|
||||
return
|
||||
|
||||
if(organs_by_name[limb.limb_name])
|
||||
to_chat(src,SPAN_WARNING("You already have a limb of this type!"))
|
||||
return
|
||||
|
||||
if(!organs_by_name[limb.parent_organ])
|
||||
to_chat(src,SPAN_WARNING("You are missing the appropriate joint to attach that limb!"))
|
||||
return
|
||||
|
||||
visible_message(SPAN_NOTICE("[src] begins attaching \the [limb] to the appropriate joint..."))
|
||||
if(!do_after(src, 10 SECONDS))
|
||||
return
|
||||
|
||||
|
||||
drop_from_inventory(limb)
|
||||
limb.replaced(src)
|
||||
|
||||
visible_message(SPAN_NOTICE("[src] attaches \the [limb] to their body!"))
|
||||
update_body()
|
||||
updatehealth()
|
||||
UpdateDamageIcon()
|
||||
|
||||
/datum/species/machine/industrial/hephaestus/get_light_color(mob/living/carbon/human/H)
|
||||
if (istype(H))
|
||||
@@ -388,7 +511,6 @@
|
||||
|
||||
eyes = "xion_eyes"
|
||||
flags = IS_IPC
|
||||
passive_temp_gain = 0
|
||||
|
||||
examine_color = "#bc4b00"
|
||||
|
||||
@@ -408,6 +530,23 @@
|
||||
BP_R_FOOT = list("path" = /obj/item/organ/external/foot/right/ipc/industrial/xion)
|
||||
)
|
||||
|
||||
has_organ = list(
|
||||
BP_BRAIN = /obj/item/organ/internal/machine/posibrain,
|
||||
BP_VOICE_SYNTHESIZER = /obj/item/organ/internal/machine/voice_synthesizer,
|
||||
BP_DIAGNOSTICS_SUITE = /obj/item/organ/internal/machine/internal_diagnostics,
|
||||
BP_HYDRAULICS = /obj/item/organ/internal/machine/hydraulics,
|
||||
BP_ACTUATORS_LEFT = /obj/item/organ/internal/machine/actuators/left,
|
||||
BP_ACTUATORS_RIGHT = /obj/item/organ/internal/machine/actuators/right,
|
||||
BP_COOLING_UNIT = /obj/item/organ/internal/machine/cooling_unit/xion,
|
||||
BP_REACTOR = /obj/item/organ/internal/machine/reactor,
|
||||
BP_ACCESS_PORT = /obj/item/organ/internal/machine/access_port,
|
||||
BP_CELL = /obj/item/organ/internal/machine/power_core,
|
||||
BP_EYES = /obj/item/organ/internal/eyes/optical_sensor,
|
||||
BP_IPCTAG = /obj/item/organ/internal/machine/ipc_tag
|
||||
)
|
||||
|
||||
machine_ui_theme = "hephaestus"
|
||||
|
||||
/datum/species/machine/industrial/xion/remote
|
||||
name = SPECIES_IPC_XION_REMOTE
|
||||
short_name = "rem_xmf"
|
||||
@@ -415,10 +554,18 @@
|
||||
spawn_flags = IS_RESTRICTED
|
||||
|
||||
has_organ = list(
|
||||
BP_BRAIN = /obj/item/organ/internal/mmi_holder/circuit,
|
||||
BP_CELL = /obj/item/organ/internal/cell,
|
||||
BP_BRAIN = /obj/item/organ/internal/machine/posibrain,
|
||||
BP_VOICE_SYNTHESIZER = /obj/item/organ/internal/machine/voice_synthesizer,
|
||||
BP_DIAGNOSTICS_SUITE = /obj/item/organ/internal/machine/internal_diagnostics,
|
||||
BP_HYDRAULICS = /obj/item/organ/internal/machine/hydraulics,
|
||||
BP_ACTUATORS_LEFT = /obj/item/organ/internal/machine/actuators/left,
|
||||
BP_ACTUATORS_RIGHT = /obj/item/organ/internal/machine/actuators/right,
|
||||
BP_COOLING_UNIT = /obj/item/organ/internal/machine/cooling_unit,
|
||||
BP_REACTOR = /obj/item/organ/internal/machine/reactor,
|
||||
BP_ACCESS_PORT = /obj/item/organ/internal/machine/access_port,
|
||||
BP_CELL = /obj/item/organ/internal/machine/power_core,
|
||||
BP_EYES = /obj/item/organ/internal/eyes/optical_sensor,
|
||||
BP_IPCTAG = /obj/item/organ/internal/ipc_tag
|
||||
BP_IPCTAG = /obj/item/organ/internal/machine/ipc_tag
|
||||
)
|
||||
|
||||
/datum/species/machine/industrial/xion/get_light_color(mob/living/carbon/human/H)
|
||||
@@ -447,11 +594,27 @@
|
||||
resist_mod = 4 // Not super strong, but still rather strong
|
||||
|
||||
appearance_flags = HAS_EYE_COLOR | HAS_UNDERWEAR | HAS_SOCKS
|
||||
flags = IS_IPC | NO_SLIP
|
||||
|
||||
examine_color = "#ff00ff"
|
||||
|
||||
blurb = "Being a corporation focused primarily on medical sciences and treatments, Zeng-Hu Pharmaceuticals had little interest in the market of synthetics in the beginning (especially considering a good portion of Zeng-Hu employees are Skrellian). However, after seeing the advances in almost all fields of the galactic market after the advent of synthetics, Zeng-Hu set aside some funds for their own robotics department, focused mainly on medical service and even science related operations. Having taken some inspiration from biological life, the chassis has an interesting leg design: digitigrade legs provide the chassis with enhanced speed. A downside to this development was the reduction of metals on the chassis. Most plates covering the sensitive interior electronics are polymer casts to reduce the weight of the unit, resulting in a not-so-durable android."
|
||||
|
||||
has_organ = list(
|
||||
BP_BRAIN = /obj/item/organ/internal/machine/posibrain,
|
||||
BP_VOICE_SYNTHESIZER = /obj/item/organ/internal/machine/voice_synthesizer,
|
||||
BP_DIAGNOSTICS_SUITE = /obj/item/organ/internal/machine/internal_diagnostics,
|
||||
BP_HYDRAULICS = /obj/item/organ/internal/machine/hydraulics,
|
||||
BP_ACTUATORS_LEFT = /obj/item/organ/internal/machine/actuators/left,
|
||||
BP_ACTUATORS_RIGHT = /obj/item/organ/internal/machine/actuators/right,
|
||||
BP_COOLING_UNIT = /obj/item/organ/internal/machine/cooling_unit/zenghu,
|
||||
BP_REACTOR = /obj/item/organ/internal/machine/reactor,
|
||||
BP_ACCESS_PORT = /obj/item/organ/internal/machine/access_port,
|
||||
BP_CELL = /obj/item/organ/internal/machine/power_core,
|
||||
BP_EYES = /obj/item/organ/internal/eyes/optical_sensor,
|
||||
BP_IPCTAG = /obj/item/organ/internal/machine/ipc_tag
|
||||
)
|
||||
|
||||
has_limbs = list(
|
||||
BP_CHEST = list("path" = /obj/item/organ/external/chest/ipc/industrial/zenghu),
|
||||
BP_GROIN = list("path" = /obj/item/organ/external/groin/ipc/industrial/zenghu),
|
||||
@@ -467,13 +630,14 @@
|
||||
)
|
||||
|
||||
inherent_verbs = list(
|
||||
/mob/living/carbon/human/proc/self_diagnostics,
|
||||
/mob/living/carbon/human/proc/check_tag
|
||||
)
|
||||
maneuvers = list(
|
||||
/singleton/maneuver/leap/zenghu
|
||||
)
|
||||
|
||||
machine_ui_theme = "zenghu"
|
||||
|
||||
|
||||
/datum/species/machine/zenghu/get_light_color(mob/living/carbon/human/H)
|
||||
if (istype(H))
|
||||
@@ -503,6 +667,22 @@
|
||||
|
||||
blurb = "Bishop Cybernetics frames are among the sleeker, flashier frames widely produced for IPCs. This brand-new, high end design has a focus on pioneering energy efficiency without sacrifice, fitting to Bishop's company vision. Cutting-edge technology in power management means this frame can operate longer while running more demanding processing algorithms than most. This extreme push to minimize power draw means this frame can be equipped with all sorts of extra equipment: a hologram for a face, flashing status displays and embedded lights solely meant for show. The one thing holding this frame back from perfection is the same common criticism leveled against almost all Bishop products: the shiny chrome and glass meant to put all of this tech on display means it's exposed and fragile. It's because of Bishop's unrelenting pursuit of vanity in their designs that these frames often suffer from issues with reliability and struggle to safely perform the same work as cheaper, more rugged frames."
|
||||
|
||||
has_organ = list(
|
||||
BP_BRAIN = /obj/item/organ/internal/machine/posibrain,
|
||||
BP_VOICE_SYNTHESIZER = /obj/item/organ/internal/machine/voice_synthesizer,
|
||||
BP_DIAGNOSTICS_SUITE = /obj/item/organ/internal/machine/internal_diagnostics,
|
||||
BP_HYDRAULICS = /obj/item/organ/internal/machine/hydraulics,
|
||||
BP_ACTUATORS_LEFT = /obj/item/organ/internal/machine/actuators/left,
|
||||
BP_ACTUATORS_RIGHT = /obj/item/organ/internal/machine/actuators/right,
|
||||
BP_COOLING_UNIT = /obj/item/organ/internal/machine/cooling_unit,
|
||||
BP_REACTOR = /obj/item/organ/internal/machine/reactor,
|
||||
BP_ACCESS_PORT = /obj/item/organ/internal/machine/access_port,
|
||||
BP_CELL = /obj/item/organ/internal/machine/power_core,
|
||||
BP_EYES = /obj/item/organ/internal/eyes/optical_sensor,
|
||||
BP_IPCTAG = /obj/item/organ/internal/machine/ipc_tag,
|
||||
BP_WIRELESS_ACCESS = /obj/item/organ/internal/machine/wireless_access
|
||||
)
|
||||
|
||||
has_limbs = list(
|
||||
BP_CHEST = list("path" = /obj/item/organ/external/chest/ipc/industrial/bishop),
|
||||
BP_GROIN = list("path" = /obj/item/organ/external/groin/ipc/industrial/bishop),
|
||||
@@ -518,10 +698,11 @@
|
||||
)
|
||||
|
||||
inherent_verbs = list(
|
||||
/mob/living/carbon/human/proc/self_diagnostics,
|
||||
/mob/living/carbon/human/proc/check_tag,
|
||||
/mob/living/carbon/human/proc/change_monitor
|
||||
)
|
||||
)
|
||||
|
||||
machine_ui_theme = "zenghu"
|
||||
|
||||
/datum/species/machine/bishop/get_light_color(mob/living/carbon/human/H)
|
||||
if (istype(H))
|
||||
@@ -559,7 +740,6 @@
|
||||
)
|
||||
|
||||
inherent_verbs = list(
|
||||
/mob/living/carbon/human/proc/self_diagnostics,
|
||||
/mob/living/carbon/human/proc/check_tag
|
||||
)
|
||||
|
||||
@@ -571,10 +751,17 @@
|
||||
spawn_flags = IS_RESTRICTED
|
||||
|
||||
has_organ = list(
|
||||
BP_BRAIN = /obj/item/organ/internal/mmi_holder/circuit,
|
||||
BP_CELL = /obj/item/organ/internal/cell,
|
||||
BP_BRAIN = /obj/item/organ/internal/machine/posibrain,
|
||||
BP_VOICE_SYNTHESIZER = /obj/item/organ/internal/machine/voice_synthesizer,
|
||||
BP_DIAGNOSTICS_SUITE = /obj/item/organ/internal/machine/internal_diagnostics,
|
||||
BP_HYDRAULICS = /obj/item/organ/internal/machine/hydraulics,
|
||||
BP_ACTUATORS_LEFT = /obj/item/organ/internal/machine/actuators/left,
|
||||
BP_ACTUATORS_RIGHT = /obj/item/organ/internal/machine/actuators/right,
|
||||
BP_COOLING_UNIT = /obj/item/organ/internal/machine/cooling_unit,
|
||||
BP_REACTOR = /obj/item/organ/internal/machine/reactor,
|
||||
BP_CELL = /obj/item/organ/internal/machine/power_core,
|
||||
BP_EYES = /obj/item/organ/internal/eyes/optical_sensor,
|
||||
BP_IPCTAG = /obj/item/organ/internal/ipc_tag
|
||||
BP_IPCTAG = /obj/item/organ/internal/machine/ipc_tag
|
||||
)
|
||||
|
||||
/datum/species/machine/unbranded/get_light_color(mob/living/carbon/human/H)
|
||||
|
||||
@@ -61,6 +61,7 @@
|
||||
rarity_value = 3
|
||||
break_cuffs = TRUE
|
||||
mob_size = 10
|
||||
mob_weight = MOB_WEIGHT_HEAVY
|
||||
climb_coeff = 1.35
|
||||
|
||||
blurb = "A heavily reptillian species, Unathi (or 'Sinta as they call themselves) hail from the Uuosa-Eso \
|
||||
|
||||
@@ -264,6 +264,8 @@
|
||||
total_health = 200
|
||||
break_cuffs = TRUE
|
||||
mob_size = 30
|
||||
mob_weight = MOB_WEIGHT_SUPERHEAVY
|
||||
mob_strength = MOB_STRENGTH_VERY_STRONG
|
||||
|
||||
speech_sounds = list('sound/voice/hiss1.ogg','sound/voice/hiss2.ogg','sound/voice/hiss3.ogg','sound/voice/hiss4.ogg')
|
||||
speech_chance = 100
|
||||
@@ -372,6 +374,8 @@
|
||||
resist_mod = 14 //also very strong
|
||||
|
||||
mob_size = 28
|
||||
mob_weight = MOB_WEIGHT_SUPERHEAVY
|
||||
mob_strength = MOB_STRENGTH_STRONG
|
||||
taste_sensitivity = TASTE_DULL
|
||||
blurb = {"Type E Vaurca, otherwise known as the Bulwarks, are a new bodyform derived from the worker caste in a collaboration by the C'thur and Nralakk scientists. Originally only the C'thur had access to these behemoths, but after a short amount of time, the bodyform started appearing in the ranks of the Zo'ra and K'lax as well, causing an even more strained relationship between the Hives.<br>
|
||||
Similar to Workers, Bulwarks are generally passive, and prefer to flee a fight rather than resist. Though due to their speed, they may still choose to defend themselves should they be unable to properly escape a battle. The main exception to this is when another Vaurca is in danger. When this occurs, they tend to put themselves in between the attacker and the Vaurca, acting as a shield of sorts. They won't go out of their way to take down the attacker, but will ensure the others get away safely.<br>
|
||||
|
||||
@@ -20,24 +20,14 @@
|
||||
robotic_analyze_mob(target_mob, user)
|
||||
add_fingerprint(user)
|
||||
|
||||
|
||||
/proc/robotic_analyze_mob (var/mob/living/M, var/mob/living/user, var/just_scan = FALSE)
|
||||
/proc/robotic_analyze_mob(var/mob/living/M, var/mob/living/user, var/just_scan = FALSE)
|
||||
if(!just_scan)
|
||||
if((user.is_clumsy() || (user.mutations & DUMB)) && prob(50))
|
||||
to_chat(user, SPAN_WARNING("You try to analyze the floor's vitals!"))
|
||||
user.visible_message(SPAN_WARNING("\The [user] has analyzed the floor's vitals!"))
|
||||
to_chat(user, SPAN_NOTICE("Analyzing Results for The floor:"))
|
||||
to_chat(user, SPAN_NOTICE("Overall Status: Healthy"))
|
||||
to_chat(user, SPAN_NOTICE("Damage Specifics: [0]-[0]-[0]-[0]"))
|
||||
to_chat(user, SPAN_NOTICE("Key: Suffocation/Toxin/Burns/Brute"))
|
||||
to_chat(user, SPAN_NOTICE("Body Temperature: ???"))
|
||||
return
|
||||
user.visible_message(SPAN_NOTICE("\The [user] has analyzed \the [M]'s components."), SPAN_NOTICE("You have analyzed \the [M]'s components."))
|
||||
|
||||
var/scan_type
|
||||
if(istype(M, /mob/living/silicon/robot))
|
||||
if(isrobot(M))
|
||||
scan_type = "robot"
|
||||
else if(istype(M, /mob/living/carbon/human))
|
||||
else if(ishuman(M))
|
||||
scan_type = "prosthetics"
|
||||
else
|
||||
to_chat(user, SPAN_WARNING("You can't analyze non-robotic things!"))
|
||||
@@ -45,68 +35,102 @@
|
||||
|
||||
switch(scan_type)
|
||||
if("robot")
|
||||
var/BU = M.getFireLoss() > 50 ? "<b>[M.getFireLoss()]</b>" : M.getFireLoss()
|
||||
var/BR = M.getBruteLoss() > 50 ? "<b>[M.getBruteLoss()]</b>" : M.getBruteLoss()
|
||||
|
||||
to_chat(user, SPAN_NOTICE("Analyzing Results for [M]:"))
|
||||
to_chat(user, SPAN_NOTICE("Overall Status: [M.stat > 1 ? "fully disabled" : "[M.health - M.getHalLoss()]% functional"]"))
|
||||
to_chat(user, "Key: <font color='#FFA500'>Electronics</font>/<span class='warning'>Brute</span>")
|
||||
to_chat(user, "Damage Specifics: <font color='#FFA500'>[BU]</font> - <span class='warning'>[BR]</span>")
|
||||
if(M.tod && M.stat == DEAD)
|
||||
to_chat(user, SPAN_NOTICE("Time of Disable: [M.tod]"))
|
||||
var/mob/living/silicon/robot/H = M
|
||||
var/list/damaged = H.get_damaged_components(1, 1, 1)
|
||||
to_chat(user, SPAN_NOTICE("Localized Damage:"))
|
||||
if(length(damaged) > 0)
|
||||
for(var/datum/robot_component/org in damaged)
|
||||
user.show_message(SPAN_NOTICE("\t [capitalize(org.name)]: [(org.installed == -1) ? SPAN_WARNING("<b>DESTROYED</b>") :""]\
|
||||
[(org.electronics_damage > 0) ? "<font color='#FFA500'>[org.electronics_damage]</font>" : 0] - [(org.brute_damage > 0) ? SPAN_WARNING("[org.brute_damage]") :0] - \
|
||||
[(org.toggled) ? "Toggled ON" : SPAN_WARNING("Toggled OFF")] - \
|
||||
[(org.powered) ? "Power ON" : SPAN_WARNING("Power OFF")]"),1)
|
||||
|
||||
else
|
||||
to_chat(user, SPAN_NOTICE("Components are OK."))
|
||||
if(H.emagged && prob(5))
|
||||
to_chat(user, SPAN_WARNING("ERROR: INTERNAL SYSTEMS COMPROMISED"))
|
||||
to_chat(user, SPAN_NOTICE("Operating Temperature: [M.bodytemperature-T0C]°C ([M.bodytemperature*1.8-459.67]°F)"))
|
||||
robot_scan(user, M)
|
||||
if("prosthetics")
|
||||
var/mob/living/carbon/human/H = M
|
||||
to_chat(user, SPAN_NOTICE("Analyzing Results for \the [H]:"))
|
||||
to_chat(user, "Key: <font color='#FFA500'>Electronics</font>/<span class='warning'>Brute</span>")
|
||||
var/obj/item/organ/internal/cell/IC = H.internal_organs_by_name[BP_CELL]
|
||||
if(IC)
|
||||
to_chat(user, SPAN_NOTICE("Cell charge: [IC.percent()] %"))
|
||||
else
|
||||
to_chat(user, SPAN_NOTICE("Cell charge: ERROR - Cell not present"))
|
||||
to_chat(user, SPAN_NOTICE("External prosthetics:"))
|
||||
var/organ_found
|
||||
if(length(H.internal_organs))
|
||||
for(var/obj/item/organ/external/E in H.organs)
|
||||
if(!(E.status & (ORGAN_ROBOT || ORGAN_ASSISTED)))
|
||||
continue
|
||||
organ_found = TRUE
|
||||
to_chat(user, "[E.name]: <span class='warning'>[E.brute_dam]</span> <font color='#FFA500'>[E.burn_dam]</font>")
|
||||
if(!organ_found)
|
||||
to_chat(user, SPAN_NOTICE("No prosthetics located."))
|
||||
to_chat(user, "<hr>")
|
||||
to_chat(user, SPAN_NOTICE("Internal prosthetics:"))
|
||||
organ_found = FALSE
|
||||
if(length(H.internal_organs))
|
||||
var/obj/item/organ/external/head = H.get_organ(BP_HEAD)
|
||||
var/show_tag = FALSE
|
||||
if(head?.open == 3) // Hatch open
|
||||
show_tag = TRUE
|
||||
for(var/obj/item/organ/O in H.internal_organs)
|
||||
if(!(O.status & (ORGAN_ROBOT || ORGAN_ASSISTED)))
|
||||
continue
|
||||
if(!show_tag && istype(O, /obj/item/organ/internal/ipc_tag))
|
||||
continue
|
||||
organ_found = TRUE
|
||||
to_chat(user, "[O.name]: <span class='warning'>[O.damage]</span>")
|
||||
to_chat(user, "<i>[O.desc]</i>")
|
||||
if(!organ_found)
|
||||
to_chat(user, SPAN_NOTICE("No prosthetics located."))
|
||||
prosthetics_scan(user, M)
|
||||
|
||||
/proc/robot_scan(mob/user, mob/living/silicon/robot/M)
|
||||
var/BU = M.getFireLoss() > 50 ? "<b>[get_robot_severity(M.getFireLoss())]</b>" : get_robot_severity(M.getFireLoss())
|
||||
var/BR = M.getBruteLoss() > 50 ? "<b>[get_robot_severity(M.getBruteLoss())]</b>" : get_robot_severity(M.getBruteLoss())
|
||||
|
||||
to_chat(user, SPAN_NOTICE("Analyzing Results for [M]:"))
|
||||
to_chat(user, SPAN_NOTICE("Overall Status: [M.stat > 1 ? "fully disabled" : "[M.health - M.getHalLoss()]% functional"]"))
|
||||
to_chat(user, "Key: <font color='#FFA500'>Electronics</font>/<span class='warning'>Physical Damage</span>")
|
||||
to_chat(user, "Damage Specifics: <font color='#FFA500'>[BU]</font> - <span class='warning'>[BR]</span>")
|
||||
if(M.tod && M.stat == DEAD)
|
||||
to_chat(user, SPAN_NOTICE("Time of Disable: [M.tod]"))
|
||||
var/mob/living/silicon/robot/H = M
|
||||
var/list/damaged = H.get_damaged_components(1, 1, 1)
|
||||
to_chat(user, SPAN_NOTICE("Localized Damage:"))
|
||||
if(length(damaged) > 0)
|
||||
for(var/datum/robot_component/org in damaged)
|
||||
user.show_message(SPAN_NOTICE("\t [capitalize(org.name)]: [(org.installed == -1) ? SPAN_WARNING("<b>DESTROYED</b>") :""]\
|
||||
[(org.electronics_damage > 0) ? "<font color='#FFA500'>[org.electronics_damage]</font>" : 0] - [(org.brute_damage > 0) ? SPAN_WARNING("[org.brute_damage]") :0] - \
|
||||
[(org.toggled) ? "Toggled ON" : SPAN_WARNING("Toggled OFF")] - \
|
||||
[(org.powered) ? "Power ON" : SPAN_WARNING("Power OFF")]"),1)
|
||||
|
||||
else
|
||||
to_chat(user, SPAN_NOTICE("Components are OK."))
|
||||
if(H.emagged && prob(5))
|
||||
to_chat(user, SPAN_WARNING("ERROR: INTERNAL SYSTEMS COMPROMISED"))
|
||||
to_chat(user, SPAN_NOTICE("Operating Temperature: [M.bodytemperature-T0C]°C ([M.bodytemperature*1.8-459.67]°F)"))
|
||||
|
||||
/proc/prosthetics_scan(mob/user, mob/living/carbon/human/H)
|
||||
to_chat(user, SPAN_NOTICE("Analyzing Results for \the [H]:"))
|
||||
if(H.stat == DEAD)
|
||||
to_chat(user, SPAN_DANGER("No neural coherence detected."))
|
||||
to_chat(user, "Key: <font color='#FFA500'>Electronics</font>/<span class='warning'>Wiring</span>")
|
||||
var/obj/item/organ/internal/machine/power_core/IC = H.internal_organs_by_name[BP_CELL]
|
||||
if(IC)
|
||||
to_chat(user, SPAN_NOTICE("Cell charge: [IC.percent()] %"))
|
||||
else
|
||||
to_chat(user, SPAN_NOTICE("Cell charge: ERROR - Cell not present"))
|
||||
to_chat(user, SPAN_NOTICE("External prosthetics:"))
|
||||
var/organ_found
|
||||
if(length(H.internal_organs))
|
||||
for(var/obj/item/organ/external/E in H.organs)
|
||||
if(!(E.status & (ORGAN_ROBOT || ORGAN_ASSISTED)))
|
||||
continue
|
||||
organ_found = TRUE
|
||||
to_chat(user, "[E.name]: <span class='warning'>[get_robot_severity(E.brute_dam)]</span> <font color='#FFA500'>[get_robot_severity(E.burn_dam)]</font>")
|
||||
if(!organ_found)
|
||||
to_chat(user, SPAN_NOTICE("No prosthetics located."))
|
||||
to_chat(user, "<hr>")
|
||||
to_chat(user, SPAN_NOTICE("Internal prosthetics:"))
|
||||
organ_found = FALSE
|
||||
if(length(H.internal_organs))
|
||||
var/obj/item/organ/external/head = H.get_organ(BP_HEAD)
|
||||
var/show_tag = FALSE
|
||||
if(head?.open == 3) // Hatch open
|
||||
show_tag = TRUE
|
||||
for(var/obj/item/organ/O in H.internal_organs)
|
||||
if(!(O.status & (ORGAN_ROBOT || ORGAN_ASSISTED)))
|
||||
continue
|
||||
if(!show_tag && istype(O, /obj/item/organ/internal/machine/ipc_tag))
|
||||
continue
|
||||
organ_found = TRUE
|
||||
var/found_damage = FALSE
|
||||
to_chat(user, SPAN_NOTICE(SPAN_BOLD("[O.name]")))
|
||||
if(O.damage)
|
||||
to_chat(user, SPAN_WARNING("Core damage detected."))
|
||||
found_damage = TRUE
|
||||
if(istype(O, /obj/item/organ/internal/machine))
|
||||
var/obj/item/organ/internal/machine/machine_organ = O
|
||||
if(machine_organ.get_integrity() < 100)
|
||||
to_chat(user, SPAN_WARNING("<b>[machine_organ.name]</b>: Integrity damage detected."))
|
||||
found_damage = TRUE
|
||||
if(!found_damage)
|
||||
to_chat(user, SPAN_NOTICE("No damage detected."))
|
||||
|
||||
if(!organ_found)
|
||||
to_chat(user, SPAN_NOTICE("No prosthetics located."))
|
||||
|
||||
/proc/get_robot_severity(amount, var/uppercase = FALSE)
|
||||
. = "undamaged"
|
||||
if(!amount)
|
||||
. = "undamaged"
|
||||
else if(amount > 100)
|
||||
. = "destroyed"
|
||||
else if(amount > 75)
|
||||
. = "falling apart"
|
||||
else if(amount > 50)
|
||||
. = "heavily compromised"
|
||||
else if(amount > 25)
|
||||
. = "problematic"
|
||||
else if(amount > 10)
|
||||
. = "fine"
|
||||
else
|
||||
. = "minor"
|
||||
|
||||
/obj/item/device/robotanalyzer/augment
|
||||
name = "retractable cyborg analyzer"
|
||||
|
||||
@@ -255,7 +255,7 @@
|
||||
|
||||
var/mob/living/carbon/human/new_shell = new(get_turf(src), chest.linked_frame)
|
||||
// replace the IPC's microbattery cell with the one that was in the robot chest
|
||||
var/obj/item/organ/internal/cell/C = new_shell.internal_organs_by_name[BP_CELL]
|
||||
var/obj/item/organ/internal/machine/power_core/C = new_shell.internal_organs_by_name[BP_CELL]
|
||||
C.replace_cell(chest.cell)
|
||||
//so people won't mess around with the chassis until it is deleted
|
||||
forceMove(new_shell)
|
||||
@@ -268,7 +268,7 @@
|
||||
newname = L.get_random_name()
|
||||
new_shell.real_name = newname
|
||||
new_shell.name = new_shell.real_name
|
||||
var/obj/item/organ/internal/mmi_holder/posibrain/P = new_shell.internal_organs_by_name[BP_BRAIN]
|
||||
var/obj/item/organ/internal/machine/posibrain/P = new_shell.internal_organs_by_name[BP_BRAIN]
|
||||
P.setup_brain()
|
||||
new_shell.change_appearance(APPEARANCE_PLASTICSURGERY, new_shell)
|
||||
qdel(src)
|
||||
|
||||
@@ -207,7 +207,7 @@
|
||||
if(ishuman(hit_mob))
|
||||
var/mob/living/carbon/human/H = hit_mob
|
||||
if(prob(20))
|
||||
var/obj/item/organ/internal/cell/cell_holder = locate() in H.internal_organs
|
||||
var/obj/item/organ/internal/machine/power_core/cell_holder = locate() in H.internal_organs
|
||||
if(cell_holder)
|
||||
var/obj/item/cell/C = cell_holder.cell
|
||||
if(C)
|
||||
|
||||
@@ -91,7 +91,7 @@
|
||||
species = SPECIES_IPC
|
||||
|
||||
/obj/effect/landmark/corpse/ipc_zombie/do_extra_customization(mob/living/carbon/human/M)
|
||||
var/obj/item/organ/internal/ipc_tag/tag = M.internal_organs_by_name[BP_IPCTAG]
|
||||
var/obj/item/organ/internal/machine/ipc_tag/tag = M.internal_organs_by_name[BP_IPCTAG]
|
||||
if(istype(tag))
|
||||
tag.serial_number = uppertext(dd_limittext(md5(M.real_name), 12))
|
||||
tag.ownership_info = IPC_OWNERSHIP_SELF
|
||||
|
||||
@@ -55,6 +55,8 @@
|
||||
var/atom/movable/screen/energy/energy_display = null
|
||||
var/atom/movable/screen/instability/instability_display = null
|
||||
var/atom/movable/screen/up_hint = null
|
||||
/// The IPC version of the fullscreen pain texture.
|
||||
var/atom/movable/screen/fullscreen/robot_pain
|
||||
|
||||
//spells hud icons - this interacts with add_spell and remove_spell
|
||||
var/list/atom/movable/screen/movable/spell_master/spell_masters = null
|
||||
@@ -252,11 +254,17 @@
|
||||
var/list/item_verbs = list()
|
||||
var/list/shouldnt_see = list() //typecache of objects that this mob shouldn't see in the stat panel. this silliness is needed because of AI alt+click and cult blood runes
|
||||
|
||||
var/list/active_genes=list()
|
||||
var/list/active_genes = list()
|
||||
|
||||
var/mob_size = MOB_MEDIUM
|
||||
/// The icon size width of the mob. Used for langchat resizing.
|
||||
var/icon_size = 32
|
||||
|
||||
/// The weight of the mob. Affects if the mob can be easily lifted or not. Separate from size, as some mobs may be big but not particularly heavy.
|
||||
var/mob_weight = MOB_WEIGHT_LIGHT
|
||||
/// The strength of the mob. Affects what kind of mobs can be thrown or carried. By default, does not give any buff.
|
||||
var/mob_strength = MOB_STRENGTH_NORMAL
|
||||
|
||||
var/list/progressbars
|
||||
|
||||
var/frozen = FALSE //related to wizard statues, if set to true, life won't process
|
||||
|
||||
@@ -443,7 +443,7 @@
|
||||
to_chat(H, SPAN_WARNING("You can only fireman carry humanoids!"))
|
||||
return
|
||||
var/mob/living/carbon/human/affected_human = affecting
|
||||
if(affected_human.species.mob_size > 25)
|
||||
if(affected_human.mob_weight > H.get_mob_strength())
|
||||
to_chat(H, SPAN_WARNING("\The [affected_human] is way too big to fireman carry!"))
|
||||
return
|
||||
if(state < GRAB_AGGRESSIVE)
|
||||
|
||||
@@ -1357,3 +1357,7 @@ GLOBAL_LIST_INIT(organ_rel_size, list(
|
||||
message_notifications.Cut(1, 2)
|
||||
|
||||
message_notifications[key_check] = world.time + next_message_time
|
||||
|
||||
/// Gets a mob's strength.
|
||||
/mob/proc/get_mob_strength()
|
||||
return mob_weight + mob_strength
|
||||
|
||||
@@ -78,6 +78,18 @@
|
||||
return
|
||||
found = TRUE
|
||||
flashlight = H
|
||||
else if(istype(H, /obj/item/computer_hardware/universal_port))
|
||||
if(universal_port)
|
||||
to_chat(user, SPAN_WARNING("\The [src]'s port slot is already occupied by \the [universal_port]."))
|
||||
return
|
||||
found = TRUE
|
||||
universal_port = H
|
||||
else if(istype(H, /obj/item/computer_hardware/access_cable_dongle))
|
||||
if(access_cable_dongle)
|
||||
to_chat(user, SPAN_WARNING("\The [src]'s port slot is already occupied by \the [access_cable_dongle]."))
|
||||
return
|
||||
found = TRUE
|
||||
access_cable_dongle = H
|
||||
if(found)
|
||||
to_chat(user, SPAN_NOTICE("You install \the [H] into \the [src]."))
|
||||
H.parent_computer = src
|
||||
@@ -128,6 +140,12 @@
|
||||
personal_ai.pai.parent_computer = null
|
||||
update_icon()
|
||||
personal_ai = null
|
||||
else if(universal_port == H)
|
||||
universal_port = null
|
||||
found = TRUE
|
||||
else if(access_cable_dongle == H)
|
||||
access_cable_dongle = null
|
||||
found = TRUE
|
||||
|
||||
if(found)
|
||||
if(user)
|
||||
@@ -165,6 +183,10 @@
|
||||
return tesla_link
|
||||
if(flashlight && initial(flashlight.name) == name)
|
||||
return flashlight
|
||||
if(universal_port && initial(universal_port.name) == name)
|
||||
return universal_port
|
||||
if(access_cable_dongle && initial(access_cable_dongle.name) == name)
|
||||
return access_cable_dongle
|
||||
return null
|
||||
|
||||
// Returns list of all components
|
||||
@@ -192,4 +214,8 @@
|
||||
all_components.Add(tesla_link)
|
||||
if(flashlight)
|
||||
all_components.Add(flashlight)
|
||||
if(universal_port)
|
||||
all_components.Add(universal_port)
|
||||
if(access_cable_dongle)
|
||||
all_components.Add(access_cable_dongle)
|
||||
return all_components
|
||||
|
||||
@@ -189,6 +189,14 @@
|
||||
if(response == "Yes")
|
||||
turn_on(user)
|
||||
|
||||
/obj/item/modular_computer/attack_ranged(mob/user, params)
|
||||
. = ..()
|
||||
if(ishuman(user) && isipc(user))
|
||||
var/mob/living/carbon/human/robot = user
|
||||
var/obj/item/organ/internal/machine/wireless_access/wireless_access_point = robot.internal_organs_by_name[BP_WIRELESS_ACCESS]
|
||||
if(wireless_access_point?.access_terminal(src))
|
||||
attack_hand(user)
|
||||
|
||||
/obj/item/modular_computer/attack_hand(var/mob/user)
|
||||
if(anchored)
|
||||
return attack_self(user)
|
||||
@@ -321,6 +329,20 @@
|
||||
return TRUE
|
||||
uninstall_component(user, H)
|
||||
return TRUE
|
||||
|
||||
if(istype(attacking_item, /obj/item/access_cable))
|
||||
var/obj/item/access_cable/access_cable = attacking_item
|
||||
if(!universal_port)
|
||||
to_chat(user, SPAN_WARNING("There isn't a port to slot \the [access_cable] into!"))
|
||||
return
|
||||
|
||||
if(universal_port.access_cable)
|
||||
to_chat(user, SPAN_WARNING("There's already a cable in the universal port!"))
|
||||
return
|
||||
|
||||
if(do_after(user, 1 SECONDS))
|
||||
visible_message(SPAN_NOTICE("[user] slots \the [access_cable] into \the [src]."))
|
||||
universal_port.insert_cable(access_cable, user)
|
||||
return ..()
|
||||
|
||||
/obj/item/modular_computer/mouse_drop_dragged(atom/over, mob/user, src_location, over_location, params)
|
||||
|
||||
@@ -47,6 +47,8 @@
|
||||
data["PC_stationdate"] = "[time2text(world.realtime, "DDD, Month DD")], [GLOB.game_year]"
|
||||
data["PC_showexitprogram"] = !!active_program
|
||||
data["PC_haslight"] = !!flashlight
|
||||
data["PC_hascable"] = !!access_cable_dongle
|
||||
data["PC_cableout"] = access_cable_dongle?.access_cable?.loc == access_cable_dongle ? FALSE : TRUE
|
||||
data["PC_lighton"] = flashlight?.enabled ? TRUE : FALSE
|
||||
data["PC_programheaders"] = list()
|
||||
if(idle_threads.len)
|
||||
@@ -146,6 +148,13 @@
|
||||
if(flashlight)
|
||||
flashlight.toggle()
|
||||
. = TRUE
|
||||
if(action == "PC_takecable")
|
||||
if(access_cable_dongle && access_cable_dongle.access_cable)
|
||||
if(access_cable_dongle.access_cable.loc == access_cable_dongle)
|
||||
access_cable_dongle.take_cable(usr)
|
||||
else
|
||||
access_cable_dongle.access_cable.retract()
|
||||
. = TRUE
|
||||
if(action == "PC_shutdown")
|
||||
shutdown_computer()
|
||||
return TRUE
|
||||
@@ -190,6 +199,11 @@
|
||||
update_icon()
|
||||
|
||||
/obj/item/modular_computer/ui_status(mob/user, datum/ui_state/state)
|
||||
if(universal_port?.access_cable)
|
||||
if(istype(universal_port.access_cable.source, /obj/item/organ/internal/machine/access_port))
|
||||
var/obj/item/organ/internal/machine/access_port/port = universal_port.access_cable.source
|
||||
if(user == port.owner)
|
||||
return UI_INTERACTIVE
|
||||
. = ..()
|
||||
if(. < UI_INTERACTIVE)
|
||||
if(user.machine)
|
||||
|
||||
@@ -125,6 +125,10 @@
|
||||
var/obj/item/computer_hardware/tesla_link/tesla_link
|
||||
/// Personal AI, can control the device via a verb when installed
|
||||
var/obj/item/device/paicard/personal_ai
|
||||
/// The universal port. Allows connection from IPCs through access cables.
|
||||
var/obj/item/computer_hardware/universal_port/universal_port
|
||||
/// The access cable dongle. Allows the computer to have its very own access cable.
|
||||
var/obj/item/computer_hardware/access_cable_dongle/access_cable_dongle
|
||||
var/obj/item/computer_hardware/flashlight/flashlight
|
||||
var/listener/listener
|
||||
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
hard_drive = new /obj/item/computer_hardware/hard_drive/super(src)
|
||||
network_card = new /obj/item/computer_hardware/network_card/wired(src)
|
||||
nano_printer = new /obj/item/computer_hardware/nano_printer(src)
|
||||
universal_port = new /obj/item/computer_hardware/universal_port(src)
|
||||
|
||||
/obj/item/modular_computer/console/preset/install_default_programs()
|
||||
..()
|
||||
@@ -140,6 +141,7 @@
|
||||
/obj/item/modular_computer/console/preset/supply/machinist/install_default_hardware()
|
||||
..()
|
||||
ai_slot = new /obj/item/computer_hardware/ai_slot(src)
|
||||
access_cable_dongle = new /obj/item/computer_hardware/access_cable_dongle(src)
|
||||
|
||||
// ERT
|
||||
/obj/item/modular_computer/console/preset/ert/install_default_hardware()
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
nano_printer.max_paper = 10
|
||||
nano_printer.stored_paper = 5
|
||||
tesla_link = new /obj/item/computer_hardware/tesla_link/charging_cable(src)
|
||||
universal_port = new /obj/item/computer_hardware/universal_port(src)
|
||||
|
||||
// the laptop in the modular computer loadout
|
||||
/obj/item/modular_computer/laptop/preset/loadout/install_default_hardware()
|
||||
@@ -122,6 +123,15 @@
|
||||
desc = "A portable computer belonging to the operation's manager."
|
||||
_app_preset_type = /datum/modular_computer_app_presets/supply/om
|
||||
|
||||
/obj/item/modular_computer/laptop/preset/supply/robotics
|
||||
name = "robotics laptop"
|
||||
desc = "A portable computer with support for specialized robotics software."
|
||||
_app_preset_type = /datum/modular_computer_app_presets/supply/machinist
|
||||
|
||||
/obj/item/modular_computer/laptop/preset/supply/robotics/install_default_hardware()
|
||||
..()
|
||||
access_cable_dongle = new /obj/item/computer_hardware/access_cable_dongle(src)
|
||||
|
||||
// Representative
|
||||
/obj/item/modular_computer/laptop/preset/representative
|
||||
name = "representative's laptop"
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
tesla_link = new/obj/item/computer_hardware/tesla_link(src)
|
||||
hard_drive = new/obj/item/computer_hardware/hard_drive(src)
|
||||
network_card = new/obj/item/computer_hardware/network_card(src)
|
||||
universal_port = new /obj/item/computer_hardware/universal_port(src)
|
||||
|
||||
/obj/item/modular_computer/telescreen/preset/generic
|
||||
_app_preset_type = /datum/modular_computer_app_presets/wall_generic
|
||||
|
||||
@@ -83,7 +83,6 @@
|
||||
. = ..()
|
||||
program_list += list(/datum/computer_file/program/comm, /datum/computer_file/program/records/employment)
|
||||
|
||||
|
||||
/*##########################
|
||||
BRIDGE CREW PRESETS
|
||||
##########################*/
|
||||
@@ -273,7 +272,7 @@
|
||||
|
||||
/datum/modular_computer_app_presets/supply/machinist/New()
|
||||
. = ..()
|
||||
program_list += list(/datum/computer_file/program/records/medical, /datum/computer_file/program/scanner/science)
|
||||
program_list += list(/datum/computer_file/program/records/medical, /datum/computer_file/program/scanner/science, /datum/computer_file/program/robotics)
|
||||
//Machinist is the bastard child of supply/operation, it doesn't have access to shit essentially
|
||||
program_list -= list(/datum/computer_file/program/civilian/cargocontrol, /datum/computer_file/program/civilian/cargodelivery, /datum/computer_file/program/away_manifest)
|
||||
|
||||
|
||||
@@ -0,0 +1,101 @@
|
||||
/datum/computer_file/program/robotics
|
||||
filename = "robotics"
|
||||
filedesc = "Robotics Interface"
|
||||
program_icon_state = "ai-fixer-empty"
|
||||
program_key_icon_state = "teal_key"
|
||||
extended_desc = "A program made to interface with positronics."
|
||||
size = 14
|
||||
requires_access_to_run = PROGRAM_ACCESS_LIST_ONE
|
||||
required_access_run = list(ACCESS_RESEARCH, ACCESS_ROBOTICS)
|
||||
required_access_download = list(ACCESS_RESEARCH, ACCESS_ROBOTICS)
|
||||
available_on_ntnet = FALSE
|
||||
tgui_id = "RoboticsComputer"
|
||||
/// The diagnostics module associated with this program.
|
||||
var/datum/tgui_module/ipc_diagnostic/diagnostic
|
||||
|
||||
/datum/computer_file/program/robotics/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state)
|
||||
. = ..()
|
||||
if(!ishuman(ui.user))
|
||||
return
|
||||
|
||||
var/mob/living/carbon/human/user = ui.user
|
||||
if(action == "run_diagnostics")
|
||||
if(computer.access_cable_dongle && computer.access_cable_dongle.access_cable)
|
||||
var/mob/living/carbon/human/synthetic = computer.access_cable_dongle.access_cable.target
|
||||
if(istype(user) && istype(synthetic))
|
||||
ui.user.visible_message(SPAN_NOTICE("[user] begins running a diagnostic scan..."))
|
||||
if(do_after(user, 3 SECONDS))
|
||||
diagnostic = new(user, synthetic)
|
||||
return TRUE
|
||||
|
||||
if(action == "open_diagnostic")
|
||||
if(computer.access_cable_dongle && computer.access_cable_dongle.access_cable)
|
||||
|
||||
if(istype(diagnostic))
|
||||
if(diagnostic.patient != computer.access_cable_dongle.access_cable.target)
|
||||
to_chat(user, SPAN_WARNING("This diagnostic is no longer valid and has been deleted."))
|
||||
qdel(diagnostic)
|
||||
return TRUE
|
||||
|
||||
var/mob/living/carbon/human/synthetic = computer.access_cable_dongle.access_cable.target
|
||||
if(istype(user) && istype(synthetic))
|
||||
diagnostic.ui_interact(user)
|
||||
return TRUE
|
||||
|
||||
/datum/computer_file/program/robotics/ui_data(mob/user)
|
||||
var/list/data = list()
|
||||
var/mob/living/carbon/human/ipc
|
||||
if(computer.access_cable_dongle && computer.access_cable_dongle.access_cable)
|
||||
var/obj/item/organ/internal/machine/access_port/port = computer.access_cable_dongle.access_cable.target
|
||||
if(istype(port))
|
||||
ipc = port.owner
|
||||
|
||||
if(isipc(ipc))
|
||||
var/datum/species/machine/machine_species = ipc.species // need to manually set to ipc species because of machine_ui_theme
|
||||
data["patient_name"] = ipc.real_name
|
||||
data["temp"] = round(convert_k2c(ipc.bodytemperature))
|
||||
data["machine_ui_theme"] = machine_species.machine_ui_theme
|
||||
|
||||
data["organs"] = list()
|
||||
for(var/obj/item/organ/internal/organ in ipc.internal_organs)
|
||||
var/list/organ_data = list()
|
||||
|
||||
if(istype(organ, /obj/item/organ/internal/machine))
|
||||
var/obj/item/organ/internal/machine/machine_organ = organ
|
||||
if(!machine_organ.diagnostics_suite_visible)
|
||||
continue
|
||||
|
||||
organ_data["wiring_status"] = machine_organ.wiring.get_status()
|
||||
organ_data["plating_status"] = machine_organ.plating.get_status()
|
||||
organ_data["electronics_status"] = machine_organ.electronics.get_status()
|
||||
organ_data["diagnostics_info"] = machine_organ.get_diagnostics_info()
|
||||
|
||||
organ_data["name"] = organ.name
|
||||
organ_data["desc"] = organ.desc
|
||||
organ_data["damage"] = organ.damage
|
||||
organ_data["max_damage"] = organ.max_damage
|
||||
|
||||
data["organs"] += list(organ_data)
|
||||
|
||||
data["robolimb_self_repair_cap"] = ROBOLIMB_SELF_REPAIR_CAP
|
||||
data["limbs"] = list()
|
||||
for(var/obj/item/organ/external/limb in ipc.organs)
|
||||
if(limb.brute_dam || limb.burn_dam)
|
||||
data["limbs"] += list(list("name" = limb.name, "brute_damage" = limb.brute_dam, "burn_damage" = limb.burn_dam, "max_damage" = limb.max_damage))
|
||||
|
||||
var/obj/item/organ/internal/machine/power_core/C = ipc.internal_organs_by_name[BP_CELL]
|
||||
if(C)
|
||||
data["charge_percent"] = C.percent()
|
||||
|
||||
var/datum/component/synthetic_endoskeleton/endoskeleton = ipc.GetComponent(/datum/component/synthetic_endoskeleton)
|
||||
if(istype(endoskeleton))
|
||||
data["endoskeleton_damage"] = endoskeleton.damage
|
||||
data["endoskeleton_max_damage"] = endoskeleton.max_damage
|
||||
|
||||
var/datum/component/armor/synthetic/synth_armor = ipc.GetComponent(/datum/component/armor/synthetic)
|
||||
if(istype(synth_armor))
|
||||
data["armor_data"] = list()
|
||||
var/list/armor_damage = synth_armor.get_visible_damage()
|
||||
for(var/key in armor_damage)
|
||||
data["armor_data"] += list(list("key" = key, "status" = armor_damage[key]))
|
||||
return data
|
||||
@@ -0,0 +1,44 @@
|
||||
/obj/item/computer_hardware/access_cable_dongle
|
||||
name = "access cable dongle"
|
||||
desc = "A dongle from which a positronic-compatible cable can be extended."
|
||||
critical = FALSE
|
||||
icon_state = "aislot"
|
||||
hardware_size = 3
|
||||
|
||||
/// The access cable currently inserted into this slot.
|
||||
var/obj/item/access_cable/access_cable
|
||||
|
||||
/obj/item/computer_hardware/access_cable_dongle/Initialize()
|
||||
. = ..()
|
||||
access_cable = new(src, src, parent_computer)
|
||||
|
||||
/obj/item/computer_hardware/access_cable_dongle/Destroy()
|
||||
if(access_cable)
|
||||
access_cable.retract()
|
||||
QDEL_NULL(access_cable)
|
||||
return ..()
|
||||
|
||||
/obj/item/computer_hardware/access_cable_dongle/proc/take_cable(mob/user)
|
||||
if(!ishuman(user))
|
||||
return
|
||||
|
||||
var/mob/living/carbon/human/H = user
|
||||
|
||||
if(use_check_and_message(H))
|
||||
return
|
||||
|
||||
if(!access_cable)
|
||||
to_chat(H, SPAN_WARNING("This table does not have an access cable anymore!"))
|
||||
return
|
||||
|
||||
if(H.get_active_hand())
|
||||
to_chat(H, SPAN_WARNING("You need a free hand to retrieve \the [access_cable]!"))
|
||||
return
|
||||
|
||||
if(access_cable.loc != src)
|
||||
to_chat(H, SPAN_WARNING("The access cable is already elsewhere!"))
|
||||
return
|
||||
|
||||
H.visible_message(SPAN_NOTICE("[H] retrieves \the [access_cable] from \the [src]."), SPAN_NOTICE("You retrieve \the [access_cable] from \the [src]."))
|
||||
access_cable.create_cable(H)
|
||||
H.put_in_active_hand(access_cable)
|
||||
@@ -1,4 +1,4 @@
|
||||
/obj/item/computer_hardware/
|
||||
/obj/item/computer_hardware
|
||||
name = "Hardware"
|
||||
desc = "Unknown Hardware."
|
||||
icon = 'icons/obj/modular_components.dmi'
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
/obj/item/computer_hardware/universal_port
|
||||
name = "universal port"
|
||||
desc = "A small, universal slot wherein an access cable can be slotted in."
|
||||
critical = FALSE
|
||||
icon_state = "aislot"
|
||||
hardware_size = 3
|
||||
|
||||
/// The access cable currently inserted into this slot.
|
||||
var/obj/item/access_cable/access_cable
|
||||
|
||||
/obj/item/computer_hardware/universal_port/Destroy()
|
||||
if(access_cable)
|
||||
access_cable.retract()
|
||||
access_cable = null
|
||||
return ..()
|
||||
|
||||
/obj/item/computer_hardware/universal_port/remove_cable(obj/item/access_cable/cable)
|
||||
..()
|
||||
access_cable = null
|
||||
|
||||
/obj/item/computer_hardware/universal_port/insert_cable(obj/item/access_cable/cable, mob/user)
|
||||
. = ..()
|
||||
access_cable = cable
|
||||
cable.create_cable(parent_computer)
|
||||
|
||||
/obj/item/computer_hardware/universal_port/cable_interact(obj/item/access_cable/cable, mob/user)
|
||||
. = ..()
|
||||
if(parent_computer)
|
||||
parent_computer.attack_self(user)
|
||||
@@ -0,0 +1,9 @@
|
||||
/datum/movespeed_modifier/synth_emp
|
||||
id = "synthemp"
|
||||
variable = TRUE
|
||||
multiplicative_slowdown = 1
|
||||
|
||||
/datum/movespeed_modifier/endoskeleton
|
||||
id = "synthendoskeleton"
|
||||
variable = TRUE
|
||||
multiplicative_slowdown = 1
|
||||
@@ -220,6 +220,18 @@
|
||||
var/modification = tgui_input_list(owner, "Select a Modification", "Organ Modification", O.possible_modifications)
|
||||
owner.change_organ(organ, modification)
|
||||
|
||||
if("organ_preset")
|
||||
if(can_change(APPEARANCE_PROSTHETICS))
|
||||
var/organ = tgui_input_list(owner, "Select an Organ", "Organ Presets", valid_organs)
|
||||
var/obj/item/organ/internal/machine/O = owner.internal_organs_by_name[organ]
|
||||
var/list/possible_presets = list()
|
||||
for(var/P in O.organ_presets)
|
||||
var/singleton/synthetic_organ_preset/preset = GET_SINGLETON(P)
|
||||
possible_presets[preset.name] = preset
|
||||
var/singleton/synthetic_organ_preset/chosen_preset = tgui_input_list(owner, "Select a Preset", "Organ Presets", possible_presets)
|
||||
if(chosen_preset)
|
||||
O.apply_preset_data(chosen_preset)
|
||||
|
||||
/datum/tgui_module/appearance_changer/ui_interact(var/mob/user, var/datum/tgui/ui)
|
||||
ui = SStgui.try_update_ui(user, src, ui)
|
||||
if(!ui)
|
||||
|
||||
@@ -0,0 +1,237 @@
|
||||
/obj/item/organ/internal/machine
|
||||
name = "generic machine organ"
|
||||
parent_organ = BP_CHEST
|
||||
organ_tag = "generic machine organ"
|
||||
robotic_sprite = FALSE
|
||||
|
||||
/// The list of organ presets to use. Linked list of ORGAN_PREF to /singleton/synthetic_organ_preset. Use only if your organ has pref settings and presets.
|
||||
/// For an example, see cooling_unit.dm. Remember to also update code\modules\client\preference_setup\general\03_body.dm at line 893!
|
||||
var/list/organ_presets
|
||||
/// The default preset to fall back to if there is no pref (aka people want the base type). Must be of type /singleton/synthetic_organ_preset.
|
||||
var/default_preset
|
||||
/// This variable forces the organ to be of a certain preset and is applied automatically on Initialize. This is used to make subtypes spawn as proper presets.
|
||||
var/forced_preset
|
||||
/// The current preset, if any. Should only ever be null or an instance.
|
||||
var/singleton/synthetic_organ_preset/current_preset
|
||||
|
||||
/// If an organ shows up in the diagnostics suite (the IPC organ verb).
|
||||
var/diagnostics_suite_visible = TRUE
|
||||
|
||||
/// The wiring datum of this organ.
|
||||
var/datum/synthetic_internal/wiring/wiring
|
||||
/// The plating datum of this organ.
|
||||
var/datum/synthetic_internal/plating/plating
|
||||
/// The electronics datum of this organ.
|
||||
var/datum/synthetic_internal/electronics/electronics
|
||||
|
||||
/// The world.time of the last integrity damage event.
|
||||
var/last_integrity_event_time = 0
|
||||
/// The amount of time that has to pass between each integrity damage event.
|
||||
var/integrity_event_cooldown = 60 SECONDS
|
||||
|
||||
/obj/item/organ/internal/machine/Initialize()
|
||||
robotize()
|
||||
. = ..()
|
||||
wiring = new(src)
|
||||
plating = new(src)
|
||||
electronics = new(src)
|
||||
if(forced_preset)
|
||||
apply_preset_data(GET_SINGLETON(forced_preset))
|
||||
|
||||
/obj/item/organ/internal/machine/Destroy()
|
||||
QDEL_NULL(wiring)
|
||||
QDEL_NULL(plating)
|
||||
QDEL_NULL(electronics)
|
||||
if(current_preset)
|
||||
current_preset = null
|
||||
return ..()
|
||||
|
||||
/obj/item/organ/internal/machine/refresh_action_button()
|
||||
. = ..()
|
||||
if(.)
|
||||
if(action_button_name)
|
||||
action.button_icon_state = initial(icon_state)
|
||||
if(action.button)
|
||||
action.button.update_icon()
|
||||
|
||||
/obj/item/organ/internal/machine/rejuvenate()
|
||||
. = ..()
|
||||
diagnostics_suite_visible = initial(diagnostics_suite_visible)
|
||||
wiring.heal_damage(wiring.max_wires)
|
||||
plating.heal_damage(plating.max_health)
|
||||
electronics.heal_damage(electronics.max_integrity)
|
||||
integrity_event_cooldown = initial(integrity_event_cooldown)
|
||||
|
||||
/obj/item/organ/internal/machine/process(seconds_per_tick)
|
||||
..()
|
||||
if(!owner)
|
||||
return
|
||||
|
||||
var/integrity = get_integrity()
|
||||
if(integrity < IPC_INTEGRITY_THRESHOLD_LOW)
|
||||
// This is when things start going Fucking Wrong.
|
||||
do_integrity_damage_effects(integrity)
|
||||
|
||||
if(damage >= max_damage)
|
||||
die()
|
||||
|
||||
/obj/item/organ/internal/machine/die()
|
||||
if(!vital)
|
||||
to_chat(owner, FONT_LARGE(SPAN_MACHINE_WARNING("Some of your sensors go dark - you've lost connection to your [src]!")))
|
||||
diagnostics_suite_visible = FALSE
|
||||
damage = max_damage
|
||||
status |= ORGAN_DEAD
|
||||
death_time = world.time
|
||||
STOP_PROCESSING(SSprocessing, src)
|
||||
if(owner && vital)
|
||||
owner.death()
|
||||
|
||||
/obj/item/organ/internal/machine/take_internal_damage(amount, silent, forced_damage = FALSE)
|
||||
// Plating defends the internal bits. First, you have to get through it.
|
||||
if(!forced_damage)
|
||||
if(plating.get_status() > 0)
|
||||
amount = plating.take_damage(amount)
|
||||
if(amount <= 0)
|
||||
return
|
||||
|
||||
var/list/component_list = list(wiring, electronics)
|
||||
component_list = shuffle(component_list)
|
||||
// After that, it's open season.
|
||||
for(var/datum/synthetic_internal/internal in component_list)
|
||||
if(internal.get_status())
|
||||
internal.take_damage(amount)
|
||||
if(internal.get_status())
|
||||
break
|
||||
|
||||
. = ..()
|
||||
|
||||
/obj/item/organ/internal/machine/emp_act(severity)
|
||||
. = ..()
|
||||
switch(severity)
|
||||
if(EMP_HEAVY)
|
||||
take_internal_damage(4 * emp_coeff)
|
||||
if(EMP_LIGHT)
|
||||
take_internal_damage(2 * emp_coeff)
|
||||
|
||||
/**
|
||||
* Called when prefs are synced to the organ to set the proper synthetic organ preset. Turns the pref into a preset singleton.
|
||||
* Remember that the base type is the default, AKA when no prefs are set that organ will spawn.
|
||||
*/
|
||||
/obj/item/organ/internal/machine/proc/get_preset_from_pref(organ_pref)
|
||||
var/singleton/synthetic_organ_preset/new_preset
|
||||
if(organ_pref && (organ_pref in organ_presets))
|
||||
new_preset = GET_SINGLETON(organ_presets[organ_pref])
|
||||
else
|
||||
new_preset = GET_SINGLETON(default_preset)
|
||||
|
||||
if(!istype(new_preset))
|
||||
crash_with("Invalid organ preset [new_preset]!")
|
||||
|
||||
apply_preset_data(new_preset)
|
||||
|
||||
/**
|
||||
* Applies the preset data to the organ. Needs a preset object supplied, not just a type.
|
||||
*/
|
||||
/obj/item/organ/internal/machine/proc/apply_preset_data(singleton/synthetic_organ_preset/preset)
|
||||
if(!istype(preset))
|
||||
crash_with("apply_preset_data called with improper preset [preset]!")
|
||||
|
||||
current_preset = preset
|
||||
preset.apply_preset(src)
|
||||
owner.update_action_buttons()
|
||||
|
||||
/**
|
||||
* This is a function used to return an overall integrity number that takes
|
||||
* the average of wiring + electronics, and then subtracts current damage from them. Those are the soft bits - plating is what defends them.
|
||||
* Returns a percentage.
|
||||
*/
|
||||
/obj/item/organ/internal/machine/proc/get_integrity()
|
||||
var/wiring_status = wiring ? wiring.get_status() : 0
|
||||
var/electronics_status = electronics ? electronics.get_status() : 0
|
||||
var/internal_component_status = (wiring_status + electronics_status) / 2
|
||||
var/damage_status = damage / 2
|
||||
return max(internal_component_status - damage_status, 0)
|
||||
|
||||
/**
|
||||
* This function returns a damage multiplier, starting from 1 and dropping to 0, depending on damage.
|
||||
* Returns a multiplier between 0 and 1.
|
||||
*/
|
||||
/obj/item/organ/internal/machine/proc/get_damage_multiplier()
|
||||
if(!damage)
|
||||
return 1
|
||||
|
||||
return 1 - (damage / max_damage)
|
||||
|
||||
/**
|
||||
* This proc is used to determine which integrity damage threshold we are at, and execute the proper proc..
|
||||
* Only called below 75%.
|
||||
*/
|
||||
/obj/item/organ/internal/machine/proc/do_integrity_damage_effects(integrity)
|
||||
if(!owner)
|
||||
return
|
||||
|
||||
var/obj/item/organ/internal/machine/posibrain/brain = owner.internal_organs_by_name[BP_BRAIN]
|
||||
if(!istype(brain)) //??? should be dead anyway so who cares
|
||||
return
|
||||
|
||||
// The cooldowns are handled in the other procs because feasibly we might want to add different cooldowns for different organs and different thresholds.
|
||||
if(can_do_integrity_damage())
|
||||
switch(integrity)
|
||||
if(IPC_INTEGRITY_THRESHOLD_MEDIUM to IPC_INTEGRITY_THRESHOLD_LOW)
|
||||
low_integrity_damage(integrity)
|
||||
if(IPC_INTEGRITY_THRESHOLD_HIGH to IPC_INTEGRITY_THRESHOLD_MEDIUM)
|
||||
medium_integrity_damage(integrity)
|
||||
if(IPC_INTEGRITY_THRESHOLD_VERY_HIGH to IPC_INTEGRITY_THRESHOLD_HIGH)
|
||||
high_integrity_damage(integrity)
|
||||
|
||||
/**
|
||||
* Returns the damage percentage of total integrity.
|
||||
* Basically the opposite of get_integrity(). Useful for damage probabilities, where you want a scaling number the more integrity damage there is on an organ.
|
||||
*/
|
||||
/obj/item/organ/internal/machine/proc/get_integrity_damage_probability(integrity)
|
||||
// integrity is a probability, so first of all check the difference between max probability and probaiblity
|
||||
// 100 - 100 = 0 | 100 - 50 = 50
|
||||
var/damage_probability = 100 - integrity
|
||||
return damage_probability
|
||||
|
||||
/**
|
||||
* Returns TRUE if the cooldown for integrity damage has expired.
|
||||
*/
|
||||
/obj/item/organ/internal/machine/proc/can_do_integrity_damage()
|
||||
if(last_integrity_event_time + integrity_event_cooldown > world.time)
|
||||
return FALSE
|
||||
return TRUE
|
||||
|
||||
/**
|
||||
* The proc called to do low-intensity integrity damage (50 to 75% damage).
|
||||
*/
|
||||
/obj/item/organ/internal/machine/proc/low_integrity_damage(integrity)
|
||||
last_integrity_event_time = world.time
|
||||
return TRUE
|
||||
|
||||
/**
|
||||
* The proc called to do mediumlow-intensity integrity damage (25 to 50% damage).
|
||||
*/
|
||||
/obj/item/organ/internal/machine/proc/medium_integrity_damage(integrity)
|
||||
last_integrity_event_time = world.time
|
||||
var/obj/item/organ/internal/machine/posibrain/brain = owner.internal_organs_by_name[BP_BRAIN]
|
||||
if(istype(brain))
|
||||
brain.damage_integrity(1)
|
||||
return TRUE
|
||||
|
||||
/**
|
||||
* The proc called to do high-intensity integrity damage (0 to 25% damage).
|
||||
*/
|
||||
/obj/item/organ/internal/machine/proc/high_integrity_damage(integrity)
|
||||
last_integrity_event_time = world.time
|
||||
var/obj/item/organ/internal/machine/posibrain/brain = owner.internal_organs_by_name[BP_BRAIN]
|
||||
if(istype(brain))
|
||||
brain.damage_integrity(2)
|
||||
return TRUE
|
||||
|
||||
/**
|
||||
* Returns extra diagnostics info, viewable from the diagnostics unit.
|
||||
*/
|
||||
/obj/item/organ/internal/machine/proc/get_diagnostics_info()
|
||||
return
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
/**
|
||||
* Synthetic organ presets are a way to allow us to have customizable and easily expandable presets for different organs.
|
||||
* This is partly due to the limitations of the organ modification system, which does not support manually selecting different types,
|
||||
* but also to allow the creation of different presets to do different things in a modular and easily expandable way.
|
||||
*/
|
||||
/singleton/synthetic_organ_preset
|
||||
/// The name the synthetic organ will have.
|
||||
var/name = "epic synthetic organ"
|
||||
/// The description synthetic organ will get.
|
||||
var/desc = "It is super epic and cool."
|
||||
/// Replacement icon state. Leave null if you don't want to replace the original state.
|
||||
var/icon_state
|
||||
|
||||
/singleton/synthetic_organ_preset/proc/apply_preset(obj/item/organ/internal/machine/organ)
|
||||
SHOULD_CALL_PARENT(TRUE)
|
||||
if(!istype(organ))
|
||||
crash_with("Synthetic organ preset called with invalid organ [organ]")
|
||||
|
||||
organ.name = name
|
||||
organ.desc = desc
|
||||
if(icon_state)
|
||||
organ.icon_state = icon_state
|
||||
@@ -0,0 +1,346 @@
|
||||
/obj/item/organ/internal/machine/access_port
|
||||
name = "universal access port"
|
||||
desc = "A slot built into nearly all synthetics for universal access to information such as diagnostics or internal processes."
|
||||
icon = 'icons/obj/organs/ipc_organs.dmi'
|
||||
icon_state = "ipc_port"
|
||||
organ_tag = BP_ACCESS_PORT
|
||||
parent_organ = BP_HEAD
|
||||
|
||||
action_button_name = "Extend or Retract Cable"
|
||||
|
||||
max_damage = 30
|
||||
relative_size = 15
|
||||
|
||||
/// Our access cable, which can be extended to connect into things.
|
||||
var/obj/item/access_cable/access_cable = /obj/item/access_cable/synthetic
|
||||
/// The internal port. This is where things get connected to to retrieve information or do effects.
|
||||
var/obj/item/internal_port
|
||||
|
||||
/obj/item/organ/internal/machine/access_port/Initialize()
|
||||
. = ..()
|
||||
access_cable = new access_cable(src, src, owner)
|
||||
RegisterSignal(access_cable, COMSIG_QDELETING, PROC_REF(clear_cable))
|
||||
add_verb(owner, /mob/living/carbon/human/proc/access_cable)
|
||||
|
||||
/obj/item/organ/internal/machine/access_port/Destroy()
|
||||
QDEL_NULL(access_cable)
|
||||
QDEL_NULL(internal_port)
|
||||
return ..()
|
||||
|
||||
/obj/item/organ/internal/machine/access_port/replaced(mob/living/carbon/human/target, obj/item/organ/external/affected)
|
||||
. = ..()
|
||||
add_verb(owner, /mob/living/carbon/human/proc/access_cable)
|
||||
|
||||
/obj/item/organ/internal/machine/access_port/removed(mob/living/carbon/human/target, mob/living/user)
|
||||
remove_verb(owner, /mob/living/carbon/human/proc/access_cable)
|
||||
. = ..()
|
||||
|
||||
/obj/item/organ/internal/machine/access_port/attack_self(mob/user)
|
||||
. = ..()
|
||||
if(user.stat == DEAD)
|
||||
return
|
||||
|
||||
if(user.incapacitated(INCAPACITATION_KNOCKOUT|INCAPACITATION_STUNNED))
|
||||
return
|
||||
|
||||
if(!access_cable)
|
||||
to_chat(user, SPAN_WARNING("You don't have an access cable anymore!"))
|
||||
return
|
||||
|
||||
// it's an organ, should never be not human type
|
||||
var/mob/living/carbon/human/synth = user
|
||||
if(synth.get_active_hand())
|
||||
to_chat(synth, SPAN_WARNING("You need a free hand to retrieve your universal access cable!"))
|
||||
return
|
||||
|
||||
if(access_cable.loc != src)
|
||||
// not sure how NOT having a target and being here would work, but it's a fallback just in case things bug out
|
||||
if(access_cable.target)
|
||||
visible_message(SPAN_NOTICE("[owner] disconnects their [access_cable] from \the [access_cable.target]."))
|
||||
access_cable.target.remove_cable(access_cable)
|
||||
access_cable.clear_cable_full()
|
||||
access_cable.forceMove(src)
|
||||
return
|
||||
|
||||
if(get_integrity() < 75)
|
||||
to_chat(user, SPAN_WARNING("You struggle to pry the cable out of the damaged port..."))
|
||||
if(!do_after(user, 2 SECONDS))
|
||||
return
|
||||
|
||||
synth.visible_message(SPAN_NOTICE("[synth] extends their universal access cable from their neck."), SPAN_NOTICE("You retrieve your universal access cable from your neck."))
|
||||
synth.put_in_active_hand(access_cable)
|
||||
|
||||
/**
|
||||
* This proc is called whenever anything is inserted into the internal port.
|
||||
*/
|
||||
/obj/item/organ/internal/machine/access_port/proc/insert_item(obj/item/jack)
|
||||
SIGNAL_HANDLER
|
||||
if(internal_port)
|
||||
crash_with("Insert_item with [jack] on access port called with [internal_port] of [owner] already present!")
|
||||
|
||||
internal_port = jack
|
||||
jack.forceMove(src)
|
||||
RegisterSignal(internal_port, COMSIG_QDELETING, PROC_REF(clear_port))
|
||||
to_chat(owner, SPAN_MACHINE_WARNING("Internal firewall notice: [internal_port] inserted into [src]."))
|
||||
|
||||
/**
|
||||
* This proc is called whenever the access cable is, for some reason, qdeleted (like with an explosion).
|
||||
*/
|
||||
/obj/item/organ/internal/machine/access_port/proc/clear_cable()
|
||||
SIGNAL_HANDLER
|
||||
if(!access_cable)
|
||||
return
|
||||
|
||||
UnregisterSignal(access_cable, COMSIG_QDELETING)
|
||||
access_cable = null
|
||||
to_chat(owner, SPAN_WARNING("You lose contact with your access cable!"))
|
||||
|
||||
/**
|
||||
* This proc is called whenever the internal access port is emptied of whatever was in there previously.
|
||||
*/
|
||||
/obj/item/organ/internal/machine/access_port/proc/clear_port()
|
||||
if(!internal_port)
|
||||
return
|
||||
|
||||
if(istype(internal_port, /obj/item/access_cable))
|
||||
var/obj/item/access_cable/ejected_cable = internal_port
|
||||
ejected_cable.target = null
|
||||
|
||||
UnregisterSignal(internal_port, COMSIG_QDELETING)
|
||||
internal_port = null
|
||||
|
||||
/obj/item/organ/internal/machine/access_port/insert_cable(obj/item/access_cable/cable, mob/user)
|
||||
. = ..()
|
||||
insert_item(cable)
|
||||
cable.create_cable(owner)
|
||||
|
||||
/obj/item/organ/internal/machine/access_port/cable_interact(obj/item/access_cable/cable, mob/user)
|
||||
var/obj/item/organ/internal/machine/internal_diagnostics/diagnostics_unit = owner.internal_organs_by_name[BP_DIAGNOSTICS_SUITE]
|
||||
if(!diagnostics_unit)
|
||||
to_chat(user, SPAN_WARNING("There is no diagnostics unit!"))
|
||||
return
|
||||
|
||||
var/obj/item/organ/internal/machine/posibrain/posibrain = owner.internal_organs_by_name[BP_BRAIN]
|
||||
if(istype(posibrain))
|
||||
if(posibrain.firewall && !user.stat)
|
||||
to_chat(user, SPAN_MACHINE_WARNING("Firewall block detected. Aborting."))
|
||||
to_chat(diagnostics_unit.owner, SPAN_MACHINE_WARNING("Your firewall has blocked an unrecognized access attempt."))
|
||||
return
|
||||
|
||||
diagnostics_unit.open_diagnostics(user)
|
||||
|
||||
/obj/item/access_cable
|
||||
name = "external access cable"
|
||||
desc = "A cable with universal access pins at its end. This is meant for jacking into synthetics to access their data."
|
||||
icon = 'icons/obj/organs/ipc_organs.dmi'
|
||||
icon_state = "cable"
|
||||
pickup_sound = 'sound/species/synthetic/access_cable_out.ogg'
|
||||
w_class = WEIGHT_CLASS_NO_CONTAINER
|
||||
|
||||
/// Where this cable is extending from.
|
||||
var/obj/source
|
||||
/// If the source is an object in another object (like an organ), then this is where we actually want the cable beam to extend from physically.
|
||||
var/atom/movable/beam_anchor
|
||||
/// Where this cable is attached to.
|
||||
var/obj/target
|
||||
/// The actual target of the /datum/beam coming from the cable.
|
||||
var/atom/movable/beam_target
|
||||
/// The beam connecting us to the source.
|
||||
var/datum/beam/cable
|
||||
/// The range this cable has. Past this range, it will disconnect.
|
||||
var/range = 3
|
||||
|
||||
/obj/item/access_cable/Initialize(mapload, atom/movable/cable_source, atom/movable/cable_beam_anchor)
|
||||
. = ..()
|
||||
if(!cable_source)
|
||||
log_debug("Access cable spawned without a source: [x] [y] [z]")
|
||||
qdel_self()
|
||||
return
|
||||
|
||||
source = cable_source
|
||||
if(cable_beam_anchor)
|
||||
beam_anchor = cable_beam_anchor
|
||||
RegisterSignal(src, COMSIG_MOVABLE_MOVED, PROC_REF(check_retract_range), TRUE)
|
||||
|
||||
/obj/item/access_cable/Destroy()
|
||||
source = null
|
||||
target = null
|
||||
beam_anchor = null
|
||||
beam_target = null
|
||||
if(cable)
|
||||
cable.End()
|
||||
QDEL_NULL(cable)
|
||||
return ..()
|
||||
|
||||
/**
|
||||
* When the cable is actually taken out of an object and thus is shown in world.
|
||||
* The parameters here might be different from the source/target variables on the cable itself.
|
||||
* For example, the source of a synthetic access cable is the power port, although that's physically inside a human mob and so we can't draw a beam to it.
|
||||
* We have to draw a beam from the human in that case.
|
||||
*/
|
||||
/obj/item/access_cable/proc/create_cable(var/atom/new_target)
|
||||
clear_cable_visuals()
|
||||
beam_target = new_target
|
||||
RegisterSignal(beam_anchor ? beam_anchor : source, COMSIG_MOVABLE_MOVED, PROC_REF(check_retract_range), TRUE)
|
||||
RegisterSignal(beam_target, COMSIG_MOVABLE_MOVED, PROC_REF(check_retract_range), TRUE)
|
||||
cable = new(beam_anchor ? beam_anchor : source, beam_target, beam_icon_state = "cable", time = -1, maxdistance = range + 1)
|
||||
cable.Start()
|
||||
|
||||
/obj/item/access_cable/dropped(mob/user)
|
||||
. = ..()
|
||||
clear_cable_visuals()
|
||||
create_cable(src)
|
||||
|
||||
/obj/item/access_cable/pickup(mob/user)
|
||||
. = ..()
|
||||
clear_cable_visuals()
|
||||
|
||||
/**
|
||||
* Signal handler.
|
||||
* If the cable moves beyond its range, automatically retract it.
|
||||
*/
|
||||
/obj/item/access_cable/proc/check_retract_range()
|
||||
SIGNAL_HANDLER
|
||||
if(source == loc)
|
||||
return
|
||||
|
||||
if(get_dist(source, src) > range)
|
||||
retract()
|
||||
|
||||
/**
|
||||
* Automatically drop the cable and then retract it to the parent.
|
||||
*/
|
||||
/obj/item/access_cable/proc/retract()
|
||||
visible_message(SPAN_NOTICE("\The [src] automatically retracts into \the [source]!"))
|
||||
forceMove(source)
|
||||
clear_cable_full()
|
||||
|
||||
/**
|
||||
* Retracts the cable back into the parent object.
|
||||
*/
|
||||
/obj/item/access_cable/proc/clear_cable_full()
|
||||
UnregisterSignal(beam_anchor ? beam_anchor : source, COMSIG_MOVABLE_MOVED)
|
||||
if(target)
|
||||
target.remove_cable(src)
|
||||
target = null
|
||||
clear_cable_visuals()
|
||||
|
||||
/**
|
||||
* Only clears the cable visuals (so, just the beam).
|
||||
*/
|
||||
/obj/item/access_cable/proc/clear_cable_visuals()
|
||||
if(beam_target)
|
||||
UnregisterSignal(beam_target, COMSIG_MOVABLE_MOVED)
|
||||
|
||||
beam_target = null
|
||||
if(cable)
|
||||
cable.End()
|
||||
QDEL_NULL(cable)
|
||||
|
||||
/obj/item/access_cable/proc/target_interact(mob/user)
|
||||
if(!target || !user)
|
||||
return
|
||||
|
||||
target.cable_interact(src, user)
|
||||
|
||||
/obj/item/access_cable/attack(mob/living/target_mob, mob/living/user, target_zone)
|
||||
if(ishuman(target_mob))
|
||||
var/mob/living/carbon/human/human = target_mob
|
||||
if(!isipc(human))
|
||||
to_chat(user, SPAN_WARNING("Where are you planning to put that...?"))
|
||||
return
|
||||
|
||||
var/obj/item/organ/internal/machine/access_port/access_port = human.internal_organs_by_name[BP_ACCESS_PORT]
|
||||
if(!access_port)
|
||||
to_chat(user, SPAN_WARNING("[human] does not have an access port!"))
|
||||
return
|
||||
|
||||
if(access_port.access_cable == src)
|
||||
to_chat(user, SPAN_WARNING("You can't put your own cable into your own access port, as funny as it would be."))
|
||||
return
|
||||
|
||||
if(access_port.is_broken())
|
||||
to_chat(user, SPAN_WARNING("[human]'s access port is completely broken! There's no way you can jack into it!"))
|
||||
return
|
||||
|
||||
if(access_port.internal_port)
|
||||
to_chat(user, SPAN_WARNING("The access port is already occupied by [access_port.internal_port]!"))
|
||||
return
|
||||
|
||||
if(user != human)
|
||||
if(human.client && !human.incapacitated(INCAPACITATION_FORCELYING|INCAPACITATION_RESTRAINED|INCAPACITATION_BUCKLED_FULLY|INCAPACITATION_BUCKLED_PARTIALLY))
|
||||
var/request = tgui_alert(human, "[user] would like to access your access port. Allow them?", "Access Port", list("Yes", "No"))
|
||||
if(request != "Yes")
|
||||
human.visible_message(SPAN_NOTICE("[human] pushes away [user]'s [src]."))
|
||||
return
|
||||
|
||||
user.visible_message(SPAN_WARNING("[user] tries to jack \the [src] into [human]'s access port..."))
|
||||
if(!do_mob(user, human, 2 SECONDS))
|
||||
return
|
||||
user.visible_message(SPAN_WARNING("[user] jacks \the [src] into [human]'s access port!"))
|
||||
|
||||
else
|
||||
user.visible_message(SPAN_WARNING("[user] jacks \the [src] into their access port!"), SPAN_WARNING("You jack \the [src] into your access port!"))
|
||||
|
||||
user.drop_from_inventory(src, get_turf(user))
|
||||
access_port.insert_cable(src, user)
|
||||
else
|
||||
. = ..()
|
||||
|
||||
/obj/item/access_cable/synthetic
|
||||
name = "universal access cable"
|
||||
desc = "A cable with universal access pins at its end. This particular access cable comes with most synthetics' access ports for quick access to electronics, firewalls, or other synthetics' diagnostics systems."
|
||||
|
||||
/obj/item/access_cable/synthetic/mechanics_hints()
|
||||
. = ..()
|
||||
. += "To retract this cable into your port, <span class='notice'>activate it in-hand."
|
||||
|
||||
/obj/item/access_cable/synthetic/attack_self(mob/user, modifiers)
|
||||
if(isipc(user))
|
||||
var/mob/living/carbon/human/synth = user
|
||||
var/obj/item/organ/internal/machine/access_port/access_port = synth.internal_organs_by_name[BP_ACCESS_PORT]
|
||||
if(!access_port)
|
||||
to_chat(synth, SPAN_WARNING("Where's your access port?!"))
|
||||
return ..()
|
||||
|
||||
if(access_port.is_broken())
|
||||
to_chat(synth, SPAN_WARNING("Your access port is completely broken! It won't go in!"))
|
||||
return ..()
|
||||
|
||||
if(access_port.get_integrity() <= IPC_INTEGRITY_THRESHOLD_MEDIUM)
|
||||
synth.visible_message(SPAN_WARNING("[synth] tries to jam [synth.get_pronoun("his")] access cable back into their access port..."), SPAN_WARNING("You try to jam your access cable back into your access port..."))
|
||||
if(!do_after(synth, 3 SECONDS))
|
||||
return ..()
|
||||
|
||||
synth.visible_message(SPAN_NOTICE("[synth] retracts [synth.get_pronoun("his")] access cable back into their access port."), SPAN_NOTICE("You retract your access cable back into your access port."))
|
||||
synth.drop_from_inventory(src, get_turf(src))
|
||||
forceMove(access_port)
|
||||
clear_cable_full()
|
||||
playsound(user, 'sound/species/synthetic/access_cable_in.ogg', 50)
|
||||
|
||||
/mob/living/carbon/human/proc/access_cable()
|
||||
set name = "Access Cable"
|
||||
set category = "Object"
|
||||
|
||||
if(!isipc(src))
|
||||
return
|
||||
|
||||
var/obj/item/organ/internal/machine/access_port/access_port = internal_organs_by_name[BP_ACCESS_PORT]
|
||||
if(!access_port)
|
||||
to_chat(src, SPAN_WARNING("Where's your access port?!"))
|
||||
return
|
||||
|
||||
if(access_port.is_broken())
|
||||
to_chat(src, SPAN_WARNING("Your access port's only feedback is crackling static and jumbled code!"))
|
||||
return
|
||||
|
||||
var/obj/item/access_cable/access_cable = access_port.access_cable
|
||||
if(!access_cable)
|
||||
to_chat(src, SPAN_WARNING("Your access cable is missing!"))
|
||||
return
|
||||
|
||||
if(!access_cable.target)
|
||||
to_chat(src, SPAN_WARNING("You need to connect your cable to something first!"))
|
||||
return
|
||||
|
||||
access_cable.target_interact(src)
|
||||
@@ -0,0 +1,31 @@
|
||||
/obj/item/organ/internal/machine/actuators
|
||||
name = "actuators"
|
||||
desc = "This mixture of electronic, pneumatic and hydraulic components allow a positronic chassis' arms to produce force and torque to allow them to move their artificial limbs."
|
||||
icon = 'icons/obj/organs/ipc_organs.dmi'
|
||||
icon_state = "ipc_actuator"
|
||||
|
||||
max_damage = 40
|
||||
relative_size = 70
|
||||
|
||||
/obj/item/organ/internal/machine/actuators/left
|
||||
name = "left arm actuators"
|
||||
organ_tag = BP_ACTUATORS_LEFT
|
||||
parent_organ = BP_L_ARM
|
||||
organ_tag = BP_ACTUATORS_LEFT
|
||||
|
||||
/obj/item/organ/internal/machine/actuators/right
|
||||
name = "right arm actuators"
|
||||
organ_tag = BP_ACTUATORS_RIGHT
|
||||
parent_organ = BP_R_ARM
|
||||
organ_tag = BP_ACTUATORS_RIGHT
|
||||
|
||||
/obj/item/organ/internal/machine/actuators/high_integrity_damage(integrity)
|
||||
if(prob(get_integrity_damage_probability()))
|
||||
spark(owner, 5, GLOB.alldirs)
|
||||
to_chat(owner, SPAN_WARNING("Your [src] malfunction, making you drop what you're holding!"))
|
||||
switch(parent_organ)
|
||||
if(BP_L_ARM)
|
||||
owner.drop_l_hand()
|
||||
if(BP_R_ARM)
|
||||
owner.drop_r_hand()
|
||||
. = ..()
|
||||
@@ -0,0 +1,255 @@
|
||||
#define COOLING_UNIT_DEFAULT_THERMOSTAT_MAX 323.15
|
||||
#define COOLING_UNIT_DEFAULT_MAX_SAFE_TEMP 423.15
|
||||
|
||||
/obj/item/organ/internal/machine/cooling_unit
|
||||
name = "air cooling unit"
|
||||
desc = "One of the most complex and vital components of a synthetic. It regulates its internal temperature and prevents the chassis from overheating."
|
||||
icon = 'icons/obj/organs/ipc_organs.dmi'
|
||||
icon_state = "ipc_fans"
|
||||
organ_tag = BP_COOLING_UNIT
|
||||
parent_organ = BP_CHEST
|
||||
possible_modifications = list("Air Cooling", "Liquid Cooling", "Passive Cooling")
|
||||
organ_presets = list(
|
||||
ORGAN_PREF_AIRCOOLED = /singleton/synthetic_organ_preset/cooling_unit/air,
|
||||
ORGAN_PREF_LIQUIDCOOLED = /singleton/synthetic_organ_preset/cooling_unit/liquid,
|
||||
ORGAN_PREF_PASSIVECOOLED = /singleton/synthetic_organ_preset/cooling_unit/passive
|
||||
)
|
||||
default_preset = /singleton/synthetic_organ_preset/cooling_unit/air
|
||||
action_button_name = "Regulate Thermostat"
|
||||
|
||||
max_damage = 70
|
||||
relative_size = 50
|
||||
|
||||
/// The power consumed when we are cooling down.
|
||||
var/base_power_consumption = 8
|
||||
/// The passive temperature change. Basically, cooling units counteract an IPC's passive temperature gain. But the IPC's temperature goes to get itself fucked if the cooling unit dies.
|
||||
/// Remember, can be negative or positive. Depends on what we're trying to stabilize towards.
|
||||
var/passive_temp_change = 2
|
||||
/// The temperature that this cooling unit tries to regulate towards.
|
||||
var/thermostat = T20C
|
||||
/// The minimum value the thermostat can reach. 0C.
|
||||
var/thermostat_min = T0C
|
||||
/// The maximum value the thermostat can reach. 50C.
|
||||
var/thermostat_max = COOLING_UNIT_DEFAULT_THERMOSTAT_MAX
|
||||
/// Can this cooling unit work in space?
|
||||
var/spaceproof = FALSE
|
||||
/// The temperature at which this cooling unit will disable running if safeties are on.
|
||||
var/maximum_safe_temperature = COOLING_UNIT_DEFAULT_MAX_SAFE_TEMP
|
||||
/// If the safeties that automatically disable sprinting when bodytemperature exceeds safe limits are disabled or not.
|
||||
var/temperature_safety = TRUE
|
||||
/// If the safety has been burnt and thus will not engage.
|
||||
var/safety_burnt = FALSE
|
||||
/// If the thermostat is locked and thus cannot be changed. Used for spooky effects, like the high integrity damage in the positronic brain.
|
||||
var/locked_thermostat = FALSE
|
||||
|
||||
/obj/item/organ/internal/machine/cooling_unit/Initialize()
|
||||
. = ..()
|
||||
if(owner)
|
||||
RegisterSignal(owner, COMSIG_IPC_HAS_SPRINTED, PROC_REF(handle_safeties))
|
||||
|
||||
/obj/item/organ/internal/machine/cooling_unit/attack_self(var/mob/user)
|
||||
. = ..()
|
||||
if(owner.last_special > world.time)
|
||||
return
|
||||
|
||||
if(user.stat == DEAD)
|
||||
return
|
||||
|
||||
if(user.incapacitated(INCAPACITATION_KNOCKOUT|INCAPACITATION_STUNNED))
|
||||
return
|
||||
|
||||
ui_interact(user)
|
||||
|
||||
/obj/item/organ/internal/machine/cooling_unit/ui_interact(mob/user, datum/tgui/ui)
|
||||
. = ..()
|
||||
ui = SStgui.try_update_ui(user, src, ui)
|
||||
if(!ui)
|
||||
ui = new(user, src, "CoolingUnitThermostat", "Cooling Unit Regulation", 400, 600)
|
||||
ui.open()
|
||||
|
||||
/obj/item/organ/internal/machine/cooling_unit/ui_data(mob/user)
|
||||
var/list/data = list()
|
||||
// K = C + 273.15 | C = K – 273.15
|
||||
// we want to pass celsius for readability,
|
||||
// the average american can't figure out celsius, let alone kelvin
|
||||
var/broken = is_broken()
|
||||
data["broken"] = broken
|
||||
if(!broken)
|
||||
data["thermostat"] = thermostat - 273.15
|
||||
data["thermostat_min"] = thermostat_min - 273.15
|
||||
data["thermostat_max"] = thermostat_max - 273.15
|
||||
data["passive_temp_change"] = passive_temp_change
|
||||
data["bodytemperature"] = owner.bodytemperature - 273.15
|
||||
data["temperature_safety"] = temperature_safety
|
||||
|
||||
var/estimated_power_consumption = base_power_consumption
|
||||
var/integrity = get_integrity()
|
||||
if(integrity < IPC_INTEGRITY_THRESHOLD_MEDIUM)
|
||||
estimated_power_consumption = rand(-50, 100 + (100 - integrity))
|
||||
|
||||
if(thermostat < initial(thermostat))
|
||||
// The higher the distance between the maximum thermostat setting and what we're actually at, the harder the cooling unit will work to cool us.
|
||||
var/temperature_distance = round(thermostat_max - thermostat, 1)
|
||||
estimated_power_consumption = temperature_distance * 0.5
|
||||
else if(thermostat > initial(thermostat))
|
||||
// higher thermostat = less power usage
|
||||
estimated_power_consumption = -(thermostat_max / thermostat) - 0.5
|
||||
|
||||
data["estimated_power_consumption"] = max(0, base_power_consumption + estimated_power_consumption)
|
||||
data["safety_burnt"] = safety_burnt
|
||||
return data
|
||||
|
||||
/obj/item/organ/internal/machine/cooling_unit/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state)
|
||||
. = ..()
|
||||
if(action == "change_thermostat")
|
||||
if(locked_thermostat)
|
||||
to_chat(owner, SPAN_MACHINE_WARNING("You can't change the thermostat manually! It just returns an error!"))
|
||||
return FALSE
|
||||
|
||||
var/new_thermostat = params["change_thermostat"]
|
||||
// remember we are getting passed celsius here
|
||||
new_thermostat += T0C
|
||||
if(new_thermostat >= thermostat_min && new_thermostat <= thermostat_max)
|
||||
thermostat = new_thermostat
|
||||
. = TRUE
|
||||
|
||||
if(action == "temperature_safety")
|
||||
if(safety_burnt)
|
||||
return
|
||||
|
||||
temperature_safety = !temperature_safety
|
||||
to_chat(usr, temperature_safety ? SPAN_NOTICE("You re-enable your temperature safety.") : SPAN_WARNING("You disable your temperature safety!"))
|
||||
. = TRUE
|
||||
|
||||
/obj/item/organ/internal/machine/cooling_unit/process(seconds_per_tick)
|
||||
. = ..()
|
||||
if(!owner)
|
||||
return
|
||||
|
||||
// Cooling units try to counteract external temperature by stabilizing towards ambient temperature.
|
||||
var/turf/T = get_turf(owner)
|
||||
if(!T)
|
||||
// Some odd scenarios can cause there to be no turf. Like getting teleported into the game from lobby.
|
||||
return
|
||||
|
||||
var/datum/gas_mixture/ambient = T.return_air()
|
||||
// Too much heat is bad for the cooling unit.
|
||||
if(owner.bodytemperature > species.heat_level_1)
|
||||
if(prob(owner.bodytemperature * 0.1))
|
||||
take_internal_damage(owner.bodytemperature * 0.01)
|
||||
|
||||
var/temperature_change = passive_temp_change
|
||||
if(owner.wear_suit)
|
||||
if(!spaceproof && istype(owner.wear_suit, /obj/item/clothing/suit/space))
|
||||
//cooling is going to SUCK if you have heat-regulating clothes
|
||||
if(owner.bodytemperature < species.heat_level_3)
|
||||
owner.bodytemperature = min(owner.bodytemperature + 5, owner.species.heat_level_2)
|
||||
temperature_change *= 0.5
|
||||
|
||||
// Check if there is somehow no air, or if we are in an ambient without enough air to properly cool us.
|
||||
if((!ambient || (ambient && owner.calculate_affecting_pressure(ambient.return_pressure()) < owner.species.warning_low_pressure)))
|
||||
if(!spaceproof)
|
||||
temperature_change *= 0
|
||||
else
|
||||
temperature_change = min(temperature_change * 3, 10) //give it a little boost to counteract temp gain in space
|
||||
|
||||
if(is_broken())
|
||||
temperature_change *= 0.5 //uh oh
|
||||
else if(is_bruised())
|
||||
temperature_change *= 0.75
|
||||
|
||||
// Now let's start cooling down!
|
||||
// No power, no party.
|
||||
var/obj/item/organ/internal/machine/power_core/cell = owner.internal_organs_by_name[BP_CELL]
|
||||
if(!istype(cell))
|
||||
return
|
||||
|
||||
// The lower our thermostat setting, the more power we consume.
|
||||
var/extra_efficiency_multiplier = 1
|
||||
var/extra_power_consumption = 0
|
||||
if(thermostat < initial(thermostat))
|
||||
// The higher the distance between the maximum thermostat setting and what we're actually at, the harder the cooling unit will work to cool us.
|
||||
var/temperature_distance = round(thermostat_max - thermostat, 1)
|
||||
extra_power_consumption = temperature_distance * 0.5
|
||||
extra_efficiency_multiplier = temperature_distance * 0.05
|
||||
else if(thermostat > initial(thermostat))
|
||||
// higher thermostat = less power usage
|
||||
extra_power_consumption = -(thermostat_max / thermostat) - 0.5
|
||||
|
||||
if(thermostat < owner.bodytemperature)
|
||||
owner.bodytemperature = max(owner.bodytemperature - temperature_change * extra_efficiency_multiplier, thermostat)
|
||||
cell.use(max(0, base_power_consumption + extra_power_consumption))
|
||||
|
||||
/obj/item/organ/internal/machine/cooling_unit/low_integrity_damage(integrity)
|
||||
if(get_integrity_damage_probability())
|
||||
to_chat(owner, SPAN_WARNING("Your temperature sensors pick up a spike in temperature."))
|
||||
owner.bodytemperature = min(owner.bodytemperature + 10, owner.species.heat_level_2)
|
||||
. = ..()
|
||||
|
||||
/obj/item/organ/internal/machine/cooling_unit/medium_integrity_damage(integrity)
|
||||
if(get_integrity_damage_probability() / 2)
|
||||
to_chat(owner, SPAN_WARNING("Your thermostat's temperature setting goes haywire!"))
|
||||
thermostat = rand(thermostat_min, thermostat_max)
|
||||
owner.bodytemperature = min(owner.bodytemperature + 20, owner.species.heat_level_2)
|
||||
|
||||
if(prob(25) && !safety_burnt)
|
||||
to_chat(owner, SPAN_WARNING("Your temperature safeties burn out! They won't work anymore!"))
|
||||
safety_burnt = TRUE
|
||||
. = ..()
|
||||
|
||||
/obj/item/organ/internal/machine/cooling_unit/high_integrity_damage(integrity)
|
||||
if(get_integrity_damage_probability() / 3)
|
||||
if(spaceproof)
|
||||
playsound(owner, pick(SOUNDS_LASER_METAL), 50)
|
||||
to_chat(owner, SPAN_DANGER(FONT_LARGE("Your laminar cooling stratum has melted. Your cooling unit will not work in space anymore!")))
|
||||
spaceproof = FALSE
|
||||
else if(thermostat_min < (initial(thermostat_min) + 100))
|
||||
playsound(owner, pick(SOUNDS_LASER_METAL), 50)
|
||||
to_chat(owner, SPAN_DANGER(FONT_LARGE("Parts of your cooling unit melt away...!")))
|
||||
update_thermostat(thermostat_min + round(rand(10, 50)))
|
||||
owner.bodytemperature = min(owner.bodytemperature + 30, owner.species.heat_level_2)
|
||||
. = ..()
|
||||
|
||||
/obj/item/organ/internal/machine/cooling_unit/proc/update_thermostat(new_thermostat_min, new_thermostat_max)
|
||||
if(new_thermostat_min)
|
||||
thermostat_min = new_thermostat_min
|
||||
if(thermostat < new_thermostat_min)
|
||||
thermostat = new_thermostat_min
|
||||
|
||||
if(thermostat_max < new_thermostat_max)
|
||||
thermostat_max = new_thermostat_min
|
||||
|
||||
if(new_thermostat_max)
|
||||
thermostat_max = new_thermostat_max
|
||||
if(new_thermostat_max < thermostat_min)
|
||||
thermostat_min = new_thermostat_max
|
||||
|
||||
/obj/item/organ/internal/machine/cooling_unit/proc/handle_safeties()
|
||||
if(!owner)
|
||||
return
|
||||
|
||||
if((owner.bodytemperature > maximum_safe_temperature) && temperature_safety && !safety_burnt)
|
||||
to_chat(owner, SPAN_DANGER("Your temperature safeties engage and stop you from running further!"))
|
||||
owner.balloon_alert(owner, "safeties engaged")
|
||||
owner.m_intent = M_WALK
|
||||
owner.hud_used.move_intent.update_move_icon(owner)
|
||||
|
||||
/obj/item/organ/internal/machine/cooling_unit/xion
|
||||
spaceproof = TRUE
|
||||
organ_presets = list(
|
||||
ORGAN_PREF_AIRCOOLED = /singleton/synthetic_organ_preset/cooling_unit/air_xion,
|
||||
ORGAN_PREF_LIQUIDCOOLED = /singleton/synthetic_organ_preset/cooling_unit/liquid_xion,
|
||||
ORGAN_PREF_PASSIVECOOLED = /singleton/synthetic_organ_preset/cooling_unit/passive_xion
|
||||
)
|
||||
default_preset = /singleton/synthetic_organ_preset/cooling_unit/air_xion
|
||||
|
||||
/obj/item/organ/internal/machine/cooling_unit/zenghu
|
||||
organ_presets = list(
|
||||
ORGAN_PREF_AIRCOOLED = /singleton/synthetic_organ_preset/cooling_unit/air_zenghu,
|
||||
ORGAN_PREF_LIQUIDCOOLED = /singleton/synthetic_organ_preset/cooling_unit/liquid_zenghu,
|
||||
ORGAN_PREF_PASSIVECOOLED = /singleton/synthetic_organ_preset/cooling_unit/passive_zenghu
|
||||
)
|
||||
default_preset = /singleton/synthetic_organ_preset/cooling_unit/air_zenghu
|
||||
|
||||
#undef COOLING_UNIT_DEFAULT_THERMOSTAT_MAX
|
||||
#undef COOLING_UNIT_DEFAULT_MAX_SAFE_TEMP
|
||||
@@ -0,0 +1,133 @@
|
||||
/*
|
||||
* These are presets for the cooling unit data. Essentially, each type of cooling unit can have its own presets (depending on pref setting)
|
||||
* that change the name, description, and functioning of the cooling unit.
|
||||
*/
|
||||
|
||||
/singleton/synthetic_organ_preset/cooling_unit
|
||||
/// The name the cooling unit organ will have.
|
||||
name = "epic cooling unit"
|
||||
/// The description the cooling unit organ will get.
|
||||
desc = "It cools epically."
|
||||
/// The passive temperature change the cooling unit will have.
|
||||
var/passive_temp_change = 3
|
||||
/// The power used when cooling down.
|
||||
var/base_power_consumption = 2.5
|
||||
/// The maximum health the cooling unit's plating will have.
|
||||
var/plating_max_health = 20
|
||||
|
||||
/singleton/synthetic_organ_preset/cooling_unit/apply_preset(obj/item/organ/internal/machine/organ)
|
||||
. = ..()
|
||||
var/obj/item/organ/internal/machine/cooling_unit/cooling_unit = organ
|
||||
cooling_unit.passive_temp_change = passive_temp_change
|
||||
cooling_unit.base_power_consumption = base_power_consumption
|
||||
cooling_unit.plating.replace_health(plating_max_health)
|
||||
|
||||
/singleton/synthetic_organ_preset/cooling_unit/air
|
||||
name = "air cooling unit"
|
||||
desc = "One of the most complex and vital components of a synthetic. It regulates its internal temperature through the use of chassis-mounted fans and prevents the frame from overheating."
|
||||
|
||||
passive_temp_change = 2
|
||||
plating_max_health = 50
|
||||
|
||||
/obj/item/organ/internal/machine/cooling_unit/air
|
||||
forced_preset = /singleton/synthetic_organ_preset/cooling_unit/air
|
||||
|
||||
/singleton/synthetic_organ_preset/cooling_unit/liquid
|
||||
name = "liquid-cooling pump and radiator array"
|
||||
desc = "An extremely complex set of cooling pipes that transport coolant throughout a synthetic's body. The most efficient type of cooling, but also the most vulnerable."
|
||||
icon_state = "ipc_liquid_cooler"
|
||||
|
||||
passive_temp_change = 3
|
||||
base_power_consumption = 7.5
|
||||
plating_max_health = 20
|
||||
|
||||
/obj/item/organ/internal/machine/cooling_unit/liquid
|
||||
forced_preset = /singleton/synthetic_organ_preset/cooling_unit/liquid
|
||||
|
||||
/singleton/synthetic_organ_preset/cooling_unit/passive
|
||||
name = "passive radiator cooling block"
|
||||
desc = "A simplistic, but efficient block of large cooling fins, which cool down a synthetic's body enough to make it work. Quite cheap, but durable."
|
||||
icon_state = "ipc_liquid_cooler"
|
||||
|
||||
passive_temp_change = 1
|
||||
base_power_consumption = 2.5
|
||||
plating_max_health = 100
|
||||
|
||||
/obj/item/organ/internal/machine/cooling_unit/passive
|
||||
forced_preset = /singleton/synthetic_organ_preset/cooling_unit/passive
|
||||
|
||||
// Xion cooling units.
|
||||
/singleton/synthetic_organ_preset/cooling_unit/air_xion
|
||||
name = "xion manufacturing advanced air cooling unit"
|
||||
desc = "A very complex air cooling setup, with high-grade laminar plasteel fans and integrated space-proof heatsinks to allow the frame to still be cooled in space."
|
||||
icon_state = "ipc_xion_fans"
|
||||
|
||||
passive_temp_change = 2
|
||||
base_power_consumption = 6
|
||||
plating_max_health = 70
|
||||
|
||||
/obj/item/organ/internal/machine/cooling_unit/air/xion
|
||||
forced_preset = /singleton/synthetic_organ_preset/cooling_unit/air_xion
|
||||
|
||||
/singleton/synthetic_organ_preset/cooling_unit/liquid_xion
|
||||
name = "xion manufacturing advanced cryo-cooling pump and radiator array"
|
||||
desc = "An extremely complex cryo-cooling setup. It uses advanced coolant to allow the frame to still function in space - but its laminar super-flow piping is extremely fragile."
|
||||
icon_state = "ipc_xion_liquid_cooler"
|
||||
|
||||
passive_temp_change = 3
|
||||
base_power_consumption = 8
|
||||
plating_max_health = 35
|
||||
|
||||
/obj/item/organ/internal/machine/cooling_unit/liquid/xion
|
||||
forced_preset = /singleton/synthetic_organ_preset/cooling_unit/liquid_xion
|
||||
|
||||
/singleton/synthetic_organ_preset/cooling_unit/passive_xion
|
||||
name = "xion manufacturing passive intra-fin array"
|
||||
desc = "The simplicity of this cooling design betrays its efficiency: an extremely durable array of laminar plasteel fins, supplemented with an expensive coating that allows the synthetic to be cooled even in space."
|
||||
icon_state = "ipc_heatsink"
|
||||
|
||||
passive_temp_change = 1
|
||||
base_power_consumption = 3.5
|
||||
plating_max_health = 120
|
||||
|
||||
/obj/item/organ/internal/machine/cooling_unit/passive/xion
|
||||
forced_preset = /singleton/synthetic_organ_preset/cooling_unit/passive_xion
|
||||
|
||||
// Zenghu cooling units.
|
||||
/singleton/synthetic_organ_preset/cooling_unit/air_zenghu
|
||||
name = "zeng-hu penta-fan air cooling system"
|
||||
desc = "A sleek and luxurious air cooling system invented by Zeng-Hu for their house-made synthetic frames. It uses a patented and exclusive type of penta-fin fan. More efficient than standard air cooling solutions, but it will not allow cooling in space."
|
||||
icon_state = "ipc_zeng_fans"
|
||||
|
||||
passive_temp_change = 4
|
||||
base_power_consumption = 7.5
|
||||
plating_max_health = 25
|
||||
|
||||
/obj/item/organ/internal/machine/cooling_unit/air/zenghu
|
||||
forced_preset = /singleton/synthetic_organ_preset/cooling_unit/air_zenghu
|
||||
|
||||
/singleton/synthetic_organ_preset/cooling_unit/liquid_zenghu
|
||||
name = "zeng-hu lamellar liquid cooling system"
|
||||
desc = "A sleek set of superimposed lamellar pipes with a custom cooling solution. In black market and enthusiast repair forums, this is known as 'the enthusiast's nightmare' due to its practical impossibility to repair in anything less than a Zeng-Hu facility; \
|
||||
the lamellar pipes are impossible to reproduce or find through a third-party solution due to their extremely complex and exclusive Zeng-Hu make."
|
||||
icon_state = "ipc_zeng_cooling"
|
||||
|
||||
passive_temp_change = 5
|
||||
base_power_consumption = 10
|
||||
plating_max_health = 15
|
||||
|
||||
/obj/item/organ/internal/machine/cooling_unit/liquid/zenghu
|
||||
forced_preset = /singleton/synthetic_organ_preset/cooling_unit/liquid_zenghu
|
||||
|
||||
/singleton/synthetic_organ_preset/cooling_unit/passive_zenghu
|
||||
name = "zeng-hu suprafin cooling fins"
|
||||
desc = "A sleek set of engraved, plasteel fins patented by Zeng-Hu as 'suprafins'. The engravings help increase thermal area to the maximum possible, and a specialized cooling solution is imprinted onto the fins to improve their cooling ability."
|
||||
icon_state = "ipc_zeng_cooling_passive"
|
||||
|
||||
passive_temp_change = 2
|
||||
base_power_consumption = 4
|
||||
plating_max_health = 75
|
||||
|
||||
/obj/item/organ/internal/machine/cooling_unit/passive/zenghu
|
||||
forced_preset = /singleton/synthetic_organ_preset/cooling_unit/passive_zenghu
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
/obj/item/organ/internal/machine/data
|
||||
name = "data core"
|
||||
organ_tag = "data core"
|
||||
parent_organ = BP_GROIN
|
||||
icon = 'icons/obj/cloning.dmi'
|
||||
icon_state = "harddisk"
|
||||
vital = FALSE
|
||||
emp_coeff = 0.1
|
||||
robotic_sprite = FALSE
|
||||
|
||||
max_damage = 30
|
||||
|
||||
/obj/item/organ/internal/machine/data/Initialize()
|
||||
robotize()
|
||||
. = ..()
|
||||
@@ -0,0 +1,54 @@
|
||||
// Hydraulics effects are mainly in /datum/species/machine/handle_sprint_cost.
|
||||
/obj/item/organ/internal/machine/hydraulics
|
||||
name = "hydraulics system"
|
||||
desc = "A byzantine system of pumps and other hydraulic components to allow a positronic chassis to stand on both its feet, and do complex tricks such as kicking you in the shins."
|
||||
icon = 'icons/obj/organs/ipc_organs.dmi'
|
||||
icon_state = "ipc_hydraulics"
|
||||
organ_tag = BP_HYDRAULICS
|
||||
parent_organ = BP_GROIN
|
||||
|
||||
max_damage = 40
|
||||
relative_size = 70
|
||||
|
||||
/obj/item/organ/internal/machine/hydraulics/Initialize()
|
||||
. = ..()
|
||||
RegisterSignal(owner, COMSIG_IPC_HAS_SPRINTED, PROC_REF(handle_hydraulics))
|
||||
|
||||
/**
|
||||
* Handles sprint effects. For example, recharging with the kinetic reactor.
|
||||
*/
|
||||
/obj/item/organ/internal/machine/hydraulics/proc/handle_hydraulics()
|
||||
SIGNAL_HANDLER
|
||||
if(!owner)
|
||||
return
|
||||
|
||||
var/obj/item/organ/internal/machine/reactor/reactor = owner.internal_organs_by_name[BP_REACTOR]
|
||||
if(!istype(reactor))
|
||||
return
|
||||
|
||||
if(get_integrity() < IPC_INTEGRITY_THRESHOLD_LOW)
|
||||
if(prob(10 * (damage / 10)))
|
||||
spark(get_turf(owner), rand(1, 5), GLOB.alldirs)
|
||||
|
||||
if(reactor.power_supply_type & POWER_SUPPLY_KINETIC)
|
||||
reactor.generate_power(reactor.base_power_generation)
|
||||
|
||||
/obj/item/organ/internal/machine/hydraulics/medium_integrity_damage(integrity)
|
||||
. = ..()
|
||||
if(!.)
|
||||
return
|
||||
|
||||
if(prob(get_integrity_damage_probability()))
|
||||
spark(owner, 3, GLOB.alldirs)
|
||||
to_chat(owner, SPAN_WARNING("Your hydraulics lock up for a second!"))
|
||||
owner.Stun(1)
|
||||
|
||||
/obj/item/organ/internal/machine/hydraulics/high_integrity_damage(integrity)
|
||||
. = ..()
|
||||
if(!.)
|
||||
return
|
||||
|
||||
if(prob(get_integrity_damage_probability()))
|
||||
spark(owner, 5, GLOB.alldirs)
|
||||
to_chat(owner, SPAN_WARNING("Your hydraulics malfunction and you trip!"))
|
||||
owner.Weaken(1)
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user