From 7d86fdf9018b91662114457c228bef9adf03ad16 Mon Sep 17 00:00:00 2001 From: Alberyk Date: Thu, 23 Apr 2020 13:27:53 -0300 Subject: [PATCH] Cyberpunk 2462: augments for real this time (#8113) This pr adds an augment option to the loadout, that by using copious amounts of shitcode, allows players to spend their snowflake points into becoming total powergamers cool augmented cyborgs. Also, make a couple of changes to allow all limbs to host internal organs and interact with them in surgery. --- aurorastation.dme | 3 + code/__defines/mobs.dm | 17 + code/controllers/subsystems/garbage-debug.dm | 1 + code/controllers/subsystems/icon_cache.dm | 1 + code/controllers/subsystems/job.dm | 51 +++ code/controllers/subsystems/ticker.dm | 1 + code/game/machinery/mecha_fabricator.dm | 8 +- .../items/devices/augment_implanter.dm | 59 ++++ .../modules/cargo/random_stock/t2_uncommon.dm | 2 +- .../preference_setup/loadout/loadout.dm | 1 + .../loadout/loadout_augments.dm | 67 ++++ .../loadout/loadout_xeno/tajara.dm | 10 +- .../loadout/loadout_xeno/unathi.dm | 26 +- .../clothing/spacesuits/rig/suits/alien.dm | 8 + .../mob/abstract/new_player/new_player.dm | 1 + code/modules/mob/living/carbon/human/human.dm | 7 + code/modules/mob/living/carbon/taste.dm | 12 +- code/modules/multiz/movement.dm | 8 +- code/modules/organs/internal/_internal.dm | 1 + code/modules/organs/organ.dm | 6 +- code/modules/organs/organ_external.dm | 13 +- code/modules/organs/organ_icon.dm | 23 +- code/modules/organs/robolimbs.dm | 29 +- code/modules/organs/subtypes/augment.dm | 294 ++++++++++++++++++ code/modules/organs/subtypes/autakh.dm | 3 +- code/modules/organs/subtypes/standard.dm | 7 + .../Chemistry-Reagents-Core.dm | 6 +- .../Chemistry-Reagents-Dispenser.dm | 8 +- code/modules/surgery/organs_internal.dm | 43 ++- html/changelogs/alberyk-augs.yml | 7 + icons/mob/human_races/augments_external.dmi | Bin 0 -> 320 bytes icons/mob/human_races/tajara/tesla_limbs.dmi | Bin 0 -> 891 bytes icons/obj/action_buttons/organs.dmi | Bin 5674 -> 9902 bytes icons/obj/surgery.dmi | Bin 43764 -> 47537 bytes 34 files changed, 694 insertions(+), 29 deletions(-) create mode 100644 code/game/objects/items/devices/augment_implanter.dm create mode 100644 code/modules/client/preference_setup/loadout/loadout_augments.dm create mode 100644 code/modules/organs/subtypes/augment.dm create mode 100644 html/changelogs/alberyk-augs.yml create mode 100644 icons/mob/human_races/augments_external.dmi create mode 100644 icons/mob/human_races/tajara/tesla_limbs.dmi diff --git a/aurorastation.dme b/aurorastation.dme index e264c1c9b45..39d019a09fb 100644 --- a/aurorastation.dme +++ b/aurorastation.dme @@ -817,6 +817,7 @@ #include "code\game\objects\items\toys.dm" #include "code\game\objects\items\trash.dm" #include "code\game\objects\items\devices\aicard.dm" +#include "code\game\objects\items\devices\augment_implanter.dm" #include "code\game\objects\items\devices\binoculars.dm" #include "code\game\objects\items\devices\chameleonproj.dm" #include "code\game\objects\items\devices\debugger.dm" @@ -1336,6 +1337,7 @@ #include "code\modules\client\preference_setup\loadout\gear_tweaks.dm" #include "code\modules\client\preference_setup\loadout\loadout.dm" #include "code\modules\client\preference_setup\loadout\loadout_accessories.dm" +#include "code\modules\client\preference_setup\loadout\loadout_augments.dm" #include "code\modules\client\preference_setup\loadout\loadout_computer.dm" #include "code\modules\client\preference_setup\loadout\loadout_cosmetics.dm" #include "code\modules\client\preference_setup\loadout\loadout_ears.dm" @@ -2177,6 +2179,7 @@ #include "code\modules\organs\internal\lungs.dm" #include "code\modules\organs\internal\stomach.dm" #include "code\modules\organs\internal\species\diona.dm" +#include "code\modules\organs\subtypes\augment.dm" #include "code\modules\organs\subtypes\autakh.dm" #include "code\modules\organs\subtypes\diona.dm" #include "code\modules\organs\subtypes\industrial.dm" diff --git a/code/__defines/mobs.dm b/code/__defines/mobs.dm index 96e6457edb3..0f10a926b85 100644 --- a/code/__defines/mobs.dm +++ b/code/__defines/mobs.dm @@ -111,6 +111,22 @@ #define BP_OPTICS "optics" #define BP_IPCTAG "ipc tag" +//Augment organs +#define BP_AUG_TIMEPIECE "integrated timepiece" +#define BP_AUG_PDA "integrated pda" +#define BP_AUG_TOOL "retractable combitool" +#define BP_AUG_PEN "retractable combipen" +#define BP_AUG_LIGHTER "retractable lighter" +#define BP_AUG_HEALTHSCAN "integrated health scanner" +#define BP_AUG_TESLA "tesla spine" +#define BP_AUG_EYE_SENSORS "integrated eyes sensors" +#define BP_AUG_HAIR "synthetic hair extensions" +#define BP_AUG_SUSPENSION "calf suspension" +#define BP_AUG_TASTE_BOOSTER "taste booster" +#define BP_AUG_RADIO "integrated radio" +#define BP_AUG_FUEL_CELL "integrated fuel cell" +#define BP_AUG_AIR_ANALYZER "integrated air analyzer" + //Organ defines #define PROCESS_ACCURACY 10 #define DEFAULT_BLOOD_AMOUNT 560 //Default blood amount in units @@ -304,6 +320,7 @@ #define PROSTHETIC_XMG "Xion Manufacturing Group" #define PROSTHETIC_DIONA "Unknown Model" #define PROSTHETIC_AUTAKH "Aut'akh Manufactured" +#define PROSTHETIC_TESLA "Tesla Powered Prosthetics" //Brain Damage defines #define BRAIN_DAMAGE_MILD 10 diff --git a/code/controllers/subsystems/garbage-debug.dm b/code/controllers/subsystems/garbage-debug.dm index e31fa720ed2..e0031ccb557 100644 --- a/code/controllers/subsystems/garbage-debug.dm +++ b/code/controllers/subsystems/garbage-debug.dm @@ -790,6 +790,7 @@ SearchVar(ntnrc_uid) SearchVar(all_robolimbs) SearchVar(chargen_robolimbs) + SearchVar(fabricator_robolimbs) SearchVar(basic_robolimb) SearchVar(moving_levels) SearchVar(cached_space) diff --git a/code/controllers/subsystems/icon_cache.dm b/code/controllers/subsystems/icon_cache.dm index dbb2108c6e0..98fa0225a25 100644 --- a/code/controllers/subsystems/icon_cache.dm +++ b/code/controllers/subsystems/icon_cache.dm @@ -44,6 +44,7 @@ var/list/markings_cache = list() // [icon]-[icon_state]-[limb_name]-[color] var/list/human_eye_cache = list() var/list/human_lip_cache = list() + var/list/internal_organ_cache = list() // Cached composited human hair (beard & hair). // Key: // hair+beard: [beard_style][r_facial][g_facial][b_facial]_[hair_style][r_hair][g_hair][b_hair] diff --git a/code/controllers/subsystems/job.dm b/code/controllers/subsystems/job.dm index 8ccb00d09a9..98f261dfef1 100644 --- a/code/controllers/subsystems/job.dm +++ b/code/controllers/subsystems/job.dm @@ -727,6 +727,10 @@ for(var/thing in prefs.gear) var/datum/gear/G = gear_datums[thing] if(G) + + if(G.augment) //augments are handled somewhere else + continue + var/permitted if(G.allowed_roles) for(var/job_name in G.allowed_roles) @@ -860,4 +864,51 @@ deferred_preference_sanitizations.Cut() + +/datum/controller/subsystem/jobs/proc/EquipAugments(mob/living/carbon/human/H, datum/preferences/prefs) + Debug("EA/([H]): Entry.") + if(!istype(H)) + Debug("EA/([H]): Abort: invalid arguments.") + return FALSE + + var/datum/job/rank = GetJob(H.mind.assigned_role) + + switch (rank.title) + if ("AI", "Cyborg") + Debug("EA/([H]): Abort: synthetic.") + return FALSE + + for(var/thing in prefs.gear) + var/datum/gear/G = gear_datums[thing] + if(G) + if(!G.augment) + continue + + var/permitted = FALSE + if(G.allowed_roles) + for(var/job_name in G.allowed_roles) + if(rank.title == job_name) + permitted = TRUE + break + else + permitted = TRUE + + if(G.whitelisted && (!(H.species.name in G.whitelisted))) + permitted = FALSE + + if(G.faction && G.faction != H.employer_faction) + permitted = FALSE + + if(!permitted) + to_chat(H, SPAN_WARNING("Your current job or whitelist status does not permit you to spawn with [thing]!")) + continue + + var/obj/item/organ/A = new G.path(H) + var/obj/item/organ/external/affected = H.get_organ(A.parent_organ) + A.replaced(H, affected) + H.update_body() + + Debug("EA/([H]): Complete.") + return TRUE + #undef Debug diff --git a/code/controllers/subsystems/ticker.dm b/code/controllers/subsystems/ticker.dm index 1d7438017ce..d07cc90122a 100644 --- a/code/controllers/subsystems/ticker.dm +++ b/code/controllers/subsystems/ticker.dm @@ -619,6 +619,7 @@ var/datum/controller/subsystem/ticker/SSticker if(player.mind.assigned_role == "Captain") captainless = FALSE if(!player_is_antag(player.mind, only_offstation_roles = 1)) + SSjobs.EquipAugments(player, player.client.prefs) SSjobs.EquipRank(player, player.mind.assigned_role, 0) equip_custom_items(player) diff --git a/code/game/machinery/mecha_fabricator.dm b/code/game/machinery/mecha_fabricator.dm index a6d6b83143d..a94354d0563 100644 --- a/code/game/machinery/mecha_fabricator.dm +++ b/code/game/machinery/mecha_fabricator.dm @@ -99,10 +99,10 @@ data["buildable"] = get_build_options() data["category"] = category data["categories"] = categories - if(chargen_robolimbs ) + if(fabricator_robolimbs ) var/list/T = list() - for(var/A in chargen_robolimbs ) - var/datum/robolimb/R = chargen_robolimbs [A] + for(var/A in fabricator_robolimbs ) + var/datum/robolimb/R = fabricator_robolimbs [A] T += list(list("id" = A, "company" = R.company)) data["manufacturers"] = T data["manufacturer"] = manufacturer @@ -134,7 +134,7 @@ category = href_list["category"] if(href_list["manufacturer"]) - if(href_list["manufacturer"] in chargen_robolimbs ) + if(href_list["manufacturer"] in fabricator_robolimbs ) manufacturer = href_list["manufacturer"] if(href_list["eject"]) diff --git a/code/game/objects/items/devices/augment_implanter.dm b/code/game/objects/items/devices/augment_implanter.dm new file mode 100644 index 00000000000..274fdc3687a --- /dev/null +++ b/code/game/objects/items/devices/augment_implanter.dm @@ -0,0 +1,59 @@ +/obj/item/device/augment_implanter + name = "augment implanter" + desc = "A complex single use injector that is used to implant augments without the need for surgery." + w_class = ITEMSIZE_NORMAL + origin_tech = list(TECH_BIO = 5, TECH_MATERIAL = 2) + icon = 'icons/obj/guns/decloner.dmi' + icon_state = "decloner" + item_state = "decloner" + contained_sprite = TRUE + var/obj/item/organ/augment_type + +/obj/item/device/augment_implanter/Initialize() + . = ..() + if(!augment_type) + augment_type = new augment_type(src) + +/obj/item/device/augment_implanter/examine(mob/user) + ..(user) + if(augment_type) + to_chat(user, FONT_SMALL(SPAN_NOTICE("\The [augment_type] can be seen floating inside \the [src]'s biogel."))) + +/obj/item/device/augment_implanter/afterattack(mob/living/L, mob/user, proximity) + if(!proximity) + return + + if(!augment_type) + to_chat(user, SPAN_WARNING("\The [src] is empty!")) + return + + if(!ishuman(L)) + to_chat(user, SPAN_WARNING("\The [src] has no effect on \the [L].")) + return + + var/mob/living/carbon/human/H = L + + if(!(H.species.name in augment_type.species_restricted)) + to_chat(user, SPAN_WARNING("\The [augment_type] is not compatible with \the [H]'s body.")) + return + + if(H.internal_organs_by_name[augment_type.organ_tag]) + to_chat(user, SPAN_WARNING("\The [H] already has a [augment_type].")) + return + + if(!do_mob(user, H, 4 SECONDS)) + return + + augment_type.replaced(H, augment_type.parent_organ) + H.update_body() + H.updatehealth() + H.UpdateDamageIcon() + augment_type = null + + user.visible_message(SPAN_WARNING("\The [user] thrusts \the [src] deep into \the [H], injecting something!")) + +/obj/item/device/augment_implanter/advanced_tesla + augment_type = /obj/item/organ/internal/augment/tesla/advanced + +/obj/item/device/augment_implanter/advanced_suspension + augment_type = /obj/item/organ/internal/augment/suspension/advanced diff --git a/code/modules/cargo/random_stock/t2_uncommon.dm b/code/modules/cargo/random_stock/t2_uncommon.dm index e0dda968b4e..3c54cb5666a 100644 --- a/code/modules/cargo/random_stock/t2_uncommon.dm +++ b/code/modules/cargo/random_stock/t2_uncommon.dm @@ -91,7 +91,7 @@ STOCK_ITEM_UNCOMMON(chempack, 5) STOCK_ITEM_UNCOMMON(robolimbs, 3) for (var/i in 1 to rand(2, 5)) - var/manuf = pick(chargen_robolimbs) + var/manuf = pick(fabricator_robolimbs) var/type = pick( \ /obj/item/robot_parts/l_arm, \ /obj/item/robot_parts/r_arm, \ diff --git a/code/modules/client/preference_setup/loadout/loadout.dm b/code/modules/client/preference_setup/loadout/loadout.dm index 42771c8c054..b0158157132 100644 --- a/code/modules/client/preference_setup/loadout/loadout.dm +++ b/code/modules/client/preference_setup/loadout/loadout.dm @@ -237,6 +237,7 @@ var/list/gear_datums = list() var/sort_category = "General" var/list/gear_tweaks = list() //List of datums which will alter the item after it has been spawned. var/flags = GEAR_HAS_NAME_SELECTION | GEAR_HAS_DESC_SELECTION + var/augment = FALSE /datum/gear/New() ..() diff --git a/code/modules/client/preference_setup/loadout/loadout_augments.dm b/code/modules/client/preference_setup/loadout/loadout_augments.dm new file mode 100644 index 00000000000..d26aa052700 --- /dev/null +++ b/code/modules/client/preference_setup/loadout/loadout_augments.dm @@ -0,0 +1,67 @@ +/datum/gear/augment + display_name = "integrated timepiece" + description = "An augment that allows the user to consult the time anywhere." + path = /obj/item/organ/internal/augment/timepiece + cost = 1 + augment = TRUE + sort_category = "Augments" + whitelisted = list("Human", "Off-Worlder Human", "Tajara", "Zhan-Khazan Tajara", "M'sai Tajara", "Aut'akh Unathi", "Skrell", "Baseline Frame", "Hephaestus G1 Industrial Frame", "Hephaestus G2 Industrial Frame", "Xion Industrial Frame", "Zeng-Hu Mobility Frame", "Bishop Accessory Frame") + flags = GEAR_NO_SELECTION + +/datum/gear/augment/eye_sensors + display_name = "integrated eye sensors" + description = "An eye augment that allows the user to deploy medical or security sensors." + path = /obj/item/organ/internal/augment/eye_sensors + cost = 4 + whitelisted = list("Human", "Off-Worlder Human", "Tajara", "Zhan-Khazan Tajara", "M'sai Tajara", "Aut'akh Unathi", "Skrell", "Baseline Frame", "Hephaestus G1 Industrial Frame", "Hephaestus G2 Industrial Frame", "Xion Industrial Frame", "Zeng-Hu Mobility Frame", "Bishop Accessory Frame", "Vaurca Worker", "Vaurca Warrior") + + +/datum/gear/augment/cyber_hair + display_name = "synthetic hair extensions" + description = "A hair augment that allows the user to change the shape and color of their hair." + path = /obj/item/organ/internal/augment/cyber_hair + cost = 2 + +/datum/gear/augment/combitool + display_name = "retractable combitool" + description = "An augment that allows the user to deploy a robotic combitool." + path = /obj/item/organ/internal/augment/tool/combitool + cost = 5 + +/datum/gear/augment/combitool/New() + ..() + var/augs = list() + augs["retractable combitool, right hand"] = /obj/item/organ/internal/augment/tool/combitool + augs["retractable combitool, left hand"] = /obj/item/organ/internal/augment/tool/combitool/left + gear_tweaks += new /datum/gear_tweak/path(augs) + +/datum/gear/augment/health_scanner + display_name = "integrated health scanner" + description = "An augment that allows the user scan their own health condition." + path = /obj/item/organ/internal/augment/health_scanner + cost = 3 + +/datum/gear/augment/suspension + display_name = "calf suspension" + description = "An augment that reduces the damage from falling from heights." + path = /obj/item/organ/internal/augment/suspension + cost = 4 + +/datum/gear/augment/taste_boosters + display_name = "taste booster selection" + description = "A selection of augments that modify the user's taste sensitivity." + path = /obj/item/organ/internal/augment/taste_booster + cost = 3 + +/datum/gear/augment/taste_boosters/New() + ..() + var/augs = list() + augs["taste booster"] = /obj/item/organ/internal/augment/taste_booster + augs["taste duller"] = /obj/item/organ/internal/augment/taste_booster/dull + gear_tweaks += new /datum/gear_tweak/path(augs) + +/datum/gear/augment/fuel_cell + display_name = "integrated fuel cell" + description = "An augment that allows the user to synthetize welding fuel into nutrients." + path = /obj/item/organ/internal/augment/fuel_cell + cost = 3 diff --git a/code/modules/client/preference_setup/loadout/loadout_xeno/tajara.dm b/code/modules/client/preference_setup/loadout/loadout_xeno/tajara.dm index 50719cf3997..f9cff3581bd 100644 --- a/code/modules/client/preference_setup/loadout/loadout_xeno/tajara.dm +++ b/code/modules/client/preference_setup/loadout/loadout_xeno/tajara.dm @@ -185,4 +185,12 @@ path = /obj/item/storage/belt/shumaila_buckle whitelisted = list("Tajara", "Zhan-Khazan Tajara", "M'sai Tajara") sort_category = "Xenowear - Tajara" - flags = GEAR_HAS_DESC_SELECTION \ No newline at end of file + flags = GEAR_HAS_DESC_SELECTION + +/datum/gear/augment/tesla_spine + display_name = "tesla spine" + description = "A People's Republic of Adhomai made tesla spine issued to disabled veterans and civilians." + path = /obj/item/organ/internal/augment/tesla + cost = 4 + whitelisted = list("Tajara", "Zhan-Khazan Tajara", "M'sai Tajara") + sort_category = "Xenowear - Tajara" diff --git a/code/modules/client/preference_setup/loadout/loadout_xeno/unathi.dm b/code/modules/client/preference_setup/loadout/loadout_xeno/unathi.dm index d8346addb06..f9f67fda06e 100644 --- a/code/modules/client/preference_setup/loadout/loadout_xeno/unathi.dm +++ b/code/modules/client/preference_setup/loadout/loadout_xeno/unathi.dm @@ -46,41 +46,41 @@ sort_category = "Xenowear - Unathi" flags = GEAR_HAS_NAME_SELECTION | GEAR_HAS_DESC_SELECTION | GEAR_HAS_COLOR_SELECTION -/datum/gear/autakh_engineering +/datum/gear/augment/autakh_engineering display_name = "engineering grasper" description = "An Aut'akh augment limb, this one is outfitted with a limited toolkit." path = /obj/item/organ/external/hand/right/autakh/tool - whitelisted = list("Aut'akh Unathi") + whitelisted = list("Unathi", "Aut'akh Unathi") sort_category = "Xenowear - Unathi" cost = 3 allowed_roles = list("Station Engineer", "Chief Engineer", "Atmospheric Technician", "Engineering Apprentice", "Roboticist") flags = GEAR_NO_SELECTION -/datum/gear/autakh_mining +/datum/gear/augment/autakh_mining display_name = "mining grasper" description = "An Aut'akh augment limb, this one is outfitted with a mining drill." path = /obj/item/organ/external/hand/right/autakh/tool/mining - whitelisted = list("Aut'akh Unathi") + whitelisted = list("Unathi", "Aut'akh Unathi") sort_category = "Xenowear - Unathi" cost = 3 allowed_roles = list("Shaft Miner") flags = GEAR_NO_SELECTION -/datum/gear/autakh_medical +/datum/gear/augment/autakh_medical display_name = "medical grasper" description = "An Aut'akh augment limb, this one is outfitted with a health scanner." path = /obj/item/organ/external/hand/right/autakh/medical - whitelisted = list("Aut'akh Unathi") + whitelisted = list("Unathi", "Aut'akh Unathi") sort_category = "Xenowear - Unathi" cost = 3 allowed_roles = list("Chief Medical Officer", "Physician", "Surgeon", "Paramedic", "Medical Resident", "Psychiatrist", "Chemist") flags = GEAR_NO_SELECTION -/datum/gear/autakh_security +/datum/gear/augment/autakh_security display_name = "security grasper" description = "An Aut'akh augment limb, this one is outfitted with an electroshock weapon." path = /obj/item/organ/external/hand/right/autakh/security - whitelisted = list("Aut'akh Unathi") + whitelisted = list("Unathi", "Aut'akh Unathi") sort_category = "Xenowear - Unathi" cost = 3 allowed_roles = list("Security Officer", "Head of Security", "Warden") @@ -138,4 +138,12 @@ cost = 1 whitelisted = list("Unathi") sort_category = "Xenowear - Unathi" - flags = GEAR_HAS_DESC_SELECTION \ No newline at end of file + flags = GEAR_HAS_DESC_SELECTION + +/datum/gear/augment/anchor + display_name = "soul anchor" + description = "An implant that connects the Aut'akh to the Mesh." + path = /obj/item/organ/internal/anchor + cost = 1 + whitelisted = list("Unathi") + sort_category = "Xenowear - Unathi" \ No newline at end of file diff --git a/code/modules/clothing/spacesuits/rig/suits/alien.dm b/code/modules/clothing/spacesuits/rig/suits/alien.dm index 14e5c53bf6e..b65ae6a1d52 100644 --- a/code/modules/clothing/spacesuits/rig/suits/alien.dm +++ b/code/modules/clothing/spacesuits/rig/suits/alien.dm @@ -96,3 +96,11 @@ /obj/item/rig_module/mounted/tesla) allowed_module_types = MODULE_GENERAL | MODULE_LIGHT_COMBAT | MODULE_HEAVY_COMBAT | MODULE_UTILITY + +/obj/item/rig/tesla/process() + ..() + if(wearer) + var/obj/item/organ/internal/augment/tesla/T = wearer.internal_organs_by_name[BP_AUG_TESLA] + if(T && !T.is_broken()) + if(cell) + cell.give(T.max_charges) diff --git a/code/modules/mob/abstract/new_player/new_player.dm b/code/modules/mob/abstract/new_player/new_player.dm index 520843cf979..a7ca37f4825 100644 --- a/code/modules/mob/abstract/new_player/new_player.dm +++ b/code/modules/mob/abstract/new_player/new_player.dm @@ -333,6 +333,7 @@ INITIALIZE_IMMEDIATE(/mob/abstract/new_player) var/mob/living/character = create_character() //creates the human and transfers vars and mind + SSjobs.EquipAugments(character, character.client.prefs) character = SSjobs.EquipPersonal(character, rank, 1,spawning_at) //equips the human // AIs don't need a spawnpoint, they must spawn at an empty core diff --git a/code/modules/mob/living/carbon/human/human.dm b/code/modules/mob/living/carbon/human/human.dm index 41da71d9f0b..4a71a702119 100644 --- a/code/modules/mob/living/carbon/human/human.dm +++ b/code/modules/mob/living/carbon/human/human.dm @@ -509,6 +509,11 @@ if (shock_damage<1) return 0 + var/obj/item/organ/internal/augment/tesla/tesla = internal_organs_by_name[BP_AUG_TESLA] + if(tesla?.check_shock()) + tesla.actual_charges = min(tesla.actual_charges+1, tesla.max_charges) + return FALSE + if(!def_zone) //The way this works is by damaging multiple areas in an "Arc" if no def_zone is provided. should be pretty easy to add more arcs if it's needed. though I can't imangine a situation that can apply. switch ((h_style == "Floorlength Braid" || h_style == "Very Long Hair") ? rand(1, 7) : rand(1, 6)) @@ -1278,6 +1283,8 @@ //Fix husks mutations.Remove(HUSK) status_flags &= ~DISFIGURED //Fixes the unknown status + if(src.client) + SSjobs.EquipAugments(src, src.client.prefs) update_body(1) update_eyes() diff --git a/code/modules/mob/living/carbon/taste.dm b/code/modules/mob/living/carbon/taste.dm index e2337ac94e0..072d4a1144f 100644 --- a/code/modules/mob/living/carbon/taste.dm +++ b/code/modules/mob/living/carbon/taste.dm @@ -18,7 +18,15 @@ calculate text size per text. var/minimum_percent = 15 if(ishuman(taster)) var/mob/living/carbon/human/H = taster - minimum_percent = round(15/ (H.isSynthetic() ? TASTE_DULL : H.species.taste_sensitivity)) + var/total_taste_sensitivity + + var/obj/item/organ/internal/augment/taste_booster/booster = H.internal_organs_by_name[BP_AUG_TASTE_BOOSTER] + if(booster && !booster.is_broken()) + total_taste_sensitivity = booster.new_taste + else + total_taste_sensitivity = H.species.taste_sensitivity + + minimum_percent = round(15 / (H.isSynthetic() ? TASTE_DULL : total_taste_sensitivity)) var/list/out = list() var/list/tastes = list() //descriptor = strength @@ -91,4 +99,4 @@ calculate text size per text. return "[temp_text][temp_text ? " " : ""][english_list(out, "something indescribable")]." /mob/living/carbon/proc/get_fullness() - return nutrition + (reagents.get_reagent_amount("nutriment") * 25) \ No newline at end of file + return nutrition + (reagents.get_reagent_amount("nutriment") * 25) diff --git a/code/modules/multiz/movement.dm b/code/modules/multiz/movement.dm index 80f9297da02..b19d0bc21dc 100644 --- a/code/modules/multiz/movement.dm +++ b/code/modules/multiz/movement.dm @@ -496,8 +496,14 @@ visible_message(span("notice", "\The [src] tucks into a roll as they hit \the [loc]!"), span("notice", "You tuck into a roll as you hit \the [loc], minimizing damage!")) + var/aug_mod = 1 + var/obj/item/organ/internal/augment/suspension/suspension = internal_organs_by_name[BP_AUG_SUSPENSION] + if(suspension && !suspension.is_broken()) + aug_mod = suspension.suspension_mod + suspension.take_damage(10) + var/z_velocity = 5*(levels_fallen**2) - var/damage = (((40 * species.fall_mod) + z_velocity) + rand(-20,20)) * combat_roll * damage_mod + var/damage = (((40 * species.fall_mod) + z_velocity) + rand(-20,20)) * combat_roll * damage_mod * aug_mod var/limb_damage = rand(0,damage/2) diff --git a/code/modules/organs/internal/_internal.dm b/code/modules/organs/internal/_internal.dm index 0cc122960ac..1f7a1b8edd7 100644 --- a/code/modules/organs/internal/_internal.dm +++ b/code/modules/organs/internal/_internal.dm @@ -6,6 +6,7 @@ var/damage_reduction = 0.5 //modifier for internal organ injury var/toxin_type = "undefined" var/relative_size = 25 //Used for size calcs + var/on_mob_icon min_broken_damage = 10 //Internal organs are frail, man. diff --git a/code/modules/organs/organ.dm b/code/modules/organs/organ.dm index f1d62d6e7da..13e59b3b9ae 100644 --- a/code/modules/organs/organ.dm +++ b/code/modules/organs/organ.dm @@ -11,6 +11,7 @@ var/status = 0 var/vital //Lose a vital limb, die immediately. var/rejecting // Is this organ already being rejected? + var/is_augment = FALSE //Organ damage stats. var/damage = 0 // amount of damage to the organ @@ -28,18 +29,19 @@ var/robotic_name var/robotic_sprite var/emp_coeff = 1 //coefficient for damages taken by EMP, if the organ is robotic. - + //Lists. var/list/transplant_data var/list/datum/autopsy_data/autopsy_data = list() var/list/organ_verbs //verb that are added when you gain the organ var/list/trace_chemicals = list() // traces of chemicals in the organ, // links chemical IDs to number of ticks for which they'll stay in the blood - + //DNA stuff. var/datum/dna/dna var/datum/species/species var/force_skintone = FALSE // If true, icon generation will skip is-robotic checks. Used for synthskin limbs. + var/list/species_restricted //used by augments and biomods to see what species can have this augment /obj/item/organ/New(loc, ...) ..() diff --git a/code/modules/organs/organ_external.dm b/code/modules/organs/organ_external.dm index 523c6ffb6b1..418aa4b43a8 100644 --- a/code/modules/organs/organ_external.dm +++ b/code/modules/organs/organ_external.dm @@ -85,6 +85,8 @@ var/image/hud_damage_image + var/augment_limit //how many augments you can fit inside this limb + /obj/item/organ/external/proc/invalidate_marking_cache() cached_markings = null @@ -1042,6 +1044,8 @@ Note that amputating the affected organ does in fact remove the infection from t brute_mod = R.brute_mod burn_mod = R.burn_mod + robotize_type = company + augment_limit += 1 //robotic limbs get one extra augment capacity dislocated = -1 //TODO, make robotic limbs a separate type, remove snowflake limb_flags &= ~ORGAN_CAN_BREAK @@ -1085,7 +1089,14 @@ Note that amputating the affected organ does in fact remove the infection from t return ..() && !is_dislocated() && !(status & ORGAN_TENDON_CUT) && (!can_feel_pain() || get_pain() < pain_disability_threshold) && brute_ratio < 1 && burn_ratio < 1 /obj/item/organ/external/proc/is_malfunctioning() - return (BP_IS_ROBOTIC(src) && (brute_ratio + burn_ratio) >= 0.3 && prob(brute_dam + burn_dam)) + if(BP_IS_ROBOTIC(src) && (brute_ratio + burn_ratio) >= 0.3 && prob(brute_dam + burn_dam)) + return TRUE + if(robotize_type) + var/datum/robolimb/R = all_robolimbs[robotize_type] + if(R.malfunctioning_check(owner)) + return TRUE + else + return FALSE /obj/item/organ/external/proc/embed(var/obj/item/W, var/silent = 0, var/supplied_message) if(!owner || loc != owner) diff --git a/code/modules/organs/organ_icon.dm b/code/modules/organs/organ_icon.dm index de5238e2c08..f130299ffdc 100644 --- a/code/modules/organs/organ_icon.dm +++ b/code/modules/organs/organ_icon.dm @@ -85,6 +85,8 @@ apply_markings() + get_internal_organs_overlay() + add_overlay(owner.generate_hair_icon()) compile_overlays() @@ -113,6 +115,19 @@ add_overlay(finished_icon) //So when it's not on your body, it has icons mob_icon.Blend(finished_icon, ICON_OVERLAY) //So when it's on your body, it has icons +/obj/item/organ/external/proc/get_internal_organs_overlay() + for(var/obj/item/organ/internal/O in internal_organs) + if(O.on_mob_icon) + var/cache_key = "[O.on_mob_icon]-[O.icon_state]" + + var/icon/organ_icon = SSicon_cache.internal_organ_cache[cache_key] + if (!organ_icon) + organ_icon = new /icon(O.on_mob_icon, O.icon_state) + SSicon_cache.internal_organ_cache[cache_key] = organ_icon + + add_overlay(organ_icon) + mob_icon.Blend(organ_icon, ICON_OVERLAY) + /obj/item/organ/external/var/icon_cache_key /obj/item/organ/external/proc/get_icon(var/skeletal) @@ -125,6 +140,7 @@ if(painted && skin_color) mob_icon.Blend(skin_color, ICON_ADD) apply_markings(restrict_to_robotic = TRUE) + get_internal_organs_overlay() else if(!dna) mob_icon = new /icon('icons/mob/human_races/human/r_human.dmi', "[icon_name][gendered_icon ? "_[gender]" : ""]") @@ -162,6 +178,7 @@ apply_markings() + get_internal_organs_overlay() if(body_hair) var/list/limb_icon_cache = SSicon_cache.limb_icons_cache @@ -212,6 +229,10 @@ for (var/marking in cached_markings) keyparts += "[marking][cached_markings[marking]["color"]]" + for(var/obj/item/organ/internal/O in internal_organs) + if(O.on_mob_icon) + keyparts += "[O.on_mob_icon]-[O.icon_state]" + . = keyparts.Join("_") /obj/item/organ/external/proc/update_marking_cache() @@ -252,4 +273,4 @@ var/list/robot_hud_colours = list("#ffffff","#cccccc","#aaaaaa","#888888","#6666 // Apply colour and return product. var/list/hud_colours = !BP_IS_ROBOTIC(src) ? flesh_hud_colours : robot_hud_colours hud_damage_image.color = hud_colours[max(1,min(Ceiling(dam_state*hud_colours.len),hud_colours.len))] - return hud_damage_image \ No newline at end of file + return hud_damage_image diff --git a/code/modules/organs/robolimbs.dm b/code/modules/organs/robolimbs.dm index 0777a72bec4..88135356dc3 100644 --- a/code/modules/organs/robolimbs.dm +++ b/code/modules/organs/robolimbs.dm @@ -1,5 +1,6 @@ var/global/list/all_robolimbs = list() var/global/list/chargen_robolimbs = list() +var/global/list/fabricator_robolimbs = list() var/global/datum/robolimb/basic_robolimb /proc/populate_robolimb_list() @@ -9,6 +10,8 @@ var/global/datum/robolimb/basic_robolimb all_robolimbs[R.company] = R if(!R.unavailable_at_chargen) chargen_robolimbs[R.company] = R + if(R.fabricator_available) + fabricator_robolimbs[R.company] = R /datum/robolimb var/company = "Unbranded" // Shown when selecting the limb. @@ -31,30 +34,38 @@ var/global/datum/robolimb/basic_robolimb var/linked_frame = "Unbranded Frame" //which machine species this limb will create var/brute_mod = 0.9 //how resistant is this mode to brute damage var/burn_mod = 1.1 //how resistant is this mode to burn damage + var/fabricator_available = FALSE //if you can print this limb in the robotics fabricator + +/datum/robolimb/proc/malfunctioning_check() + return FALSE /datum/robolimb/bishop company = PROSTHETIC_BC desc = "This limb is coated in a brilliant silver illuminated from the inside with blue status lights." icon = 'icons/mob/human_races/ipc/r_ind_bishop.dmi' linked_frame = "Bishop Accessory Frame" + fabricator_available = TRUE /datum/robolimb/hesphaistos company = PROSTHETIC_HI desc = "This limb is covered in thick plating coated with a militaristic olive drab." icon = 'icons/mob/human_races/ipc/r_ind_hephaestus.dmi' linked_frame = "Hephaestus G2 Industrial Frame" + fabricator_available = TRUE /datum/robolimb/zenghu company = PROSTHETIC_ZH desc = "This limb has sleek white plating over a graphene-based nanofiber weave." icon = 'icons/mob/human_races/ipc/r_ind_zenghu.dmi' linked_frame = "Zeng-Hu Mobility Frame" + fabricator_available = TRUE /datum/robolimb/xion company = PROSTHETIC_XMG desc = "This limb has a minimalist black and grey casing with exposed orange wiring channels." icon = 'icons/mob/human_races/ipc/r_ind_xion.dmi' linked_frame = "Xion Industrial Frame" + fabricator_available = TRUE /datum/robolimb/ipc company = PROSTHETIC_IPC @@ -63,6 +74,7 @@ var/global/datum/robolimb/basic_robolimb unavailable_at_chargen = 1 paintable = 1 linked_frame = "Baseline Frame" + fabricator_available = TRUE /datum/robolimb/industrial company = PROSTHETIC_IND @@ -70,6 +82,7 @@ var/global/datum/robolimb/basic_robolimb icon = 'icons/mob/human_races/ipc/r_industrial.dmi' unavailable_at_chargen = 1 linked_frame = "Hephaestus G1 Industrial Frame" + fabricator_available = TRUE /datum/robolimb/terminator company = PROSTHETIC_HK @@ -83,6 +96,7 @@ var/global/datum/robolimb/basic_robolimb icon = 'icons/mob/human_races/human/r_human.dmi' species_can_use = list("Human") linked_frame = "Shell Frame" + fabricator_available = TRUE /datum/robolimb/autakh company = PROSTHETIC_AUTAKH @@ -93,4 +107,17 @@ var/global/datum/robolimb/basic_robolimb unavailable_at_chargen = 1 paintable = 1 brute_mod = 1 - burn_mod = 1 \ No newline at end of file + burn_mod = 1 + +/datum/robolimb/tesla + company = PROSTHETIC_TESLA + desc = "A limb designed to be used by the People's Republic of Adhomai Tesla Brigade. This civilian version is issued to disabled veterans and civilians." + icon = 'icons/mob/human_races/tajara/tesla_limbs.dmi' + species_can_use = list("Tajara", "Zhan-Khazan Tajara", "M'sai Tajara") + +/datum/robolimb/tesla/malfunctioning_check(var/mob/living/carbon/human/H) + var/obj/item/organ/internal/augment/tesla/T = H.internal_organs_by_name[BP_AUG_TESLA] + if(T && !T.is_broken()) + return FALSE + else + return TRUE diff --git a/code/modules/organs/subtypes/augment.dm b/code/modules/organs/subtypes/augment.dm new file mode 100644 index 00000000000..ff985ead8d8 --- /dev/null +++ b/code/modules/organs/subtypes/augment.dm @@ -0,0 +1,294 @@ +/obj/item/organ/internal/augment + name = "augment" + icon_state = "augment" + parent_organ = BP_CHEST + organ_tag = "augment" + robotic = 2 + emp_coeff = 2 + is_augment = TRUE + species_restricted = list("Human","Off-Worlder Human", + "Tajara", "Zhan-Khazan Tajara", "M'sai Tajara", + "Unathi", "Aut'akh Unathi", "Skrell", + "Baseline Frame", "Hephaestus G1 Industrial Frame", + "Hephaestus G2 Industrial Frame", "Xion Industrial Frame", + "Zeng-Hu Mobility Frame", "Bishop Accessory Frame") + var/cooldown = 150 + var/action_button_icon = "augment" + var/activable = FALSE + +/obj/item/organ/internal/augment/Initialize() + robotize() + . = ..() + +/obj/item/organ/internal/augment/refresh_action_button() + . = ..() + if(.) + if(activable) + action.button_icon_state = action_button_icon + if(action.button) + action.button.UpdateIcon() + +/obj/item/organ/internal/augment/attack_self(var/mob/user) + . = ..() + + if(.) + + if(owner.last_special > world.time) + to_chat(owner, SPAN_WARNING("\The [src] is still recharging!")) + return FALSE + + if(use_check_and_message(owner)) + return FALSE + + if(is_bruised()) + if(do_bruised_act()) + return FALSE + + if(is_broken()) + if(do_broken_act()) + return FALSE + + owner.last_special = world.time + cooldown + return TRUE + + +/obj/item/organ/internal/augment/proc/do_broken_act() + spark(get_turf(owner), 3) + return TRUE + +/obj/item/organ/internal/augment/proc/do_bruised_act() + spark(get_turf(owner), 3) + return FALSE + +/obj/item/organ/internal/augment/timepiece + name = "integrated timepiece" + icon_state = "augment-clock" + parent_organ = BP_HEAD + action_button_name = "Activate Integrated Timepiece" + activable = TRUE + organ_tag = BP_AUG_TIMEPIECE + action_button_icon = "augment-clock" + cooldown = 10 + +/obj/item/organ/internal/augment/timepiece/attack_self(var/mob/user) + . = ..() + + if(!.) + return FALSE + + to_chat(owner, SPAN_NOTICE("Hello [user], it is currently: '[worldtime2text()]'. Today's date is '[time2text(world.time, "Month DD")]. [game_year]'. Have a lovely day.")) + if (emergency_shuttle.get_status_panel_eta()) + to_chat(owner, SPAN_WARNING("Notice: You have one (1) scheduled flight, ETA: [emergency_shuttle.get_status_panel_eta()].")) + +/obj/item/organ/internal/augment/tool + name = "retractable widget" + action_button_name = "Deploy Widget" + cooldown = 10 + activable = TRUE + var/obj/item/augment_type + + +/obj/item/organ/internal/augment/tool/attack_self(var/mob/user) + . = ..() + + if(!.) + return FALSE + + + if(!augment_type) + return FALSE + + if (locate(augment_type) in owner) + to_chat(owner, SPAN_WARNING("\The [src] is already enabled!")) + return + + if(owner.get_active_hand()) + to_chat(owner, SPAN_WARNING("You must empty your active hand before enabling your [src]!")) + return + + var/obj/item/M = new augment_type(owner) + owner.put_in_active_hand(M) + owner.visible_message(SPAN_NOTICE("\The [M] slides out of \the [owner]'s [src.loc]."), SPAN_NOTICE("You deploy \the [M]!")) + +/obj/item/organ/internal/augment/tool/combitool + name = "retractable combitool" + icon_state = "augment-tool" + action_button_name = "Deploy Combitool" + action_button_icon = "augment-tool" + parent_organ = BP_R_HAND + organ_tag = BP_AUG_TOOL + augment_type = /obj/item/combitool/robotic + +/obj/item/organ/internal/augment/tool/combitool/left + parent_organ = BP_L_HAND + +/obj/item/organ/internal/augment/health_scanner + name = "integrated health scanner" + action_button_name = "Activate Health Scanner" + action_button_icon = "health" + organ_tag = BP_AUG_HEALTHSCAN + activable = TRUE + cooldown = 8 + +/obj/item/organ/internal/augment/health_scanner/attack_self(var/mob/user) + . = ..() + if(!.) + return FALSE + + health_scan_mob(owner, owner) + +/obj/item/organ/internal/augment/tesla + name = "tesla spine" + icon_state = "tesla_spine" + organ_tag = BP_AUG_TESLA + on_mob_icon = 'icons/mob/human_races/augments_external.dmi' + species_restricted = list("Tajara", "Zhan-Khazan Tajara", "M'sai Tajara") + var/max_charges = 1 + var/actual_charges = 0 + var/recharge_time = 5 //this is in minutes + +/obj/item/organ/internal/augment/tesla/proc/check_shock() + if(is_broken()) + return FALSE + if(is_bruised()) + if(prob(50)) + return FALSE + if(actual_charges >= max_charges) + return FALSE + else + do_tesla_act() + return TRUE + +/obj/item/organ/internal/augment/tesla/proc/do_tesla_act() + if(owner) + to_chat(owner, FONT_LARGE(SPAN_DANGER("You feel your [src.name] surge with energy!"))) + spark(get_turf(owner), 3) + addtimer(CALLBACK(src, .proc/disarm), recharge_time MINUTES) + if(is_bruised() && prob(50)) + owner.electrocute_act(40, owner) + +/obj/item/organ/internal/augment/tesla/proc/disarm() + if(actual_charges <= 0) + return + actual_charges = min(actual_charges - 1, max_charges) + if(actual_charges > 0) + addtimer(CALLBACK(src, .proc/disarm), recharge_time MINUTES) + if(is_broken()) + visible_message(SPAN_DANGER("\The [owner] crackles with energy!")) + playsound(owner, 'sound/magic/LightningShock.ogg', 75, 1) + tesla_zap(owner, 7, 1500) + +/obj/item/organ/internal/augment/tesla/advanced + name = "advanced tesla spine" + max_charges = 15 + cooldown = 50 + emp_coeff = 1 + action_button_icon = "tesla_spine" + action_button_name = "Activate Tesla Coil" + activable = TRUE + +/obj/item/organ/internal/augment/tesla/advanced/attack_self(var/mob/user) + . = ..() + + if(!.) + return FALSE + + visible_message(SPAN_DANGER("\The [owner] crackles with energy!")) + playsound(owner, 'sound/magic/LightningShock.ogg', 75, 1) + tesla_zap(owner, 7, 1500) + +/obj/item/organ/internal/augment/eye_sensors + name = "integrated eye sensors" + icon_state = "augment_eyes" + cooldown = 25 + activable = TRUE + organ_tag = BP_AUG_EYE_SENSORS + action_button_name = "Toggle Eye Sensors" + + var/static/list/hud_types = list( + "Disabled", + "Security", + "Medical") + + var/selected_hud = "Disabled" + +/obj/item/organ/internal/augment/eye_sensors/attack_self(var/mob/user) + . = ..() + + if(!.) + return FALSE + + var/choice = input("Select the Sensor Type.", "Bionic Eyes Sensors") as null|anything in hud_types + + selected_hud = choice + +/obj/item/organ/internal/augment/eye_sensors/process() + ..() + + if(!owner) + return + + switch(selected_hud) + + if("Security") + req_access = list(access_security) + if(allowed(owner)) + process_sec_hud(owner, 1) + + if("Medical") + req_access = list(access_medical) + if(allowed(owner)) + process_med_hud(owner, 1) + +/obj/item/organ/internal/augment/eye_sensors/emp_act(severity) + ..() + var/obj/item/organ/internal/eyes/E = owner.get_eyes() + if(!E) + return + E.take_damage(5) + +/obj/item/organ/internal/augment/cyber_hair + name = "synthetic hair extensions" + cooldown = 20 + action_button_icon = "cyber_hair" + organ_tag = BP_AUG_HAIR + activable = TRUE + action_button_name = "Activate Synthetic Hair Extensions" + +/obj/item/organ/internal/augment/cyber_hair/attack_self(var/mob/user) + . = ..() + + if(!.) + return FALSE + + owner.visible_message(SPAN_NOTICE("\The [owner]'s hair begins to rapidly shift in shape and length.")) + owner.change_appearance(APPEARANCE_ALL_HAIR, owner.loc, owner, check_species_whitelist = 1) + +/obj/item/organ/internal/augment/suspension + name = "calf suspension" + icon_state = "suspension" + organ_tag = BP_AUG_SUSPENSION + parent_organ = BP_GROIN + min_broken_damage = 20 + max_damage = 20 + var/suspension_mod = 0.8 + +/obj/item/organ/internal/augment/suspension/advanced + name = "advanced calf suspension" + min_broken_damage = 50 + max_damage = 50 + suspension_mod = 0 + +/obj/item/organ/internal/augment/taste_booster + name = "taste booster" + organ_tag = BP_AUG_TASTE_BOOSTER + parent_organ = BP_HEAD + var/new_taste = TASTE_SENSITIVE //this will replace the species' taste var + +/obj/item/organ/internal/augment/taste_booster/dull + name = "taste duller" + new_taste = TASTE_DULL + +/obj/item/organ/internal/augment/fuel_cell + name = "integrated fuel cell" + organ_tag = BP_AUG_FUEL_CELL \ No newline at end of file diff --git a/code/modules/organs/subtypes/autakh.dm b/code/modules/organs/subtypes/autakh.dm index 771893df7d1..8dd7789c329 100644 --- a/code/modules/organs/subtypes/autakh.dm +++ b/code/modules/organs/subtypes/autakh.dm @@ -334,7 +334,8 @@ desc = "An integrated combitool module." icon_state = "digitool" item_state = "digitool" - + w_class = ITEMSIZE_LARGE + /obj/item/combitool/robotic/throw_at() usr.drop_from_inventory(src) diff --git a/code/modules/organs/subtypes/standard.dm b/code/modules/organs/subtypes/standard.dm index 77e2f7a8e90..e8dc90b0758 100644 --- a/code/modules/organs/subtypes/standard.dm +++ b/code/modules/organs/subtypes/standard.dm @@ -19,6 +19,7 @@ limb_flags = ORGAN_CAN_BREAK parent_organ = null encased = "ribcage" + augment_limit = 3 /obj/item/organ/external/groin name = "lower body" @@ -35,6 +36,7 @@ artery_name = "iliac artery" dislocated = -1 gendered_icon = 1 + augment_limit = 3 /obj/item/organ/external/arm limb_name = "l_arm" @@ -50,6 +52,7 @@ tendon_name = "palmaris longus tendon" artery_name = "basilic vein" amputation_point = "left shoulder" + augment_limit = 2 /obj/item/organ/external/arm/right limb_name = "r_arm" @@ -76,6 +79,7 @@ artery_name = "femoral artery" amputation_point = "left hip" limb_flags = ORGAN_CAN_AMPUTATE | ORGAN_CAN_BREAK | ORGAN_CAN_MAIM | ORGAN_HAS_TENDON + augment_limit = 2 /obj/item/organ/external/leg/right limb_name = "r_leg" @@ -100,6 +104,7 @@ amputation_point = "left ankle" limb_flags = ORGAN_CAN_AMPUTATE | ORGAN_CAN_BREAK | ORGAN_CAN_MAIM | ORGAN_CAN_STAND maim_bonus = 1 + augment_limit = 1 /obj/item/organ/external/foot/removed() if(owner) @@ -130,6 +135,7 @@ amputation_point = "left wrist" limb_flags = ORGAN_CAN_AMPUTATE | ORGAN_CAN_BREAK | ORGAN_CAN_MAIM | ORGAN_CAN_GRASP | ORGAN_HAS_TENDON maim_bonus = 1 + augment_limit = 1 /obj/item/organ/external/hand/removed() owner.drop_from_inventory(owner.gloves) @@ -163,6 +169,7 @@ amputation_point = "neck" gendered_icon = 1 encased = "skull" + augment_limit = 3 var/can_intake_reagents = 1 /obj/item/organ/external/head/removed() diff --git a/code/modules/reagents/Chemistry-Reagents/Chemistry-Reagents-Core.dm b/code/modules/reagents/Chemistry-Reagents/Chemistry-Reagents-Core.dm index 8db132568ca..5bccb29c9e1 100644 --- a/code/modules/reagents/Chemistry-Reagents/Chemistry-Reagents-Core.dm +++ b/code/modules/reagents/Chemistry-Reagents/Chemistry-Reagents-Core.dm @@ -275,7 +275,11 @@ return /datum/reagent/fuel/affect_blood(var/mob/living/carbon/M, var/alien, var/removed) - M.adjustToxLoss(2 * removed) + var/obj/item/organ/internal/augment/fuel_cell/aug = M.internal_organs_by_name[BP_AUG_FUEL_CELL] + if(aug && !aug.is_broken()) + M.adjustNutritionLoss(-8 * removed) + else + M.adjustToxLoss(2 * removed) /datum/reagent/fuel/touch_mob(var/mob/living/L, var/amount) . = ..() diff --git a/code/modules/reagents/Chemistry-Reagents/Chemistry-Reagents-Dispenser.dm b/code/modules/reagents/Chemistry-Reagents/Chemistry-Reagents-Dispenser.dm index 8f04afa73d4..0e9e6850139 100644 --- a/code/modules/reagents/Chemistry-Reagents/Chemistry-Reagents-Dispenser.dm +++ b/code/modules/reagents/Chemistry-Reagents/Chemistry-Reagents-Dispenser.dm @@ -160,7 +160,7 @@ if (halluci) M.hallucination = max(M.hallucination, halluci) - + if(caffeine) M.add_chemical_effect(CE_PULSE, caffeine*2) if(!caffeine_mod) @@ -269,7 +269,11 @@ fallback_specific_heat = 0.549 //Unknown /datum/reagent/hydrazine/affect_blood(var/mob/living/carbon/M, var/alien, var/removed) - M.adjustToxLoss(4 * removed) + var/obj/item/organ/internal/augment/fuel_cell/aug = M.internal_organs_by_name[BP_AUG_FUEL_CELL] + if(aug && !aug.is_broken()) + M.adjustNutritionLoss(-12 * removed) + else + M.adjustToxLoss(4 * removed) /datum/reagent/hydrazine/affect_touch(var/mob/living/carbon/M, var/alien, var/removed) // Hydrazine is both toxic and flammable. M.adjust_fire_stacks(removed / 12) diff --git a/code/modules/surgery/organs_internal.dm b/code/modules/surgery/organs_internal.dm index bb3adc07e77..d31453bb85b 100644 --- a/code/modules/surgery/organs_internal.dm +++ b/code/modules/surgery/organs_internal.dm @@ -9,7 +9,12 @@ return 0 var/obj/item/organ/external/affected = target.get_organ(target_zone) - return affected && affected.open == (affected.encased ? 3 : 2) + if(affected.encased) + return affected && affected.open == (affected.encased ? 3 : 2) + if(BP_IS_ROBOTIC(affected)) + return affected.augment_limit && affected.open == 3 + else + return affected.augment_limit && affected.open == 2 ////////////////////////////////////////////////////////////////// // CHEST INTERNAL ORGAN SURGERY // @@ -148,6 +153,10 @@ if(I && istype(I)) I.status |= ORGAN_CUT_AWAY + target.update_body() + target.updatehealth() + target.UpdateDamageIcon() + /datum/surgery_step/internal/detach_organ/fail_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) var/obj/item/organ/external/affected = target.get_organ(target_zone) user.visible_message("[user]'s hand slips, slicing an artery inside [target]'s [affected.name] with \the [tool]!", \ @@ -205,6 +214,10 @@ else playsound(target.loc, 'sound/items/Ratchet.ogg', 50, 1) + target.update_body() + target.updatehealth() + target.UpdateDamageIcon() + /datum/surgery_step/internal/remove_organ/fail_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) var/obj/item/organ/external/affected = target.get_organ(target_zone) user.visible_message("[user]'s hand slips, damaging [target]'s [affected.name] with \the [tool]!", \ @@ -246,12 +259,30 @@ if(O.organ_tag == "limb") return 0 - else if(target.species.has_organ[O.organ_tag]) + else if(target.species.has_organ[O.organ_tag] || O.is_augment) if(O.damage > (O.max_damage * 0.75)) to_chat(user, "\The [O.organ_tag] [o_is] in no state to be transplanted.") return SURGERY_FAILURE + if(O.species_restricted) + if(!target.species.name in O.species_restricted) + to_chat(user, SPAN_WARNING("\The [O] is not compatible with \the [target]'s biology.")) + return SURGERY_FAILURE + + if(O.is_augment) + if(affected.augment_limit) + var/total_augments + for(var/obj/item/organ/internal/I in affected.internal_organs) + if(I.is_augment) + total_augments += 1 + if(total_augments >= affected.augment_limit) + to_chat(user, SPAN_WARNING("There is no space left in \the [affected] to implant \the [O].")) + return SURGERY_FAILURE + else + to_chat(user, SPAN_WARNING("There is no space in \the [affected] to implant \the [O].")) + return SURGERY_FAILURE + if(!target.internal_organs_by_name[O.organ_tag]) organ_missing = 1 else @@ -285,6 +316,10 @@ O.replaced(target,affected) playsound(target.loc, 'sound/effects/squelch1.ogg', 50, 1) + target.update_body() + target.updatehealth() + target.UpdateDamageIcon() + /datum/surgery_step/internal/replace_organ/fail_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) user.visible_message("[user]'s hand slips, damaging \the [tool]!", \ "Your hand slips, damaging \the [tool]!") @@ -334,6 +369,10 @@ if(I && istype(I)) I.status &= ~ORGAN_CUT_AWAY + target.update_body() + target.updatehealth() + target.UpdateDamageIcon() + /datum/surgery_step/internal/attach_organ/fail_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) var/obj/item/organ/external/affected = target.get_organ(target_zone) user.visible_message("[user]'s hand slips, damaging the flesh in [target]'s [affected.name] with \the [tool]!", \ diff --git a/html/changelogs/alberyk-augs.yml b/html/changelogs/alberyk-augs.yml new file mode 100644 index 00000000000..f97286de98d --- /dev/null +++ b/html/changelogs/alberyk-augs.yml @@ -0,0 +1,7 @@ +author: Alberyk, Kyres1 + +delete-after: True + +changes: + - rscadd: "Added a couple of augments to the custom loadout." + - rscadd: "Added tesla limbs for the Tajara species." diff --git a/icons/mob/human_races/augments_external.dmi b/icons/mob/human_races/augments_external.dmi new file mode 100644 index 0000000000000000000000000000000000000000..74c345f5a7bbf88736f97abc2ba0e50ea8411f84 GIT binary patch literal 320 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0J3?w7mbKU|e(Ey(i*8>L**xOm|-L)ZN0Pyu5}kY6x^!?PP{Ku$qbNJNQCYH@N=WKhlO#F@nvH#g*lHV9hnrO5WG@l ztA)DZz8wn2`k|fO#;TiFNGzG!ZM;^)&|LJ0*^{8Kg0IDl(tHfetujklzc-!)+8yiZ z;uzx5nVcZOYQoyn)bvA?W2OY>gHQz-k)C+Q*`1Pg+B2G)K59$ws2Q-aJ_- zc2GltO@Se}Lv-fhCf~`-LbEw%GqpOVF=?BzGA_|bII=8ZOUnXd1_tJ{?8n<5?6?H9 Oh{4m<&t;ucLK6TP;c|-r literal 0 HcmV?d00001 diff --git a/icons/mob/human_races/tajara/tesla_limbs.dmi b/icons/mob/human_races/tajara/tesla_limbs.dmi new file mode 100644 index 0000000000000000000000000000000000000000..cb74cd7e705f4c6c974a50554791b48a04d7b7ff GIT binary patch literal 891 zcmV->1BCpEP)hO!y}Gb(ZDgdPn83imE2<9c00001bW%=J06^y0W&i*H zj(SvBbVOxyV{&P5bZKvH004NLQ&wiFEu_#xGi!&v&s2HS)i!-e#F*g;&Hbkh(Axc$I zd`4nk3K518rK~7ECpDc2!-!E;6rYx#UqXao_>?Itxca$(0~r8N^=5k&r5nir00L`C zL_t(|ob8*el$0Dy|T@=bPC#X&t+pQzir?$Vr}`3;<2 z)ElV=r$cA(_Kn}b=|#OnHRz3-(Pm7RSb4|QO{1*4JLI4s|ts_ z*Nb{~u5O6R24DRKd%djJ(RbK-2Ky@ZDHQ+!0001Bm`(AKZWXi`6*tak0Vov7_PbzN?18>G9$5-!!f z)U})r0;43-Sj@P7KNV{dk`AI=teZkiHQ?o)c!a@yn+En)8f0x6C{GaoY}3Hr4*AsR zqD_P7`pE)8aF8UO$Q002BA%8itk2bx0qeI*Zgh~t9Xlqq7? z`jLKLbkpAbhUbO*oRuK`zQ_aK{S^$z6Yy2<{*wz9NV0E3Iza@{h^>0}zew00>55A_ z4ia+6$@r<|KZ;AL5Dk9Je2o;000000Dwob zJMk$}{$)`bMa8x}4D6b}CL@CNl-9GEe2bL#w`GIDmZZFFEfP>kV1LEbAQFM;VQxdd z$;#<)GaoR$DG8!ktFHk8000000Qj%q{lAtNni;VEUrP+lVEz9?Vrc0JegjY+bUoTe RqEP?<002ovPDHLkV1gylmp=di literal 0 HcmV?d00001 diff --git a/icons/obj/action_buttons/organs.dmi b/icons/obj/action_buttons/organs.dmi index 90dfa66959443852e60f58fce4e5125cc788bf5d..0db0a83f09ded4ac6c84f6afb631ddaaf2fc05a9 100644 GIT binary patch literal 9902 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 literal 5674 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 delta 5915 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