From 7978efa75f2952f68467df01fc39612b532100cf Mon Sep 17 00:00:00 2001 From: Matt Atlas Date: Mon, 1 Jun 2026 12:32:39 +0200 Subject: [PATCH] A lot of IPC rework bugfixes. (#22561) - bugfix: "Synthetic external armour now deteriorates with the actual damage taken. Previously, the calculation led to the armour instead taking less damage the less it was blocked." - bugfix: "Fixing the synthetic endoskeleton now fixes the permanent paincrit effect on IPCs. This was caused by the self preservation status being toggled when the endoskeleton was destroyed, but it was never reset when the endoskeleton was fixed." - bugfix: "Species components are now added and removed properly, meaning you can switch from IPC to human and back and forth as a mercenary once more." - bugfix: "The Bishop internal PDA now uses your actual ID on your person as its own ID." - bugfix: "Fixed the endoskeleton welder repair surgery. You can do this surgery by using a welder while aiming chest and after having opened the chest fully." - bugfix: "The endoskeleton now takes damage from EMPs as well. This should make them A LOT more effective against IPCs." - qol: "The posibrain will now show up in diagnostics." - rscadd: "Posibrains can now be destroyed by hitting them. This will completely kill the IPC's consciousness!" Co-authored-by: Matt Atlas --- code/__DEFINES/organs.dm | 4 +- .../components/armor/synthetic_armor.dm | 2 +- .../synthetic_endoskeleton.dm | 3 +- code/modules/mob/living/carbon/brain/MMI.dm | 1 + .../mob/living/carbon/brain/posibrain.dm | 14 +++- .../living/carbon/human/species/species.dm | 13 +++- .../carbon/human/species/station/ipc/ipc.dm | 3 +- .../internal/species/machine/_generic.dm | 15 ++++- .../internal/species/machine/posibrain.dm | 11 +++- .../species/machine/wireless_access.dm | 5 ++ code/modules/organs/organ_external.dm | 2 +- code/modules/surgery/robotics.dm | 2 +- html/changelogs/mattatlas-ipcreworkfixes.yml | 65 +++++++++++++++++++ 13 files changed, 126 insertions(+), 14 deletions(-) create mode 100644 html/changelogs/mattatlas-ipcreworkfixes.yml diff --git a/code/__DEFINES/organs.dm b/code/__DEFINES/organs.dm index 7aaf62e4086..33aecdde263 100644 --- a/code/__DEFINES/organs.dm +++ b/code/__DEFINES/organs.dm @@ -49,8 +49,8 @@ */ #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" +/// This is raised when you want to send damage to the synthetic endoskeleton. Must supply a damage number. +#define COMSIG_DAMAGE_TO_ENDOSKELETON "machine_internal_damage" /// Sent when the burst damage is cleared by the posibrain. #define COMSIG_SYNTH_EMP_DAMAGE_CLEARED "emp_damage_cleared" diff --git a/code/datums/components/armor/synthetic_armor.dm b/code/datums/components/armor/synthetic_armor.dm index f7b24768494..79d01d71ed6 100644 --- a/code/datums/components/armor/synthetic_armor.dm +++ b/code/datums/components/armor/synthetic_armor.dm @@ -23,7 +23,7 @@ var/key = get_armor_key(damage_type, damage_flags) var/damage_taken if(blocked) - damage_taken = round(damage * blocked) + damage_taken = damage * (1 - blocked) else damage_taken = damage var/new_armor = max(0, get_value(key) - armor_degradation_coef * damage_taken) diff --git a/code/datums/components/synthetic_endoskeleton/synthetic_endoskeleton.dm b/code/datums/components/synthetic_endoskeleton/synthetic_endoskeleton.dm index b7415dd7cd9..ad8bd423cf8 100644 --- a/code/datums/components/synthetic_endoskeleton/synthetic_endoskeleton.dm +++ b/code/datums/components/synthetic_endoskeleton/synthetic_endoskeleton.dm @@ -23,7 +23,7 @@ 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_DAMAGE_TO_ENDOSKELETON, 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)) @@ -55,6 +55,7 @@ owner.add_or_update_variable_movespeed_modifier(/datum/movespeed_modifier/endoskeleton, multiplicative_slowdown = 1) if(0.75 to 1) owner.add_or_update_variable_movespeed_modifier(/datum/movespeed_modifier/endoskeleton, multiplicative_slowdown = 1.5) + SEND_SIGNAL(owner, COMSIG_SYNTH_SET_SELF_PRESERVATION, FALSE) if(!damage) STOP_PROCESSING(SSprocessing, src) diff --git a/code/modules/mob/living/carbon/brain/MMI.dm b/code/modules/mob/living/carbon/brain/MMI.dm index 0cfb28f2fe0..7cd76b21f25 100644 --- a/code/modules/mob/living/carbon/brain/MMI.dm +++ b/code/modules/mob/living/carbon/brain/MMI.dm @@ -144,6 +144,7 @@ new /obj/effect/decal/cleanable/blood/gibs(get_turf(src)) set_cradle_state(STATE_EMPTY) update_name() + return ..() /obj/item/mmi/attack_self(mob/user) if(cradle_state == STATE_BRAIN) diff --git a/code/modules/mob/living/carbon/brain/posibrain.dm b/code/modules/mob/living/carbon/brain/posibrain.dm index 1e11b4f98eb..de5fa482c8c 100644 --- a/code/modules/mob/living/carbon/brain/posibrain.dm +++ b/code/modules/mob/living/carbon/brain/posibrain.dm @@ -7,6 +7,10 @@ origin_tech = list(TECH_ENGINEERING = 4, TECH_MATERIAL = 4, TECH_BLUESPACE = 2, TECH_DATA = 4) req_access = list(ACCESS_ROBOTICS) can_be_ipc = TRUE + + should_use_health = TRUE + maxhealth = OBJECT_HEALTH_MEDIUM + var/searching = FALSE /obj/item/mmi/digital/posibrain/Initialize() @@ -15,6 +19,13 @@ brainmob.name = L.get_random_name() brainmob.real_name = brainmob.name +/obj/item/mmi/digital/posibrain/on_death(damage, damage_flags, damage_type, armor_penetration, obj/weapon) + playsound(src, SFX_BREAK_GLASS, 100, 1) + visible_message(SPAN_DANGER("\The [src] shatters spectacularly into a million pieces!")) + to_chat(brainmob, SPAN_DANGER("Your vision goes dark as your posibrain is destroyed, and your consciousness ceases to be.")) + new /obj/effect/decal/cleanable/blood/gibs/robot(get_turf(src)) + . = ..() + /obj/item/mmi/digital/posibrain/update_icon() if(brainmob.ckey) icon_state = "[initial(icon_state)]-occupied" @@ -23,9 +34,6 @@ else icon_state = initial(icon_state) -/obj/item/mmi/digital/posibrain/attackby(obj/item/attacking_item, mob/user) - return - /obj/item/mmi/digital/posibrain/attack_self(mob/user) if(brainmob.ckey) to_chat(user, SPAN_WARNING("\The [src] already has an active occupant!")) diff --git a/code/modules/mob/living/carbon/human/species/species.dm b/code/modules/mob/living/carbon/human/species/species.dm index 7c3d6f250a5..6301f9c2334 100644 --- a/code/modules/mob/living/carbon/human/species/species.dm +++ b/code/modules/mob/living/carbon/human/species/species.dm @@ -471,6 +471,9 @@ /// Controls whether this species spawns with a Morale Component. var/has_morale = TRUE + /// A list of species components that should only EVER apply to this species. This is because some components must be removed if the species changes (imagine changing from IPC to human as a merc). + var/list/species_components + /datum/species/proc/get_eyes(var/mob/living/carbon/human/H) return @@ -625,7 +628,11 @@ for(var/spell/spell in H.spell_list) if(istype(spell, spell_path)) H.remove_spell(spell) - return + + if(length(species_components)) + for(var/comp_type in species_components) + for(var/datum/component/comp in H.GetComponents(comp_type)) + qdel(comp) /datum/species/proc/add_inherent_verbs(var/mob/living/carbon/human/H) if(inherent_verbs) @@ -660,6 +667,10 @@ if(has_psionics) H.set_psi_rank(has_psionics) + if(length(species_components)) + for(var/comp_type in species_components) + H.AddComponent(comp_type) + /datum/species/proc/handle_death(var/mob/living/carbon/human/H, var/gibbed = 0) //Handles any species-specific death events (such as dionaea nymph spawns). return diff --git a/code/modules/mob/living/carbon/human/species/station/ipc/ipc.dm b/code/modules/mob/living/carbon/human/species/station/ipc/ipc.dm index 0c5dccdfe32..7930b942fcf 100644 --- a/code/modules/mob/living/carbon/human/species/station/ipc/ipc.dm +++ b/code/modules/mob/living/carbon/human/species/station/ipc/ipc.dm @@ -163,6 +163,8 @@ melee = ARMOR_MELEE_KNIVES ) + species_components = list(/datum/component/synthetic_endoskeleton) + // Special snowflake machine vars. var/sprint_temperature_factor = 1.05 /// Species-based multiplier to movement power costs in the power core. @@ -217,7 +219,6 @@ /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/machine/power_core/C = H.internal_organs_by_name[BP_CELL] if(C) diff --git a/code/modules/organs/internal/species/machine/_generic.dm b/code/modules/organs/internal/species/machine/_generic.dm index 00e5c71a49e..bb6e4df0934 100644 --- a/code/modules/organs/internal/species/machine/_generic.dm +++ b/code/modules/organs/internal/species/machine/_generic.dm @@ -62,6 +62,11 @@ electronics.heal_damage(electronics.max_integrity) integrity_event_cooldown = initial(integrity_event_cooldown) +/obj/item/organ/internal/machine/heal_damage(amount) + . = ..() + if(initial(diagnostics_suite_visible) && !diagnostics_suite_visible) + diagnostics_suite_visible = TRUE + /obj/item/organ/internal/machine/process(seconds_per_tick) ..() if(!owner) @@ -107,11 +112,17 @@ /obj/item/organ/internal/machine/emp_act(severity) . = ..() + var/damage_taken switch(severity) if(EMP_HEAVY) - take_internal_damage(4 * emp_coeff) + damage_taken = 15 * emp_coeff + take_internal_damage(damage_taken) if(EMP_LIGHT) - take_internal_damage(2 * emp_coeff) + damage_taken = 10 * emp_coeff + take_internal_damage(damage_taken) + + if(damage_taken) + SEND_SIGNAL(owner, COMSIG_DAMAGE_TO_ENDOSKELETON, damage_taken) /** * Called when prefs are synced to the organ to set the proper synthetic organ preset. Turns the pref into a preset singleton. diff --git a/code/modules/organs/internal/species/machine/posibrain.dm b/code/modules/organs/internal/species/machine/posibrain.dm index 58d4b6897be..bf1e8f715a0 100644 --- a/code/modules/organs/internal/species/machine/posibrain.dm +++ b/code/modules/organs/internal/species/machine/posibrain.dm @@ -7,7 +7,6 @@ parent_organ = BP_HEAD vital = TRUE robotic_sprite = FALSE - diagnostics_suite_visible = FALSE emp_coeff = 0.5 @@ -15,6 +14,9 @@ relative_size = 85 + maxhealth = OBJECT_HEALTH_MEDIUM + should_use_health = TRUE + /// The type of 'robotic brain'. Must be a subtype of /obj/item/mmi/digital. var/robotic_brain_type = /obj/item/mmi/digital/posibrain /// The stored MMI object. @@ -61,6 +63,13 @@ QDEL_NULL(sizzle) return ..() +/obj/item/organ/internal/machine/posibrain/on_death(damage, damage_flags, damage_type, armor_penetration, obj/weapon) + playsound(src, SFX_BREAK_GLASS, 100, 1) + visible_message(SPAN_DANGER("\The [src] shatters spectacularly into a million pieces!")) + to_chat(owner, SPAN_DANGER("Your vision goes dark as your posibrain is destroyed, and your consciousness ceases to be.")) + new /obj/effect/decal/cleanable/blood/gibs/robot(get_turf(src)) + . = ..() + /obj/item/organ/internal/machine/posibrain/rejuvenate() . = ..() SEND_SIGNAL(owner, COMSIG_SYNTH_ENDOSKELETON_FULL_REPAIR) diff --git a/code/modules/organs/internal/species/machine/wireless_access.dm b/code/modules/organs/internal/species/machine/wireless_access.dm index 39ee7808597..373eab72814 100644 --- a/code/modules/organs/internal/species/machine/wireless_access.dm +++ b/code/modules/organs/internal/species/machine/wireless_access.dm @@ -75,6 +75,11 @@ else crash_with("Something terrible happened in synthetic internal PDA init! Loc: [loc]") +/obj/item/modular_computer/handheld/pda/synthetic_internal/GetID() + var/obj/item/organ/internal/machine/wireless_access/access_point = loc + if(access_point.owner) + return access_point.owner.GetIdCard() + /obj/item/modular_computer/handheld/pda/synthetic_internal/Destroy() if(access_point) access_point.internal_pda = null diff --git a/code/modules/organs/organ_external.dm b/code/modules/organs/organ_external.dm index 1f8acb92216..e75fbc3331c 100644 --- a/code/modules/organs/organ_external.dm +++ b/code/modules/organs/organ_external.dm @@ -505,7 +505,7 @@ add_pain(0.6 * burn + 0.4 * brute) if(owner) - SEND_SIGNAL(owner, COMSIG_EXTERNAL_ORGAN_DAMAGE, burn + brute) + SEND_SIGNAL(owner, COMSIG_DAMAGE_TO_ENDOSKELETON, burn + brute) //If there are still hurties to dispense if (spillover) diff --git a/code/modules/surgery/robotics.dm b/code/modules/surgery/robotics.dm index 258a519542d..23edf40dea0 100644 --- a/code/modules/surgery/robotics.dm +++ b/code/modules/surgery/robotics.dm @@ -776,7 +776,7 @@ if(!istype(endoskeleton)) return FALSE - return affected && affected.open == ORGAN_ENCASED_RETRACTED && affected.organ_tag == BP_CHEST && target_zone != BP_MOUTH && endoskeleton.damage > 0 + return affected && affected.open == ORGAN_ENCASED_RETRACTED && affected.limb_name == BP_CHEST && target_zone != BP_MOUTH && endoskeleton.damage > 0 /singleton/surgery_step/robotics/repair_endoskeleton/begin_step(mob/user, mob/living/carbon/human/target, target_zone, obj/item/tool) user.visible_message("[user] begins to repair the support structures of [target]'s endoskeleton with \the [tool]." , \ diff --git a/html/changelogs/mattatlas-ipcreworkfixes.yml b/html/changelogs/mattatlas-ipcreworkfixes.yml new file mode 100644 index 00000000000..fd0a6f31a46 --- /dev/null +++ b/html/changelogs/mattatlas-ipcreworkfixes.yml @@ -0,0 +1,65 @@ +################################ +# Example Changelog File +# +# Note: This file, and files beginning with ".", and files that don't end in ".yml" will not be read. If you change this file, you will look really dumb. +# +# Your changelog will be merged with a master changelog. (New stuff added only, and only on the date entry for the day it was merged.) +# When it is, any changes listed below will disappear. +# +# Valid Prefixes: +# bugfix +# - (fixes bugs) +# wip +# - (work in progress) +# qol +# - (quality of life) +# soundadd +# - (adds a sound) +# sounddel +# - (removes a sound) +# rscadd +# - (adds a feature) +# rscdel +# - (removes a feature) +# imageadd +# - (adds an image or sprite) +# imagedel +# - (removes an image or sprite) +# spellcheck +# - (fixes spelling or grammar) +# experiment +# - (experimental change) +# balance +# - (balance changes) +# code_imp +# - (misc internal code change) +# refactor +# - (refactors code) +# config +# - (makes a change to the config files) +# admin +# - (makes changes to administrator tools) +# server +# - (miscellaneous changes to server) +################################# + +# Your name. +author: MattAtlas + +# Optional: Remove this file after generating master changelog. Useful for PR changelogs that won't get used again. +delete-after: True + +# Any changes you've made. See valid prefix list above. +# INDENT WITH TWO SPACES. NOT TABS. SPACES. +# SCREW THIS UP AND IT WON'T WORK. +# Also, this gets changed to [] after reading. Just remove the brackets when you add new shit. +# Please surround your changes in double quotes ("). It works without them, but if you use certain characters it screws up compiling. The quotes will not show up in the changelog. +changes: + - bugfix: "Synthetic external armour now deteriorates with the actual damage taken. Previously, the calculation led to the armour instead taking less damage the less it was blocked." + - bugfix: "Fixing the synthetic endoskeleton now fixes the permanent paincrit effect on IPCs. This was caused by the self preservation status being toggled when the endoskeleton was destroyed, but it was never reset when the endoskeleton was fixed." + - bugfix: "Species components are now added and removed properly, meaning you can switch from IPC to human and back and forth as a mercenary once more." + - bugfix: "The Bishop internal PDA now uses your actual ID on your person as its own ID." + - bugfix: "Fixed the endoskeleton welder repair surgery. You can do this surgery by using a welder while aiming chest and after having opened the chest fully." + - bugfix: "The endoskeleton now takes damage from EMPs as well. This should make them A LOT more effective against IPCs." + - qol: "The posibrain will now show up in diagnostics." + - rscadd: "Posibrains can now be destroyed by hitting them. This will completely kill the IPC's consciousness!"