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:
Matt Atlas
2025-12-21 17:26:23 +01:00
committed by GitHub
parent 1898ad3417
commit e0aa218843
201 changed files with 5962 additions and 896 deletions
+4
View File
@@ -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
+31 -4
View File
@@ -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
+4 -3
View File
@@ -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]&deg;C ([M.bodytemperature*1.8-459.67]&deg;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]&deg;C ([M.bodytemperature*1.8-459.67]&deg;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
+9 -1
View File
@@ -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
+1 -1
View File
@@ -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)
+4
View File
@@ -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