From 5e270c8f9c3da1949c7d07bd45328eb594ed2a91 Mon Sep 17 00:00:00 2001 From: Changelogs Date: Thu, 23 Nov 2023 01:13:59 +0000 Subject: [PATCH 01/72] Automatic changelog compile [ci skip] --- html/changelogs/AutoChangeLog-pr-774.yml | 4 ---- html/changelogs/AutoChangeLog-pr-780.yml | 4 ---- html/changelogs/archive/2023-11.yml | 9 +++++++++ 3 files changed, 9 insertions(+), 8 deletions(-) delete mode 100644 html/changelogs/AutoChangeLog-pr-774.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-780.yml diff --git a/html/changelogs/AutoChangeLog-pr-774.yml b/html/changelogs/AutoChangeLog-pr-774.yml deleted file mode 100644 index eb01bc4609b..00000000000 --- a/html/changelogs/AutoChangeLog-pr-774.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "san7890" -delete-after: True -changes: - - code_imp: "The currently operating rust-g version on a live server is posted to places like the runtime.log, in the same place where the revision information and any applicable test merges already were. /:cl:" \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-780.yml b/html/changelogs/AutoChangeLog-pr-780.yml deleted file mode 100644 index d94f0207782..00000000000 --- a/html/changelogs/AutoChangeLog-pr-780.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "Nerev4r" -delete-after: True -changes: - - rscadd: "NanoTrasen, after extensive testing in a variety of stars' light wavelengths, have deemed their PDAs ready enough to actually use the onboard cameras they already had." \ No newline at end of file diff --git a/html/changelogs/archive/2023-11.yml b/html/changelogs/archive/2023-11.yml index 2462f64f68e..cc422becc6d 100644 --- a/html/changelogs/archive/2023-11.yml +++ b/html/changelogs/archive/2023-11.yml @@ -1146,3 +1146,12 @@ this in poor ways may displease the Gods. Woe upon your lineage. - rscadd: A single pack of glowshroom mycelium has been added to the Hearth's starting seed stores for the benefit of creative healers, shamans, and radiation enthusiasts. +2023-11-23: + Nerev4r: + - rscadd: NanoTrasen, after extensive testing in a variety of stars' light wavelengths, + have deemed their PDAs ready enough to actually use the onboard cameras they + already had. + san7890: + - code_imp: 'The currently operating rust-g version on a live server is posted to + places like the runtime.log, in the same place where the revision information + and any applicable test merges already were. /:cl:' From ac9d7c0979871ec1b00615aa99942c9ba9032973 Mon Sep 17 00:00:00 2001 From: Iajret Creature <122297233+Steals-The-PRs@users.noreply.github.com> Date: Thu, 23 Nov 2023 12:08:50 +0300 Subject: [PATCH 02/72] Fixes borers being unable to inject chemicals (#781) Update BorerChem.jsx Co-authored-by: Iajret <8430839+Iajret@users.noreply.github.com> --- tgui/packages/tgui/interfaces/BorerChem.jsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tgui/packages/tgui/interfaces/BorerChem.jsx b/tgui/packages/tgui/interfaces/BorerChem.jsx index 35eb63857fc..8f5210ed0fa 100644 --- a/tgui/packages/tgui/interfaces/BorerChem.jsx +++ b/tgui/packages/tgui/interfaces/BorerChem.jsx @@ -44,7 +44,7 @@ export const BorerChem = (props, context) => { disabled={data.onCooldown || data.notEnoughChemicals} onClick={() => act('inject', { - reagent: chemical.id, + reagent: chemical.title, }) } /> From 3ccbce2cea2c88455ef643fee170ad8453360655 Mon Sep 17 00:00:00 2001 From: Yaroslav Nurkov <78199449+AnywayFarus@users.noreply.github.com> Date: Thu, 23 Nov 2023 12:09:22 +0300 Subject: [PATCH 03/72] Automatic changelog for PR #781 [ci skip] --- html/changelogs/AutoChangeLog-pr-781.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-781.yml diff --git a/html/changelogs/AutoChangeLog-pr-781.yml b/html/changelogs/AutoChangeLog-pr-781.yml new file mode 100644 index 00000000000..bc9451e99b6 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-781.yml @@ -0,0 +1,4 @@ +author: "Iajret" +delete-after: True +changes: + - bugfix: "borers can once again fill their hosts with various wonders of chemistry" \ No newline at end of file From e62dcd7ee357a47e118c333b943d24b395f735fe Mon Sep 17 00:00:00 2001 From: Iajret Creature <122297233+Steals-The-PRs@users.noreply.github.com> Date: Thu, 23 Nov 2023 12:10:08 +0300 Subject: [PATCH 04/72] [MIRROR] Adds some more engi borg modules and buffs the engi borg RPED [MDB IGNORE] (#785) * Adds some more engi borg modules and buffs the engi borg RPED (#79374) --------- Co-authored-by: SkyratBot <59378654+SkyratBot@users.noreply.github.com> Co-authored-by: Autisem <36102060+Autisem@users.noreply.github.com> --- code/__DEFINES/nozzle_define.dm | 4 +++ code/game/machinery/rechargestation.dm | 5 ++- .../objects/items/robot/robot_upgrades.dm | 33 ++++++++++++++++++- code/game/objects/items/tanks/watertank.dm | 5 --- .../designs/mechfabricator_designs.dm | 11 +++++++ code/modules/research/stock_parts.dm | 8 ++++- code/modules/research/techweb/all_nodes.dm | 1 + tgstation.dme | 1 + 8 files changed, 60 insertions(+), 8 deletions(-) create mode 100644 code/__DEFINES/nozzle_define.dm diff --git a/code/__DEFINES/nozzle_define.dm b/code/__DEFINES/nozzle_define.dm new file mode 100644 index 00000000000..06b43c1acc6 --- /dev/null +++ b/code/__DEFINES/nozzle_define.dm @@ -0,0 +1,4 @@ +/// 3 differnt modes for the firefighter extinquisher +#define EXTINGUISHER 0 +#define RESIN_LAUNCHER 1 +#define RESIN_FOAM 2 diff --git a/code/game/machinery/rechargestation.dm b/code/game/machinery/rechargestation.dm index 415dacc9f17..f875617bd40 100644 --- a/code/game/machinery/rechargestation.dm +++ b/code/game/machinery/rechargestation.dm @@ -156,4 +156,7 @@ /obj/machinery/recharge_station/proc/process_occupant(seconds_per_tick) if(!occupant) return - SEND_SIGNAL(occupant, COMSIG_PROCESS_BORGCHARGER_OCCUPANT, recharge_speed * seconds_per_tick / 2, repairs, sendmats) + var/main_draw = use_power_from_net(recharge_speed * seconds_per_tick, take_any = TRUE) //Pulls directly from the Powernet to dump into the cell + if(!main_draw) + return + SEND_SIGNAL(occupant, COMSIG_PROCESS_BORGCHARGER_OCCUPANT, main_draw, repairs, sendmats) diff --git a/code/game/objects/items/robot/robot_upgrades.dm b/code/game/objects/items/robot/robot_upgrades.dm index 37c95a418db..b029a099875 100644 --- a/code/game/objects/items/robot/robot_upgrades.dm +++ b/code/game/objects/items/robot/robot_upgrades.dm @@ -598,7 +598,6 @@ /obj/item/borg/upgrade/rped/action(mob/living/silicon/robot/R, user = usr) . = ..() if(.) - var/obj/item/storage/part_replacer/cyborg/RPED = locate() in R if(RPED) to_chat(user, span_warning("This unit is already equipped with a RPED module!")) @@ -615,6 +614,38 @@ if (RPED) R.model.remove_module(RPED, TRUE) +/obj/item/borg/upgrade/inducer + name = "engineering integrated power inducer" + desc = "An integrated inducer that can charge a device's internal cell from power provided by the cyborg." + require_model = TRUE + model_type = list(/obj/item/robot_model/engineering, /obj/item/robot_model/saboteur) + model_flags = BORG_MODEL_ENGINEERING + +/obj/item/borg/upgrade/inducer/action(mob/living/silicon/robot/R, user = usr) + . = ..() + if(.) + var/obj/item/inducer/cyborg/inter_inducer = locate() in R + if(inter_inducer) + return FALSE + inter_inducer = new(R.model) + R.model.basic_modules += inter_inducer + R.model.add_module(inter_inducer, FALSE, TRUE) + inter_inducer.cell = R.cell + +/obj/item/borg/upgrade/inducer/deactivate(mob/living/silicon/robot/R, user = usr) + . = ..() + if (.) + var/obj/item/inducer/cyborg/inter_inducer = locate() in R.model + if (inter_inducer) + R.model.remove_module(inter_inducer, TRUE) + inter_inducer.cell = null + +/obj/item/inducer/cyborg + name = "Internal inducer" + powertransfer = 1500 + icon = 'icons/obj/tools.dmi' + icon_state = "inducer-engi" + /obj/item/borg/upgrade/pinpointer name = "medical cyborg crew pinpointer" desc = "A crew pinpointer module for the medical cyborg. Permits remote access to the crew monitor." diff --git a/code/game/objects/items/tanks/watertank.dm b/code/game/objects/items/tanks/watertank.dm index 558c287e1e5..29dcdbcf702 100644 --- a/code/game/objects/items/tanks/watertank.dm +++ b/code/game/objects/items/tanks/watertank.dm @@ -205,11 +205,6 @@ to_chat(user, span_notice("You [amount_per_transfer_from_this == 10 ? "remove" : "affix"] the nozzle. You'll now use [amount_per_transfer_from_this] units per spray.")) //ATMOS FIRE FIGHTING BACKPACK - -#define EXTINGUISHER 0 -#define RESIN_LAUNCHER 1 -#define RESIN_FOAM 2 - /obj/item/watertank/atmos name = "backpack firefighter tank" desc = "A refrigerated and pressurized backpack tank with extinguisher nozzle, intended to fight fires. Swaps between extinguisher, resin launcher and a smaller scale resin foamer." diff --git a/code/modules/research/designs/mechfabricator_designs.dm b/code/modules/research/designs/mechfabricator_designs.dm index 6a86bcbaae1..8c1bfa246a7 100644 --- a/code/modules/research/designs/mechfabricator_designs.dm +++ b/code/modules/research/designs/mechfabricator_designs.dm @@ -1581,6 +1581,17 @@ RND_CATEGORY_MECHFAB_CYBORG_MODULES + RND_SUBCATEGORY_MECHFAB_CYBORG_MODULES_ENGINEERING ) +/datum/design/borg_upgrade_inducer + name = "Cyborg inducer" + id = "borg_upgrade_inducer" + build_type = MECHFAB + build_path = /obj/item/borg/upgrade/inducer + materials = list(/datum/material/iron = SHEET_MATERIAL_AMOUNT * 5, /datum/material/glass = SHEET_MATERIAL_AMOUNT * 2.5, /datum/material/silver = SHEET_MATERIAL_AMOUNT * 2) + construction_time = 120 + category = list( + RND_CATEGORY_MECHFAB_CYBORG_MODULES + RND_SUBCATEGORY_MECHFAB_CYBORG_MODULES_ENGINEERING + ) + /datum/design/borg_upgrade_circuit_app name = "Circuit Manipulator" id = "borg_upgrade_circuitapp" diff --git a/code/modules/research/stock_parts.dm b/code/modules/research/stock_parts.dm index 86b9f2dfafe..6638f56c1b4 100644 --- a/code/modules/research/stock_parts.dm +++ b/code/modules/research/stock_parts.dm @@ -197,12 +197,18 @@ If you create T5+ please take a pass at mech_fabricator.dm. The parts being good /obj/item/storage/part_replacer/cyborg //SKYRAT EDIT - ICON OVERRIDEN BY AESTHETICS - SEE MODULE name = "rapid part exchange device" - desc = "Special mechanical module made to store, sort, and apply standard machine parts." + desc = "Special mechanical module made to store, sort, and apply standard machine parts. This one has an extra large compartment for more parts." icon_state = "borgrped" inhand_icon_state = "RPED" lefthand_file = 'icons/mob/inhands/items/devices_lefthand.dmi' righthand_file = 'icons/mob/inhands/items/devices_righthand.dmi' +/obj/item/storage/part_replacer/cyborg/Initialize(mapload) + . = ..() + atom_storage.max_slots = 400 + atom_storage.max_total_storage = 800 + atom_storage.max_specific_storage = WEIGHT_CLASS_GIGANTIC + /obj/item/storage/part_replacer/proc/get_sorted_parts(ignore_stacks = FALSE) var/list/part_list = list() //Assemble a list of current parts, then sort them by their rating! diff --git a/code/modules/research/techweb/all_nodes.dm b/code/modules/research/techweb/all_nodes.dm index d46bb35d8c3..28710bbfb8d 100644 --- a/code/modules/research/techweb/all_nodes.dm +++ b/code/modules/research/techweb/all_nodes.dm @@ -1017,6 +1017,7 @@ "borg_upgrade_lavaproof", "borg_upgrade_rped", "borg_upgrade_hypermod", + "borg_upgrade_inducer", ) research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 2000) diff --git a/tgstation.dme b/tgstation.dme index fe320badfde..f12d1d4b3dc 100644 --- a/tgstation.dme +++ b/tgstation.dme @@ -154,6 +154,7 @@ #include "code\__DEFINES\movespeed_modification.dm" #include "code\__DEFINES\multiz.dm" #include "code\__DEFINES\nitrile.dm" +#include "code\__DEFINES\nozzle_define.dm" #include "code\__DEFINES\nuclear_bomb.dm" #include "code\__DEFINES\obj_flags.dm" #include "code\__DEFINES\observers.dm" From 957a7183c66e2528e775e87fbfb5e4fe7946ed64 Mon Sep 17 00:00:00 2001 From: Yaroslav Nurkov <78199449+AnywayFarus@users.noreply.github.com> Date: Thu, 23 Nov 2023 12:10:31 +0300 Subject: [PATCH 05/72] Automatic changelog for PR #785 [ci skip] --- html/changelogs/AutoChangeLog-pr-785.yml | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-785.yml diff --git a/html/changelogs/AutoChangeLog-pr-785.yml b/html/changelogs/AutoChangeLog-pr-785.yml new file mode 100644 index 00000000000..ae557880c5f --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-785.yml @@ -0,0 +1,6 @@ +author: "Autisem" +delete-after: True +changes: + - rscadd: "Cyborg inducer for engineering borgs" + - balance: "The borg RPED can hold as many part as the BSRPED now" + - balance: "Cyborg chargers now draw from the power net as cell chargers do" \ No newline at end of file From 8b5e65d78fde7090ef712afa6606725fb79fd14c Mon Sep 17 00:00:00 2001 From: Iajret Creature <122297233+Steals-The-PRs@users.noreply.github.com> Date: Thu, 23 Nov 2023 12:11:10 +0300 Subject: [PATCH 06/72] [MIRROR] [NO GBP] ACTUALLY Allows dogtags to fit into wallets [MDB IGNORE] (#777) * [NO GBP] ACTUALLY Allows dogtags to fit into wallets * Update wallets.dm * Update wallets.dm * Update wallets.dm * Update wallets.dm --------- Co-authored-by: SkyratBot <59378654+SkyratBot@users.noreply.github.com> Co-authored-by: OrionTheFox <76465278+OrionTheFox@users.noreply.github.com> Co-authored-by: Bloop <13398309+vinylspiders@users.noreply.github.com> --- code/game/objects/items/storage/wallets.dm | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/code/game/objects/items/storage/wallets.dm b/code/game/objects/items/storage/wallets.dm index 7a75ba88674..7cb0afc2079 100644 --- a/code/game/objects/items/storage/wallets.dm +++ b/code/game/objects/items/storage/wallets.dm @@ -28,10 +28,14 @@ /obj/item/seeds, /obj/item/stack/medical, /obj/item/toy/crayon, + /obj/item/clothing/accessory/dogtag, /obj/item/coin, - /obj/item/food/chococoin, + /obj/item/coupon, /obj/item/dice, /obj/item/disk, + /obj/item/flashlight/pen, + /obj/item/folder/biscuit, + /obj/item/food/chococoin, /obj/item/implanter, /obj/item/laser_pointer, /obj/item/lighter, @@ -44,8 +48,11 @@ /obj/item/reagent_containers/syringe, /obj/item/reagent_containers/pill, /obj/item/screwdriver, + /obj/item/seeds, /obj/item/spess_knife, - /obj/item/stamp), + /obj/item/stack/medical, + /obj/item/stamp, + /obj/item/toy/crayon), list(/obj/item/screwdriver/power)) /obj/item/storage/wallet/Exited(atom/movable/gone, direction) From 5b636ed82ae6e3fa8da9e2cd51f81f526fabf91c Mon Sep 17 00:00:00 2001 From: Yaroslav Nurkov <78199449+AnywayFarus@users.noreply.github.com> Date: Thu, 23 Nov 2023 12:22:29 +0300 Subject: [PATCH 07/72] Automatic changelog for PR #777 [ci skip] --- html/changelogs/AutoChangeLog-pr-777.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-777.yml diff --git a/html/changelogs/AutoChangeLog-pr-777.yml b/html/changelogs/AutoChangeLog-pr-777.yml new file mode 100644 index 00000000000..68d328d9913 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-777.yml @@ -0,0 +1,4 @@ +author: "OrionTheFox" +delete-after: True +changes: + - qol: "Allergy Dogtags (and any other dogtags, really) are now actually whitelisted to fit into wallets." \ No newline at end of file From 6edd548ad70fa47f71aff0ed86778f3287534bff Mon Sep 17 00:00:00 2001 From: Changelogs Date: Thu, 23 Nov 2023 12:28:28 +0000 Subject: [PATCH 08/72] Automatic changelog compile [ci skip] --- html/changelogs/AutoChangeLog-pr-777.yml | 4 ---- html/changelogs/AutoChangeLog-pr-781.yml | 4 ---- html/changelogs/AutoChangeLog-pr-785.yml | 6 ------ html/changelogs/archive/2023-11.yml | 9 +++++++++ 4 files changed, 9 insertions(+), 14 deletions(-) delete mode 100644 html/changelogs/AutoChangeLog-pr-777.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-781.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-785.yml diff --git a/html/changelogs/AutoChangeLog-pr-777.yml b/html/changelogs/AutoChangeLog-pr-777.yml deleted file mode 100644 index 68d328d9913..00000000000 --- a/html/changelogs/AutoChangeLog-pr-777.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "OrionTheFox" -delete-after: True -changes: - - qol: "Allergy Dogtags (and any other dogtags, really) are now actually whitelisted to fit into wallets." \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-781.yml b/html/changelogs/AutoChangeLog-pr-781.yml deleted file mode 100644 index bc9451e99b6..00000000000 --- a/html/changelogs/AutoChangeLog-pr-781.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "Iajret" -delete-after: True -changes: - - bugfix: "borers can once again fill their hosts with various wonders of chemistry" \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-785.yml b/html/changelogs/AutoChangeLog-pr-785.yml deleted file mode 100644 index ae557880c5f..00000000000 --- a/html/changelogs/AutoChangeLog-pr-785.yml +++ /dev/null @@ -1,6 +0,0 @@ -author: "Autisem" -delete-after: True -changes: - - rscadd: "Cyborg inducer for engineering borgs" - - balance: "The borg RPED can hold as many part as the BSRPED now" - - balance: "Cyborg chargers now draw from the power net as cell chargers do" \ No newline at end of file diff --git a/html/changelogs/archive/2023-11.yml b/html/changelogs/archive/2023-11.yml index cc422becc6d..9764f72e362 100644 --- a/html/changelogs/archive/2023-11.yml +++ b/html/changelogs/archive/2023-11.yml @@ -1147,10 +1147,19 @@ - rscadd: A single pack of glowshroom mycelium has been added to the Hearth's starting seed stores for the benefit of creative healers, shamans, and radiation enthusiasts. 2023-11-23: + Autisem: + - rscadd: Cyborg inducer for engineering borgs + - balance: The borg RPED can hold as many part as the BSRPED now + - balance: Cyborg chargers now draw from the power net as cell chargers do + Iajret: + - bugfix: borers can once again fill their hosts with various wonders of chemistry Nerev4r: - rscadd: NanoTrasen, after extensive testing in a variety of stars' light wavelengths, have deemed their PDAs ready enough to actually use the onboard cameras they already had. + OrionTheFox: + - qol: Allergy Dogtags (and any other dogtags, really) are now actually whitelisted + to fit into wallets. san7890: - code_imp: 'The currently operating rust-g version on a live server is posted to places like the runtime.log, in the same place where the revision information From fb5783cba83a1fe2feb8b83fa48699741a1a13bf Mon Sep 17 00:00:00 2001 From: Iajret Creature <122297233+Steals-The-PRs@users.noreply.github.com> Date: Thu, 23 Nov 2023 21:25:48 +0300 Subject: [PATCH 09/72] [MIRROR] Reworks transformation sting to be temporarily in living mobs, forever in dead mobs (#764) * [MIRROR] Reworks transformation sting to be temporarily in living mobs, forever in dead mobs [MDB IGNORE] (#24002) * Reworks transformation sting to be temporarily in living mobs, forever in dead mobs * Modular updates * Recaches the icons generated in the `changeling` unit test * Pain * More tweaks * Disable unit test * Let's see if we can pass test temporarily * Makes transformation sting unobtainable more cleanly * Unit test * Cursed proc * Kill the unholy copy pasta Seriously this stuff is just awful. This is not maintainable. * test this * Update comments * Fixing the screenshot test, maybe? * grrr * Update changeling.dm * Attempt to fix this nonsense * Update changeling.dm * Update changeling.dm * Update changeling.dm * Update dna.dm * Fixes it? * Screenshot test * Update _traits.dm * Update _traits.dm * Fix this * Update dna.dm * Update dna.dm * Hmm * This proc needs a new name * I want to scream but I have no mutant parts * Fix * Update species.dm * Update species.dm * Update species.dm * Update species.dm * Some touch ups --------- Co-authored-by: MrMelbert <51863163+MrMelbert@users.noreply.github.com> Co-authored-by: Giz <13398309+vinylspiders@users.noreply.github.com> Co-authored-by: Jolly <70232195+Jolly-66@users.noreply.github.com> * FF species * adding our tesharies as valid species for tails and ears --------- Co-authored-by: SkyratBot <59378654+SkyratBot@users.noreply.github.com> Co-authored-by: MrMelbert <51863163+MrMelbert@users.noreply.github.com> Co-authored-by: Giz <13398309+vinylspiders@users.noreply.github.com> Co-authored-by: Jolly <70232195+Jolly-66@users.noreply.github.com> Co-authored-by: Iajret --- code/__DEFINES/traits/declarations.dm | 5 +- code/__DEFINES/~skyrat_defines/DNA.dm | 1 + code/__HELPERS/global_lists.dm | 2 +- code/__HELPERS/mobs.dm | 10 +- code/_globalvars/lists/flavor_misc.dm | 6 +- code/_globalvars/traits/_traits.dm | 6 +- code/_globalvars/traits/admin_tooling.dm | 2 - .../mutant_bodypart_overlay.dm | 16 ++- code/datums/components/irradiated.dm | 2 +- code/datums/diseases/dna_spread.dm | 2 +- code/datums/dna.dm | 84 +++++++++++---- code/datums/mutations/void_magnet.dm | 2 +- .../datums/quirks/negative_quirks/allergic.dm | 2 +- code/datums/sprite_accessories.dm | 6 +- code/datums/status_effects/debuffs/debuffs.dm | 8 +- .../debuffs/dna_transformation.dm | 91 ++++++++++++++++ .../status_effects/debuffs/drowsiness.dm | 2 +- code/datums/status_effects/debuffs/drunk.dm | 2 +- code/datums/status_effects/neutral.dm | 2 +- code/datums/wounds/bones.dm | 2 +- code/datums/wounds/burns.dm | 2 +- code/datums/wounds/pierce.dm | 2 +- code/datums/wounds/slash.dm | 2 +- code/game/machinery/stasis.dm | 6 +- code/modules/admin/create_mob.dm | 46 ++++---- .../antagonists/changeling/changeling.dm | 4 +- .../changeling/powers/tiny_prick.dm | 59 +++++++---- .../nightmare/nightmare_species.dm | 1 - .../bitrunning/components/netpod_healing.dm | 7 ++ code/modules/mapping/mapping_helpers.dm | 1 - .../mob/living/carbon/alien/larva/life.dm | 2 +- .../mob/living/carbon/human/_species.dm | 39 ++++--- code/modules/mob/living/carbon/human/dummy.dm | 22 ++-- .../mob/living/carbon/human/examine.dm | 2 +- code/modules/mob/living/carbon/human/human.dm | 4 +- code/modules/mob/living/carbon/human/life.dm | 2 +- .../carbon/human/species_types/android.dm | 11 +- .../carbon/human/species_types/ethereal.dm | 6 +- .../carbon/human/species_types/felinid.dm | 5 +- .../carbon/human/species_types/golems.dm | 13 ++- .../carbon/human/species_types/humans.dm | 4 - .../human/species_types/lizardpeople.dm | 5 +- .../carbon/human/species_types/monkeys.dm | 8 +- .../carbon/human/species_types/mothmen.dm | 7 +- .../carbon/human/species_types/plasmamen.dm | 5 +- .../carbon/human/species_types/podpeople.dm | 3 - .../carbon/human/species_types/skeletons.dm | 8 +- .../carbon/human/species_types/zombies.dm | 9 +- code/modules/mob/living/carbon/life.dm | 2 +- code/modules/mob/living/life.dm | 2 +- code/modules/mob/living/living.dm | 2 +- code/modules/surgery/bodyparts/_bodyparts.dm | 4 +- code/modules/surgery/organs/external/tails.dm | 14 ++- code/modules/unit_tests/_unit_tests.dm | 1 + code/modules/unit_tests/changeling.dm | 99 ++++++++++++++++++ .../transformation_sting_appearances.png | Bin 0 -> 1274 bytes .../changeling/powers/tiny_prick.dm | 3 + .../code/modules/client/preferences.dm | 11 +- .../client/preferences/mutant_parts.dm | 3 + .../code/modules/mob/living/human/species.dm | 2 +- .../modules/better_vox/code/vox_species.dm | 7 +- .../modules/customization/__DEFINES/lists.dm | 11 ++ .../customization/__HELPERS/global_lists.dm | 13 +++ .../modules/customization/datums/dna.dm | 63 ----------- .../mob/dead/new_player/preferences_setup.dm | 2 +- .../new_player/sprite_accessories/ears.dm | 3 +- .../new_player/sprite_accessories/tails.dm | 2 +- .../new_player/sprite_accessories/wings.dm | 2 +- .../modules/mob/living/carbon/human/human.dm | 5 +- .../mob/living/carbon/human/species.dm | 56 ++++++---- .../mob/living/carbon/human/species/akula.dm | 20 ++-- .../living/carbon/human/species/aquatic.dm | 26 +++-- .../mob/living/carbon/human/species/ghoul.dm | 12 ++- .../species/hemophage/hemophage_species.dm | 8 +- .../living/carbon/human/species/humanoid.dm | 20 ++-- .../mob/living/carbon/human/species/insect.dm | 24 +++-- .../mob/living/carbon/human/species/lizard.dm | 34 +++--- .../mob/living/carbon/human/species/mammal.dm | 35 ++++--- .../mob/living/carbon/human/species/monkey.dm | 6 +- .../mob/living/carbon/human/species/moth.dm | 18 ++-- .../living/carbon/human/species/podweak.dm | 10 +- .../carbon/human/species/roundstartslime.dm | 24 +++-- .../mob/living/carbon/human/species/skrell.dm | 16 ++- .../living/carbon/human/species/tajaran.dm | 23 ++-- .../mob/living/carbon/human/species/unathi.dm | 29 ++--- .../mob/living/carbon/human/species/vox.dm | 24 +++-- .../living/carbon/human/species/vulpkanin.dm | 23 ++-- .../mob/living/carbon/human/species/xeno.dm | 16 +-- .../code/wounds/synth/blunt/robotic_blunt.dm | 2 +- .../wounds/synth/blunt/secures_internals.dm | 2 +- .../code/wounds/synth/robotic_burns.dm | 2 +- .../code/wounds/synth/robotic_slash.dm | 2 +- .../modules/modular_implants/code/nifs.dm | 2 +- .../stasisrework/code/stasissleeper.dm | 6 +- .../modules/synths/code/species/synthetic.dm | 23 ++-- .../modules/teshari/code/_teshari.dm | 12 ++- tff_modular/modules/nabbers/code/_nabbers.dm | 8 +- .../modules/teshari_reborn/code/teshari.dm | 13 ++- tgstation.dme | 2 + 99 files changed, 801 insertions(+), 486 deletions(-) create mode 100644 code/datums/status_effects/debuffs/dna_transformation.dm create mode 100644 code/modules/unit_tests/changeling.dm create mode 100644 code/modules/unit_tests/screenshots/transformation_sting_appearances.png create mode 100644 modular_skyrat/master_files/code/modules/antagonists/changeling/powers/tiny_prick.dm diff --git a/code/__DEFINES/traits/declarations.dm b/code/__DEFINES/traits/declarations.dm index 6c774453782..536b1023a5a 100644 --- a/code/__DEFINES/traits/declarations.dm +++ b/code/__DEFINES/traits/declarations.dm @@ -75,6 +75,9 @@ Remember to update _globalvars/traits.dm if you're adding/removing/renaming trai #define TRAIT_GUN_NATURAL "gunnatural" /// Causes death-like unconsciousness #define TRAIT_DEATHCOMA "deathcoma" +/// The mob has the stasis effect. +/// Does nothing on its own, applied via status effect. +#define TRAIT_STASIS "in_stasis" /// Makes the owner appear as dead to most forms of medical examination #define TRAIT_FAKEDEATH "fakedeath" #define TRAIT_DISFIGURED "disfigured" @@ -161,8 +164,6 @@ Remember to update _globalvars/traits.dm if you're adding/removing/renaming trai #define TRAIT_LIVERLESS_METABOLISM "liverless_metabolism" /// Humans with this trait cannot be turned into zombies #define TRAIT_NO_ZOMBIFY "no_zombify" -/// Humans with this trait cannot be affected by changeling transformation stings -#define TRAIT_NO_TRANSFORMATION_STING "no_transformation_sting" /// Carbons with this trait can't have their DNA copied by diseases nor changelings #define TRAIT_NO_DNA_COPY "no_dna_copy" /// Carbons with this trait cant have their dna scrambled by genetics or a disease retrovirus. diff --git a/code/__DEFINES/~skyrat_defines/DNA.dm b/code/__DEFINES/~skyrat_defines/DNA.dm index 8e9c220c9e1..6ac4d165ee6 100644 --- a/code/__DEFINES/~skyrat_defines/DNA.dm +++ b/code/__DEFINES/~skyrat_defines/DNA.dm @@ -34,6 +34,7 @@ // Defines for mutant bodyparts indexes #define MUTANT_INDEX_NAME "name" +#define MUTANT_INDEX_CAN_RANDOMIZE "can_randomize" #define MUTANT_INDEX_COLOR_LIST "color" #define MUTANT_INDEX_EMISSIVE_LIST "emissive" diff --git a/code/__HELPERS/global_lists.dm b/code/__HELPERS/global_lists.dm index 8eacab9e2d5..c6fa9d09ac8 100644 --- a/code/__HELPERS/global_lists.dm +++ b/code/__HELPERS/global_lists.dm @@ -17,9 +17,9 @@ //SKYRAT EDIT REMOVAL BEGIN - CUSTOMIZATION /* init_sprite_accessory_subtypes(/datum/sprite_accessory/body_markings, GLOB.body_markings_list) - init_sprite_accessory_subtypes(/datum/sprite_accessory/tails, GLOB.tails_list, add_blank = TRUE) init_sprite_accessory_subtypes(/datum/sprite_accessory/tails/human, GLOB.tails_list_human, add_blank = TRUE) init_sprite_accessory_subtypes(/datum/sprite_accessory/tails/lizard, GLOB.tails_list_lizard, add_blank = TRUE) + init_sprite_accessory_subtypes(/datum/sprite_accessory/tails/monkey, GLOB.tails_list_monkey, add_blank = TRUE) init_sprite_accessory_subtypes(/datum/sprite_accessory/snouts, GLOB.snouts_list) init_sprite_accessory_subtypes(/datum/sprite_accessory/horns,GLOB.horns_list) init_sprite_accessory_subtypes(/datum/sprite_accessory/ears, GLOB.ears_list) diff --git a/code/__HELPERS/mobs.dm b/code/__HELPERS/mobs.dm index df98ab953fa..5a408937a04 100644 --- a/code/__HELPERS/mobs.dm +++ b/code/__HELPERS/mobs.dm @@ -58,7 +58,7 @@ /proc/random_backpack() return pick(GLOB.backpacklist) -//SKYRAT EDIT REMOVAL - CUSTOMIZATION (moved to modular) +// SKYRAT EDIT REMOVAL - CUSTOMIZATION (moved to modular) /* /proc/random_features() if(!GLOB.tails_list.len) @@ -113,9 +113,8 @@ "tail_monkey" = "Monkey", "pod_hair" = pick(GLOB.pod_hair_list), )) - */ - //SKYRAT EDIT REMOVAL END - +*/ +//SKYRAT EDIT REMOVAL END /proc/random_hairstyle(gender) switch(gender) @@ -589,8 +588,6 @@ GLOBAL_LIST_EMPTY(species_list) #define ISADVANCEDTOOLUSER(mob) (HAS_TRAIT(mob, TRAIT_ADVANCEDTOOLUSER) && !HAS_TRAIT(mob, TRAIT_DISCOORDINATED_TOOL_USER)) -#define IS_IN_STASIS(mob) (mob.has_status_effect(/datum/status_effect/grouped/stasis) || mob.has_status_effect(/datum/status_effect/embryonic)) - /// Gets the client of the mob, allowing for mocking of the client. /// You only need to use this if you know you're going to be mocking clients somewhere else. #define GET_CLIENT(mob) (##mob.client || ##mob.mock_client) @@ -631,7 +628,6 @@ GLOBAL_LIST_EMPTY(species_list) moblist += mob_to_sort // SKYRAT EDIT END - SOULCATCHERS return moblist - ///returns a mob type controlled by a specified ckey /proc/get_mob_by_ckey(key) if(!key) diff --git a/code/_globalvars/lists/flavor_misc.dm b/code/_globalvars/lists/flavor_misc.dm index dbf9a47f9f7..afb15912694 100644 --- a/code/_globalvars/lists/flavor_misc.dm +++ b/code/_globalvars/lists/flavor_misc.dm @@ -30,9 +30,9 @@ GLOBAL_LIST_EMPTY(legs_list) GLOBAL_LIST_EMPTY(animated_spines_list) //Mutant Human bits -GLOBAL_LIST_EMPTY(tails_list) -GLOBAL_LIST_EMPTY(tails_list_human) //Only exists for preference choices. Use "tails_list" otherwise. -GLOBAL_LIST_EMPTY(tails_list_lizard) //See above! +GLOBAL_LIST_EMPTY(tails_list_human) +GLOBAL_LIST_EMPTY(tails_list_lizard) +GLOBAL_LIST_EMPTY(tails_list_monkey) GLOBAL_LIST_EMPTY(ears_list) GLOBAL_LIST_EMPTY(wings_list) GLOBAL_LIST_EMPTY(wings_open_list) diff --git a/code/_globalvars/traits/_traits.dm b/code/_globalvars/traits/_traits.dm index d76376ded36..b1d1c5eaac3 100644 --- a/code/_globalvars/traits/_traits.dm +++ b/code/_globalvars/traits/_traits.dm @@ -287,7 +287,6 @@ GLOBAL_LIST_INIT(traits_by_type, list( "TRAIT_NO_JUMPSUIT" = TRAIT_NO_JUMPSUIT, "TRAIT_NO_MINDSWAP" = TRAIT_NO_MINDSWAP, "TRAIT_NO_MIRROR_REFLECTION" = TRAIT_NO_MIRROR_REFLECTION, - //"TRAIT_NO_PLASMA_TRANSFORM" = TRAIT_NO_PLASMA_TRANSFORM, SKYRAT EDIT - TODO - These require transformation sting pr "TRAIT_NO_SLIP_ALL" = TRAIT_NO_SLIP_ALL, "TRAIT_NO_SLIP_ICE" = TRAIT_NO_SLIP_ICE, "TRAIT_NO_SLIP_SLIDE" = TRAIT_NO_SLIP_SLIDE, @@ -366,7 +365,7 @@ GLOBAL_LIST_INIT(traits_by_type, list( "TRAIT_ROCK_METAMORPHIC" = TRAIT_ROCK_METAMORPHIC, "TRAIT_ROD_SUPLEX" = TRAIT_ROD_SUPLEX, "TRAIT_SABRAGE_PRO" = TRAIT_SABRAGE_PRO, - "TRAIT_SACRIFICED" = TRAIT_SACRIFICED, // SKYRAT EDIT ADDITION + "TRAIT_SACRIFICED" = TRAIT_SACRIFICED, "TRAIT_SECURITY_HUD" = TRAIT_SECURITY_HUD, "TRAIT_SEE_GLASS_COLORS" = TRAIT_SEE_GLASS_COLORS, "TRAIT_SELF_AWARE" = TRAIT_SELF_AWARE, @@ -394,7 +393,7 @@ GLOBAL_LIST_INIT(traits_by_type, list( "TRAIT_SPRAY_PAINTABLE" = TRAIT_SPRAY_PAINTABLE, "TRAIT_STABLEHEART" = TRAIT_STABLEHEART, "TRAIT_STABLELIVER" = TRAIT_STABLELIVER, - //"TRAIT_STASIS" = TRAIT_STASIS, TODO - SKYRAT EDIT - TODO - These require transformation sting pr + "TRAIT_STASIS" = TRAIT_STASIS, "TRAIT_STRONG_GRABBER" = TRAIT_STRONG_GRABBER, "TRAIT_STUNIMMUNE" = TRAIT_STUNIMMUNE, "TRAIT_SUCCUMB_OVERRIDE" = TRAIT_SUCCUMB_OVERRIDE, @@ -423,7 +422,6 @@ GLOBAL_LIST_INIT(traits_by_type, list( "TRAIT_UNBREAKABLE" = TRAIT_UNBREAKABLE, "TRAIT_UNDENSE" = TRAIT_UNDENSE, "TRAIT_UNDERWATER_BASKETWEAVING_KNOWLEDGE" = TRAIT_UNDERWATER_BASKETWEAVING_KNOWLEDGE, - //"TRAIT_UNHUSKABLE" = TRAIT_UNHUSKABLE, SKYRAT EDIT - TODO - These require transformation sting pr "TRAIT_UNINTELLIGIBLE_SPEECH" = TRAIT_UNINTELLIGIBLE_SPEECH, "TRAIT_UNKNOWN" = TRAIT_UNKNOWN, "TRAIT_UNNATURAL_RED_GLOWY_EYES" = TRAIT_UNNATURAL_RED_GLOWY_EYES, diff --git a/code/_globalvars/traits/admin_tooling.dm b/code/_globalvars/traits/admin_tooling.dm index 388ea89cc7e..b65a31c79f7 100644 --- a/code/_globalvars/traits/admin_tooling.dm +++ b/code/_globalvars/traits/admin_tooling.dm @@ -129,7 +129,6 @@ GLOBAL_LIST_INIT(admin_visible_traits, list( "TRAIT_NO_BLOOD_OVERLAY" = TRAIT_NO_BLOOD_OVERLAY, "TRAIT_NO_DNA_COPY" = TRAIT_NO_DNA_COPY, "TRAIT_NO_GLIDE" = TRAIT_NO_GLIDE, - //"TRAIT_NO_PLASMA_TRANSFORM" = TRAIT_NO_PLASMA_TRANSFORM, SKYRAT EDIT - TODO - These require transformation sting pr "TRAIT_NO_SLIP_ALL" = TRAIT_NO_SLIP_ALL, "TRAIT_NO_SLIP_ICE" = TRAIT_NO_SLIP_ICE, "TRAIT_NO_SLIP_SLIDE" = TRAIT_NO_SLIP_SLIDE, @@ -215,7 +214,6 @@ GLOBAL_LIST_INIT(admin_visible_traits, list( "TRAIT_UI_BLOCKED" = TRAIT_UI_BLOCKED, "TRAIT_UNDENSE" = TRAIT_UNDENSE, "TRAIT_UNDERWATER_BASKETWEAVING_KNOWLEDGE" = TRAIT_UNDERWATER_BASKETWEAVING_KNOWLEDGE, - //"TRAIT_UNHUSKABLE" = TRAIT_UNHUSKABLE, SKYRAT EDIT - TODO - These require transformation sting pr "TRAIT_UNINTELLIGIBLE_SPEECH" = TRAIT_UNINTELLIGIBLE_SPEECH, "TRAIT_UNKNOWN" = TRAIT_UNKNOWN, "TRAIT_UNNATURAL_RED_GLOWY_EYES" = TRAIT_UNNATURAL_RED_GLOWY_EYES, diff --git a/code/datums/bodypart_overlays/mutant_bodypart_overlay.dm b/code/datums/bodypart_overlays/mutant_bodypart_overlay.dm index 486f9411934..7dd453163c5 100644 --- a/code/datums/bodypart_overlays/mutant_bodypart_overlay.dm +++ b/code/datums/bodypart_overlays/mutant_bodypart_overlay.dm @@ -123,12 +123,18 @@ ///Sprite accessories are singletons, stored list("Big Snout" = instance of /datum/sprite_accessory/snout/big), so here we get that singleton /datum/bodypart_overlay/mutant/proc/fetch_sprite_datum(datum/sprite_accessory/accessory_path) - var/list/feature_list = get_global_feature_list() - - return feature_list[initial(accessory_path.name)] + return fetch_sprite_datum_from_name(initial(accessory_path.name)) ///Get the singleton from the sprite name /datum/bodypart_overlay/mutant/proc/fetch_sprite_datum_from_name(accessory_name) var/list/feature_list = get_global_feature_list() - - return feature_list[accessory_name] + var/found = feature_list[accessory_name] + if(found) + return found + + if(!length(feature_list)) + CRASH("External organ [type] returned no sprite datums from get_global_feature_list(), so no accessories could be found!") + else if(accessory_name) + CRASH("External organ [type] couldn't find sprite accessory [accessory_name]!") + else + CRASH("External organ [type] had fetch_sprite_datum called with a null accessory name!") diff --git a/code/datums/components/irradiated.dm b/code/datums/components/irradiated.dm index c8a57f3761a..bffd56459bf 100644 --- a/code/datums/components/irradiated.dm +++ b/code/datums/components/irradiated.dm @@ -96,7 +96,7 @@ process_tox_damage(human_parent, seconds_per_tick) /datum/component/irradiated/proc/should_halt_effects(mob/living/carbon/human/target) - if (IS_IN_STASIS(target)) + if (HAS_TRAIT(target, TRAIT_STASIS)) return TRUE if (HAS_TRAIT(target, TRAIT_HALT_RADIATION_EFFECTS)) diff --git a/code/datums/diseases/dna_spread.dm b/code/datums/diseases/dna_spread.dm index 7783465aabd..48ca9506e2e 100644 --- a/code/datums/diseases/dna_spread.dm +++ b/code/datums/diseases/dna_spread.dm @@ -24,7 +24,7 @@ return FALSE //Only species that can be spread by transformation sting can be spread by the retrovirus - if(HAS_TRAIT(affected_mob, TRAIT_NO_TRANSFORMATION_STING) || HAS_TRAIT(affected_mob, TRAIT_NO_DNA_COPY)) + if(HAS_TRAIT(affected_mob, TRAIT_NO_DNA_COPY)) cure() return FALSE diff --git a/code/datums/dna.dm b/code/datums/dna.dm index 2d745cb6290..d27779387ed 100644 --- a/code/datums/dna.dm +++ b/code/datums/dna.dm @@ -84,8 +84,9 @@ GLOBAL_LIST_INIT(total_uf_len_by_block, populate_total_uf_len_by_block()) var/blood_type ///The type of mutant race the player is if applicable (i.e. potato-man) var/datum/species/species = new /datum/species/human - ///first value is mutant color - var/list/features = list("FFF") + /// Assoc list of feature keys to their value + /// Note if you set these manually, and do not update [unique_features] afterwards, it will likely be reset. + var/list/features = list("mcolor" = "#FFFFFF") ///Stores the hashed values of the person's non-human features var/unique_features ///Stores the real name of the person who originally got this dna datum. Used primarely for changelings, @@ -135,12 +136,17 @@ GLOBAL_LIST_INIT(total_uf_len_by_block, populate_total_uf_len_by_block()) destination.dna.features = features.Copy() destination.dna.real_name = real_name destination.dna.temporary_mutations = temporary_mutations.Copy() + //SKYRAT EDIT ADDITION BEGIN - CUSTOMIZATION + destination.dna.mutant_bodyparts = mutant_bodyparts.Copy() + destination.dna.body_markings = body_markings.Copy() + destination.dna.update_body_size() + //SKYRAT EDIT ADDITION END if(transfer_SE) destination.dna.mutation_index = mutation_index destination.dna.default_mutation_genes = default_mutation_genes if(transfer_species) //destination.set_species(species.type, icon_update=0) - ORIGINAL - destination.set_species(species.type, TRUE, null, features.Copy(), mutant_bodyparts.Copy(), body_markings.Copy()) //SKYRAT EDIT CHANGE - CUSTOMIZATION + destination.set_species(species.type, TRUE, FALSE, features.Copy(), mutant_bodyparts.Copy(), body_markings.Copy()) //SKYRAT EDIT CHANGE - CUSTOMIZATION /datum/dna/proc/copy_dna(datum/dna/new_dna) new_dna.unique_enzymes = unique_enzymes @@ -381,7 +387,9 @@ GLOBAL_LIST_INIT(total_uf_len_by_block, populate_total_uf_len_by_block()) if(DNA_LIZARD_MARKINGS_BLOCK) set_uni_feature_block(blocknumber, construct_block(GLOB.body_markings_list.Find(features["body_markings"]), GLOB.body_markings_list.len)) if(DNA_TAIL_BLOCK) - set_uni_feature_block(blocknumber, construct_block(GLOB.tails_list.Find(features["tail_lizard"]), GLOB.tails_list.len)) + set_uni_feature_block(blocknumber, construct_block(GLOB.tails_list_human.Find(features["tail_cat"]), GLOB.tails_list_human.len)) + if(DNA_LIZARD_TAIL_BLOCK) + set_uni_feature_block(blocknumber, construct_block(GLOB.tails_list_lizard.Find(features["tail_lizard"]), GLOB.tails_list_lizard.len)) if(DNA_SNOUT_BLOCK) set_uni_feature_block(blocknumber, construct_block(GLOB.snouts_list.Find(features["snout"]), GLOB.snouts_list.len)) if(DNA_HORNS_BLOCK) @@ -468,25 +476,41 @@ GLOBAL_LIST_INIT(total_uf_len_by_block, populate_total_uf_len_by_block()) if(message) to_chat(holder, message) -//used to update dna UI, UE, and dna.real_name. +/// Updates the UI, UE, and UF of the DNA according to the features, appearance, name, etc. of the DNA / holder. /datum/dna/proc/update_dna_identity() unique_identity = generate_unique_identity() unique_enzymes = generate_unique_enzymes() unique_features = generate_unique_features() -//SKYRAT EDIT REMOVAL BEGIN - CUSTOMIZATION (moved to modular) -/* -/datum/dna/proc/initialize_dna(newblood_type, skip_index = FALSE) +/** + * Sets up DNA codes and initializes some features. + * + * * newblood_type - Optional, the blood type to set the DNA to + * * create_mutation_blocks - If true, generate_dna_blocks is called, which is used to set up mutation blocks (what a mob can naturally mutate). + * * randomize_features - If true, all entries in the features list will be randomized. + */ +/datum/dna/proc/initialize_dna(newblood_type, create_mutation_blocks = TRUE, randomize_features = TRUE) if(newblood_type) blood_type = newblood_type - unique_enzymes = generate_unique_enzymes() - unique_identity = generate_unique_identity() - if(!skip_index) //I hate this + if(create_mutation_blocks) //I hate this generate_dna_blocks() - features = random_features() - unique_features = generate_unique_features() -*/ -//SKYRAT EDIT REMOVAL END + mutant_bodyparts = species.get_mutant_bodyparts(features, existing_mutant_bodyparts = randomize_features ? list() : mutant_bodyparts) // SKYRAT EDIT ADDITION + if(randomize_features) + /* SKYRAT EDIT REMOVAL - We don't really want this, do we? We get the same effect from get_mutant_bodyparts() on our end, but without mixing up weird species features. + var/static/list/all_species_protoypes + if(isnull(all_species_protoypes)) + all_species_protoypes = list() + for(var/species_path in subtypesof(/datum/species)) + all_species_protoypes += new species_path() + + for(var/datum/species/random_species as anything in all_species_protoypes) + features |= random_species.randomize_features() + SKYRAT EDIT REMOVAL END */ + body_markings = species.get_random_body_markings(features) // SKYRAT EDIT ADDITION + + features["mcolor"] = "#[random_color()]" + + update_dna_identity() /datum/dna/stored //subtype used by brain mob's stored_dna @@ -519,9 +543,7 @@ GLOBAL_LIST_INIT(total_uf_len_by_block, populate_total_uf_len_by_block()) stored_dna.species = mrace //not calling any species update procs since we're a brain, not a monkey/human -//SKYRAT EDIT REMOVAL BEGIN - CUSTOMIZATION (moved to modular_skyrat/modules/customization/code/datums/dna.dm) -/* -/mob/living/carbon/set_species(datum/species/mrace, icon_update = TRUE, pref_load = FALSE) +/mob/living/carbon/set_species(datum/species/mrace, icon_update = TRUE, pref_load = FALSE, list/override_features, list/override_mutantparts, list/override_markings) // SKYRAT EDIT CHANGE - ORIGINAL: /mob/living/carbon/set_species(datum/species/mrace, icon_update = TRUE, pref_load = FALSE) if(QDELETED(src)) CRASH("You're trying to change your species post deletion, this is a recipe for madness") if(isnull(mrace)) @@ -547,10 +569,32 @@ GLOBAL_LIST_INIT(total_uf_len_by_block, populate_total_uf_len_by_block()) if (old_species.properly_gained) old_species.on_species_loss(src, new_race, pref_load) + // SKYRAT EDIT ADDITION START - BODYPARTS AND FEATURES + // We need to instantiate the list with compatible mutant parts so we don't break things + + if(override_mutantparts && override_mutantparts.len) + for(var/feature in dna.mutant_bodyparts) + override_mutantparts[feature] = dna.mutant_bodyparts[feature] + dna.mutant_bodyparts = override_mutantparts + + if(override_markings && override_markings.len) + for(var/feature in dna.body_markings) + override_markings[feature] = dna.body_markings[feature] + dna.body_markings = override_markings + + if(override_features && override_features.len) + for(var/feature in dna.features) + override_features[feature] = dna.features[feature] + dna.features = override_features + + apply_customizable_dna_features_to_species() + dna.unique_features = dna.generate_unique_features() + + dna.update_body_size() + // SKYRAT EDIT ADDITION END + dna.species.on_species_gain(src, old_species, pref_load) log_mob_tag("TAG: [tag] SPECIES: [key_name(src)] \[[mrace]\]") -*/ -//SKYRAT EDIT REMOVAL END /mob/living/carbon/human/set_species(datum/species/mrace, icon_update = TRUE, pref_load = FALSE) ..() diff --git a/code/datums/mutations/void_magnet.dm b/code/datums/mutations/void_magnet.dm index d6636b0b630..48f04eda636 100644 --- a/code/datums/mutations/void_magnet.dm +++ b/code/datums/mutations/void_magnet.dm @@ -60,7 +60,7 @@ /datum/action/cooldown/spell/void/cursed/proc/on_life(mob/living/source, seconds_per_tick, times_fired) SIGNAL_HANDLER - if(!isliving(source) || IS_IN_STASIS(source) || source.stat == DEAD || HAS_TRAIT(source, TRAIT_NO_TRANSFORM)) + if(!isliving(source) || HAS_TRAIT(source, TRAIT_STASIS) || source.stat == DEAD || HAS_TRAIT(source, TRAIT_NO_TRANSFORM)) return if(!is_valid_target(source)) diff --git a/code/datums/quirks/negative_quirks/allergic.dm b/code/datums/quirks/negative_quirks/allergic.dm index d6a510f62b6..64b4c560bde 100644 --- a/code/datums/quirks/negative_quirks/allergic.dm +++ b/code/datums/quirks/negative_quirks/allergic.dm @@ -48,7 +48,7 @@ if(!iscarbon(quirk_holder)) return - if(IS_IN_STASIS(quirk_holder)) + if(HAS_TRAIT(quirk_holder, TRAIT_STASIS)) return if(quirk_holder.stat == DEAD) diff --git a/code/datums/sprite_accessories.dm b/code/datums/sprite_accessories.dm index 44f77fc1d76..c0c6578437e 100644 --- a/code/datums/sprite_accessories.dm +++ b/code/datums/sprite_accessories.dm @@ -1783,11 +1783,13 @@ color_src = HAIR_COLOR /datum/sprite_accessory/tails/monkey - name = "Monkey" icon = 'icons/mob/human/species/monkey/monkey_tail.dmi' - icon_state = "monkey" color_src = FALSE +/datum/sprite_accessory/tails/monkey/standard + name = "Monkey" + icon_state = "monkey" + /datum/sprite_accessory/pod_hair icon = 'icons/mob/human/species/podperson_hair.dmi' em_block = TRUE diff --git a/code/datums/status_effects/debuffs/debuffs.dm b/code/datums/status_effects/debuffs/debuffs.dm index fccb6a5d8f5..2865a230f43 100644 --- a/code/datums/status_effects/debuffs/debuffs.dm +++ b/code/datums/status_effects/debuffs/debuffs.dm @@ -278,8 +278,8 @@ . = ..() if(!.) return - owner.add_traits(list(TRAIT_IMMOBILIZED, TRAIT_HANDS_BLOCKED, TRAIT_NUMBED), TRAIT_STATUS_EFFECT(id))//SKYRAT EDIT START - STASIS APPLIES NUMBING - owner.throw_alert("stasis numbed", /atom/movable/screen/alert/numbed) //SKYRAT EDIT END + owner.add_traits(list(TRAIT_IMMOBILIZED, TRAIT_HANDS_BLOCKED, TRAIT_STASIS, TRAIT_NUMBED), TRAIT_STATUS_EFFECT(id)) // SKYRAT EDIT CHANGE - ORIGINAL: owner.add_traits(list(TRAIT_IMMOBILIZED, TRAIT_HANDS_BLOCKED, TRAIT_STASIS), TRAIT_STATUS_EFFECT(id)) + owner.throw_alert("stasis numbed", /atom/movable/screen/alert/numbed) //SKYRAT EDIT ADDITION - STASIS APPLIES NUMBED owner.add_filter("stasis_status_ripple", 2, list("type" = "ripple", "flags" = WAVE_BOUNDED, "radius" = 0, "size" = 2)) var/filter = owner.get_filter("stasis_status_ripple") animate(filter, radius = 0, time = 0.2 SECONDS, size = 2, easing = JUMP_EASING, loop = -1, flags = ANIMATION_PARALLEL) @@ -294,8 +294,8 @@ owner.Sleeping(15 SECONDS) //SKYRAT EDIT END /datum/status_effect/grouped/stasis/on_remove() - owner.remove_traits(list(TRAIT_IMMOBILIZED, TRAIT_HANDS_BLOCKED, TRAIT_NUMBED), TRAIT_STATUS_EFFECT(id)) //SKYRAT EDIT START - STASIS END REMOVES NUMBING - owner.clear_alert("stasis numbed") //SKYRAT EDIT END + owner.remove_traits(list(TRAIT_IMMOBILIZED, TRAIT_HANDS_BLOCKED, TRAIT_STASIS, TRAIT_NUMBED), TRAIT_STATUS_EFFECT(id)) // SKYRAT EDIT CHANGE - ORIGINAL: owner.remove_traits(list(TRAIT_IMMOBILIZED, TRAIT_HANDS_BLOCKED, TRAIT_STASIS), TRAIT_STATUS_EFFECT(id)) + owner.clear_alert("stasis numbed") //SKYRAT EDIT ADDITION - STASIS APPLIED NUMBED owner.remove_filter("stasis_status_ripple") update_time_of_death() if(iscarbon(owner)) diff --git a/code/datums/status_effects/debuffs/dna_transformation.dm b/code/datums/status_effects/debuffs/dna_transformation.dm new file mode 100644 index 00000000000..33b6eb1d913 --- /dev/null +++ b/code/datums/status_effects/debuffs/dna_transformation.dm @@ -0,0 +1,91 @@ +/// Transforms a carbon mob into a new DNA for a set amount of time, +/// then turns them back to how they were before transformation. +/datum/status_effect/temporary_transformation + id = "temp_dna_transformation" + tick_interval = -1 + duration = 1 MINUTES // set in on creation, this just needs to be any value to process + alert_type = null + /// A reference to a COPY of the DNA that the mob will be transformed into. + var/datum/dna/new_dna + /// A reference to a COPY of the DNA of the mob prior to transformation. + var/datum/dna/old_dna + +/datum/status_effect/temporary_transformation/Destroy() + . = ..() // parent must be called first, so we clear DNA refs AFTER transforming back... yeah i know + QDEL_NULL(new_dna) + QDEL_NULL(old_dna) + +/datum/status_effect/temporary_transformation/on_creation(mob/living/new_owner, new_duration = 1 MINUTES, datum/dna/dna_to_copy) + src.duration = (new_duration == INFINITY) ? -1 : new_duration + src.new_dna = new() + src.old_dna = new() + dna_to_copy.copy_dna(new_dna) + return ..() + +/datum/status_effect/temporary_transformation/on_apply() + if(!iscarbon(owner)) + return FALSE + + var/mob/living/carbon/transforming = owner + if(!transforming.has_dna()) + return FALSE + + // Save the old DNA + transforming.dna.copy_dna(old_dna) + // Makes them into the new DNA + new_dna.transfer_identity(transforming) + transforming.real_name = new_dna.real_name + transforming.name = transforming.get_visible_name() + transforming.updateappearance(mutcolor_update = TRUE) + transforming.domutcheck() + return TRUE + +/datum/status_effect/temporary_transformation/on_remove() + var/mob/living/carbon/transforming = owner + + if(!QDELING(owner)) // Don't really need to do appearance stuff if we're being deleted + old_dna.transfer_identity(transforming) + transforming.updateappearance(mutcolor_update = TRUE) + transforming.domutcheck() + + transforming.real_name = old_dna.real_name // Name is fine though + transforming.name = transforming.get_visible_name() + +/datum/status_effect/temporary_transformation/trans_sting + /// Tracks the time left on the effect when the owner last died. Used to pause the effect. + var/time_before_pause = -1 + /// Signals which we react to to determine if we should pause the effect. + var/static/list/update_on_signals = list( + COMSIG_MOB_STATCHANGE, + SIGNAL_ADDTRAIT(TRAIT_STASIS), + SIGNAL_REMOVETRAIT(TRAIT_STASIS), + SIGNAL_ADDTRAIT(TRAIT_DEATHCOMA), + SIGNAL_REMOVETRAIT(TRAIT_DEATHCOMA), + ) + +/datum/status_effect/temporary_transformation/trans_sting/on_apply() + . = ..() + if(!.) + return + RegisterSignals(owner, update_on_signals, PROC_REF(pause_effect)) + pause_effect(owner) // for if we sting a dead guy + +/datum/status_effect/temporary_transformation/trans_sting/on_remove() + . = ..() + UnregisterSignal(owner, update_on_signals) + +/datum/status_effect/temporary_transformation/trans_sting/proc/pause_effect(mob/living/source) + SIGNAL_HANDLER + + // Pause if we're dead, appear dead, or in stasis + if(source.stat == DEAD || HAS_TRAIT(source, TRAIT_DEATHCOMA) || HAS_TRAIT(source, TRAIT_STASIS)) + if(duration == -1) + return // Already paused + + time_before_pause = duration - world.time + duration = -1 + + // Resume if we're none of the above and also were paused + else if(time_before_pause != -1) + duration = time_before_pause + world.time + time_before_pause = -1 diff --git a/code/datums/status_effects/debuffs/drowsiness.dm b/code/datums/status_effects/debuffs/drowsiness.dm index ebf1f43796c..cd99e879066 100644 --- a/code/datums/status_effects/debuffs/drowsiness.dm +++ b/code/datums/status_effects/debuffs/drowsiness.dm @@ -29,7 +29,7 @@ /datum/status_effect/drowsiness/tick(seconds_between_ticks) // You do not feel drowsy while unconscious or in stasis - if(owner.stat >= UNCONSCIOUS || IS_IN_STASIS(owner)) + if(owner.stat >= UNCONSCIOUS || HAS_TRAIT(owner, TRAIT_STASIS)) return // Resting helps against drowsiness diff --git a/code/datums/status_effects/debuffs/drunk.dm b/code/datums/status_effects/debuffs/drunk.dm index e46915922e5..061c008def8 100644 --- a/code/datums/status_effects/debuffs/drunk.dm +++ b/code/datums/status_effects/debuffs/drunk.dm @@ -65,7 +65,7 @@ /datum/status_effect/inebriated/tick(seconds_between_ticks) // Drunk value does not decrease while dead or in stasis - if(owner.stat == DEAD || IS_IN_STASIS(owner)) + if(owner.stat == DEAD || HAS_TRAIT(owner, TRAIT_STASIS)) return // Every tick, the drunk value decrases by diff --git a/code/datums/status_effects/neutral.dm b/code/datums/status_effects/neutral.dm index 48b14f36cd0..416fe031341 100644 --- a/code/datums/status_effects/neutral.dm +++ b/code/datums/status_effects/neutral.dm @@ -526,7 +526,7 @@ monkey_tail.Insert(human_mob, drop_if_replaced = FALSE) var/datum/species/human_species = human_mob.dna?.species if(human_species) - human_species.randomize_features(human_mob) + human_species.randomize_active_features(human_mob) human_species.randomize_active_underwear(human_mob) owner.remove_status_effect(/datum/status_effect/eigenstasium) diff --git a/code/datums/wounds/bones.dm b/code/datums/wounds/bones.dm index d4624acbb92..1df5ff689ff 100644 --- a/code/datums/wounds/bones.dm +++ b/code/datums/wounds/bones.dm @@ -75,7 +75,7 @@ /datum/wound/blunt/bone/handle_process(seconds_per_tick, times_fired) . = ..() - if (!victim || IS_IN_STASIS(victim)) + if (!victim || HAS_TRAIT(victim, TRAIT_STASIS)) return if(limb.body_zone == BODY_ZONE_HEAD && brain_trauma_group && world.time > next_trauma_cycle) diff --git a/code/datums/wounds/burns.dm b/code/datums/wounds/burns.dm index 39e91d06fb6..c041c4fd003 100644 --- a/code/datums/wounds/burns.dm +++ b/code/datums/wounds/burns.dm @@ -36,7 +36,7 @@ /datum/wound/burn/flesh/handle_process(seconds_per_tick, times_fired) - if (!victim || IS_IN_STASIS(victim)) + if (!victim || HAS_TRAIT(victim, TRAIT_STASIS)) return . = ..() diff --git a/code/datums/wounds/pierce.dm b/code/datums/wounds/pierce.dm index ec166584632..7304d21365c 100644 --- a/code/datums/wounds/pierce.dm +++ b/code/datums/wounds/pierce.dm @@ -64,7 +64,7 @@ return BLOOD_FLOW_STEADY /datum/wound/pierce/bleed/handle_process(seconds_per_tick, times_fired) - if (!victim || IS_IN_STASIS(victim)) + if (!victim || HAS_TRAIT(victim, TRAIT_STASIS)) return set_blood_flow(min(blood_flow, WOUND_SLASH_MAX_BLOODFLOW)) diff --git a/code/datums/wounds/slash.dm b/code/datums/wounds/slash.dm index 4475d95f508..d17b59cf80b 100644 --- a/code/datums/wounds/slash.dm +++ b/code/datums/wounds/slash.dm @@ -134,7 +134,7 @@ /datum/wound/slash/flesh/handle_process(seconds_per_tick, times_fired) - if (!victim || IS_IN_STASIS(victim)) + if (!victim || HAS_TRAIT(victim, TRAIT_STASIS)) return // in case the victim has the NOBLOOD trait, the wound will simply not clot on it's own diff --git a/code/game/machinery/stasis.dm b/code/game/machinery/stasis.dm index 8bcdba43d05..b3020c8d749 100644 --- a/code/game/machinery/stasis.dm +++ b/code/game/machinery/stasis.dm @@ -52,7 +52,7 @@ /obj/machinery/stasis/Exited(atom/movable/gone, direction) if(gone == occupant) var/mob/living/L = gone - if(IS_IN_STASIS(L)) + if(HAS_TRAIT(L, TRAIT_STASIS)) thaw_them(L) return ..() @@ -139,9 +139,9 @@ return var/mob/living/L_occupant = occupant if(stasis_running()) - if(!IS_IN_STASIS(L_occupant)) + if(!HAS_TRAIT(L_occupant, TRAIT_STASIS)) chill_out(L_occupant) - else if(IS_IN_STASIS(L_occupant)) + else if(HAS_TRAIT(L_occupant, TRAIT_STASIS)) thaw_them(L_occupant) /obj/machinery/stasis/screwdriver_act(mob/living/user, obj/item/I) diff --git a/code/modules/admin/create_mob.dm b/code/modules/admin/create_mob.dm index 36dd0416bde..8c574d207b2 100644 --- a/code/modules/admin/create_mob.dm +++ b/code/modules/admin/create_mob.dm @@ -10,36 +10,28 @@ user << browse(create_panel_helper(create_mob_html), "window=create_mob;size=425x475") -/proc/randomize_human(mob/living/carbon/human/human) - if(human.dna.species.sexes) - human.gender = pick(MALE, FEMALE, PLURAL, NEUTER) - else - human.gender = PLURAL +/** + * Randomizes everything about a human, including DNA and name + */ +/proc/randomize_human(mob/living/carbon/human/human, randomize_mutations = FALSE) + human.gender = human.dna.species.sexes ? pick(MALE, FEMALE, PLURAL, NEUTER) : PLURAL human.physique = human.gender human.real_name = human.dna?.species.random_name(human.gender) || random_unique_name(human.gender) - human.name = human.real_name - human.hairstyle = random_hairstyle(human.gender) - human.facial_hairstyle = random_facial_hairstyle(human.gender) - human.hair_color = "#[random_color()]" - human.facial_hair_color = human.hair_color - var/random_eye_color = random_eye_color() - human.eye_color_left = random_eye_color - human.eye_color_right = random_eye_color - human.dna.blood_type = random_blood_type() - human.dna.features["mcolor"] = "#[random_color()]" + human.name = human.get_visible_name() + human.set_hairstyle(random_hairstyle(human.gender), update = FALSE) + human.set_facial_hairstyle(random_facial_hairstyle(human.gender), update = FALSE) + human.set_haircolor("#[random_color()]", update = FALSE) + human.set_facial_haircolor(human.hair_color, update = FALSE) + human.eye_color_left = random_eye_color() + human.eye_color_right = human.eye_color_left + human.skin_tone = random_skin_tone() human.dna.species.randomize_active_underwear_only(human) - /*SKYRAT EDIT OLD - for(var/datum/species/species_path as anything in subtypesof(/datum/species)) - var/datum/species/new_species = new species_path - new_species.randomize_features(human) - SKYRAT EDIT ADDITION BEGIN - CUSTOMIZATION*/ - human.dna.species.randomize_features(human) - human.dna.mutant_bodyparts = human.dna.species.get_random_mutant_bodyparts(human.dna.features) - human.dna.body_markings = human.dna.species.get_random_body_markings(human.dna.features) + // Needs to be called towards the end to update all the UIs just set above + human.dna.initialize_dna(newblood_type = random_blood_type(), create_mutation_blocks = randomize_mutations, randomize_features = TRUE) + // SKYRAT EDIT ADDITION BEGIN - CUSTOMIZATION human.dna.species.mutant_bodyparts = human.dna.mutant_bodyparts.Copy() human.dna.species.body_markings = human.dna.body_markings.Copy() - //SKYRAT EDIT ADDITION END + // SKYRAT EDIT ADDITION END + // Snowflake stuff (ethereals) human.dna.species.spec_updatehealth(human) - human.dna.update_dna_identity() - human.updateappearance() - human.update_body(is_creating = TRUE) + human.updateappearance(mutcolor_update = TRUE) diff --git a/code/modules/antagonists/changeling/changeling.dm b/code/modules/antagonists/changeling/changeling.dm index 808117057fd..e909fdfc0ad 100644 --- a/code/modules/antagonists/changeling/changeling.dm +++ b/code/modules/antagonists/changeling/changeling.dm @@ -940,11 +940,13 @@ attempted_fake_scar.fake = TRUE user.regenerate_icons() - + user.name = user.get_visible_name() + current_profile = chosen_profile // SKYRAT EDIT START chosen_dna.transfer_identity(user, TRUE) user.updateappearance(mutcolor_update = TRUE, eyeorgancolor_update = TRUE) user.regenerate_icons() + user.name = user.get_visible_name() current_profile = chosen_profile // SKYRAT EDIT END //THE FLUFFY FRONTIER EDIT ADDITION BEGIN - Blooper diff --git a/code/modules/antagonists/changeling/powers/tiny_prick.dm b/code/modules/antagonists/changeling/powers/tiny_prick.dm index eb6ccccd8b5..f8c1bfc5160 100644 --- a/code/modules/antagonists/changeling/powers/tiny_prick.dm +++ b/code/modules/antagonists/changeling/powers/tiny_prick.dm @@ -66,38 +66,61 @@ to_chat(target, span_warning("You feel a tiny prick.")) return 1 -//SKYRAT EDIT REMOVAL BEGIN - CHANGELING_TRANSFORMATION_REMOVAL -/* /datum/action/changeling/sting/transformation name = "Transformation Sting" - desc = "We silently sting a human, injecting a retrovirus that forces them to transform. Costs 50 chemicals." - helptext = "The victim will transform much like a changeling would. Does not provide a warning to others. Mutations will not be transferred, and monkeys will become human." + desc = "We silently sting an organism, injecting a retrovirus that forces them to transform." + helptext = "The victim will transform much like a changeling would. \ + For complex humanoids, the transformation is temporarily, but the duration is paused while the victim is dead or in stasis. \ + For more simple humanoids, such as monkeys, the transformation is permanent. \ + Does not provide a warning to others. Mutations will not be transferred." button_icon_state = "sting_transform" - chemical_cost = 50 - dna_cost = 3 - var/datum/changeling_profile/selected_dna = null + chemical_cost = 33 // Low enough that you can sting only two people in quick succession + dna_cost = 2 + /// A reference to our active profile, which we grab DNA from + VAR_FINAL/datum/changeling_profile/selected_dna + /// Duration of the sting + var/sting_duration = 8 MINUTES + +/datum/action/changeling/sting/transformation/Grant(mob/grant_to) + . = ..() + build_all_button_icons(UPDATE_BUTTON_NAME) -/datum/action/changeling/sting/transformation/Trigger(trigger_flags) - var/mob/user = usr +/datum/action/changeling/sting/transformation/update_button_name(atom/movable/screen/movable/action_button/button, force) + . = ..() + button.desc += " Lasts [DisplayTimeText(sting_duration)] for humans, but duration is paused while dead or in stasis." + button.desc += " Costs [chemical_cost] chemicals." + +/datum/action/changeling/sting/transformation/Destroy() + selected_dna = null + return ..() + +/datum/action/changeling/sting/transformation/set_sting(mob/user) + selected_dna = null var/datum/antagonist/changeling/changeling = user.mind.has_antag_datum(/datum/antagonist/changeling) - if(changeling.chosen_sting) - unset_sting(user) + var/datum/changeling_profile/new_selected_dna = changeling.select_dna() + if(QDELETED(src) || QDELETED(changeling) || QDELETED(user)) return - selected_dna = changeling.select_dna() - if(!selected_dna) - return - if(HAS_TRAIT(user, TRAIT_NO_TRANSFORMATION_STING)) - user.balloon_alert(user, "incompatible DNA!") + if(!new_selected_dna || changeling.chosen_sting || selected_dna) // selected other sting or other DNA while sleeping return + selected_dna = new_selected_dna return ..() /datum/action/changeling/sting/transformation/can_sting(mob/user, mob/living/carbon/target) . = ..() if(!.) return - if(!iscarbon(target) || HAS_TRAIT(target, TRAIT_HUSK) || HAS_TRAIT(target, TRAIT_NO_TRANSFORMATION_STING)) + // Similar checks here are ran to that of changeling can_absorb_dna - + // Logic being that if their DNA is incompatible with us, it's also bad for transforming + if(!iscarbon(target) \ + || !target.has_dna() \ + || HAS_TRAIT(target, TRAIT_HUSK) \ + || HAS_TRAIT(target, TRAIT_BADDNA) \ + || (HAS_TRAIT(target, TRAIT_NO_DNA_COPY) && !ismonkey(target))) // sure, go ahead, make a monk-clone user.balloon_alert(user, "incompatible DNA!") return FALSE + if(target.has_status_effect(/datum/status_effect/temporary_transformation/trans_sting)) + user.balloon_alert(user, "already transformed!") + return FALSE return TRUE /datum/action/changeling/sting/transformation/sting_action(mob/living/user, mob/living/target) @@ -113,8 +136,6 @@ to_chat(user, final_message) return TRUE return FALSE -*/ -//SKYRAT EDIT REMOVAL END /datum/action/changeling/sting/false_armblade name = "False Armblade Sting" diff --git a/code/modules/antagonists/nightmare/nightmare_species.dm b/code/modules/antagonists/nightmare/nightmare_species.dm index 2db4ca2bb2c..068bb2b6c5c 100644 --- a/code/modules/antagonists/nightmare/nightmare_species.dm +++ b/code/modules/antagonists/nightmare/nightmare_species.dm @@ -20,7 +20,6 @@ TRAIT_NOHUNGER, TRAIT_NOBLOOD, TRAIT_NO_DNA_COPY, - TRAIT_NO_TRANSFORMATION_STING, TRAIT_NODISMEMBER, TRAIT_NEVER_WOUNDED, ) diff --git a/code/modules/bitrunning/components/netpod_healing.dm b/code/modules/bitrunning/components/netpod_healing.dm index 8cb363517de..98fdb5ba021 100644 --- a/code/modules/bitrunning/components/netpod_healing.dm +++ b/code/modules/bitrunning/components/netpod_healing.dm @@ -49,6 +49,13 @@ id = "embryonic" alert_type = /atom/movable/screen/alert/status_effect/embryonic +/datum/status_effect/embryonic/on_apply() + ADD_TRAIT(owner, TRAIT_STASIS, TRAIT_STATUS_EFFECT(id)) + return TRUE + +/datum/status_effect/embryonic/on_remove() + REMOVE_TRAIT(owner, TRAIT_STASIS, TRAIT_STATUS_EFFECT(id)) + /atom/movable/screen/alert/status_effect/embryonic name = "Embryonic Stasis" icon_state = "netpod_stasis" diff --git a/code/modules/mapping/mapping_helpers.dm b/code/modules/mapping/mapping_helpers.dm index 359c3edf4ea..6494f4252e5 100644 --- a/code/modules/mapping/mapping_helpers.dm +++ b/code/modules/mapping/mapping_helpers.dm @@ -917,7 +917,6 @@ INITIALIZE_IMMEDIATE(/obj/effect/mapping_helpers/no_lava) if(new_human_species) new_human.set_species(new_human_species) new_human_species = new_human.dna.species - new_human_species.randomize_features(new_human) new_human.fully_replace_character_name(new_human.real_name, new_human_species.random_name(new_human.gender, TRUE, TRUE)) else stack_trace("failed to spawn cadaver with species ID [species_to_pick]") //if it's invalid they'll just be a human, so no need to worry too much aside from yelling at the server owner lol. diff --git a/code/modules/mob/living/carbon/alien/larva/life.dm b/code/modules/mob/living/carbon/alien/larva/life.dm index 2e2674e14e7..147079ae720 100644 --- a/code/modules/mob/living/carbon/alien/larva/life.dm +++ b/code/modules/mob/living/carbon/alien/larva/life.dm @@ -3,7 +3,7 @@ /mob/living/carbon/alien/larva/Life(seconds_per_tick = SSMOBS_DT, times_fired) if(HAS_TRAIT(src, TRAIT_NO_TRANSFORM)) return - if(!..() || IS_IN_STASIS(src) || (amount_grown >= max_grown)) + if(!..() || HAS_TRAIT(src, TRAIT_STASIS) || (amount_grown >= max_grown)) return // We're dead, in stasis, or already grown. // GROW! amount_grown = min(amount_grown + (0.5 * seconds_per_tick), max_grown) diff --git a/code/modules/mob/living/carbon/human/_species.dm b/code/modules/mob/living/carbon/human/_species.dm index b847b7a73da..10c3288e0cd 100644 --- a/code/modules/mob/living/carbon/human/_species.dm +++ b/code/modules/mob/living/carbon/human/_species.dm @@ -858,19 +858,30 @@ GLOBAL_LIST_EMPTY(features_by_species) randomize_active_underwear_only(human_mob) human_mob.update_body() -///Proc that will randomize all the external organs (i.e. horns, frills, tails etc.) of a species' associated mob -/datum/species/proc/randomize_external_organs(mob/living/carbon/human/human_mob) +/datum/species/proc/randomize_active_features(mob/living/carbon/human/human_mob) + var/list/new_features = randomize_features() + for(var/feature_key in new_features) + human_mob.dna.features[feature_key] = new_features[feature_key] + human_mob.updateappearance(mutcolor_update = TRUE) + +/** + * Returns a list of features, randomized, to be used by DNA + */ +/datum/species/proc/randomize_features() + SHOULD_CALL_PARENT(TRUE) + + var/list/new_features = list() + var/static/list/organs_to_randomize = list() for(var/obj/item/organ/external/organ_path as anything in external_organs) - var/obj/item/organ/external/randomized_organ = human_mob.get_organ_by_type(organ_path) - if(randomized_organ) - var/datum/bodypart_overlay/mutant/overlay = randomized_organ.bodypart_overlay - var/new_look = pick(overlay.get_global_feature_list()) - human_mob.dna.features["[overlay.feature_key]"] = new_look - mutant_bodyparts["[overlay.feature_key]"] = new_look - -///Proc that randomizes all the appearance elements (external organs, markings, hair etc.) of a species' associated mob. Function set by child procs -/datum/species/proc/randomize_features(mob/living/carbon/human/human_mob) - return + var/overlay_path = initial(organ_path.bodypart_overlay) + var/datum/bodypart_overlay/mutant/sample_overlay = organs_to_randomize[overlay_path] + if(isnull(sample_overlay)) + sample_overlay = new overlay_path() + organs_to_randomize[overlay_path] = sample_overlay + + new_features["[sample_overlay.feature_key]"] = pick(sample_overlay.get_global_feature_list()) + + return new_features /datum/species/proc/spec_life(mob/living/carbon/human/H, seconds_per_tick, times_fired) SHOULD_CALL_PARENT(TRUE) @@ -1307,7 +1318,7 @@ GLOBAL_LIST_EMPTY(features_by_species) return //Only stabilise core temp when alive and not in statis - if(humi.stat < DEAD && !IS_IN_STASIS(humi)) + if(humi.stat < DEAD && !HAS_TRAIT(humi, TRAIT_STASIS)) body_temperature_core(humi, seconds_per_tick, times_fired) //These do run in statis @@ -1315,7 +1326,7 @@ GLOBAL_LIST_EMPTY(features_by_species) body_temperature_alerts(humi, seconds_per_tick, times_fired) //Do not cause more damage in statis - if(!IS_IN_STASIS(humi)) + if(!HAS_TRAIT(humi, TRAIT_STASIS)) body_temperature_damage(humi, seconds_per_tick, times_fired) /** diff --git a/code/modules/mob/living/carbon/human/dummy.dm b/code/modules/mob/living/carbon/human/dummy.dm index 3c29bf93847..44fe6d1a1c0 100644 --- a/code/modules/mob/living/carbon/human/dummy.dm +++ b/code/modules/mob/living/carbon/human/dummy.dm @@ -75,9 +75,7 @@ INITIALIZE_IMMEDIATE(/mob/living/carbon/human/dummy) cut_overlays(TRUE) /mob/living/carbon/human/dummy/setup_human_dna() - create_dna() - randomize_human(src) - dna.initialize_dna(skip_index = TRUE) //Skip stuff that requires full round init. + randomize_human(src, randomize_mutations = FALSE) /mob/living/carbon/human/dummy/log_mob_tag(text) return @@ -89,7 +87,6 @@ INITIALIZE_IMMEDIATE(/mob/living/carbon/human/dummy) return consistent_entry /proc/create_consistent_human_dna(mob/living/carbon/human/target) - target.dna.initialize_dna(skip_index = TRUE) /* SKYRAT EDIT START - Customization - ORIGINAL: target.dna.features["mcolor"] = COLOR_VIBRANT_LIME target.dna.features["ethcolor"] = COLOR_WHITE @@ -109,6 +106,17 @@ INITIALIZE_IMMEDIATE(/mob/living/carbon/human/dummy) target.dna.features["mcolor"] = COLOR_VIBRANT_LIME target.dna.features["ethcolor"] = COLOR_WHITE // SKYRAT EDIT END + target.dna.initialize_dna(create_mutation_blocks = FALSE, randomize_features = FALSE) + // UF and UI are nondeterministic, even though the features are the same some blocks will randomize slightly + // In practice this doesn't matter, but this is for the sake of 100%(ish) consistency + var/static/consistent_UF + var/static/consistent_UI + if(isnull(consistent_UF) || isnull(consistent_UI)) + consistent_UF = target.dna.unique_features + consistent_UI = target.dna.unique_identity + else + target.dna.unique_features = consistent_UF + target.dna.unique_identity = consistent_UI /// Provides a dummy that is consistently bald, white, naked, etc. /mob/living/carbon/human/dummy/consistent @@ -122,11 +130,7 @@ INITIALIZE_IMMEDIATE(/mob/living/carbon/human/dummy) /mob/living/carbon/human/consistent/setup_human_dna() create_consistent_human_dna(src) - -/mob/living/carbon/human/consistent/update_body(is_creating) - ..() - if(is_creating) - fully_replace_character_name(real_name, "John Doe") + fully_replace_character_name(real_name, "John Doe") /mob/living/carbon/human/consistent/domutcheck() return // We skipped adding any mutations so this runtimes diff --git a/code/modules/mob/living/carbon/human/examine.dm b/code/modules/mob/living/carbon/human/examine.dm index b7b6456b775..94c7143060c 100644 --- a/code/modules/mob/living/carbon/human/examine.dm +++ b/code/modules/mob/living/carbon/human/examine.dm @@ -487,7 +487,7 @@ //SKYRAT EDIT ADDITION END //SKYRAT EDIT ADDITION BEGIN - CUSTOMIZATION - for(var/genital in possible_genitals) + for(var/genital in GLOB.possible_genitals) if(dna.species.mutant_bodyparts[genital]) var/datum/sprite_accessory/genital/G = GLOB.sprite_accessories[genital][dna.species.mutant_bodyparts[genital][MUTANT_INDEX_NAME]] if(G) diff --git a/code/modules/mob/living/carbon/human/human.dm b/code/modules/mob/living/carbon/human/human.dm index 0905a4ac40f..a75253e1517 100644 --- a/code/modules/mob/living/carbon/human/human.dm +++ b/code/modules/mob/living/carbon/human/human.dm @@ -54,9 +54,7 @@ ADD_TRAIT(src, TRAIT_AGEUSIA, NO_TONGUE_TRAIT) /mob/living/carbon/human/proc/setup_human_dna() - //initialize dna. for spawned humans; overwritten by other code - randomize_human(src) - dna.initialize_dna() + randomize_human(src, randomize_mutations = TRUE) /mob/living/carbon/human/Destroy() QDEL_NULL(physiology) diff --git a/code/modules/mob/living/carbon/human/life.dm b/code/modules/mob/living/carbon/human/life.dm index 2e061d32a6b..be355bddbea 100644 --- a/code/modules/mob/living/carbon/human/life.dm +++ b/code/modules/mob/living/carbon/human/life.dm @@ -28,7 +28,7 @@ //Body temperature stability and damage dna.species.handle_body_temperature(src, seconds_per_tick, times_fired) - if(!IS_IN_STASIS(src)) + if(!HAS_TRAIT(src, TRAIT_STASIS)) if(stat != DEAD) //handle active mutations for(var/datum/mutation/human/human_mutation as anything in dna.mutations) diff --git a/code/modules/mob/living/carbon/human/species_types/android.dm b/code/modules/mob/living/carbon/human/species_types/android.dm index 55f13dbfabf..af21d304cb7 100644 --- a/code/modules/mob/living/carbon/human/species_types/android.dm +++ b/code/modules/mob/living/carbon/human/species_types/android.dm @@ -3,24 +3,23 @@ id = SPECIES_ANDROID examine_limb_id = SPECIES_HUMAN inherent_traits = list( - TRAIT_NO_UNDERWEAR, TRAIT_GENELESS, TRAIT_LIMBATTACHMENT, + TRAIT_LIVERLESS_METABOLISM, + TRAIT_NOBLOOD, TRAIT_NOBREATH, TRAIT_NOCLONELOSS, TRAIT_NOFIRE, TRAIT_NOHUNGER, - TRAIT_LIVERLESS_METABOLISM, + TRAIT_NO_DNA_COPY, + TRAIT_NO_UNDERWEAR, TRAIT_PIERCEIMMUNE, TRAIT_RADIMMUNE, TRAIT_RESISTCOLD, TRAIT_RESISTHEAT, - TRAIT_RESISTLOWPRESSURE, TRAIT_RESISTHIGHPRESSURE, + TRAIT_RESISTLOWPRESSURE, TRAIT_TOXIMMUNE, - TRAIT_NOBLOOD, - TRAIT_NO_DNA_COPY, - TRAIT_NO_TRANSFORMATION_STING, TRAIT_NOCRITDAMAGE, ) diff --git a/code/modules/mob/living/carbon/human/species_types/ethereal.dm b/code/modules/mob/living/carbon/human/species_types/ethereal.dm index 4c28d190eff..abe7d058181 100644 --- a/code/modules/mob/living/carbon/human/species_types/ethereal.dm +++ b/code/modules/mob/living/carbon/human/species_types/ethereal.dm @@ -104,8 +104,10 @@ return randname -/datum/species/ethereal/randomize_features(mob/living/carbon/human/human_mob) - human_mob.dna.features["ethcolor"] = GLOB.color_list_ethereal[pick(GLOB.color_list_ethereal)] +/datum/species/ethereal/randomize_features() + var/list/features = ..() + features["ethcolor"] = GLOB.color_list_ethereal[pick(GLOB.color_list_ethereal)] + return features /datum/species/ethereal/spec_updatehealth(mob/living/carbon/human/ethereal) . = ..() diff --git a/code/modules/mob/living/carbon/human/species_types/felinid.dm b/code/modules/mob/living/carbon/human/species_types/felinid.dm index 4773cf769ad..e22940db2ad 100644 --- a/code/modules/mob/living/carbon/human/species_types/felinid.dm +++ b/code/modules/mob/living/carbon/human/species_types/felinid.dm @@ -48,8 +48,9 @@ return ..() /datum/species/human/felinid/randomize_features(mob/living/carbon/human/human_mob) - randomize_external_organs(human_mob) - return ..() + var/list/features = ..() + features["ears"] = pick("None", "Cat") + return features /proc/mass_purrbation() for(var/mob in GLOB.human_list) diff --git a/code/modules/mob/living/carbon/human/species_types/golems.dm b/code/modules/mob/living/carbon/human/species_types/golems.dm index 91ec9dfe0c5..c86b8c9a276 100644 --- a/code/modules/mob/living/carbon/human/species_types/golems.dm +++ b/code/modules/mob/living/carbon/human/species_types/golems.dm @@ -3,19 +3,18 @@ name = "Golem" id = SPECIES_GOLEM inherent_traits = list( - TRAIT_NO_UNDERWEAR, TRAIT_GENELESS, TRAIT_LAVA_IMMUNE, - TRAIT_NOBREATH, + TRAIT_NEVER_WOUNDED, TRAIT_NOBLOOD, + TRAIT_NOBREATH, + TRAIT_NODISMEMBER, TRAIT_NOFIRE, + TRAIT_NO_AUGMENTS, + TRAIT_NO_DNA_COPY, + TRAIT_NO_UNDERWEAR, TRAIT_PIERCEIMMUNE, TRAIT_RADIMMUNE, - TRAIT_NO_DNA_COPY, - TRAIT_NO_TRANSFORMATION_STING, - TRAIT_NO_AUGMENTS, - TRAIT_NODISMEMBER, - TRAIT_NEVER_WOUNDED ) mutantheart = null mutantlungs = null diff --git a/code/modules/mob/living/carbon/human/species_types/humans.dm b/code/modules/mob/living/carbon/human/species_types/humans.dm index b169beba940..c7a181027e6 100644 --- a/code/modules/mob/living/carbon/human/species_types/humans.dm +++ b/code/modules/mob/living/carbon/human/species_types/humans.dm @@ -13,9 +13,6 @@ human.set_haircolor("#bb9966", update = FALSE) // brown human.set_hairstyle("Business Hair", update = TRUE) -/datum/species/human/randomize_features(mob/living/carbon/human/human_mob) - human_mob.skin_tone = random_skin_tone() - /datum/species/human/get_scream_sound(mob/living/carbon/human/human) if(human.physique == MALE) if(prob(1)) @@ -82,4 +79,3 @@ )) return to_add - diff --git a/code/modules/mob/living/carbon/human/species_types/lizardpeople.dm b/code/modules/mob/living/carbon/human/species_types/lizardpeople.dm index 5f91cbb2830..45e34d96bfd 100644 --- a/code/modules/mob/living/carbon/human/species_types/lizardpeople.dm +++ b/code/modules/mob/living/carbon/human/species_types/lizardpeople.dm @@ -75,8 +75,9 @@ //SKYRAT EDIT REMOVAL BEGIN /* /datum/species/lizard/randomize_features(mob/living/carbon/human/human_mob) - human_mob.dna.features["body_markings"] = pick(GLOB.body_markings_list) - randomize_external_organs(human_mob) + var/list/features = ..() + features["body_markings"] = pick(GLOB.body_markings_list) + return features */ //SKYRAT EDIT REMOVAL END diff --git a/code/modules/mob/living/carbon/human/species_types/monkeys.dm b/code/modules/mob/living/carbon/human/species_types/monkeys.dm index df289c514dc..8fb36e7c4e2 100644 --- a/code/modules/mob/living/carbon/human/species_types/monkeys.dm +++ b/code/modules/mob/living/carbon/human/species_types/monkeys.dm @@ -12,13 +12,13 @@ meat = /obj/item/food/meat/slab/monkey knife_butcher_results = list(/obj/item/food/meat/slab/monkey = 5, /obj/item/stack/sheet/animalhide/monkey = 1) inherent_traits = list( - TRAIT_NO_UNDERWEAR, - TRAIT_NO_BLOOD_OVERLAY, TRAIT_GUN_NATURAL, + TRAIT_NO_AUGMENTS, + TRAIT_NO_BLOOD_OVERLAY, + TRAIT_NO_DNA_COPY, + TRAIT_NO_UNDERWEAR, TRAIT_VENTCRAWLER_NUDE, TRAIT_WEAK_SOUL, - TRAIT_NO_TRANSFORMATION_STING, - TRAIT_NO_AUGMENTS, ) no_equip_flags = ITEM_SLOT_OCLOTHING | ITEM_SLOT_GLOVES | ITEM_SLOT_FEET | ITEM_SLOT_SUITSTORE changesource_flags = MIRROR_BADMIN | WABBAJACK | MIRROR_PRIDE | MIRROR_MAGIC | ERT_SPAWN | SLIME_EXTRACT diff --git a/code/modules/mob/living/carbon/human/species_types/mothmen.dm b/code/modules/mob/living/carbon/human/species_types/mothmen.dm index df816fbca35..8f3cd84e1e5 100644 --- a/code/modules/mob/living/carbon/human/species_types/mothmen.dm +++ b/code/modules/mob/living/carbon/human/species_types/mothmen.dm @@ -59,9 +59,10 @@ if(istype(attacking_item, /obj/item/melee/flyswatter)) damage_mods += 10 // Yes, a 10x damage modifier -/datum/species/moth/randomize_features(mob/living/carbon/human/human_mob) - human_mob.dna.features["moth_markings"] = pick(GLOB.moth_wings_list) - randomize_external_organs(human_mob) +/datum/species/moth/randomize_features() + var/list/features = ..() + features["moth_markings"] = pick(GLOB.moth_wings_list) // SKYRAT EDIT CHANGE - ORIGINAL: features["moth_markings"] = pick(GLOB.moth_markings_list) + return features /datum/species/moth/get_scream_sound(mob/living/carbon/human/human) return 'sound/voice/moth/scream_moth.ogg' diff --git a/code/modules/mob/living/carbon/human/species_types/plasmamen.dm b/code/modules/mob/living/carbon/human/species_types/plasmamen.dm index 67f57f75a5a..9facc517c1c 100644 --- a/code/modules/mob/living/carbon/human/species_types/plasmamen.dm +++ b/code/modules/mob/living/carbon/human/species_types/plasmamen.dm @@ -8,11 +8,10 @@ inherent_traits = list( TRAIT_GENELESS, TRAIT_HARDLY_WOUNDED, - TRAIT_RADIMMUNE, - TRAIT_RESISTCOLD, TRAIT_NOBLOOD, TRAIT_NO_DNA_COPY, - TRAIT_NO_TRANSFORMATION_STING, + TRAIT_RADIMMUNE, + TRAIT_RESISTCOLD, ) inherent_biotypes = MOB_HUMANOID|MOB_MINERAL diff --git a/code/modules/mob/living/carbon/human/species_types/podpeople.dm b/code/modules/mob/living/carbon/human/species_types/podpeople.dm index 0b645fd120a..5cf2355c86c 100644 --- a/code/modules/mob/living/carbon/human/species_types/podpeople.dm +++ b/code/modules/mob/living/carbon/human/species_types/podpeople.dm @@ -105,6 +105,3 @@ )) return to_add - -/datum/species/pod/randomize_features(mob/living/carbon/human_mob) - randomize_external_organs(human_mob) diff --git a/code/modules/mob/living/carbon/human/species_types/skeletons.dm b/code/modules/mob/living/carbon/human/species_types/skeletons.dm index a63afeeea29..f2682da2eba 100644 --- a/code/modules/mob/living/carbon/human/species_types/skeletons.dm +++ b/code/modules/mob/living/carbon/human/species_types/skeletons.dm @@ -10,19 +10,19 @@ TRAIT_FAKEDEATH, TRAIT_GENELESS, TRAIT_LIMBATTACHMENT, + TRAIT_NOBLOOD, TRAIT_NOBREATH, TRAIT_NOCLONELOSS, - TRAIT_RADIMMUNE, + TRAIT_NO_DNA_COPY, + TRAIT_NO_UNDERWEAR, TRAIT_PIERCEIMMUNE, + TRAIT_RADIMMUNE, TRAIT_RESISTCOLD, TRAIT_RESISTHEAT, TRAIT_RESISTHIGHPRESSURE, TRAIT_RESISTLOWPRESSURE, TRAIT_TOXIMMUNE, TRAIT_XENO_IMMUNE, - TRAIT_NOBLOOD, - TRAIT_NO_DNA_COPY, - TRAIT_NO_TRANSFORMATION_STING, ) inherent_biotypes = MOB_UNDEAD|MOB_HUMANOID mutanttongue = /obj/item/organ/internal/tongue/bone diff --git a/code/modules/mob/living/carbon/human/species_types/zombies.dm b/code/modules/mob/living/carbon/human/species_types/zombies.dm index 14c4c4d1c15..e567b1a292b 100644 --- a/code/modules/mob/living/carbon/human/species_types/zombies.dm +++ b/code/modules/mob/living/carbon/human/species_types/zombies.dm @@ -7,22 +7,22 @@ mutanttongue = /obj/item/organ/internal/tongue/zombie inherent_traits = list( // SHARED WITH ALL ZOMBIES - TRAIT_NO_ZOMBIFY, TRAIT_EASILY_WOUNDED, TRAIT_EASYDISMEMBER, TRAIT_FAKEDEATH, TRAIT_LIMBATTACHMENT, + TRAIT_LIVERLESS_METABOLISM, TRAIT_NOBREATH, TRAIT_NOCLONELOSS, TRAIT_NODEATH, TRAIT_NOHUNGER, - TRAIT_LIVERLESS_METABOLISM, + TRAIT_NO_DNA_COPY, + TRAIT_NO_ZOMBIFY, TRAIT_RADIMMUNE, TRAIT_RESISTCOLD, TRAIT_RESISTHIGHPRESSURE, TRAIT_RESISTLOWPRESSURE, TRAIT_TOXIMMUNE, - TRAIT_NO_TRANSFORMATION_STING, // HIGH FUNCTIONING UNIQUE TRAIT_NOBLOOD, TRAIT_SUCCUMB_OVERRIDE, @@ -105,11 +105,12 @@ TRAIT_EASYDISMEMBER, TRAIT_FAKEDEATH, TRAIT_LIMBATTACHMENT, + TRAIT_LIVERLESS_METABOLISM, TRAIT_NOBREATH, TRAIT_NOCLONELOSS, TRAIT_NODEATH, TRAIT_NOHUNGER, - TRAIT_LIVERLESS_METABOLISM, + TRAIT_NO_DNA_COPY, TRAIT_RADIMMUNE, TRAIT_RESISTCOLD, TRAIT_RESISTHIGHPRESSURE, diff --git a/code/modules/mob/living/carbon/life.dm b/code/modules/mob/living/carbon/life.dm index a6b766289c0..182eba52b71 100644 --- a/code/modules/mob/living/carbon/life.dm +++ b/code/modules/mob/living/carbon/life.dm @@ -13,7 +13,7 @@ damageoverlaytemp = 0 update_damage_hud() - if(IS_IN_STASIS(src)) + if(HAS_TRAIT(src, TRAIT_STASIS)) . = ..() reagents.handle_stasis_chems(src, seconds_per_tick, times_fired) else diff --git a/code/modules/mob/living/life.dm b/code/modules/mob/living/life.dm index 446e92f09f0..356653745e8 100644 --- a/code/modules/mob/living/life.dm +++ b/code/modules/mob/living/life.dm @@ -40,7 +40,7 @@ if(isnull(loc) || HAS_TRAIT(src, TRAIT_NO_TRANSFORM)) return - if(!IS_IN_STASIS(src)) + if(!HAS_TRAIT(src, TRAIT_STASIS)) if(stat != DEAD) //Mutations and radiation diff --git a/code/modules/mob/living/living.dm b/code/modules/mob/living/living.dm index 6095638318d..5e4a564125c 100644 --- a/code/modules/mob/living/living.dm +++ b/code/modules/mob/living/living.dm @@ -509,7 +509,7 @@ return TRUE if(!(flags & IGNORE_GRAB) && pulledby && pulledby.grab_state >= GRAB_AGGRESSIVE) return TRUE - if(!(flags & IGNORE_STASIS) && IS_IN_STASIS(src)) + if(!(flags & IGNORE_STASIS) && HAS_TRAIT(src, TRAIT_STASIS)) return TRUE return FALSE diff --git a/code/modules/surgery/bodyparts/_bodyparts.dm b/code/modules/surgery/bodyparts/_bodyparts.dm index 00f66b370be..c24e9f8ceca 100644 --- a/code/modules/surgery/bodyparts/_bodyparts.dm +++ b/code/modules/surgery/bodyparts/_bodyparts.dm @@ -1267,12 +1267,12 @@ if(BLEED_OVERLAY_LOW to BLEED_OVERLAY_MED) new_bleed_icon = "[body_zone]_1" if(BLEED_OVERLAY_MED to BLEED_OVERLAY_GUSH) - if(owner.body_position == LYING_DOWN || IS_IN_STASIS(owner) || owner.stat == DEAD) + if(owner.body_position == LYING_DOWN || HAS_TRAIT(owner, TRAIT_STASIS) || owner.stat == DEAD) new_bleed_icon = "[body_zone]_2s" else new_bleed_icon = "[body_zone]_2" if(BLEED_OVERLAY_GUSH to INFINITY) - if(IS_IN_STASIS(owner) || owner.stat == DEAD) + if(HAS_TRAIT(owner, TRAIT_STASIS) || owner.stat == DEAD) new_bleed_icon = "[body_zone]_2s" else new_bleed_icon = "[body_zone]_3" diff --git a/code/modules/surgery/organs/external/tails.dm b/code/modules/surgery/organs/external/tails.dm index e21f277ecf6..bfeb128eb7a 100644 --- a/code/modules/surgery/organs/external/tails.dm +++ b/code/modules/surgery/organs/external/tails.dm @@ -7,11 +7,12 @@ zone = BODY_ZONE_PRECISE_GROIN slot = ORGAN_SLOT_EXTERNAL_TAIL - bodypart_overlay = /datum/bodypart_overlay/mutant/tail - //dna_block = DNA_TAIL_BLOCK // SKYRAT EDIT REMOVAL - Customization - We have our own system to handle DNA. restyle_flags = EXTERNAL_RESTYLE_FLESH + // defaults to cat, but the parent type shouldn't be created regardless + bodypart_overlay = /datum/bodypart_overlay/mutant/tail/cat + ///Does this tail have a wagging sprite, and is it currently wagging? var/wag_flags = NONE ///The original owner of this tail @@ -83,7 +84,7 @@ organ_owner.update_body_parts() UnregisterSignal(organ_owner, COMSIG_LIVING_DEATH) -///Tail parent type (which is MONKEEEEEEEEEEE by default), with wagging functionality +///Tail parent type, with wagging functionality /datum/bodypart_overlay/mutant/tail layers = EXTERNAL_FRONT|EXTERNAL_BEHIND feature_key = "tail" // SKYRAT EDIT - Customization - ORIGINAL: feature_key = "tail_monkey" @@ -92,8 +93,10 @@ /datum/bodypart_overlay/mutant/tail/get_base_icon_state() return (wagging ? "wagging_" : "") + sprite_datum.icon_state //add the wagging tag if we be wagging +// SKYRAT EDIT ADDITION - CUSTOMIZATION /datum/bodypart_overlay/mutant/tail/get_global_feature_list() - return GLOB.sprite_accessories["tail"] // SKYRAT EDIT - Customization - ORIGINAL: return GLOB.tails_list + return GLOB.sprite_accessories["tail"] +// SKYRAT EDIT ADDITION END /datum/bodypart_overlay/mutant/tail/can_draw_on_bodypart(mob/living/carbon/human/human) if(human.wear_suit && (human.wear_suit.flags_inv & HIDEJUMPSUIT)) @@ -124,6 +127,9 @@ color_source = NONE feature_key = "tail" // SKYRAT EDIT - Customization - ORIGINAL: feature_key = "tail_monkey" +/datum/bodypart_overlay/mutant/tail/monkey/get_global_feature_list() + return GLOB.sprite_accessories["tail"] // SKYRAT EDIT CHANGE - ORIGINAL: return GLOB.tails_list_monkey + /obj/item/organ/external/tail/lizard name = "lizard tail" desc = "A severed lizard tail. Somewhere, no doubt, a lizard hater is very pleased with themselves." diff --git a/code/modules/unit_tests/_unit_tests.dm b/code/modules/unit_tests/_unit_tests.dm index d9d163b8702..56c10327441 100644 --- a/code/modules/unit_tests/_unit_tests.dm +++ b/code/modules/unit_tests/_unit_tests.dm @@ -109,6 +109,7 @@ #include "card_mismatch.dm" #include "cardboard_cutouts.dm" #include "chain_pull_through_space.dm" +#include "changeling.dm" #include "chat_filter.dm" #include "circuit_component_category.dm" #include "client_colours.dm" diff --git a/code/modules/unit_tests/changeling.dm b/code/modules/unit_tests/changeling.dm new file mode 100644 index 00000000000..449188a75fd --- /dev/null +++ b/code/modules/unit_tests/changeling.dm @@ -0,0 +1,99 @@ +/// Tests transformation sting goes back and forth correctly +/datum/unit_test/transformation_sting + var/ling_name = "Is-A-Changeling" + var/base_victim_name + var/last_frame = 1 + var/icon/final_icon + +/datum/unit_test/transformation_sting/Run() + var/mob/living/carbon/human/ling = setup_ling() + var/mob/living/carbon/human/victim = setup_victim() + var/datum/antagonist/changeling/ling_datum = ling.mind.has_antag_datum(/datum/antagonist/changeling) + + // Get the ability we're testing + ling_datum.give_power(/datum/action/changeling/sting/transformation) // SKYRAT EDIT CHANGE - Transformation sting not purchasable here - ORIGINAL : ling_datum.purchase_power(/datum/action/changeling/sting/transformation) + var/datum/action/changeling/sting/transformation/sting_action = locate() in ling.actions + sting_action.selected_dna = ling_datum.current_profile + sting_action.sting_duration = 0.5 SECONDS // just makes sure everything settles. + + // Check that they look different before stinging + add_to_screenshot(ling, victim, both_species = TRUE) + + // Do the sting, make the transformation + sting_action.sting_action(ling, victim) + // Check their name and species align + TEST_ASSERT(victim.has_status_effect(/datum/status_effect/temporary_transformation), "Victim did not get temporary transformation status effect on being transformation stung.") + TEST_ASSERT_EQUAL(victim.real_name, ling_name, "Victim real name did not change on being transformation stung.") + TEST_ASSERT_EQUAL(victim.name, ling_name, "Victim name did not change on being transformation stung.") + TEST_ASSERT_EQUAL(victim.dna.species.type, ling.dna.species.type, "Victim species did not change on being transformation stung.") + TEST_ASSERT_EQUAL(victim.dna.features["mcolor"], ling.dna.features["mcolor"], "Victim mcolor did not change on being transformation stung.") + // Check they actually look the same + add_to_screenshot(ling, victim) + + // Make sure we give it enough time such that the status effect process ticks over and finishes + sleep(sting_action.sting_duration + 0.5 SECONDS) + + // Check their name and species reset correctly + TEST_ASSERT_EQUAL(victim.name, base_victim_name, "Victim name did not change back after transformation sting expired.") + TEST_ASSERT_EQUAL(victim.real_name, base_victim_name, "Victim real name did not change back after transformation sting expired.") + TEST_ASSERT_NOTEQUAL(victim.dna.species.type, ling.dna.species.type, "Victim species did not change back after transformation sting expired.") + TEST_ASSERT_NOTEQUAL(victim.dna.features["mcolor"], ling.dna.features["mcolor"], "Victim mcolor did not reset after transformation sting expired.") + // Check they actually look different again + add_to_screenshot(ling, victim, both_species = TRUE) + + test_screenshot("appearances", final_icon) + +/// Adds both mobs to the screenshot test, if both_species is TRUE, it also adds the victim in lizard form +/datum/unit_test/transformation_sting/proc/add_to_screenshot(mob/living/carbon/human/ling, mob/living/carbon/human/victim, both_species = FALSE) + if(isnull(final_icon)) + final_icon = icon('icons/effects/effects.dmi', "nothing") + + // If we have a lot of dna features with a lot of parts (icons) + // This'll eventually runtime into a bad icon operation + // So we're recaching the icons here to prevent it from failing + final_icon = icon(final_icon) + final_icon.Insert(getFlatIcon(ling, no_anim = TRUE), dir = SOUTH, frame = last_frame) + final_icon.Insert(getFlatIcon(victim, no_anim = TRUE), dir = NORTH, frame = last_frame) + + if(both_species) + var/prior_species = victim.dna.species.type + victim.set_species(/datum/species/lizard) + final_icon.Insert(getFlatIcon(victim, no_anim = TRUE), dir = EAST, frame = last_frame) + victim.set_species(prior_species) + + last_frame += 1 + +/datum/unit_test/transformation_sting/proc/setup_victim() + var/mob/living/carbon/human/victim = allocate(/mob/living/carbon/human/consistent) + base_victim_name = victim.real_name + victim.mind_initialize() + return victim + +/datum/unit_test/transformation_sting/proc/setup_ling() + var/mob/living/carbon/human/ling = allocate(/mob/living/carbon/human/consistent) + // Because we use two consistent humans, we need to change some of the features to know they're actually updating to new values. + // The more DNA features and random things we change, the more likely we are to catch something not updating correctly. + // Yeah guess who/what this is, I dare you. + ling.dna.features["mcolor"] = "#886600" + ling.dna.mutant_bodyparts["tail"] = list(MUTANT_INDEX_NAME = "Smooth", MUTANT_INDEX_COLOR_LIST = list("#886600", "#886600", "#886600")) // SKYRAT EDIT CHANGE - ORIGINAL: ling.dna.features["tail_lizard"] = "Smooth" + ling.dna.mutant_bodyparts["snout"] = list(MUTANT_INDEX_NAME = "Sharp + Light", MUTANT_INDEX_COLOR_LIST = list("#886600", "#886600", "#886600")) // SKYRAT EDIT CHANGE - ORIGINAL: ling.dna.features["snout"] = "Sharp + Light" + ling.dna.mutant_bodyparts["horns"] = list(MUTANT_INDEX_NAME = "Curled", MUTANT_INDEX_COLOR_LIST = list("#292826", "#292826", "#8292826")) // SKYRAT EDIT CHANGE - ORIGINAL: ling.dna.features["horns"] = "Curved" + ling.dna.mutant_bodyparts["frills"] = list(MUTANT_INDEX_NAME = "Short", MUTANT_INDEX_COLOR_LIST = list("#886600", "#886600", "#886600")) // SKYRAT EDIT CHANGE - ORIGINAL: ling.dna.features["frills"] = "Sort" + ling.dna.mutant_bodyparts["spines"] = list(MUTANT_INDEX_NAME = "Long + Membrane", MUTANT_INDEX_COLOR_LIST = list("#886600", "#886600", "#886600")) // SKYRAT EDIT CHANGE - ORIGINAL: ling.dna.features["spines"] = "Long + Membrane" + ling.dna.body_markings["chest"] = list("Light Belly" = list("#886600", 0)) // SKYRAT EDIT CHANGE - ORIGINAL : ling.dna.features[body_markings] = list("Light Belly") + ling.dna.features["legs"] = DIGITIGRADE_LEGS + ling.eye_color_left = "#FFFFFF" + ling.eye_color_right = "#FFFFFF" + ling.dna.update_ui_block(DNA_EYE_COLOR_LEFT_BLOCK) + ling.dna.update_ui_block(DNA_EYE_COLOR_RIGHT_BLOCK) + ling.set_species(/datum/species/lizard) + + ling.real_name = ling_name + ling.dna.real_name = ling_name + ling.name = ling_name + ling.dna.initialize_dna(create_mutation_blocks = FALSE, randomize_features = FALSE) + + ling.mind_initialize() + ling.mind.add_antag_datum(/datum/antagonist/changeling) + + return ling diff --git a/code/modules/unit_tests/screenshots/transformation_sting_appearances.png b/code/modules/unit_tests/screenshots/transformation_sting_appearances.png new file mode 100644 index 0000000000000000000000000000000000000000..ce0545d1b568cb767f1495f255fc69581b34cc9b GIT binary patch literal 1274 zcmZ`(e>l?#7=O2~Hu;gYaToR2{3wgmv?o(B<8WDM4aGgW#`2@c7Ov#y)R7TMl4EtH zAJijsl}mTAG@a`FSV}vgFItp(&`pN1TiqY`*S*j4zMuE=yzl3I-@jflC*WIS0}BHH zF!tTz#nqum=RAEx7l$t8rRpGo;}_&D{bDxO6t)YPl8FABp!Zxc6hTfTFzg|52WU|_ zyZ}KE?D7Gq1Fcs3BOhku4+rb6=w_ttg4`&87D(C&@0xG5=A>=g4Es0`?hDZYz;Oi+ zC&=6l4itdxu-p`2J($)MX6uxgByK<;u-+(iauB8jg(P`JCh`;Z3X}E<;sKH+fjfi= zKTN9vg_BdS?YBDGcl_BISRYK2)6tg9aDa*@q{j-Mwkh{KK9zii# zAIifMD`-YJjjI|At-5;mQwiO*{R`UNeX+-s39Sve?eXNO1B)BQ6_$H^yQafT|B8P< z_-2l*s8zVr9$J1bQne>p-`i=^{|5EI{ zpb=Z~%peX2Csc6W*^2X9=Oq&;s`ukmZRLwF zr`v5 z5K~4+k)ne{w!2i48n9QGVdqE!EzebShT!^~3o>KI9Uuv$BheYN7A<(iu!;EDZXOSEMoyPlUBbi`rvRVn#&VFL26kQL?FGZBY}$S{^F; z?bV~Q#V6j)Ntlk%u@)O?i8SCQe9%1Y^Yl=Vj9c+`&WRsr9;7YAhh4>x2xO(^2}{!w zp4TNAhqi;UCCrI4QwWM ze{N>6boxv~Jx?-a>gXQ$0>*G;7Os-xfbi_|Qu)72TXgqW%u^iGIOLEjvTe@v7~(K> zH0Giz>-4OLr}{jz{yX=!hHT|La#+h6a4(uRdHw&XG_x@iWfa?1AsK#d{kjhVzTN>| JwVu2q{{UWrFERiC literal 0 HcmV?d00001 diff --git a/modular_skyrat/master_files/code/modules/antagonists/changeling/powers/tiny_prick.dm b/modular_skyrat/master_files/code/modules/antagonists/changeling/powers/tiny_prick.dm new file mode 100644 index 00000000000..0eaf7f50f9f --- /dev/null +++ b/modular_skyrat/master_files/code/modules/antagonists/changeling/powers/tiny_prick.dm @@ -0,0 +1,3 @@ +// Transformation sting is not able to be purchased +/datum/action/changeling/sting/transformation + dna_cost = CHANGELING_POWER_UNOBTAINABLE diff --git a/modular_skyrat/master_files/code/modules/client/preferences.dm b/modular_skyrat/master_files/code/modules/client/preferences.dm index bc97b467cd9..2532bc4c308 100644 --- a/modular_skyrat/master_files/code/modules/client/preferences.dm +++ b/modular_skyrat/master_files/code/modules/client/preferences.dm @@ -111,28 +111,29 @@ return language /datum/preferences/proc/validate_species_parts() - var/list/target_bodyparts = pref_species.default_mutant_bodyparts.Copy() + var/list/default_bodyparts = GLOB.default_mutant_bodyparts[pref_species.name] + var/list/target_bodyparts = default_bodyparts.Copy() // Remove all "extra" accessories for(var/key in mutant_bodyparts) if(!GLOB.sprite_accessories[key]) // That accessory no longer exists, remove it mutant_bodyparts -= key continue - if(!pref_species.default_mutant_bodyparts[key]) + if(!GLOB.default_mutant_bodyparts[pref_species.name][key]) mutant_bodyparts -= key continue if(!GLOB.sprite_accessories[key][mutant_bodyparts[key][MUTANT_INDEX_NAME]]) // The individual accessory no longer exists - mutant_bodyparts[key][MUTANT_INDEX_NAME] = pref_species.default_mutant_bodyparts[key] + mutant_bodyparts[key][MUTANT_INDEX_NAME] = GLOB.default_mutant_bodyparts[pref_species.name[key][MUTANT_INDEX_NAME]] validate_color_keys_for_part(key) // Validate the color count of each accessory that wasnt removed // Add any missing accessories for(var/key in target_bodyparts) if(!mutant_bodyparts[key]) var/datum/sprite_accessory/SA - if(target_bodyparts[key] == ACC_RANDOM) + if(target_bodyparts[key][MUTANT_INDEX_CAN_RANDOMIZE]) SA = random_accessory_of_key_for_species(key, pref_species) else - SA = GLOB.sprite_accessories[key][target_bodyparts[key]] + SA = GLOB.sprite_accessories[key][target_bodyparts[key][MUTANT_INDEX_NAME]] var/final_list = list() final_list[MUTANT_INDEX_NAME] = SA.name final_list[MUTANT_INDEX_COLOR_LIST] = SA.get_default_color(features, pref_species) diff --git a/modular_skyrat/master_files/code/modules/client/preferences/mutant_parts.dm b/modular_skyrat/master_files/code/modules/client/preferences/mutant_parts.dm index fd11a6bd3b5..57c26e4dd37 100644 --- a/modular_skyrat/master_files/code/modules/client/preferences/mutant_parts.dm +++ b/modular_skyrat/master_files/code/modules/client/preferences/mutant_parts.dm @@ -164,6 +164,9 @@ . = ..() var/obj/item/bodypart/head/our_head = target.get_bodypart(BODY_ZONE_HEAD) + if(isnull(our_head)) // dullahans. + return + if(.) our_head.bodytype |= BODYTYPE_SNOUTED else diff --git a/modular_skyrat/master_files/code/modules/mob/living/human/species.dm b/modular_skyrat/master_files/code/modules/mob/living/human/species.dm index 30df82a7f11..1bb68a1f10f 100644 --- a/modular_skyrat/master_files/code/modules/mob/living/human/species.dm +++ b/modular_skyrat/master_files/code/modules/mob/living/human/species.dm @@ -14,7 +14,7 @@ var/datum/preference/preference = GLOB.preference_entries[preference_type] if ( \ - (preference.relevant_mutant_bodypart in default_mutant_bodyparts) \ + (preference.relevant_mutant_bodypart in GLOB.default_mutant_bodyparts[name]) \ || (preference.relevant_inherent_trait in inherent_traits) \ || (preference.relevant_head_flag && check_head_flags(preference.relevant_head_flag)) \ ) diff --git a/modular_skyrat/modules/better_vox/code/vox_species.dm b/modular_skyrat/modules/better_vox/code/vox_species.dm index 4d3f1b237c9..8fdd3506cc0 100644 --- a/modular_skyrat/modules/better_vox/code/vox_species.dm +++ b/modular_skyrat/modules/better_vox/code/vox_species.dm @@ -17,9 +17,6 @@ breathid = "n2" mutant_bodyparts = list() mutanttongue = /obj/item/organ/internal/tongue/vox - default_mutant_bodyparts = list( - "tail" = "Vox Primalis Tail", - ) payday_modifier = 1.0 outfit_important_for_life = /datum/outfit/vox species_language_holder = /datum/language_holder/vox @@ -50,6 +47,10 @@ LOADOUT_ITEM_EARS = VOX_PRIMALIS_EARS_ICON, ) +/datum/species/vox_primalis/get_default_mutant_bodyparts() + return list( + "tail" = list(MUTANT_INDEX_NAME = "Vox Primalis Tail", MUTANT_INDEX_CAN_RANDOMIZE = FALSE), + ) /datum/species/vox_primalis/pre_equip_species_outfit(datum/job/job, mob/living/carbon/human/equipping, visuals_only) . = ..() diff --git a/modular_skyrat/modules/customization/__DEFINES/lists.dm b/modular_skyrat/modules/customization/__DEFINES/lists.dm index b0877b91b76..6c5d6bf496b 100644 --- a/modular_skyrat/modules/customization/__DEFINES/lists.dm +++ b/modular_skyrat/modules/customization/__DEFINES/lists.dm @@ -2,6 +2,17 @@ GLOBAL_LIST_EMPTY(sprite_accessories) GLOBAL_LIST_EMPTY(generic_accessories) GLOBAL_LIST_EMPTY(genetic_accessories) +/// What accessories can a species have as well as their default accessory of such type e.g. "frills" = "Aquatic". Default accessory colors is dictated by the accessory properties and mutcolors of the specie +GLOBAL_LIST_EMPTY(default_mutant_bodyparts) +GLOBAL_LIST_INIT(possible_genitals, list( + ORGAN_SLOT_VAGINA, + ORGAN_SLOT_WOMB, + ORGAN_SLOT_TESTICLES, + ORGAN_SLOT_BREASTS, + ORGAN_SLOT_ANUS, + ORGAN_SLOT_PENIS +)) + GLOBAL_LIST_EMPTY(body_markings) GLOBAL_LIST_EMPTY_TYPED(body_markings_per_limb, /list) GLOBAL_LIST_EMPTY(body_marking_sets) diff --git a/modular_skyrat/modules/customization/__HELPERS/global_lists.dm b/modular_skyrat/modules/customization/__HELPERS/global_lists.dm index a2dca2e39be..cc2c6c9e3e8 100644 --- a/modular_skyrat/modules/customization/__HELPERS/global_lists.dm +++ b/modular_skyrat/modules/customization/__HELPERS/global_lists.dm @@ -1,5 +1,6 @@ /proc/make_skyrat_datum_references() make_sprite_accessory_references() + make_default_mutant_bodypart_references() make_body_marking_references() make_body_marking_set_references() make_body_marking_dna_block_references() @@ -30,6 +31,18 @@ if(P.generic && !GLOB.generic_accessories[P.key]) GLOB.generic_accessories[P.key] = P.generic +/proc/make_default_mutant_bodypart_references() + // Build the global list for default species' mutant_bodyparts + for(var/path in subtypesof(/datum/species)) + var/datum/species/species_type = path + var/datum/species/species_instance = new species_type + if(!isnull(species_instance.name)) + GLOB.default_mutant_bodyparts[species_instance.name] = species_instance.get_default_mutant_bodyparts() + if(species_instance.can_have_genitals) + for(var/genital in GLOB.possible_genitals) + GLOB.default_mutant_bodyparts[species_instance.name] += list((genital) = list(MUTANT_INDEX_NAME = "None", MUTANT_INDEX_CAN_RANDOMIZE = FALSE)) + qdel(species_instance) + /proc/make_body_marking_references() // Here we build the global list for all body markings for(var/path in subtypesof(/datum/body_marking)) diff --git a/modular_skyrat/modules/customization/datums/dna.dm b/modular_skyrat/modules/customization/datums/dna.dm index 7e0fb14838c..e29e403e97b 100644 --- a/modular_skyrat/modules/customization/datums/dna.dm +++ b/modular_skyrat/modules/customization/datums/dna.dm @@ -57,16 +57,6 @@ GLOBAL_LIST_EMPTY(total_uf_len_by_block) ///Current body size, used for proper re-sizing and keeping track of that var/current_body_size = BODY_SIZE_NORMAL -/datum/dna/proc/initialize_dna(newblood_type, skip_index = FALSE) - if(newblood_type) - blood_type = newblood_type - unique_enzymes = generate_unique_enzymes() - unique_identity = generate_unique_identity() - if(!skip_index) //I hate this - generate_dna_blocks() - mutant_bodyparts = species.get_random_mutant_bodyparts(features) - unique_features = generate_unique_features() - /datum/dna/proc/generate_unique_features() var/list/data = list() @@ -186,59 +176,6 @@ GLOBAL_LIST_EMPTY(total_uf_len_by_block) holder.maptext_height = 32 * features["body_size"] // Adjust runechat height current_body_size = features["body_size"] -/mob/living/carbon/set_species(datum/species/mrace, icon_update = TRUE, pref_load = FALSE, list/override_features, list/override_mutantparts, list/override_markings, retain_features = FALSE, retain_mutantparts = FALSE) - if(QDELETED(src)) - CRASH("You're trying to change your species post deletion, this is a recipe for madness") - if(isnull(mrace)) - CRASH("set_species called without a species to set to") - if(!has_dna()) - return - - var/datum/species/new_race - if(ispath(mrace)) - new_race = new mrace - else if(istype(mrace)) - if(QDELING(mrace)) - CRASH("someone is calling set_species() and is passing it a qdeling species datum, this is VERY bad, stop it") - new_race = mrace - else - CRASH("set_species called with an invalid mrace [mrace]") - - death_sound = new_race.death_sound - - var/datum/species/old_species = dna.species - dna.species = new_race - - if (old_species.properly_gained) - old_species.on_species_loss(src, new_race, pref_load) - - //BODYPARTS AND FEATURES - We need to instantiate the list with compatible mutant parts so we don't break things - - if(override_mutantparts && override_mutantparts.len) - for(var/feature in dna.mutant_bodyparts) - override_mutantparts[feature] = dna.mutant_bodyparts[feature] - dna.mutant_bodyparts = override_mutantparts - - if(override_markings && override_markings.len) - for(var/feature in dna.body_markings) - override_markings[feature] = dna.body_markings[feature] - dna.body_markings = override_markings - - if(override_features && override_features.len) - for(var/feature in dna.features) - override_features[feature] = dna.features[feature] - dna.features = override_features - //END OF BODYPARTS AND FEATURES - - apply_customizable_dna_features_to_species() - dna.unique_features = dna.generate_unique_features() - - dna.update_body_size() - - dna.species.on_species_gain(src, old_species, pref_load) - log_mob_tag("TAG: [tag] SPECIES: [key_name(src)] \[[mrace]\]") - - /mob/living/carbon/proc/apply_customizable_dna_features_to_species() if(!has_dna()) CRASH("[src] does not have DNA") diff --git a/modular_skyrat/modules/customization/modules/mob/dead/new_player/preferences_setup.dm b/modular_skyrat/modules/customization/modules/mob/dead/new_player/preferences_setup.dm index 543a0c15cc1..c2bfd6c7d49 100644 --- a/modular_skyrat/modules/customization/modules/mob/dead/new_player/preferences_setup.dm +++ b/modular_skyrat/modules/customization/modules/mob/dead/new_player/preferences_setup.dm @@ -162,7 +162,7 @@ var/list/new_features = pref_species.get_random_features() //We do this to keep flavor text, genital sizes etc. for(var/key in new_features) features[key] = new_features[key] - mutant_bodyparts = pref_species.get_random_mutant_bodyparts(features) + mutant_bodyparts = pref_species.get_mutant_bodyparts(features) body_markings = pref_species.get_random_body_markings(features) if(pref_species.use_skintones) features["uses_skintones"] = TRUE diff --git a/modular_skyrat/modules/customization/modules/mob/dead/new_player/sprite_accessories/ears.dm b/modular_skyrat/modules/customization/modules/mob/dead/new_player/sprite_accessories/ears.dm index b27d27bae0a..e4f05a3b205 100644 --- a/modular_skyrat/modules/customization/modules/mob/dead/new_player/sprite_accessories/ears.dm +++ b/modular_skyrat/modules/customization/modules/mob/dead/new_player/sprite_accessories/ears.dm @@ -34,7 +34,6 @@ /datum/sprite_accessory/ears/fox color_src = USE_ONE_COLOR - /datum/sprite_accessory/ears/mutant icon = 'modular_skyrat/master_files/icons/mob/sprite_accessory/ears.dmi' organ_type = /obj/item/organ/external/ears // SET BACK TO THIS AS SOON AS WE GET EARS AS EXTERNAL ORGANS: organ_type = /obj/item/organ/internal/ears/mutant @@ -289,7 +288,7 @@ icon_state = "deerear" /datum/sprite_accessory/ears/mutant/teshari - recommended_species = list(SPECIES_TESHARI) + recommended_species = list(SPECIES_TESHARI, SPECIES_TESHARI_ALT) //FLUFFY FRONTIER EDIT - TESHARI_REBORN /datum/sprite_accessory/ears/mutant/teshari/regular name = "Teshari Regular" diff --git a/modular_skyrat/modules/customization/modules/mob/dead/new_player/sprite_accessories/tails.dm b/modular_skyrat/modules/customization/modules/mob/dead/new_player/sprite_accessories/tails.dm index 4831414ca85..ef9212cb509 100644 --- a/modular_skyrat/modules/customization/modules/mob/dead/new_player/sprite_accessories/tails.dm +++ b/modular_skyrat/modules/customization/modules/mob/dead/new_player/sprite_accessories/tails.dm @@ -78,7 +78,7 @@ recommended_species = list(SPECIES_MAMMAL, SPECIES_HUMAN, SPECIES_SYNTH, SPECIES_TAJARAN, SPECIES_HUMANOID, SPECIES_GHOUL) /datum/sprite_accessory/tails/mammal/teshari - recommended_species = list(SPECIES_TESHARI) + recommended_species = list(SPECIES_TESHARI, SPECIES_TESHARI_ALT) //FLUFFY FRONTIER EDIT - TESHARI_REBORN /datum/sprite_accessory/tails/mammal/wagging/vulpkanin recommended_species = list(SPECIES_MAMMAL, SPECIES_HUMAN, SPECIES_SYNTH, SPECIES_VULP, SPECIES_HUMANOID, SPECIES_GHOUL) diff --git a/modular_skyrat/modules/customization/modules/mob/dead/new_player/sprite_accessories/wings.dm b/modular_skyrat/modules/customization/modules/mob/dead/new_player/sprite_accessories/wings.dm index c21b8859d21..03a68cb6925 100644 --- a/modular_skyrat/modules/customization/modules/mob/dead/new_player/sprite_accessories/wings.dm +++ b/modular_skyrat/modules/customization/modules/mob/dead/new_player/sprite_accessories/wings.dm @@ -313,7 +313,7 @@ icon_state = "brown" /datum/sprite_accessory/wings/moth/burnt - name = "Moth (Burnt)" + name = "Burnt Off" icon_state = "burnt_off" locked = TRUE diff --git a/modular_skyrat/modules/customization/modules/mob/living/carbon/human/human.dm b/modular_skyrat/modules/customization/modules/mob/living/carbon/human/human.dm index 78c597e7864..a8499e2fcdb 100644 --- a/modular_skyrat/modules/customization/modules/mob/living/carbon/human/human.dm +++ b/modular_skyrat/modules/customization/modules/mob/living/carbon/human/human.dm @@ -1,9 +1,6 @@ // This DMI holds our radial icons for the 'hide mutant parts' verb #define HIDING_RADIAL_DMI 'modular_skyrat/modules/customization/modules/mob/living/carbon/human/MOD_sprite_accessories/icons/radial.dmi' -/mob/living/carbon/human - var/static/list/possible_genitals = list(ORGAN_SLOT_PENIS, ORGAN_SLOT_TESTICLES, ORGAN_SLOT_VAGINA, ORGAN_SLOT_BREASTS, ORGAN_SLOT_ANUS) - /mob/living/carbon/human/Topic(href, href_list) . = ..() @@ -11,7 +8,7 @@ switch(href_list["lookup_info"]) if("genitals") var/list/line = list() - for(var/genital in possible_genitals) + for(var/genital in GLOB.possible_genitals) if(!dna.species.mutant_bodyparts[genital]) continue var/datum/sprite_accessory/genital/G = GLOB.sprite_accessories[genital][dna.species.mutant_bodyparts[genital][MUTANT_INDEX_NAME]] diff --git a/modular_skyrat/modules/customization/modules/mob/living/carbon/human/species.dm b/modular_skyrat/modules/customization/modules/mob/living/carbon/human/species.dm index 357e827e744..08d83bd7313 100644 --- a/modular_skyrat/modules/customization/modules/mob/living/carbon/human/species.dm +++ b/modular_skyrat/modules/customization/modules/mob/living/carbon/human/species.dm @@ -27,32 +27,37 @@ GLOBAL_LIST_EMPTY(customizable_races) var/list/custom_worn_icons = list() ///Is this species restricted from changing their body_size in character creation? var/body_size_restricted = FALSE - ///What accessories can a species have aswell as their default accessory of such type e.g. "frills" = "Aquatic". Default accessory colors is dictated by the accessory properties and mutcolors of the specie - var/list/default_mutant_bodyparts = list() - /// A static list of all genital slot possibilities. - var/static/list/genitals_list = list(ORGAN_SLOT_VAGINA, ORGAN_SLOT_WOMB, ORGAN_SLOT_TESTICLES, ORGAN_SLOT_BREASTS, ORGAN_SLOT_ANUS, ORGAN_SLOT_PENIS) /// Are we lore protected? This prevents people from changing the species lore or species name. var/lore_protected = FALSE +/// Returns a list of the default mutant bodyparts, and whether or not they can be randomized or not +/datum/species/proc/get_default_mutant_bodyparts() + return list() + /datum/species/proc/handle_mutant_bodyparts(mob/living/carbon/human/owner, forced_colour, force_update = FALSE) return -/datum/species/New() - . = ..() - if(can_have_genitals) - for(var/genital in genitals_list) - default_mutant_bodyparts[genital] = "None" - /datum/species/dullahan mutant_bodyparts = list() /datum/species/human/felinid mutant_bodyparts = list() - default_mutant_bodyparts = list("tail" = "Cat", "ears" = "Cat") + +/datum/species/human/felinid/get_default_mutant_bodyparts() + return list( + "tail" = list(MUTANT_INDEX_NAME = "Cat", MUTANT_INDEX_CAN_RANDOMIZE = FALSE), + "ears" = list(MUTANT_INDEX_NAME = "Cat", MUTANT_INDEX_CAN_RANDOMIZE = FALSE), + ) /datum/species/human mutant_bodyparts = list() - default_mutant_bodyparts = list("ears" = "None", "tail" = "None", "wings" = "None") + +/datum/species/human/get_default_mutant_bodyparts() + return list( + "ears" = list(MUTANT_INDEX_NAME = "None", MUTANT_INDEX_CAN_RANDOMIZE = FALSE), + "tail" = list(MUTANT_INDEX_NAME = "None", MUTANT_INDEX_CAN_RANDOMIZE = FALSE), + "wings" = list(MUTANT_INDEX_NAME = "None", MUTANT_INDEX_CAN_RANDOMIZE = FALSE), + ) /datum/species/mush mutant_bodyparts = list() @@ -75,20 +80,35 @@ GLOBAL_LIST_EMPTY(customizable_races) always_customizable = TRUE /datum/species/randomize_features(mob/living/carbon/human/human_mob) - return + var/list/features = ..() + return features -/datum/species/proc/get_random_mutant_bodyparts(list/features) //Needs features to base the colour off of +/** + * Returns a list of mutant_bodyparts + * + * Gets the default species mutant_bodyparts list for the given species datum and sets up its sprite accessories. + * + * Arguments: + * * features - Features are needed for the part color + * * existing_mutant_bodyparts - When passed a list of existing mutant bodyparts, the existing ones will not get overwritten + */ +/datum/species/proc/get_mutant_bodyparts(list/features, list/existing_mutant_bodyparts) //Needs features to base the colour off of var/list/mutantpart_list = list() - var/list/bodyparts_to_add = default_mutant_bodyparts.Copy() + if(LAZYLEN(existing_mutant_bodyparts)) + mutantpart_list = existing_mutant_bodyparts.Copy() + var/list/default_bodypart_data = GLOB.default_mutant_bodyparts[name] + var/list/bodyparts_to_add = default_bodypart_data.Copy() if(CONFIG_GET(flag/disable_erp_preferences)) - for(var/genital in genitals_list) + for(var/genital in GLOB.possible_genitals) bodyparts_to_add.Remove(genital) for(var/key in bodyparts_to_add) + if(LAZYLEN(existing_mutant_bodyparts) && existing_mutant_bodyparts[key]) + continue var/datum/sprite_accessory/SP - if(bodyparts_to_add[key] == ACC_RANDOM) + if(default_bodypart_data[key][MUTANT_INDEX_CAN_RANDOMIZE]) SP = random_accessory_of_key_for_species(key, src) else - SP = GLOB.sprite_accessories[key][bodyparts_to_add[key]] + SP = GLOB.sprite_accessories[key][bodyparts_to_add[key][MUTANT_INDEX_NAME]] if(!SP) CRASH("Cant find accessory of [key] key, [bodyparts_to_add[key]] name, for species [id]") var/list/color_list = SP.get_default_color(features, src) diff --git a/modular_skyrat/modules/customization/modules/mob/living/carbon/human/species/akula.dm b/modular_skyrat/modules/customization/modules/mob/living/carbon/human/species/akula.dm index 19492ef4456..95733d3df2b 100644 --- a/modular_skyrat/modules/customization/modules/mob/living/carbon/human/species/akula.dm +++ b/modular_skyrat/modules/customization/modules/mob/living/carbon/human/species/akula.dm @@ -29,10 +29,6 @@ ) inherent_biotypes = MOB_ORGANIC|MOB_HUMANOID mutant_bodyparts = list() - default_mutant_bodyparts = list( - "tail" = ACC_RANDOM, - "legs" = "Normal Legs" - ) outfit_important_for_life = /datum/outfit/akula payday_modifier = 1.0 changesource_flags = MIRROR_BADMIN | WABBAJACK | MIRROR_MAGIC | MIRROR_PRIDE | ERT_SPAWN | RACE_SWAP | SLIME_EXTRACT @@ -47,6 +43,12 @@ /// This variable stores the timer datum which appears if the mob becomes wet var/dry_up_timer = TIMER_ID_NULL +/datum/species/akula/get_default_mutant_bodyparts() + return list( + "tail" = list(MUTANT_INDEX_NAME = "Akula", MUTANT_INDEX_CAN_RANDOMIZE = TRUE), + "legs" = list(MUTANT_INDEX_NAME = "Normal Legs", MUTANT_INDEX_CAN_RANDOMIZE = FALSE), + ) + /datum/species/akula/get_species_description() return placeholder_description @@ -60,7 +62,8 @@ "Yet, despite their differences, all Agurkrral citizens swim freely in their kingdom's waters. Even the most controlling border princes, even those in the Old Principalities working the slave trade, know better than to openly erode a citizen's right to life, property, and speech. Any alien species can become an Agurkrral citizen, and even non-citizens enjoy the right to life, with executions outright banned. The aristocracy remains well-educated, even the edgerunner warlords of the New Principalities, and the Kingdom as a whole enjoys its status as a nation that's now a true rival to Sol. Larger, more populated, and better developed; though, having to 'integrate' Solarian technologies, goods, and peoples to fully succeed. The Azuleans are even known as an environmentally-focused people; although they hold no care for lands they cannot make use of, modern nobles are still in charge of maintaining the biosphere of lands they control, to allow their strangely engineered flora and fauna to thrive, and for the people to have healthy and clean waters to live in.", ) -/datum/species/akula/randomize_features(mob/living/carbon/human/human_mob) +/datum/species/akula/randomize_features() + var/list/features = ..() var/main_color var/secondary_color var/tertiary_color @@ -82,9 +85,10 @@ main_color = "#DB35DE" secondary_color = "#BE3AFE" tertiary_color = "#F5E2EE" - human_mob.dna.features["mcolor"] = main_color - human_mob.dna.features["mcolor2"] = secondary_color - human_mob.dna.features["mcolor3"] = tertiary_color + features["mcolor"] = main_color + features["mcolor2"] = secondary_color + features["mcolor3"] = tertiary_color + return features /datum/species/akula/prepare_human_for_preview(mob/living/carbon/human/akula) var/main_color = "#1CD3E5" diff --git a/modular_skyrat/modules/customization/modules/mob/living/carbon/human/species/aquatic.dm b/modular_skyrat/modules/customization/modules/mob/living/carbon/human/species/aquatic.dm index 80aa57ca8ca..2fa8525ff48 100644 --- a/modular_skyrat/modules/customization/modules/mob/living/carbon/human/species/aquatic.dm +++ b/modular_skyrat/modules/customization/modules/mob/living/carbon/human/species/aquatic.dm @@ -11,14 +11,6 @@ inherent_biotypes = MOB_ORGANIC|MOB_HUMANOID mutant_bodyparts = list() mutanttongue = /obj/item/organ/internal/tongue/aquatic - default_mutant_bodyparts = list( - "tail" = ACC_RANDOM, - "snout" = ACC_RANDOM, - "horns" = "None", - "ears" = ACC_RANDOM, - "legs" = "Normal Legs", - "wings" = "None" - ) payday_modifier = 1.0 changesource_flags = MIRROR_BADMIN | WABBAJACK | MIRROR_MAGIC | MIRROR_PRIDE | ERT_SPAWN | RACE_SWAP | SLIME_EXTRACT examine_limb_id = SPECIES_AKULA @@ -31,6 +23,16 @@ BODY_ZONE_R_LEG = /obj/item/bodypart/leg/right/mutant/aquatic, ) +/datum/species/aquatic/get_default_mutant_bodyparts() + return list( + "tail" = list(MUTANT_INDEX_NAME = "Shark", MUTANT_INDEX_CAN_RANDOMIZE = TRUE), + "snout" = list(MUTANT_INDEX_NAME = "Shark", MUTANT_INDEX_CAN_RANDOMIZE = TRUE), + "horns" = list(MUTANT_INDEX_NAME = "None", MUTANT_INDEX_CAN_RANDOMIZE = FALSE), + "ears" = list(MUTANT_INDEX_NAME = "Hammerhead", MUTANT_INDEX_CAN_RANDOMIZE = TRUE), + "legs" = list(MUTANT_INDEX_NAME = "Normal Legs", MUTANT_INDEX_CAN_RANDOMIZE = FALSE), + "wings" = list(MUTANT_INDEX_NAME = "None", MUTANT_INDEX_CAN_RANDOMIZE = FALSE), + ) + /obj/item/organ/internal/tongue/aquatic liked_foodtypes = SEAFOOD | MEAT | FRUIT | GORE disliked_foodtypes = CLOTH | GROSS @@ -38,6 +40,7 @@ /datum/species/aquatic/randomize_features(mob/living/carbon/human/human_mob) + var/list/features = ..() var/main_color var/second_color var/random = rand(1,5) @@ -58,9 +61,10 @@ if(5) main_color = "#444444" second_color = "#DDDDEE" - human_mob.dna.features["mcolor"] = main_color - human_mob.dna.features["mcolor2"] = second_color - human_mob.dna.features["mcolor3"] = second_color + features["mcolor"] = main_color + features["mcolor2"] = second_color + features["mcolor3"] = second_color + return features /datum/species/aquatic/get_random_body_markings(list/passed_features) var/name = "Shark" diff --git a/modular_skyrat/modules/customization/modules/mob/living/carbon/human/species/ghoul.dm b/modular_skyrat/modules/customization/modules/mob/living/carbon/human/species/ghoul.dm index 0b615d6bfc1..f0b2c18d297 100644 --- a/modular_skyrat/modules/customization/modules/mob/living/carbon/human/species/ghoul.dm +++ b/modular_skyrat/modules/customization/modules/mob/living/carbon/human/species/ghoul.dm @@ -4,11 +4,6 @@ examine_limb_id = SPECIES_GHOUL can_have_genitals = FALSE //WHY WOULD YOU WANT TO FUCK ONE OF THESE THINGS? mutant_bodyparts = list("ghoulcolor" = "Tan Necrotic") - default_mutant_bodyparts = list( - "tail" = "None", - "ears" = "None", - "legs" = "Normal Legs" - ) mutanttongue = /obj/item/organ/internal/tongue/ghoul inherent_traits = list( TRAIT_ADVANCEDTOOLUSER, @@ -36,6 +31,13 @@ //i dont have to worry about sprites due to limbs_icon, thank god //also the head needs to be normal for hair to work +/datum/species/ghoul/get_default_mutant_bodyparts() + return list( + "tail" = list(MUTANT_INDEX_NAME = "None", MUTANT_INDEX_CAN_RANDOMIZE = FALSE), + "ears" = list(MUTANT_INDEX_NAME = "None", MUTANT_INDEX_CAN_RANDOMIZE = FALSE), + "legs" = list(MUTANT_INDEX_NAME = "Normal Legs", MUTANT_INDEX_CAN_RANDOMIZE = FALSE), + ) + /proc/proof_ghoul_features(list/inFeatures) // Missing Defaults in DNA? Randomize! if(inFeatures["ghoulcolor"] == null || inFeatures["ghoulcolor"] == "") diff --git a/modular_skyrat/modules/customization/modules/mob/living/carbon/human/species/hemophage/hemophage_species.dm b/modular_skyrat/modules/customization/modules/mob/living/carbon/human/species/hemophage/hemophage_species.dm index 6f721354cd5..a74eb02b7fd 100644 --- a/modular_skyrat/modules/customization/modules/mob/living/carbon/human/species/hemophage/hemophage_species.dm +++ b/modular_skyrat/modules/customization/modules/mob/living/carbon/human/species/hemophage/hemophage_species.dm @@ -17,9 +17,6 @@ TRAIT_USES_SKINTONES, ) inherent_biotypes = MOB_HUMANOID | MOB_ORGANIC - default_mutant_bodyparts = list( - "legs" = "Normal Legs" - ) exotic_bloodtype = "U" mutantheart = /obj/item/organ/internal/heart/hemophage mutantliver = /obj/item/organ/internal/liver/hemophage @@ -31,6 +28,10 @@ skinned_type = /obj/item/stack/sheet/animalhide/human veteran_only = TRUE +/datum/species/hemophage/get_default_mutant_bodyparts() + return list( + "legs" = list(MUTANT_INDEX_NAME = "Normal Legs", MUTANT_INDEX_CAN_RANDOMIZE = FALSE), + ) /datum/species/hemophage/check_roundstart_eligible() if(check_holidays(HALLOWEEN)) @@ -38,7 +39,6 @@ return ..() - /datum/species/hemophage/on_species_gain(mob/living/carbon/human/new_hemophage, datum/species/old_species, pref_load) . = ..() to_chat(new_hemophage, HEMOPHAGE_SPAWN_TEXT) diff --git a/modular_skyrat/modules/customization/modules/mob/living/carbon/human/species/humanoid.dm b/modular_skyrat/modules/customization/modules/mob/living/carbon/human/species/humanoid.dm index 41f3715e8ca..33d15682332 100644 --- a/modular_skyrat/modules/customization/modules/mob/living/carbon/human/species/humanoid.dm +++ b/modular_skyrat/modules/customization/modules/mob/living/carbon/human/species/humanoid.dm @@ -9,19 +9,21 @@ ) inherent_biotypes = MOB_ORGANIC|MOB_HUMANOID mutant_bodyparts = list() - default_mutant_bodyparts = list( - "tail" = "None", - "snout" = "None", - "ears" = "None", - "legs" = "Normal Legs", - "wings" = "None", - "taur" = "None", - "horns" = "None" - ) changesource_flags = MIRROR_BADMIN | WABBAJACK | MIRROR_MAGIC | MIRROR_PRIDE | ERT_SPAWN | RACE_SWAP | SLIME_EXTRACT payday_modifier = 1.0 examine_limb_id = SPECIES_HUMAN +/datum/species/humanoid/get_default_mutant_bodyparts() + return list( + "tail" = list(MUTANT_INDEX_NAME = "None", MUTANT_INDEX_CAN_RANDOMIZE = FALSE), + "snout" = list(MUTANT_INDEX_NAME = "None", MUTANT_INDEX_CAN_RANDOMIZE = FALSE), + "ears" = list(MUTANT_INDEX_NAME = "None", MUTANT_INDEX_CAN_RANDOMIZE = FALSE), + "legs" = list(MUTANT_INDEX_NAME = "Normal Legs", MUTANT_INDEX_CAN_RANDOMIZE = FALSE), + "wings" = list(MUTANT_INDEX_NAME = "None", MUTANT_INDEX_CAN_RANDOMIZE = FALSE), + "taur" = list(MUTANT_INDEX_NAME = "None", MUTANT_INDEX_CAN_RANDOMIZE = FALSE), + "horns" = list(MUTANT_INDEX_NAME = "None", MUTANT_INDEX_CAN_RANDOMIZE = FALSE), + ) + /datum/species/humanoid/get_species_description() return "This is a template species for your own creations!" diff --git a/modular_skyrat/modules/customization/modules/mob/living/carbon/human/species/insect.dm b/modular_skyrat/modules/customization/modules/mob/living/carbon/human/species/insect.dm index 50f2cbec142..880ecec4ca4 100644 --- a/modular_skyrat/modules/customization/modules/mob/living/carbon/human/species/insect.dm +++ b/modular_skyrat/modules/customization/modules/mob/living/carbon/human/species/insect.dm @@ -9,17 +9,6 @@ ) inherent_biotypes = MOB_ORGANIC|MOB_HUMANOID|MOB_BUG mutant_bodyparts = list() - default_mutant_bodyparts = list( - "tail" = "None", - "snout" = "None", - "horns" = "None", - "ears" = "None", - "legs" = "Normal Legs", - "taur" = "None", - "fluff" = "None", - "wings" = "Bee", - "moth_antennae" = "None" - ) mutanttongue = /obj/item/organ/internal/tongue/insect payday_modifier = 1.0 changesource_flags = MIRROR_BADMIN | WABBAJACK | MIRROR_MAGIC | MIRROR_PRIDE | ERT_SPAWN | RACE_SWAP | SLIME_EXTRACT @@ -34,6 +23,19 @@ ) eyes_icon = 'modular_skyrat/modules/organs/icons/insect_eyes.dmi' +/datum/species/insect/get_default_mutant_bodyparts() + return list( + "tail" = list(MUTANT_INDEX_NAME = "None", MUTANT_INDEX_CAN_RANDOMIZE = FALSE), + "snout" = list(MUTANT_INDEX_NAME = "None", MUTANT_INDEX_CAN_RANDOMIZE = FALSE), + "horns" = list(MUTANT_INDEX_NAME = "None", MUTANT_INDEX_CAN_RANDOMIZE = FALSE), + "ears" = list(MUTANT_INDEX_NAME = "None", MUTANT_INDEX_CAN_RANDOMIZE = FALSE), + "legs" = list(MUTANT_INDEX_NAME = "Normal Legs", MUTANT_INDEX_CAN_RANDOMIZE = FALSE), + "taur" = list(MUTANT_INDEX_NAME = "None", MUTANT_INDEX_CAN_RANDOMIZE = FALSE), + "fluff" = list(MUTANT_INDEX_NAME = "None", MUTANT_INDEX_CAN_RANDOMIZE = FALSE), + "wings" = list(MUTANT_INDEX_NAME = "Bee", MUTANT_INDEX_CAN_RANDOMIZE = FALSE), + "moth_antennae" = list(MUTANT_INDEX_NAME = "None", MUTANT_INDEX_CAN_RANDOMIZE = FALSE), + ) + /datum/species/insect/get_species_description() return placeholder_description diff --git a/modular_skyrat/modules/customization/modules/mob/living/carbon/human/species/lizard.dm b/modular_skyrat/modules/customization/modules/mob/living/carbon/human/species/lizard.dm index dd938a43e21..82ea0cf9c31 100644 --- a/modular_skyrat/modules/customization/modules/mob/living/carbon/human/species/lizard.dm +++ b/modular_skyrat/modules/customization/modules/mob/living/carbon/human/species/lizard.dm @@ -1,20 +1,23 @@ /datum/species/lizard mutant_bodyparts = list() external_organs = list() - default_mutant_bodyparts = list( - "tail" = ACC_RANDOM, - "snout" = ACC_RANDOM, - "spines" = ACC_RANDOM, - "frills" = ACC_RANDOM, - "horns" = ACC_RANDOM, - "body_markings" = ACC_RANDOM, - "legs" = DIGITIGRADE_LEGS, - "taur" = "None", - "wings" = "None", - ) payday_modifier = 1.0 -/datum/species/lizard/randomize_features(mob/living/carbon/human/human_mob) +/datum/species/lizard/get_default_mutant_bodyparts() + return list( + "tail" = list(MUTANT_INDEX_NAME = "Smooth", MUTANT_INDEX_CAN_RANDOMIZE = TRUE), + "snout" = list(MUTANT_INDEX_NAME = "Sharp + Light", MUTANT_INDEX_CAN_RANDOMIZE = TRUE), + "spines" = list(MUTANT_INDEX_NAME = "Long + Membrane", MUTANT_INDEX_CAN_RANDOMIZE = TRUE), + "frills" = list(MUTANT_INDEX_NAME = "Short", MUTANT_INDEX_CAN_RANDOMIZE = TRUE), + "horns" = list(MUTANT_INDEX_NAME = "Curled", MUTANT_INDEX_CAN_RANDOMIZE = TRUE), + "body_markings" = list(MUTANT_INDEX_NAME = "Light Belly", MUTANT_INDEX_CAN_RANDOMIZE = TRUE), + "legs" = list(MUTANT_INDEX_NAME = DIGITIGRADE_LEGS, MUTANT_INDEX_CAN_RANDOMIZE = FALSE), + "taur" = list(MUTANT_INDEX_NAME = "None", MUTANT_INDEX_CAN_RANDOMIZE = FALSE), + "wings" = list(MUTANT_INDEX_NAME = "None", MUTANT_INDEX_CAN_RANDOMIZE = FALSE), + ) + +/datum/species/lizard/randomize_features() + var/list/features = ..() var/main_color = "#[random_color()]" var/second_color var/third_color @@ -29,9 +32,10 @@ if(3) //Third case, more randomisation second_color = "#[random_color()]" third_color = "#[random_color()]" - human_mob.dna.features["mcolor"] = main_color - human_mob.dna.features["mcolor2"] = second_color - human_mob.dna.features["mcolor3"] = third_color + features["mcolor"] = main_color + features["mcolor2"] = second_color + features["mcolor3"] = third_color + return features /datum/species/lizard/prepare_human_for_preview(mob/living/carbon/human/lizard, lizard_color = "#009999") lizard.dna.features["mcolor"] = lizard_color diff --git a/modular_skyrat/modules/customization/modules/mob/living/carbon/human/species/mammal.dm b/modular_skyrat/modules/customization/modules/mob/living/carbon/human/species/mammal.dm index 801695b4274..7bf7d0014d6 100644 --- a/modular_skyrat/modules/customization/modules/mob/living/carbon/human/species/mammal.dm +++ b/modular_skyrat/modules/customization/modules/mob/living/carbon/human/species/mammal.dm @@ -10,18 +10,6 @@ inherent_biotypes = MOB_ORGANIC|MOB_HUMANOID mutant_bodyparts = list() mutanttongue = /obj/item/organ/internal/tongue/mammal - default_mutant_bodyparts = list( - "tail" = ACC_RANDOM, - "snout" = ACC_RANDOM, - "horns" = "None", - "ears" = ACC_RANDOM, - "legs" = ACC_RANDOM, - "taur" = "None", - "fluff" = "None", - "wings" = "None", - "head_acc" = "None", - "neck_acc" = "None" - ) payday_modifier = 1.0 changesource_flags = MIRROR_BADMIN | WABBAJACK | MIRROR_MAGIC | MIRROR_PRIDE | ERT_SPAWN | RACE_SWAP | SLIME_EXTRACT bodypart_overrides = list( @@ -33,6 +21,19 @@ BODY_ZONE_R_LEG = /obj/item/bodypart/leg/right/mutant, ) +/datum/species/mammal/get_default_mutant_bodyparts() + return list( + "tail" = list(MUTANT_INDEX_NAME = "Husky", MUTANT_INDEX_CAN_RANDOMIZE = TRUE), + "snout" = list(MUTANT_INDEX_NAME = "Husky", MUTANT_INDEX_CAN_RANDOMIZE = TRUE), + "horns" = list(MUTANT_INDEX_NAME = "None", MUTANT_INDEX_CAN_RANDOMIZE = FALSE), + "ears" = list(MUTANT_INDEX_NAME = "Husky", MUTANT_INDEX_CAN_RANDOMIZE = TRUE), + "legs" = list(MUTANT_INDEX_NAME = "Normal Legs", MUTANT_INDEX_CAN_RANDOMIZE = TRUE), + "taur" = list(MUTANT_INDEX_NAME = "None", MUTANT_INDEX_CAN_RANDOMIZE = FALSE), + "fluff" = list(MUTANT_INDEX_NAME = "None", MUTANT_INDEX_CAN_RANDOMIZE = FALSE), + "wings" = list(MUTANT_INDEX_NAME = "None", MUTANT_INDEX_CAN_RANDOMIZE = FALSE), + "head_acc" = list(MUTANT_INDEX_NAME = "None", MUTANT_INDEX_CAN_RANDOMIZE = FALSE), + "neck_acc" = list(MUTANT_INDEX_NAME = "None", MUTANT_INDEX_CAN_RANDOMIZE = FALSE), + ) /obj/item/organ/internal/tongue/mammal liked_foodtypes = GRAIN | MEAT @@ -40,7 +41,8 @@ toxic_foodtypes = TOXIC -/datum/species/mammal/randomize_features(mob/living/carbon/human/human_mob) +/datum/species/mammal/randomize_features() + var/list/features = ..() var/main_color var/second_color var/third_color @@ -74,9 +76,10 @@ main_color = "#[random_color()]" second_color = "#[random_color()]" third_color = "#[random_color()]" - human_mob.dna.features["mcolor"] = main_color - human_mob.dna.features["mcolor2"] = second_color - human_mob.dna.features["mcolor3"] = third_color + features["mcolor"] = main_color + features["mcolor2"] = second_color + features["mcolor3"] = third_color + return features /datum/species/mammal/get_random_body_markings(list/passed_features) var/name = "None" diff --git a/modular_skyrat/modules/customization/modules/mob/living/carbon/human/species/monkey.dm b/modular_skyrat/modules/customization/modules/mob/living/carbon/human/species/monkey.dm index 2b46cb02c21..fdcb5630d31 100644 --- a/modular_skyrat/modules/customization/modules/mob/living/carbon/human/species/monkey.dm +++ b/modular_skyrat/modules/customization/modules/mob/living/carbon/human/species/monkey.dm @@ -1,5 +1,7 @@ -/datum/species/monkey - default_mutant_bodyparts = list("tail" = "Monkey") +/datum/species/monkey/get_default_mutant_bodyparts() + return list( + "tail" = list(MUTANT_INDEX_NAME = "Monkey", MUTANT_INDEX_CAN_RANDOMIZE = FALSE), + ) /datum/species/monkey/prepare_human_for_preview(mob/living/carbon/human/monke) regenerate_organs(monke, src, visual_only = TRUE) diff --git a/modular_skyrat/modules/customization/modules/mob/living/carbon/human/species/moth.dm b/modular_skyrat/modules/customization/modules/mob/living/carbon/human/species/moth.dm index 6628060ee92..04a452712a4 100644 --- a/modular_skyrat/modules/customization/modules/mob/living/carbon/human/species/moth.dm +++ b/modular_skyrat/modules/customization/modules/mob/living/carbon/human/species/moth.dm @@ -1,10 +1,5 @@ /datum/species/moth mutant_bodyparts = list() - default_mutant_bodyparts = list( - "fluff" = "None", - "wings" = ACC_RANDOM, - "moth_antennae" = ACC_RANDOM, - ) inherent_traits = list( TRAIT_HAS_MARKINGS, TRAIT_TACKLING_WINGED_ATTACKER, @@ -12,8 +7,17 @@ TRAIT_MUTANT_COLORS, ) -/datum/species/moth/randomize_features(mob/living/carbon/human/human_mob) - human_mob.dna.features["mcolor"] = "#E5CD99" +/datum/species/moth/get_default_mutant_bodyparts() + return list( + "fluff" = list(MUTANT_INDEX_NAME = "Plain", MUTANT_INDEX_CAN_RANDOMIZE = FALSE), + "wings" = list(MUTANT_INDEX_NAME = "Moth (Plain)", MUTANT_INDEX_CAN_RANDOMIZE = TRUE), + "moth_antennae" = list(MUTANT_INDEX_NAME = "Plain", MUTANT_INDEX_CAN_RANDOMIZE = TRUE), + ) + +/datum/species/moth/randomize_features() + var/list/features = ..() + features["mcolor"] = "#E5CD99" + return features /datum/species/moth/get_random_body_markings(list/passed_features) var/name = "None" diff --git a/modular_skyrat/modules/customization/modules/mob/living/carbon/human/species/podweak.dm b/modular_skyrat/modules/customization/modules/mob/living/carbon/human/species/podweak.dm index 90a4e4298a7..73b66a22c57 100644 --- a/modular_skyrat/modules/customization/modules/mob/living/carbon/human/species/podweak.dm +++ b/modular_skyrat/modules/customization/modules/mob/living/carbon/human/species/podweak.dm @@ -7,12 +7,14 @@ TRAIT_LITERATE, ) mutant_bodyparts = list() - default_mutant_bodyparts = list( - "pod_hair" = ACC_RANDOM, - "legs" = "Normal Legs" - ) payday_modifier = 1.0 +/datum/species/pod/get_default_mutant_bodyparts() + return list( + "pod_hair" = list(MUTANT_INDEX_NAME = "Ivy", MUTANT_INDEX_CAN_RANDOMIZE = TRUE), + "legs" = list(MUTANT_INDEX_NAME = "Normal Legs", MUTANT_INDEX_CAN_RANDOMIZE = FALSE), + ) + /datum/species/pod/podweak name = "Podperson" id = SPECIES_PODPERSON_WEAK diff --git a/modular_skyrat/modules/customization/modules/mob/living/carbon/human/species/roundstartslime.dm b/modular_skyrat/modules/customization/modules/mob/living/carbon/human/species/roundstartslime.dm index 422c1fd12cd..eec5fb6e5c7 100644 --- a/modular_skyrat/modules/customization/modules/mob/living/carbon/human/species/roundstartslime.dm +++ b/modular_skyrat/modules/customization/modules/mob/living/carbon/human/species/roundstartslime.dm @@ -1,20 +1,22 @@ /datum/species/jelly - default_mutant_bodyparts = list( - "tail" = "None", - "snout" = "None", - "ears" = "None", - "taur" = "None", - "wings" = "None", - "legs" = "Normal Legs", - "horns" = "None", - "spines" = "None", - "frills" = "None", - ) mutant_bodyparts = list() hair_color = "mutcolor" hair_alpha = 160 //a notch brighter so it blends better. facial_hair_alpha = 160 +/datum/species/jelly/get_default_mutant_bodyparts() + return list( + "tail" = list(MUTANT_INDEX_NAME = "None", MUTANT_INDEX_CAN_RANDOMIZE = FALSE), + "snout" = list(MUTANT_INDEX_NAME = "None", MUTANT_INDEX_CAN_RANDOMIZE = FALSE), + "ears" = list(MUTANT_INDEX_NAME = "None", MUTANT_INDEX_CAN_RANDOMIZE = FALSE), + "legs" = list(MUTANT_INDEX_NAME = "Normal Legs", MUTANT_INDEX_CAN_RANDOMIZE = FALSE), + "taur" = list(MUTANT_INDEX_NAME = "None", MUTANT_INDEX_CAN_RANDOMIZE = FALSE), + "wings" = list(MUTANT_INDEX_NAME = "None", MUTANT_INDEX_CAN_RANDOMIZE = FALSE), + "horns" = list(MUTANT_INDEX_NAME = "None", MUTANT_INDEX_CAN_RANDOMIZE = FALSE), + "spines" = list(MUTANT_INDEX_NAME = "None", MUTANT_INDEX_CAN_RANDOMIZE = FALSE), + "frills" = list(MUTANT_INDEX_NAME = "None", MUTANT_INDEX_CAN_RANDOMIZE = FALSE), + ) + /datum/species/jelly/get_species_description() return placeholder_description diff --git a/modular_skyrat/modules/customization/modules/mob/living/carbon/human/species/skrell.dm b/modular_skyrat/modules/customization/modules/mob/living/carbon/human/species/skrell.dm index 47cd5be08c0..b489e6a1c74 100644 --- a/modular_skyrat/modules/customization/modules/mob/living/carbon/human/species/skrell.dm +++ b/modular_skyrat/modules/customization/modules/mob/living/carbon/human/species/skrell.dm @@ -16,7 +16,6 @@ mutant_bodyparts = list() mutanttongue = /obj/item/organ/internal/tongue/skrell payday_modifier = 1.0 - default_mutant_bodyparts = list("skrell_hair" = ACC_RANDOM) changesource_flags = MIRROR_BADMIN | WABBAJACK | MIRROR_MAGIC | MIRROR_PRIDE | ERT_SPAWN | RACE_SWAP | SLIME_EXTRACT eyes_icon = 'modular_skyrat/modules/organs/icons/skrell_eyes.dmi' mutantbrain = /obj/item/organ/internal/brain/skrell @@ -34,13 +33,19 @@ BODY_ZONE_R_LEG = /obj/item/bodypart/leg/right/mutant/skrell, ) +/datum/species/skrell/get_default_mutant_bodyparts() + return list( + "skrell_hair" = list(MUTANT_INDEX_NAME = "Male", MUTANT_INDEX_CAN_RANDOMIZE = TRUE), + ) + /datum/species/skrell/get_species_description() return placeholder_description /datum/species/skrell/get_species_lore() return list(placeholder_lore) -/datum/species/skrell/randomize_features(mob/living/carbon/human/human_mob) +/datum/species/skrell/randomize_features() + var/list/features = ..() var/main_color var/random = rand(1,6) //Choose from a range of green-blue colors @@ -57,9 +62,10 @@ main_color = "#22BBFF" if(6) main_color = "#2266FF" - human_mob.dna.features["mcolor"] = main_color - human_mob.dna.features["mcolor2"] = main_color - human_mob.dna.features["mcolor3"] = main_color + features["mcolor"] = main_color + features["mcolor2"] = main_color + features["mcolor3"] = main_color + return features /datum/species/skrell/prepare_human_for_preview(mob/living/carbon/human/skrell) var/skrell_color = "#22BBFF" diff --git a/modular_skyrat/modules/customization/modules/mob/living/carbon/human/species/tajaran.dm b/modular_skyrat/modules/customization/modules/mob/living/carbon/human/species/tajaran.dm index e5739b23624..e26208ec567 100644 --- a/modular_skyrat/modules/customization/modules/mob/living/carbon/human/species/tajaran.dm +++ b/modular_skyrat/modules/customization/modules/mob/living/carbon/human/species/tajaran.dm @@ -11,12 +11,6 @@ mutanttongue = /obj/item/organ/internal/tongue/cat/tajaran inherent_biotypes = MOB_ORGANIC|MOB_HUMANOID mutant_bodyparts = list() - default_mutant_bodyparts = list( - "tail" = ACC_RANDOM, - "snout" = ACC_RANDOM, - "ears" = ACC_RANDOM, - "legs" = "Normal Legs" - ) payday_modifier = 1.0 species_language_holder = /datum/language_holder/tajaran changesource_flags = MIRROR_BADMIN | WABBAJACK | MIRROR_MAGIC | MIRROR_PRIDE | ERT_SPAWN | RACE_SWAP | SLIME_EXTRACT @@ -30,13 +24,21 @@ BODY_ZONE_R_LEG = /obj/item/bodypart/leg/right/mutant, ) +/datum/species/tajaran/get_default_mutant_bodyparts() + return list( + "tail" = list(MUTANT_INDEX_NAME = "Cat (Big)", MUTANT_INDEX_CAN_RANDOMIZE = TRUE), + "snout" = list(MUTANT_INDEX_NAME = "Cat, normal", MUTANT_INDEX_CAN_RANDOMIZE = TRUE), + "ears" = list(MUTANT_INDEX_NAME = "Cat, normal", MUTANT_INDEX_CAN_RANDOMIZE = TRUE), + "legs" = list(MUTANT_INDEX_NAME = "Normal Legs", MUTANT_INDEX_CAN_RANDOMIZE = FALSE), + ) /obj/item/organ/internal/tongue/cat/tajaran liked_foodtypes = GRAIN | MEAT disliked_foodtypes = CLOTH -/datum/species/tajaran/randomize_features(mob/living/carbon/human/human_mob) +/datum/species/tajaran/randomize_features() + var/list/features = ..() var/main_color var/second_color var/random = rand(1,5) @@ -57,9 +59,10 @@ if(5) main_color = "#DDCC99" second_color = "#DDCCAA" - human_mob.dna.features["mcolor"] = main_color - human_mob.dna.features["mcolor2"] = second_color - human_mob.dna.features["mcolor3"] = second_color + features["mcolor"] = main_color + features["mcolor2"] = second_color + features["mcolor3"] = second_color + return features /datum/species/tajaran/get_random_body_markings(list/passed_features) var/name = pick("Tajaran", "Floof", "Floofer") diff --git a/modular_skyrat/modules/customization/modules/mob/living/carbon/human/species/unathi.dm b/modular_skyrat/modules/customization/modules/mob/living/carbon/human/species/unathi.dm index c744097639a..e2638e06e3e 100644 --- a/modular_skyrat/modules/customization/modules/mob/living/carbon/human/species/unathi.dm +++ b/modular_skyrat/modules/customization/modules/mob/living/carbon/human/species/unathi.dm @@ -10,15 +10,6 @@ inherent_biotypes = MOB_ORGANIC|MOB_HUMANOID mutant_bodyparts = list() mutanttongue = /obj/item/organ/internal/tongue/unathi - default_mutant_bodyparts = list( - "tail" = ACC_RANDOM, - "snout" = ACC_RANDOM, - "spines" = "None", - "frills" = "None", - "horns" = ACC_RANDOM, - "body_markings" = ACC_RANDOM, - "legs" = "Normal Legs" - ) payday_modifier = 1.0 changesource_flags = MIRROR_BADMIN | WABBAJACK | MIRROR_MAGIC | MIRROR_PRIDE | ERT_SPAWN | RACE_SWAP | SLIME_EXTRACT examine_limb_id = SPECIES_LIZARD @@ -33,6 +24,16 @@ BODY_ZONE_R_LEG = /obj/item/bodypart/leg/right/lizard, ) +/datum/species/unathi/get_default_mutant_bodyparts() + return list( + "tail" = list(MUTANT_INDEX_NAME = "Smooth", MUTANT_INDEX_CAN_RANDOMIZE = TRUE), + "snout" = list(MUTANT_INDEX_NAME = "Sharp + Light", MUTANT_INDEX_CAN_RANDOMIZE = TRUE), + "spines" = list(MUTANT_INDEX_NAME = "None", MUTANT_INDEX_CAN_RANDOMIZE = FALSE), + "frills" = list(MUTANT_INDEX_NAME = "None", MUTANT_INDEX_CAN_RANDOMIZE = FALSE), + "horns" = list(MUTANT_INDEX_NAME = "Curled", MUTANT_INDEX_CAN_RANDOMIZE = TRUE), + "body_markings" = list(MUTANT_INDEX_NAME = "Smooth Belly", MUTANT_INDEX_CAN_RANDOMIZE = TRUE), + "legs" = list(MUTANT_INDEX_NAME = "Normal Legs", MUTANT_INDEX_CAN_RANDOMIZE = FALSE), + ) /obj/item/organ/internal/tongue/unathi liked_foodtypes = GORE | MEAT | SEAFOOD | NUTS @@ -40,7 +41,8 @@ toxic_foodtypes = TOXIC -/datum/species/unathi/randomize_features(mob/living/carbon/human/human_mob) +/datum/species/unathi/randomize_features() + var/list/features = ..() var/main_color var/second_color var/random = rand(1,5) @@ -61,9 +63,10 @@ if(5) main_color = "#33BB11" second_color = "#339911" - human_mob.dna.features["mcolor"] = main_color - human_mob.dna.features["mcolor2"] = second_color - human_mob.dna.features["mcolor3"] = second_color + features["mcolor"] = main_color + features["mcolor2"] = second_color + features["mcolor3"] = second_color + return features /datum/species/unathi/get_species_description() return placeholder_description diff --git a/modular_skyrat/modules/customization/modules/mob/living/carbon/human/species/vox.dm b/modular_skyrat/modules/customization/modules/mob/living/carbon/human/species/vox.dm index 059019f249e..ecf2d84f623 100644 --- a/modular_skyrat/modules/customization/modules/mob/living/carbon/human/species/vox.dm +++ b/modular_skyrat/modules/customization/modules/mob/living/carbon/human/species/vox.dm @@ -16,12 +16,6 @@ mutantbrain = /obj/item/organ/internal/brain/vox breathid = "n2" mutant_bodyparts = list() - default_mutant_bodyparts = list( - "tail" = "Vox Tail", - "legs" = DIGITIGRADE_LEGS, - "snout" = "Vox Snout", - "spines" = ACC_RANDOM - ) payday_modifier = 1.0 outfit_important_for_life = /datum/outfit/vox species_language_holder = /datum/language_holder/vox @@ -51,6 +45,14 @@ LOADOUT_ITEM_EARS = VOX_EARS_ICON ) +/datum/species/vox/get_default_mutant_bodyparts() + return list( + "tail" = list(MUTANT_INDEX_NAME = "Vox Tail", MUTANT_INDEX_CAN_RANDOMIZE = FALSE), + "legs" = list(MUTANT_INDEX_NAME = DIGITIGRADE_LEGS, MUTANT_INDEX_CAN_RANDOMIZE = FALSE), + "snout" = list(MUTANT_INDEX_NAME = "Vox Snout", MUTANT_INDEX_CAN_RANDOMIZE = FALSE), + "spines" = list(MUTANT_INDEX_NAME = "Vox Bands", MUTANT_INDEX_CAN_RANDOMIZE = TRUE), + ) + /datum/species/vox/pre_equip_species_outfit(datum/job/job, mob/living/carbon/human/equipping, visuals_only) . = ..() if(job?.vox_outfit) @@ -69,10 +71,12 @@ return randname -/datum/species/vox/randomize_features(mob/living/carbon/human/human_mob) - human_mob.dna.features["mcolor"] = pick("#77DD88", "#77DDAA", "#77CCDD", "#77DDCC") - human_mob.dna.features["mcolor2"] = pick("#EEDD88", "#EECC88") - human_mob.dna.features["mcolor3"] = pick("#222222", "#44EEFF", "#44FFBB", "#8844FF", "#332233") +/datum/species/vox/randomize_features() + var/list/features = ..() + features["mcolor"] = pick("#77DD88", "#77DDAA", "#77CCDD", "#77DDCC") + features["mcolor2"] = pick("#EEDD88", "#EECC88") + features["mcolor3"] = pick("#222222", "#44EEFF", "#44FFBB", "#8844FF", "#332233") + return features /datum/species/vox/get_random_body_markings(list/passed_features) var/name = pick(list("Vox", "Vox Hive", "Vox Nightling", "Vox Heart", "Vox Tiger")) diff --git a/modular_skyrat/modules/customization/modules/mob/living/carbon/human/species/vulpkanin.dm b/modular_skyrat/modules/customization/modules/mob/living/carbon/human/species/vulpkanin.dm index 62e001c5f74..410d5200eed 100644 --- a/modular_skyrat/modules/customization/modules/mob/living/carbon/human/species/vulpkanin.dm +++ b/modular_skyrat/modules/customization/modules/mob/living/carbon/human/species/vulpkanin.dm @@ -10,12 +10,6 @@ inherent_biotypes = MOB_ORGANIC|MOB_HUMANOID mutant_bodyparts = list() mutanttongue = /obj/item/organ/internal/tongue/vulpkanin - default_mutant_bodyparts = list( - "tail" = ACC_RANDOM, - "snout" = ACC_RANDOM, - "ears" = ACC_RANDOM, - "legs" = "Normal Legs" - ) species_language_holder = /datum/language_holder/vulpkanin payday_modifier = 1.0 changesource_flags = MIRROR_BADMIN | WABBAJACK | MIRROR_MAGIC | MIRROR_PRIDE | ERT_SPAWN | RACE_SWAP | SLIME_EXTRACT @@ -29,6 +23,13 @@ BODY_ZONE_R_LEG = /obj/item/bodypart/leg/right/mutant, ) +/datum/species/vulpkanin/get_default_mutant_bodyparts() + return list( + "tail" = list(MUTANT_INDEX_NAME = "Fox", MUTANT_INDEX_CAN_RANDOMIZE = TRUE), + "snout" = list(MUTANT_INDEX_NAME = "Mammal, Long", MUTANT_INDEX_CAN_RANDOMIZE = TRUE), + "ears" = list(MUTANT_INDEX_NAME = "Fox", MUTANT_INDEX_CAN_RANDOMIZE = TRUE), + "legs" = list(MUTANT_INDEX_NAME = "Normal Legs", MUTANT_INDEX_CAN_RANDOMIZE = FALSE), + ) /obj/item/organ/internal/tongue/vulpkanin liked_foodtypes = RAW | MEAT @@ -36,7 +37,8 @@ toxic_foodtypes = TOXIC -/datum/species/vulpkanin/randomize_features(mob/living/carbon/human/human_mob) +/datum/species/vulpkanin/randomize_features() + var/list/features = ..() var/main_color var/second_color var/random = rand(1,5) @@ -57,9 +59,10 @@ if(5) main_color = "#999999" second_color = "#EEEEEE" - human_mob.dna.features["mcolor"] = main_color - human_mob.dna.features["mcolor2"] = second_color - human_mob.dna.features["mcolor3"] = second_color + features["mcolor"] = main_color + features["mcolor2"] = second_color + features["mcolor3"] = second_color + return features /datum/species/vulpkanin/get_random_body_markings(list/passed_features) var/name = pick("Fox", "Floof", "Floofer") diff --git a/modular_skyrat/modules/customization/modules/mob/living/carbon/human/species/xeno.dm b/modular_skyrat/modules/customization/modules/mob/living/carbon/human/species/xeno.dm index b4dbe252503..cb73afdc4e1 100644 --- a/modular_skyrat/modules/customization/modules/mob/living/carbon/human/species/xeno.dm +++ b/modular_skyrat/modules/customization/modules/mob/living/carbon/human/species/xeno.dm @@ -12,13 +12,6 @@ inherent_biotypes = MOB_ORGANIC|MOB_HUMANOID mutanttongue = /obj/item/organ/internal/tongue/xeno_hybrid mutant_bodyparts = list() - default_mutant_bodyparts = list( - "tail" = "Xenomorph Tail", - "xenodorsal" = ACC_RANDOM, - "xenohead" = ACC_RANDOM, - "legs" = DIGITIGRADE_LEGS, - "taur" = "None" - ) external_organs = list() payday_modifier = 1.0 changesource_flags = MIRROR_BADMIN | WABBAJACK | MIRROR_MAGIC | MIRROR_PRIDE | ERT_SPAWN | RACE_SWAP | SLIME_EXTRACT @@ -34,6 +27,15 @@ meat = /obj/item/food/meat/slab/xeno skinned_type = /obj/item/stack/sheet/animalhide/xeno +/datum/species/xeno/get_default_mutant_bodyparts() + return list( + "tail" = list(MUTANT_INDEX_NAME = "Xenomorph Tail", MUTANT_INDEX_CAN_RANDOMIZE = FALSE), + "xenodorsal" = list(MUTANT_INDEX_NAME = "Standard", MUTANT_INDEX_CAN_RANDOMIZE = TRUE), + "xenohead" = list(MUTANT_INDEX_NAME = "Standard", MUTANT_INDEX_CAN_RANDOMIZE = TRUE), + "legs" = list(MUTANT_INDEX_NAME = DIGITIGRADE_LEGS, MUTANT_INDEX_CAN_RANDOMIZE = FALSE), + "taur" = list(MUTANT_INDEX_NAME = "None", MUTANT_INDEX_CAN_RANDOMIZE = FALSE), + ) + /datum/species/xeno/get_species_description() return placeholder_description diff --git a/modular_skyrat/modules/medical/code/wounds/synth/blunt/robotic_blunt.dm b/modular_skyrat/modules/medical/code/wounds/synth/blunt/robotic_blunt.dm index 52995365b01..66cbbb510b2 100644 --- a/modular_skyrat/modules/medical/code/wounds/synth/blunt/robotic_blunt.dm +++ b/modular_skyrat/modules/medical/code/wounds/synth/blunt/robotic_blunt.dm @@ -140,7 +140,7 @@ /datum/wound/blunt/robotic/handle_process(seconds_per_tick, times_fired) . = ..() - if (!victim || IS_IN_STASIS(victim)) + if (!victim || HAS_TRAIT(victim, TRAIT_STASIS)) return if (limb.body_zone == BODY_ZONE_HEAD && brain_trauma_group && world.time > next_trauma_cycle) diff --git a/modular_skyrat/modules/medical/code/wounds/synth/blunt/secures_internals.dm b/modular_skyrat/modules/medical/code/wounds/synth/blunt/secures_internals.dm index e9e9ce3cb68..d4483dafb0b 100644 --- a/modular_skyrat/modules/medical/code/wounds/synth/blunt/secures_internals.dm +++ b/modular_skyrat/modules/medical/code/wounds/synth/blunt/secures_internals.dm @@ -20,7 +20,7 @@ /datum/wound/blunt/robotic/secures_internals/handle_process(seconds_per_tick, times_fired) . = ..() - if (!victim || IS_IN_STASIS(victim)) + if (!victim || HAS_TRAIT(victim, TRAIT_STASIS)) return if (gelled) diff --git a/modular_skyrat/modules/medical/code/wounds/synth/robotic_burns.dm b/modular_skyrat/modules/medical/code/wounds/synth/robotic_burns.dm index 24ac18eeab6..16540ac9f36 100644 --- a/modular_skyrat/modules/medical/code/wounds/synth/robotic_burns.dm +++ b/modular_skyrat/modules/medical/code/wounds/synth/robotic_burns.dm @@ -126,7 +126,7 @@ if (outgoing_bodytemp_coeff <= 0) return var/statis_mult = 1 - if (IS_IN_STASIS(victim)) // stasis heavily reduces the ingoing and outgoing transfer of heat + if (HAS_TRAIT(victim, TRAIT_STASIS)) // stasis heavily reduces the ingoing and outgoing transfer of heat statis_mult *= OVERHEAT_ON_STASIS_HEAT_MULT var/difference_from_average = max((BODYTEMP_NORMAL - victim.bodytemperature), 0) diff --git a/modular_skyrat/modules/medical/code/wounds/synth/robotic_slash.dm b/modular_skyrat/modules/medical/code/wounds/synth/robotic_slash.dm index 1a0c730c68c..2d20b0edbb2 100644 --- a/modular_skyrat/modules/medical/code/wounds/synth/robotic_slash.dm +++ b/modular_skyrat/modules/medical/code/wounds/synth/robotic_slash.dm @@ -194,7 +194,7 @@ var/base_mult = 1 if (victim) - if (IS_IN_STASIS(victim)) + if (HAS_TRAIT(victim, TRAIT_STASIS)) base_mult *= ELECTRICAL_DAMAGE_ON_STASIS_MULT if (victim.body_position == LYING_DOWN) base_mult *= ELECTRICAL_DAMAGE_LYING_DOWN_MULT diff --git a/modular_skyrat/modules/modular_implants/code/nifs.dm b/modular_skyrat/modules/modular_implants/code/nifs.dm index 12d9c67ad81..5d2b1aabd4a 100644 --- a/modular_skyrat/modules/modular_implants/code/nifs.dm +++ b/modular_skyrat/modules/modular_implants/code/nifs.dm @@ -185,7 +185,7 @@ /obj/item/organ/internal/cyberimp/brain/nif/process(seconds_per_tick) . = ..() - if(!linked_mob || broken || IS_IN_STASIS(linked_mob)) + if(!linked_mob || broken || HAS_TRAIT(linked_mob, TRAIT_STASIS)) return FALSE if(calibrating) diff --git a/modular_skyrat/modules/stasisrework/code/stasissleeper.dm b/modular_skyrat/modules/stasisrework/code/stasissleeper.dm index ffeb12dc56e..3510fa5c269 100644 --- a/modular_skyrat/modules/stasisrework/code/stasissleeper.dm +++ b/modular_skyrat/modules/stasisrework/code/stasissleeper.dm @@ -75,7 +75,7 @@ visible_message(span_notice("[occupant] emerges from [src]!"), span_notice("You climb out of [src]!")) open_machine() - if(IS_IN_STASIS(user)) + if(HAS_TRAIT(user, TRAIT_STASIS)) thaw_them(user) /obj/machinery/stasissleeper/proc/stasis_running() @@ -112,9 +112,9 @@ return var/mob/living/L_occupant = occupant if(stasis_running()) - if(!IS_IN_STASIS(L_occupant)) + if(!HAS_TRAIT(L_occupant, TRAIT_STASIS)) chill_out(L_occupant) - else if(IS_IN_STASIS(L_occupant)) + else if(HAS_TRAIT(L_occupant, TRAIT_STASIS)) thaw_them(L_occupant) /obj/machinery/stasissleeper/screwdriver_act(mob/living/user, obj/item/used_item) diff --git a/modular_skyrat/modules/synths/code/species/synthetic.dm b/modular_skyrat/modules/synths/code/species/synthetic.dm index 124985d73da..e3167ab4a4f 100644 --- a/modular_skyrat/modules/synths/code/species/synthetic.dm +++ b/modular_skyrat/modules/synths/code/species/synthetic.dm @@ -18,19 +18,8 @@ TRAIT_LITERATE, TRAIT_NOCRITDAMAGE, // We do our own handling of crit damage. TRAIT_ROBOTIC_DNA_ORGANS, - TRAIT_NO_TRANSFORMATION_STING, ) mutant_bodyparts = list() - default_mutant_bodyparts = list( - "tail" = "None", - "ears" = "None", - "legs" = "Normal Legs", - "snout" = "None", - MUTANT_SYNTH_ANTENNA = "None", - MUTANT_SYNTH_SCREEN = "None", - MUTANT_SYNTH_CHASSIS = "Default Chassis", - MUTANT_SYNTH_HEAD = "Default Head", - ) changesource_flags = MIRROR_BADMIN | WABBAJACK | MIRROR_MAGIC | MIRROR_PRIDE | ERT_SPAWN | RACE_SWAP | SLIME_EXTRACT reagent_flags = PROCESS_SYNTHETIC payday_modifier = 1.0 // Matches the rest of the pay penalties the non-human crew have @@ -63,6 +52,18 @@ /// This is the screen that is given to the user after they get revived. On death, their screen is temporarily set to BSOD before it turns off, hence the need for this var. var/saved_screen = "Blank" +/datum/species/synthetic/get_default_mutant_bodyparts() + return list( + "tail" = list(MUTANT_INDEX_NAME = "None", MUTANT_INDEX_CAN_RANDOMIZE = FALSE), + "ears" = list(MUTANT_INDEX_NAME = "None", MUTANT_INDEX_CAN_RANDOMIZE = FALSE), + "legs" = list(MUTANT_INDEX_NAME = "Normal Legs", MUTANT_INDEX_CAN_RANDOMIZE = FALSE), + "snout" = list(MUTANT_INDEX_NAME = "None", MUTANT_INDEX_CAN_RANDOMIZE = FALSE), + MUTANT_SYNTH_ANTENNA = list(MUTANT_INDEX_NAME = "None", MUTANT_INDEX_CAN_RANDOMIZE = FALSE), + MUTANT_SYNTH_SCREEN = list(MUTANT_INDEX_NAME = "None", MUTANT_INDEX_CAN_RANDOMIZE = FALSE), + MUTANT_SYNTH_CHASSIS = list(MUTANT_INDEX_NAME = "Default Chassis", MUTANT_INDEX_CAN_RANDOMIZE = FALSE), + MUTANT_SYNTH_HEAD = list(MUTANT_INDEX_NAME = "Default Head", MUTANT_INDEX_CAN_RANDOMIZE = FALSE), + ) + /datum/species/synthetic/spec_life(mob/living/carbon/human/human) . = ..() diff --git a/modular_skyrat/modules/teshari/code/_teshari.dm b/modular_skyrat/modules/teshari/code/_teshari.dm index 84dc35e59c2..ed1663d6f9a 100644 --- a/modular_skyrat/modules/teshari/code/_teshari.dm +++ b/modular_skyrat/modules/teshari/code/_teshari.dm @@ -14,11 +14,6 @@ TRAIT_NO_UNDERWEAR, TRAIT_HAS_MARKINGS, ) - default_mutant_bodyparts = list( - "tail" = ACC_RANDOM, - "ears" = ACC_RANDOM, - "legs" = "Normal Legs" - ) digitigrade_customization = DIGITIGRADE_NEVER changesource_flags = MIRROR_BADMIN | WABBAJACK | MIRROR_MAGIC | MIRROR_PRIDE | ERT_SPAWN | RACE_SWAP | SLIME_EXTRACT payday_modifier = 1.0 @@ -53,6 +48,13 @@ BODY_ZONE_R_LEG = /obj/item/bodypart/leg/right/mutant/teshari, ) +/datum/species/teshari/get_default_mutant_bodyparts() + return list( + "tail" = list(MUTANT_INDEX_NAME = "Teshari (Default)", MUTANT_INDEX_CAN_RANDOMIZE = TRUE), + "ears" = list(MUTANT_INDEX_NAME = "Teshari Regular", MUTANT_INDEX_CAN_RANDOMIZE = TRUE), + "legs" = list(MUTANT_INDEX_NAME = "Normal Legs", MUTANT_INDEX_CAN_RANDOMIZE = FALSE), + ) + /obj/item/organ/internal/tongue/teshari liked_foodtypes = MEAT diff --git a/tff_modular/modules/nabbers/code/_nabbers.dm b/tff_modular/modules/nabbers/code/_nabbers.dm index b18982429cd..79c98824c84 100644 --- a/tff_modular/modules/nabbers/code/_nabbers.dm +++ b/tff_modular/modules/nabbers/code/_nabbers.dm @@ -87,6 +87,7 @@ H.apply_damage(NABBER_DAMAGE_ONBURNING, OXY) /datum/species/nabber/randomize_features(mob/living/carbon/human/human_mob) + var/list/features = ..() var/main_color var/random = rand(1,6) switch(random) @@ -102,9 +103,10 @@ main_color = "#c0ad00" if(6) main_color = "#e6ff03" - human_mob.dna.features["mcolor"] = main_color - human_mob.dna.features["mcolor2"] = main_color - human_mob.dna.features["mcolor3"] = main_color + features["mcolor"] = main_color + features["mcolor2"] = main_color + features["mcolor3"] = main_color + return features /datum/species/nabber/prepare_human_for_preview(mob/living/carbon/human/nabber) var/nabber_color = "#00ac1d" diff --git a/tff_modular/modules/teshari_reborn/code/teshari.dm b/tff_modular/modules/teshari_reborn/code/teshari.dm index e6317be4a4f..5c16af2ad85 100644 --- a/tff_modular/modules/teshari_reborn/code/teshari.dm +++ b/tff_modular/modules/teshari_reborn/code/teshari.dm @@ -41,9 +41,6 @@ LOADOUT_ITEM_ACCESSORY = TESHARI_ACCESSORIES_ICON, LOADOUT_ITEM_EARS = TESHARI_EARS_ICON ) - default_mutant_bodyparts = list( - "legs" = "Normal Legs" - ) coldmod = TESHARI_ALT_COLDMOD heatmod = TESHARI_ALT_HEATMOD bodytemp_normal = BODYTEMP_NORMAL + (TEHSARI_ALT_TEMP_OFFSET/2) @@ -76,15 +73,17 @@ . = ..() teshari_agility.Destroy() teshari_echolocation.Destroy() + qdel(C.GetComponent(/datum/component/weak_body)) C.mob_size = initial(C.mob_size) /datum/species/teshari/alt/randomize_features(mob/living/carbon/human/human_mob) - . = ..() + var/list/features = ..() var/main_color = pick(COLOR_GRAY, COLOR_DARK_BROWN, COLOR_ALMOST_BLACK, COLOR_DARK_RED, COLOR_DARK_CYAN) var/second_color = pick(COLOR_WHITE, COLOR_BLACK, COLOR_BLUE, COLOR_VIOLET) - human_mob.dna.features["mcolor"] = main_color - human_mob.dna.features["mcolor2"] = second_color - human_mob.dna.features["mcolor3"] = second_color + features["mcolor"] = main_color + features["mcolor2"] = second_color + features["mcolor3"] = second_color + return features /datum/species/teshari/alt/create_pref_unique_perks() var/list/perk_descriptions = list() diff --git a/tgstation.dme b/tgstation.dme index f12d1d4b3dc..4ea0689bc46 100644 --- a/tgstation.dme +++ b/tgstation.dme @@ -1834,6 +1834,7 @@ #include "code\datums\status_effects\debuffs\debuffs.dm" #include "code\datums\status_effects\debuffs\decloning.dm" #include "code\datums\status_effects\debuffs\dizziness.dm" +#include "code\datums\status_effects\debuffs\dna_transformation.dm" #include "code\datums\status_effects\debuffs\drowsiness.dm" #include "code\datums\status_effects\debuffs\drugginess.dm" #include "code\datums\status_effects\debuffs\drunk.dm" @@ -6173,6 +6174,7 @@ #include "modular_skyrat\master_files\code\modules\antagonists\_common\antag_datum.dm" #include "modular_skyrat\master_files\code\modules\antagonists\ashwalker\ashwalker.dm" #include "modular_skyrat\master_files\code\modules\antagonists\changeling\changeling.dm" +#include "modular_skyrat\master_files\code\modules\antagonists\changeling\powers\tiny_prick.dm" #include "modular_skyrat\master_files\code\modules\antagonists\cult\cult_items.dm" #include "modular_skyrat\master_files\code\modules\antagonists\ert\ert.dm" #include "modular_skyrat\master_files\code\modules\antagonists\pirate\pirate_outfits.dm" From 6191d845f3ccc11c7c1c27a1a8bd8c79cf6c041f Mon Sep 17 00:00:00 2001 From: Yaroslav Nurkov <78199449+AnywayFarus@users.noreply.github.com> Date: Thu, 23 Nov 2023 21:45:57 +0300 Subject: [PATCH 10/72] Automatic changelog for PR #764 [ci skip] --- html/changelogs/AutoChangeLog-pr-764.yml | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-764.yml diff --git a/html/changelogs/AutoChangeLog-pr-764.yml b/html/changelogs/AutoChangeLog-pr-764.yml new file mode 100644 index 00000000000..8a41e1c0adc --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-764.yml @@ -0,0 +1,8 @@ +author: "Melbert" +delete-after: True +changes: + - balance: "Transformation sting now lasts 8 minutes, down from permanent. However, the effect is paused for dead and stasis mobs, making it permanent SO LONG AS they stay dead or in stasis. The effect is also permanent if used on a monkey." + - balance: "Transformation sting now costs 33 chemicals, down from 50." + - balance: "Transformation sting now costs 2 dna points, down from 3." + - bugfix: "Transformation sting works on monkeys again." + - refactor: "Refactored a bit of human randomization." \ No newline at end of file From 19e98303b02e2db0609370a16b736eb1f148e050 Mon Sep 17 00:00:00 2001 From: Iajret Creature <122297233+Steals-The-PRs@users.noreply.github.com> Date: Thu, 23 Nov 2023 22:11:57 +0300 Subject: [PATCH 11/72] [MIRROR] Makes gas visuals send less assets [MDB IGNORE] (#25213) (#797) * Makes gas visuals send less assets (#78955) ![Discord_2023-10-12_13-21-06](https://github.com/tgstation/tgstation/assets/1234602/e13cb015-dd94-48d9-a593-4258609049d1) ~~I'll see how this works out for the downstream, if it improves the situation for them I'll check the profiler to see how much it affects performance.~~ This reduces assets that need to be sent to the client, how much is hard to tell but a downstream that was having issues due to it got reduced issues when testing with this. Server side costs are roughly equivalent now that I switched to using a straight color in the color matrix filter. * Makes gas visuals send less assets --------- Co-authored-by: SkyratBot <59378654+SkyratBot@users.noreply.github.com> Co-authored-by: Emmett Gaines --- code/__HELPERS/colors.dm | 12 +++++++ .../atmospherics/machinery/datum_pipeline.dm | 31 +++++++++++++++---- 2 files changed, 37 insertions(+), 6 deletions(-) diff --git a/code/__HELPERS/colors.dm b/code/__HELPERS/colors.dm index cc3d083f640..58f4d61ea30 100644 --- a/code/__HELPERS/colors.dm +++ b/code/__HELPERS/colors.dm @@ -17,6 +17,18 @@ return final_color +/// Given a color in the format of "#RRGGBB" or "#RRGGBBAA", gives back a 4 entry list with the number values of each +/proc/split_color(color) + var/list/output = list() + output += hex2num(copytext(color, 2, 4)) + output += hex2num(copytext(color, 4, 6)) + output += hex2num(copytext(color, 6, 8)) + if(length(color) == 9) + output += hex2num(copytext(color, 8, 10)) + else + output += 255 + return output + ///Returns a random color picked from a list, has 2 modes (0 and 1), mode 1 doesn't pick white, black or gray /proc/random_colour(mode = 0) switch(mode) diff --git a/code/modules/atmospherics/machinery/datum_pipeline.dm b/code/modules/atmospherics/machinery/datum_pipeline.dm index 060f7bfdd8f..d86531b5429 100644 --- a/code/modules/atmospherics/machinery/datum_pipeline.dm +++ b/code/modules/atmospherics/machinery/datum_pipeline.dm @@ -325,11 +325,9 @@ if(gas_visuals[icon_file]) return gas_visuals[icon_file] - var/obj/effect/abstract/new_overlay = new + var/obj/effect/abstract/gas_visual/new_overlay = new new_overlay.icon = icon_file - new_overlay.appearance_flags = RESET_COLOR | KEEP_APART - new_overlay.vis_flags = VIS_INHERIT_ICON_STATE | VIS_INHERIT_LAYER | VIS_INHERIT_PLANE | VIS_INHERIT_ID - new_overlay.color = gasmix_color + new_overlay.ChangeColor(gasmix_color) gas_visuals[icon_file] = new_overlay return new_overlay @@ -337,8 +335,8 @@ /// Called when the gasmix color has changed and the gas visuals need to be updated. /datum/pipeline/proc/UpdateGasVisuals() for(var/icon/source as anything in gas_visuals) - var/obj/effect/abstract/overlay = gas_visuals[source] - animate(overlay, time=5, color=gasmix_color) + var/obj/effect/abstract/gas_visual/overlay = gas_visuals[source] + overlay.ChangeColor(gasmix_color) /// After updating, this proc handles looking at the new gas mixture and blends the colors together according to percentage of the gas mix. /datum/pipeline/proc/CalculateGasmixColor(datum/gas_mixture/source) @@ -370,3 +368,24 @@ if(gasmix_color != current_color) gasmix_color = current_color UpdateGasVisuals() + +/obj/effect/abstract/gas_visual + appearance_flags = RESET_COLOR | KEEP_APART + vis_flags = VIS_INHERIT_ICON_STATE | VIS_INHERIT_LAYER | VIS_INHERIT_PLANE | VIS_INHERIT_ID + var/current_color + var/color_filter + +/obj/effect/abstract/gas_visual/Initialize(mapload) + . = ..() + color_filter = filter(type="color", color=matrix()) + filters += color_filter + color_filter = filters[filters.len] + if(current_color) + animate(color_filter, color=current_color, time=5) + +/obj/effect/abstract/gas_visual/proc/ChangeColor(new_color) + current_color = new_color + if(isnull(color_filter)) + // Called before init + return + animate(color_filter, time=5, color=new_color) From d3823207e79eab53f39b1ce18a752617e3c48016 Mon Sep 17 00:00:00 2001 From: Iajret Creature <122297233+Steals-The-PRs@users.noreply.github.com> Date: Thu, 23 Nov 2023 22:12:09 +0300 Subject: [PATCH 12/72] [MIRROR] Fix duplicate vv_get_dropdown() on atom/movable [MDB IGNORE] (#25212) (#796) * Fix duplicate vv_get_dropdown() on atom/movable (#79890) ## About The Pull Request Fix duplicate vv_get_dropdown() on atom/movable I just merged the old format into the new one. * Fix duplicate vv_get_dropdown() on atom/movable --------- Co-authored-by: SkyratBot <59378654+SkyratBot@users.noreply.github.com> Co-authored-by: Xander3359 <66163761+Xander3359@users.noreply.github.com> --- code/__DEFINES/vv.dm | 2 ++ code/game/atoms_movable.dm | 22 ++++++++++++++++------ 2 files changed, 18 insertions(+), 6 deletions(-) diff --git a/code/__DEFINES/vv.dm b/code/__DEFINES/vv.dm index f6cb654b1d5..919556a6be9 100644 --- a/code/__DEFINES/vv.dm +++ b/code/__DEFINES/vv.dm @@ -103,6 +103,8 @@ #define VV_HK_ARMOR_MOD "mod_obj_armor" // /atom/movable +#define VV_HK_OBSERVE_FOLLOW "observe_follow" +#define VV_HK_GET_MOVABLE "get_movable" #define VV_HK_DEADCHAT_PLAYS "deadchat_plays" // /obj diff --git a/code/game/atoms_movable.dm b/code/game/atoms_movable.dm index 9208ea7a9a2..b200e688caa 100644 --- a/code/game/atoms_movable.dm +++ b/code/game/atoms_movable.dm @@ -1460,12 +1460,6 @@ animate(src, pixel_x = pixel_x + pixel_x_diff, pixel_y = pixel_y + pixel_y_diff, transform=rotated_transform, time = 1, easing=BACK_EASING|EASE_IN, flags = ANIMATION_PARALLEL) animate(pixel_x = pixel_x - pixel_x_diff, pixel_y = pixel_y - pixel_y_diff, transform=initial_transform, time = 2, easing=SINE_EASING, flags = ANIMATION_PARALLEL) -/atom/movable/vv_get_dropdown() - . = ..() - . += "" - . += "" - - /* Language procs * Unless you are doing something very specific, these are the ones you want to use. */ @@ -1630,6 +1624,9 @@ /atom/movable/vv_get_dropdown() . = ..() + VV_DROPDOWN_OPTION("", "---------") + VV_DROPDOWN_OPTION(VV_HK_OBSERVE_FOLLOW, "Observe Follow") + VV_DROPDOWN_OPTION(VV_HK_GET_MOVABLE, "Get Movable") VV_DROPDOWN_OPTION(VV_HK_EDIT_PARTICLES, "Edit Particles") VV_DROPDOWN_OPTION(VV_HK_DEADCHAT_PLAYS, "Start/Stop Deadchat Plays") VV_DROPDOWN_OPTION(VV_HK_ADD_FANTASY_AFFIX, "Add Fantasy Affix") @@ -1640,6 +1637,19 @@ if(!.) return + if(href_list[VV_HK_OBSERVE_FOLLOW]) + if(!check_rights(R_ADMIN)) + return + usr.client?.admin_follow(src) + + if(href_list[VV_HK_GET_MOVABLE]) + if(!check_rights(R_ADMIN)) + return + + if(QDELETED(src)) + return + forceMove(get_turf(usr)) + if(href_list[VV_HK_EDIT_PARTICLES] && check_rights(R_VAREDIT)) var/client/C = usr.client C?.open_particle_editor(src) From 13baa58e4b6181f2cc9c3abf3e9efa6347c54eef Mon Sep 17 00:00:00 2001 From: Iajret Creature <122297233+Steals-The-PRs@users.noreply.github.com> Date: Thu, 23 Nov 2023 22:12:25 +0300 Subject: [PATCH 13/72] [MIRROR] fixes gutlunch udder production & some general changes to the udder [MDB IGNORE] (#25208) (#795) * fixes gutlunch udder production & some general changes to the udder (#79893) ## About The Pull Request When the ranching PR came out (we love it downstream), there seemed to be an issue-- the gutlunches would produce milk instead of the miner's salve that the code said it would. I looked into it and realized that some of the code would not take into consideration if the udder already had a preset reagent to create. I've changed some of the arguments for the procs to be called override instead, which will be empty. If you want something that functions similarly to the udder but want it to produce something else and not care about creating a new udder, you can just use the override when attaching the component; otherwise, leave it blank for milk (or whatever kind of reagent the udder you want will produce). Additionally, gutlunches not only did not produce miner's salve, but with the special ores, it did not produce any of the additional reagents. This was fixed by just adding a return TRUE at the end of the normal udder. ![image](https://github.com/tgstation/tgstation/assets/55967837/c13676d7-7b05-4007-8786-744bfcb70673) ![image](https://github.com/tgstation/tgstation/assets/55967837/3edf912e-49c5-4931-853f-7fc463b17852) Perhaps it is out of scope (if it is too extreme, please let me know), but I have changed the probability 95 to not produce milk to a var instead, which means you can have udders that are more prone to producing their milk reagent. 95 is still technically the default, but I have made it 5 in a more readable manner (as in you have a 5 percent chance to get milk every 2 seconds if the udder has it's required food type, if any). ## Why It's Good For The Game Some of this PR is fixes-- we wanted certain behaviors that were not happening and so I fixed that. Other parts of the PR are for, in the future, if we want udders that have higher/lower chances to produce its milk reagent. ## Changelog :cl: fix: gutlunches now produce miner salve instead of milk, as well as the other reagents if fed the correct ore /:cl: * fixes gutlunch udder production & some general changes to the udder --------- Co-authored-by: SkyratBot <59378654+SkyratBot@users.noreply.github.com> Co-authored-by: jjpark-kb <55967837+jjpark-kb@users.noreply.github.com> --- code/datums/components/udder.dm | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/code/datums/components/udder.dm b/code/datums/components/udder.dm index 7a2f7b56b7b..3c8a0297897 100644 --- a/code/datums/components/udder.dm +++ b/code/datums/components/udder.dm @@ -10,11 +10,11 @@ var/datum/callback/on_milk_callback //udder_type and reagent_produced_typepath are typepaths, not reference -/datum/component/udder/Initialize(udder_type = /obj/item/udder, datum/callback/on_milk_callback, datum/callback/on_generate_callback, reagent_produced_typepath = /datum/reagent/consumable/milk) +/datum/component/udder/Initialize(udder_type = /obj/item/udder, datum/callback/on_milk_callback, datum/callback/on_generate_callback, reagent_produced_override) if(!isliving(parent)) //technically is possible to drop this on carbons... but you wouldn't do that to me, would you? return COMPONENT_INCOMPATIBLE udder = new udder_type(null) - udder.add_features(parent, on_generate_callback, reagent_produced_typepath) + udder.add_features(parent, on_generate_callback, reagent_produced_override) src.on_milk_callback = on_milk_callback /datum/component/udder/RegisterWithParent() @@ -67,6 +67,8 @@ var/reagent_produced_typepath = /datum/reagent/consumable/milk ///how much the udder holds var/size = 50 + ///the probability that the udder will produce the reagent (0 - 100) + var/production_probability = 5 ///mob that has the udder component var/mob/living/udder_mob ///optional proc to callback to when the udder generates milk @@ -78,11 +80,12 @@ ///hunger key we set to look for food var/hunger_key = BB_CHECK_HUNGRY -/obj/item/udder/proc/add_features(parent, callback, reagent = /datum/reagent/consumable/milk) +/obj/item/udder/proc/add_features(parent, callback, reagent_override) udder_mob = parent on_generate_callback = callback create_reagents(size, REAGENT_HOLDER_ALIVE) - reagent_produced_typepath = reagent + if(reagent_override) + reagent_produced_typepath = reagent_override initial_conditions() if(isnull(require_consume_type)) return @@ -157,12 +160,13 @@ */ /obj/item/udder/proc/generate() if(!isnull(require_consume_type) && !(locate(require_consume_type) in src)) - return - if(prob(95)) - return + return FALSE + if(!prob(production_probability)) + return FALSE reagents.add_reagent(reagent_produced_typepath, rand(5, 10), added_purity = 1) if(on_generate_callback) on_generate_callback.Invoke(reagents.total_volume, reagents.maximum_volume) + return TRUE /** * Proc called from attacking the component parent with the correct item, moves reagents into the glass basically. From c04fb7653fdc42d86c897ecb9e5e251d01dd8db6 Mon Sep 17 00:00:00 2001 From: Iajret Creature <122297233+Steals-The-PRs@users.noreply.github.com> Date: Thu, 23 Nov 2023 22:12:33 +0300 Subject: [PATCH 14/72] [MIRROR] [NO GBP]RCD can build directional windows on top of existing grills [MDB IGNORE] (#25206) (#794) * [NO GBP]RCD can build directional windows on top of existing grills (#79864) ## About The Pull Request - Fixes https://github.com/Skyrat-SS13/Skyrat-tg/issues/23788 So after #77858 was merged an unintentional side effect was rcd could no longer build directional windows on grills if they already existed on the turf. Sure rcd won't build a grill and then build a directional window on top of that but if a grill already exists on the turf the rcd should still be able to build directional windows on that grill as it helps in repairing mapped in directional windows and such. If you want to build a grill first set the mode to full tile window, build the grill and then switch to directional window to build a window on top of that grill. Or just select directional window mode and build the windows directly without a grill, choice is yours ## Changelog :cl: fix: RCD can build directional windows on top of existing grills & without them. /:cl: * [NO GBP]RCD can build directional windows on top of existing grills --------- Co-authored-by: SkyratBot <59378654+SkyratBot@users.noreply.github.com> Co-authored-by: SyncIt21 <110812394+SyncIt21@users.noreply.github.com> --- code/game/objects/items/rcd/RCD.dm | 8 ++++---- code/game/objects/structures/grille.dm | 17 ++++++++++++++--- 2 files changed, 18 insertions(+), 7 deletions(-) diff --git a/code/game/objects/items/rcd/RCD.dm b/code/game/objects/items/rcd/RCD.dm index 297c8a1eabd..ab97026a6a1 100644 --- a/code/game/objects/items/rcd/RCD.dm +++ b/code/game/objects/items/rcd/RCD.dm @@ -138,14 +138,14 @@ var/list/structures_to_ignore if(istype(target, /obj/structure/grille)) if(is_full_tile) //if we are trying to build full-tile windows we ignore the grille - structures_to_ignore = list(target) - else //no building directional windows on grills - return FALSE + structures_to_ignore = list(/obj/structure/grille) + else //when building directional windows we ignore the grill and other directional windows + structures_to_ignore = list(/obj/structure/grille, /obj/structure/window) else //for directional windows we ignore other directional windows as they can be in diffrent directions on the turf. structures_to_ignore = list(/obj/structure/window) //check if we can build our window on the grill - if(target_turf.is_blocked_turf(exclude_mobs = !is_full_tile, source_atom = null, ignore_atoms = structures_to_ignore, type_list = !is_full_tile)) + if(target_turf.is_blocked_turf(exclude_mobs = !is_full_tile, source_atom = null, ignore_atoms = structures_to_ignore, type_list = TRUE)) playsound(loc, 'sound/machines/click.ogg', 50, TRUE) balloon_alert(user, "something is blocking the turf") return FALSE diff --git a/code/game/objects/structures/grille.dm b/code/game/objects/structures/grille.dm index bb82c6fb294..73f3972ef83 100644 --- a/code/game/objects/structures/grille.dm +++ b/code/game/objects/structures/grille.dm @@ -68,7 +68,13 @@ var/cost = 0 var/delay = 0 - if(the_rcd.rcd_design_path == /obj/structure/window/fulltile) + if(the_rcd.rcd_design_path == /obj/structure/window) + cost = 4 + delay = 2 SECONDS + else if(the_rcd.rcd_design_path == /obj/structure/window/reinforced) + cost = 6 + delay = 2.5 SECONDS + else if(the_rcd.rcd_design_path == /obj/structure/window/fulltile) cost = 8 delay = 3 SECONDS else if(the_rcd.rcd_design_path == /obj/structure/window/reinforced/fulltile) @@ -101,8 +107,13 @@ var/obj/structure/window/window_path = rcd_data["[RCD_DESIGN_PATH]"] if(!ispath(window_path)) CRASH("Invalid window path type in RCD: [window_path]") - if(!initial(window_path.fulltile)) //only fulltile windows can be built here - return FALSE + + //checks if its a valid build direction + if(!initial(window_path.fulltile)) + if(!valid_build_direction(loc, user.dir, is_fulltile = FALSE)) + balloon_alert(user, "window already here!") + return FALSE + var/obj/structure/window/WD = new window_path(T, user.dir) WD.set_anchored(TRUE) return TRUE From 36c801c170bb6760d94d9ef7f4c76f1e5a7fca30 Mon Sep 17 00:00:00 2001 From: Iajret Creature <122297233+Steals-The-PRs@users.noreply.github.com> Date: Thu, 23 Nov 2023 22:13:15 +0300 Subject: [PATCH 15/72] [MIRROR] Removes non-working "Make AI" VV [MDB IGNORE] (#25207) (#793) * Removes non-working "Make AI" VV (#79889) ## About The Pull Request Removes the "Make AI" from the VV dropdown. ## Why It's Good For The Game This button doesn't work, and this function already exists in the player panel. It doesn't make sense to exist in multiple places, with it not working in 1 particular place. ## Changelog :cl: admin: Remove "Make AI" from VV dropdown /:cl: * Removes non-working "Make AI" VV --------- Co-authored-by: SkyratBot <59378654+SkyratBot@users.noreply.github.com> Co-authored-by: Xander3359 <66163761+Xander3359@users.noreply.github.com> --- code/__DEFINES/vv.dm | 1 - code/modules/mob/living/carbon/carbon.dm | 7 ------- 2 files changed, 8 deletions(-) diff --git a/code/__DEFINES/vv.dm b/code/__DEFINES/vv.dm index 919556a6be9..039533cffa5 100644 --- a/code/__DEFINES/vv.dm +++ b/code/__DEFINES/vv.dm @@ -140,7 +140,6 @@ #define VV_HK_GIVE_GUARDIAN_SPIRIT "give_guardian_spirit" // /mob/living/carbon -#define VV_HK_MAKE_AI "aiify" #define VV_HK_MODIFY_BODYPART "mod_bodypart" #define VV_HK_MODIFY_ORGANS "organs_modify" #define VV_HK_MARTIAL_ART "give_martial_art" diff --git a/code/modules/mob/living/carbon/carbon.dm b/code/modules/mob/living/carbon/carbon.dm index 6a34c7fd005..5d8d6dd425c 100644 --- a/code/modules/mob/living/carbon/carbon.dm +++ b/code/modules/mob/living/carbon/carbon.dm @@ -1063,7 +1063,6 @@ /mob/living/carbon/vv_get_dropdown() . = ..() VV_DROPDOWN_OPTION("", "---------") - VV_DROPDOWN_OPTION(VV_HK_MAKE_AI, "Make AI") VV_DROPDOWN_OPTION(VV_HK_MODIFY_BODYPART, "Modify bodypart") VV_DROPDOWN_OPTION(VV_HK_MODIFY_ORGANS, "Modify organs") VV_DROPDOWN_OPTION(VV_HK_MARTIAL_ART, "Give Martial Arts") @@ -1121,12 +1120,6 @@ to_chat(usr, "Failed to replace bodypart! They might be incompatible.") admin_ticket_log("[key_name_admin(usr)] has attempted to modify the bodyparts of [src]") - if(href_list[VV_HK_MAKE_AI]) - if(!check_rights(R_SPAWN)) - return - if(tgui_alert(usr,"Confirm mob type change?",,list("Transform","Cancel")) != "Transform") - return - usr.client.holder.Topic("vv_override", list("makeai"=href_list[VV_HK_TARGET])) if(href_list[VV_HK_MODIFY_ORGANS]) if(!check_rights(NONE)) return From 8b98c822835541f8ac44b194530ecb82e630a4fa Mon Sep 17 00:00:00 2001 From: Iajret Creature <122297233+Steals-The-PRs@users.noreply.github.com> Date: Thu, 23 Nov 2023 22:13:23 +0300 Subject: [PATCH 16/72] Adds 4 new snouts (#24638) (#790) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * acradorsnouts * snout3fix * Fix for snout 3 --------- Co-authored-by: ๑ï <111681347+Smol42@users.noreply.github.com> Co-authored-by: Giz <13398309+vinylspiders@users.noreply.github.com> --- .../icons/mob/sprite_accessory/snouts.dmi | Bin 19540 -> 20548 bytes .../new_player/sprite_accessories/snout.dm | 24 ++++++++++++++++++ 2 files changed, 24 insertions(+) diff --git a/modular_skyrat/master_files/icons/mob/sprite_accessory/snouts.dmi b/modular_skyrat/master_files/icons/mob/sprite_accessory/snouts.dmi index 86f4c783e2016c6cff23aedfd070a407a982abfe..fa2fc8b89aac73bafcf206083b75065d4fcabd16 100644 GIT binary patch literal 20548 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 diff --git a/modular_skyrat/modules/customization/modules/mob/dead/new_player/sprite_accessories/snout.dm b/modular_skyrat/modules/customization/modules/mob/dead/new_player/sprite_accessories/snout.dm index 8ab45ecf430..ce8dc17424b 100644 --- a/modular_skyrat/modules/customization/modules/mob/dead/new_player/sprite_accessories/snout.dm +++ b/modular_skyrat/modules/customization/modules/mob/dead/new_player/sprite_accessories/snout.dm @@ -433,3 +433,27 @@ color_src = USE_MATRIXED_COLORS name = "Acrador (Short)" icon_state = "acrador_short" + +/datum/sprite_accessory/snouts/acrador_1 + icon = 'modular_skyrat/master_files/icons/mob/sprite_accessory/snouts.dmi' + color_src = USE_MATRIXED_COLORS + name = "Acrador 1 (Normal)" + icon_state = "acrador_1" + +/datum/sprite_accessory/snouts/acrador_2 + icon = 'modular_skyrat/master_files/icons/mob/sprite_accessory/snouts.dmi' + color_src = USE_MATRIXED_COLORS + name = "Acrador 2 (Normal)" + icon_state = "acrador_2" + +/datum/sprite_accessory/snouts/acrador_3 + icon = 'modular_skyrat/master_files/icons/mob/sprite_accessory/snouts.dmi' + color_src = USE_MATRIXED_COLORS + name = "Acrador 3 (Normal)" + icon_state = "acrador_3" + +/datum/sprite_accessory/snouts/acrador_4 + icon = 'modular_skyrat/master_files/icons/mob/sprite_accessory/snouts.dmi' + color_src = USE_MATRIXED_COLORS + name = "Acrador 4 (Normal)" + icon_state = "acrador_4" From 8542ffb512499e87cedace1cd7323b3cd4ee6031 Mon Sep 17 00:00:00 2001 From: Iajret Creature <122297233+Steals-The-PRs@users.noreply.github.com> Date: Thu, 23 Nov 2023 22:13:38 +0300 Subject: [PATCH 17/72] [MIRROR] Monkey Business actually spawns monkeys on the station. [MDB IGNORE] (#24589) (#789) * Monkey Business actually spawns monkeys on the station. (#79276) ## About The Pull Request The monkey business unit test was apparently not actually spawning monkeys on the station like it was supposed to. It was trying to find open turfs inside of area _typepaths_, which obviously do not contain turfs. Functionally, this means it was summoning a number of monkeys into the same turf of the unit test z-level equal to the number of areas on the station map. Now it will actually place one monkey in every area of the station itself. This was an incidental discovery while trying to diagnose #79147 with Jacquerel. We still don't know what's causing that one, and I doubt this will do anything about it, but nonetheless the unit test wasn't working right. ## Why It's Good For The Game Makes a unit test do what it was actually intended to do, which is put a bunch of monkeys all over the station and see if they ruin anything. This might actually cause _more_ test failures since they're being put in a less controlled environment, but we'll see. ## Changelog Nothing player facing. * Monkey Business actually spawns monkeys on the station. --------- Co-authored-by: SkyratBot <59378654+SkyratBot@users.noreply.github.com> Co-authored-by: lizardqueenlexi <105025397+lizardqueenlexi@users.noreply.github.com> Co-authored-by: Bloop <13398309+vinylspiders@users.noreply.github.com> --- code/modules/unit_tests/monkey_business.dm | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/code/modules/unit_tests/monkey_business.dm b/code/modules/unit_tests/monkey_business.dm index 20bfffe6a48..80044a0486d 100644 --- a/code/modules/unit_tests/monkey_business.dm +++ b/code/modules/unit_tests/monkey_business.dm @@ -14,7 +14,8 @@ /datum/unit_test/monkey_business/Run() for(var/monkey_id in 1 to length(GLOB.the_station_areas)) - var/mob/living/carbon/human/monkey = allocate(/mob/living/carbon/human/consistent, get_first_open_turf_in_area(GLOB.the_station_areas[monkey_id])) + var/area/monkey_zone = GLOB.areas_by_type[GLOB.the_station_areas[monkey_id]] + var/mob/living/carbon/human/monkey = allocate(/mob/living/carbon/human/consistent, get_first_open_turf_in_area(monkey_zone)) monkey.set_species(/datum/species/monkey) monkey.set_name("Monkey [monkey_id]") if(monkey_id % monkey_angry_nth == 0) // BLOOD FOR THE BLOOD GODS From 23f71418134fecf6af9bd1f47b6992887483b6f3 Mon Sep 17 00:00:00 2001 From: Iajret Creature <122297233+Steals-The-PRs@users.noreply.github.com> Date: Thu, 23 Nov 2023 22:14:07 +0300 Subject: [PATCH 18/72] crafting gutlunch trough and mining bag feeding (#25192) (#788) * crafting gutlunch trough and mining bag feeding * Update modular_skyrat/modules/ashwalkers/code/buildings/gutluncher_foodtrough.dm * fix --------- Co-authored-by: jjpark-kb <55967837+jjpark-kb@users.noreply.github.com> Co-authored-by: Bloop <13398309+vinylspiders@users.noreply.github.com> --- .../code/game/objects/items/stacks/sheets/sheet_types.dm | 1 + .../ashwalkers/code/buildings/gutluncher_foodtrough.dm | 6 ++++++ tgstation.dme | 1 + 3 files changed, 8 insertions(+) create mode 100644 modular_skyrat/modules/ashwalkers/code/buildings/gutluncher_foodtrough.dm diff --git a/modular_skyrat/master_files/code/game/objects/items/stacks/sheets/sheet_types.dm b/modular_skyrat/master_files/code/game/objects/items/stacks/sheets/sheet_types.dm index d68f78c5d46..3a59d18fc52 100644 --- a/modular_skyrat/master_files/code/game/objects/items/stacks/sheets/sheet_types.dm +++ b/modular_skyrat/master_files/code/game/objects/items/stacks/sheets/sheet_types.dm @@ -78,6 +78,7 @@ GLOBAL_LIST_INIT(skyrat_wood_recipes, list( new/datum/stack_recipe("produce bin", /obj/machinery/smartfridge/producebin, 10, time = 2 SECONDS, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_STRUCTURE), new/datum/stack_recipe("storage barrel", /obj/structure/closet/crate/wooden/storage_barrel, 4, time = 2 SECONDS, one_per_turf = TRUE, on_solid_ground = FALSE, category = CAT_STRUCTURE), new/datum/stack_recipe("worm barrel", /obj/structure/wormfarm, 5, time = 2 SECONDS, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_TOOLS), + new/datum/stack_recipe("gutlunch trough", /obj/structure/ore_container/gutlunch_trough, 5, time = 2 SECONDS, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_STRUCTURE), new/datum/stack_recipe("sturdy wooden fence", /obj/structure/railing/wooden_fencing, 5, time = 2 SECONDS, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_TOOLS), new/datum/stack_recipe("sturdy wooden fence gate", /obj/structure/railing/wooden_fencing/gate, 5, time = 2 SECONDS, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_TOOLS), )) diff --git a/modular_skyrat/modules/ashwalkers/code/buildings/gutluncher_foodtrough.dm b/modular_skyrat/modules/ashwalkers/code/buildings/gutluncher_foodtrough.dm new file mode 100644 index 00000000000..fec1b4c1715 --- /dev/null +++ b/modular_skyrat/modules/ashwalkers/code/buildings/gutluncher_foodtrough.dm @@ -0,0 +1,6 @@ +/obj/structure/ore_container/gutlunch_trough/attackby(obj/item/attacking_item, mob/living/carbon/human/user, list/modifiers) + if(!istype(attacking_item, /obj/item/storage/bag/ore)) + return ..() + + for(var/obj/item/stack/ore/stored_ore in attacking_item.contents) + attacking_item.atom_storage?.attempt_remove(stored_ore, src) diff --git a/tgstation.dme b/tgstation.dme index 4ea0689bc46..c4dd1ffa322 100644 --- a/tgstation.dme +++ b/tgstation.dme @@ -6490,6 +6490,7 @@ #include "modular_skyrat\modules\ashwalkers\code\buildings\ash_farming.dm" #include "modular_skyrat\modules\ashwalkers\code\buildings\ash_tendril.dm" #include "modular_skyrat\modules\ashwalkers\code\buildings\fuelwell.dm" +#include "modular_skyrat\modules\ashwalkers\code\buildings\gutluncher_foodtrough.dm" #include "modular_skyrat\modules\ashwalkers\code\buildings\railroad.dm" #include "modular_skyrat\modules\ashwalkers\code\buildings\tendril_cursing.dm" #include "modular_skyrat\modules\ashwalkers\code\buildings\wormfarm.dm" From b0f2c2c832233bff775c52ce13c3606be8bf7d40 Mon Sep 17 00:00:00 2001 From: Iajret Creature <122297233+Steals-The-PRs@users.noreply.github.com> Date: Thu, 23 Nov 2023 22:14:37 +0300 Subject: [PATCH 19/72] [MIRROR] Fixes Window Damage Overlays [MDB IGNORE] (#25201) (#787) * Fixes Window Damage Overlays (#79876) ## About The Pull Request Since https://github.com/tgstation/tgstation/pull/78719, Windows lacked their damage overlays. This PR removes the **_one_** line responsible that broke the overlays. ## Why It's Good For The Game Fixes: https://github.com/tgstation/tgstation/issues/79082 ## Changelog :cl: TwistedSilicon fix: Window damage overlays have been fixed. /:cl:
Before https://github.com/tgstation/tgstation/assets/106436013/694d2e46-0c76-4695-ad52-72c3cc292646
After https://github.com/tgstation/tgstation/assets/106436013/d843fe5c-aaab-4784-827e-5132e7acdd5e
![image](https://github.com/tgstation/tgstation/assets/106436013/77c40048-5e2c-4db7-b5c1-581bf78d6999) (I swear one day I will make a PR longer than 2 lines... but today is not that day.) --------- * Fixes Window Damage Overlays --------- Co-authored-by: SkyratBot <59378654+SkyratBot@users.noreply.github.com> Co-authored-by: TwistedCicrularConvexLens <106436013+TwistedCicrularConvexLens@users.noreply.github.com> Co-authored-by: Fikou <23585223+Fikou@ users.noreply.github.com> --- code/game/objects/structures/window.dm | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/code/game/objects/structures/window.dm b/code/game/objects/structures/window.dm index 4260e7ba19f..a1676f0d39f 100644 --- a/code/game/objects/structures/window.dm +++ b/code/game/objects/structures/window.dm @@ -26,7 +26,6 @@ var/fulltile = FALSE var/glass_type = /obj/item/stack/sheet/glass var/glass_amount = 1 - var/mutable_appearance/crack_overlay var/real_explosion_block //ignore this, just use explosion_block var/break_sound = SFX_SHATTER var/knock_sound = 'sound/effects/glassknock.ogg' @@ -419,11 +418,9 @@ var/ratio = atom_integrity / max_integrity ratio = CEILING(ratio*4, 1) * 25 - cut_overlay(crack_overlay) if(ratio > 75) return - crack_overlay = mutable_appearance('icons/obj/structures.dmi', "damage[ratio]", -(layer+0.1)) - . += crack_overlay + . += mutable_appearance('icons/obj/structures.dmi', "damage[ratio]", -(layer+0.1)) /obj/structure/window/should_atmos_process(datum/gas_mixture/air, exposed_temperature) return exposed_temperature > T0C + heat_resistance From b7edf5216252706341b394e8a6f27d99f3b27b15 Mon Sep 17 00:00:00 2001 From: Iajret Creature <122297233+Steals-The-PRs@users.noreply.github.com> Date: Thu, 23 Nov 2023 22:15:04 +0300 Subject: [PATCH 20/72] [FIX] Chameleon Is Toggleable Again (#25154) (#786) * red gold and green * wew --------- Co-authored-by: Nerevar <12636964+Nerev4r@users.noreply.github.com> Co-authored-by: Snakebittenn <12636964+Snakebittenn@users.noreply.github.com> --- .../code/datums/mutations/chameleon.dm | 28 +++++++++++++++++++ tgstation.dme | 1 + 2 files changed, 29 insertions(+) create mode 100644 modular_skyrat/master_files/code/datums/mutations/chameleon.dm diff --git a/modular_skyrat/master_files/code/datums/mutations/chameleon.dm b/modular_skyrat/master_files/code/datums/mutations/chameleon.dm new file mode 100644 index 00000000000..7bd88ed3eb2 --- /dev/null +++ b/modular_skyrat/master_files/code/datums/mutations/chameleon.dm @@ -0,0 +1,28 @@ +// toggleable chameleon skin +/datum/mutation/human/chameleon + power_path = /datum/action/cooldown/spell/chameleon_skin_activate + +/datum/action/cooldown/spell/chameleon_skin_activate + name = "Activate Chameleon Skin" + desc = "The chromatophores in your skin adjust to your surroundings, as long as you stay still." + spell_requirements = NONE + button_icon = 'icons/mob/actions/actions_minor_antag.dmi' + button_icon_state = "ninja_cloak" + +/datum/action/cooldown/spell/chameleon_skin_activate/cast(list/targets, mob/user = usr) + . = ..() + + if(HAS_TRAIT(user,TRAIT_CHAMELEON_SKIN)) + chameleon_skin_deactivate(user) + return + + ADD_TRAIT(user, TRAIT_CHAMELEON_SKIN, GENETIC_MUTATION) + to_chat(user, "The pigmentation of your skin shifts and starts to take on the colors of your surroundings.") + +/datum/action/cooldown/spell/chameleon_skin_activate/proc/chameleon_skin_deactivate(mob/user = usr) + if(!HAS_TRAIT_FROM(user,TRAIT_CHAMELEON_SKIN, GENETIC_MUTATION)) + return + + REMOVE_TRAIT(user, TRAIT_CHAMELEON_SKIN, GENETIC_MUTATION) + user.alpha = 255 + to_chat(user, text("Your skin shifts as it shimmers back into its original colors.")) diff --git a/tgstation.dme b/tgstation.dme index c4dd1ffa322..5ae674aea32 100644 --- a/tgstation.dme +++ b/tgstation.dme @@ -6113,6 +6113,7 @@ #include "modular_skyrat\master_files\code\datums\mood_events\generic_negative_events.dm" #include "modular_skyrat\master_files\code\datums\mood_events\needs_events.dm" #include "modular_skyrat\master_files\code\datums\mutations\_mutations.dm" +#include "modular_skyrat\master_files\code\datums\mutations\chameleon.dm" #include "modular_skyrat\master_files\code\datums\mutations\hulk.dm" #include "modular_skyrat\master_files\code\datums\quirks\_quirk.dm" #include "modular_skyrat\master_files\code\datums\quirks\negative.dm" From 905fc1d00bd97f75d22638f9fec4ca5d79f35f15 Mon Sep 17 00:00:00 2001 From: Iajret Creature <122297233+Steals-The-PRs@users.noreply.github.com> Date: Thu, 23 Nov 2023 22:15:19 +0300 Subject: [PATCH 21/72] removes our modular stamina multiplier, because it's applied ontop of TG's (#25164) (#784) * Update combat.dm * these 2 * Update code/modules/mob/living/carbon/human/_species.dm --------- Co-authored-by: RatFromTheJungle <62520989+RatFromTheJungle@users.noreply.github.com> Co-authored-by: Bloop <13398309+vinylspiders@users.noreply.github.com> --- code/__DEFINES/~skyrat_defines/combat.dm | 1 - code/modules/mob/living/carbon/human/_species.dm | 4 ++-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/code/__DEFINES/~skyrat_defines/combat.dm b/code/__DEFINES/~skyrat_defines/combat.dm index 54659715cc3..a29811e9349 100644 --- a/code/__DEFINES/~skyrat_defines/combat.dm +++ b/code/__DEFINES/~skyrat_defines/combat.dm @@ -1,4 +1,3 @@ -#define PUNCH_STAMINA_MULTIPLIER 2.6 //Stamina threshold from which resisting a grab becomes hard #define STAMINA_THRESHOLD_HARD_RESIST 80 diff --git a/code/modules/mob/living/carbon/human/_species.dm b/code/modules/mob/living/carbon/human/_species.dm index 10c3288e0cd..1215179d0ef 100644 --- a/code/modules/mob/living/carbon/human/_species.dm +++ b/code/modules/mob/living/carbon/human/_species.dm @@ -1232,10 +1232,10 @@ GLOBAL_LIST_EMPTY(features_by_species) target.force_say() log_combat(user, target, grappled ? "grapple punched" : "kicked") target.apply_damage(damage, attack_type, affecting, armor_block - limb_accuracy, attack_direction = attack_direction) - target.apply_damage(damage * PUNCH_STAMINA_MULTIPLIER, STAMINA, affecting, armor_block - limb_accuracy) // SKYRAT EDIT CHANGE - ORIGINAL : target.apply_damage(damage * 1.5, STAMINA, affecting, armor_block - limb_accuracy) + target.apply_damage(damage*1.5, STAMINA, affecting, armor_block - limb_accuracy) else // Normal attacks do not gain the benefit of armor penetration. target.apply_damage(damage, attack_type, affecting, armor_block, attack_direction = attack_direction, sharpness = unarmed_sharpness) //SKYRAT EDIT - Applies sharpness if it does - ORIGINAL: target.apply_damage(damage, attack_type, affecting, armor_block, attack_direction = attack_direction) - target.apply_damage(damage * PUNCH_STAMINA_MULTIPLIER, STAMINA, affecting, armor_block) //SKYRAT EDIT CHANGE: target.apply_damage(damage*1.5, STAMINA, affecting, armor_block) + target.apply_damage(damage*1.5, STAMINA, affecting, armor_block) if(damage >= 9) target.force_say() log_combat(user, target, "punched") From bd423721c8204452f19239903527fe307064c9d4 Mon Sep 17 00:00:00 2001 From: Yaroslav Nurkov <78199449+AnywayFarus@users.noreply.github.com> Date: Thu, 23 Nov 2023 22:15:36 +0300 Subject: [PATCH 22/72] Automatic changelog for PR #795 [ci skip] --- html/changelogs/AutoChangeLog-pr-795.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-795.yml diff --git a/html/changelogs/AutoChangeLog-pr-795.yml b/html/changelogs/AutoChangeLog-pr-795.yml new file mode 100644 index 00000000000..01610a2bd18 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-795.yml @@ -0,0 +1,4 @@ +author: "jjpark-kb" +delete-after: True +changes: + - bugfix: "gutlunches now produce miner salve instead of milk, as well as the other reagents if fed the correct ore" \ No newline at end of file From 3a16510fe0f0cd22f139e0719eebac54ead32dd1 Mon Sep 17 00:00:00 2001 From: Yaroslav Nurkov <78199449+AnywayFarus@users.noreply.github.com> Date: Thu, 23 Nov 2023 22:16:09 +0300 Subject: [PATCH 23/72] Automatic changelog for PR #794 [ci skip] --- html/changelogs/AutoChangeLog-pr-794.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-794.yml diff --git a/html/changelogs/AutoChangeLog-pr-794.yml b/html/changelogs/AutoChangeLog-pr-794.yml new file mode 100644 index 00000000000..5575fc89378 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-794.yml @@ -0,0 +1,4 @@ +author: "SyncIt21" +delete-after: True +changes: + - bugfix: "RCD can build directional windows on top of existing grills & without them." \ No newline at end of file From f9160b66d4f7f07c814ee6ee2a58ca92525bfd55 Mon Sep 17 00:00:00 2001 From: Yaroslav Nurkov <78199449+AnywayFarus@users.noreply.github.com> Date: Thu, 23 Nov 2023 22:16:36 +0300 Subject: [PATCH 24/72] Automatic changelog for PR #793 [ci skip] --- html/changelogs/AutoChangeLog-pr-793.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-793.yml diff --git a/html/changelogs/AutoChangeLog-pr-793.yml b/html/changelogs/AutoChangeLog-pr-793.yml new file mode 100644 index 00000000000..f375987f1c4 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-793.yml @@ -0,0 +1,4 @@ +author: "Xander3359" +delete-after: True +changes: + - admin: "Remove \"Make AI\" from VV dropdown" \ No newline at end of file From 9bea74677b7f5e686ff7cf8a711b4ed7199c83b4 Mon Sep 17 00:00:00 2001 From: Yaroslav Nurkov <78199449+AnywayFarus@users.noreply.github.com> Date: Thu, 23 Nov 2023 22:16:53 +0300 Subject: [PATCH 25/72] Automatic changelog for PR #790 [ci skip] --- html/changelogs/AutoChangeLog-pr-790.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-790.yml diff --git a/html/changelogs/AutoChangeLog-pr-790.yml b/html/changelogs/AutoChangeLog-pr-790.yml new file mode 100644 index 00000000000..db441e24d90 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-790.yml @@ -0,0 +1,4 @@ +author: "Smol42" +delete-after: True +changes: + - rscadd: "Added four acrador snouts." \ No newline at end of file From a274ca8cec03d755d09d18728cc8ed3375a10958 Mon Sep 17 00:00:00 2001 From: Yaroslav Nurkov <78199449+AnywayFarus@users.noreply.github.com> Date: Thu, 23 Nov 2023 22:17:41 +0300 Subject: [PATCH 26/72] Automatic changelog for PR #788 [ci skip] --- html/changelogs/AutoChangeLog-pr-788.yml | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-788.yml diff --git a/html/changelogs/AutoChangeLog-pr-788.yml b/html/changelogs/AutoChangeLog-pr-788.yml new file mode 100644 index 00000000000..e9429200cfc --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-788.yml @@ -0,0 +1,5 @@ +author: "jjpark-kb" +delete-after: True +changes: + - rscadd: "you can craft the gutlunch trough" + - qol: "you can fill the gutlunch trough with a mining bag" \ No newline at end of file From d33aa954c72b6667dcf019aa3de52afadfd2332d Mon Sep 17 00:00:00 2001 From: Iajret Creature <122297233+Steals-The-PRs@users.noreply.github.com> Date: Thu, 23 Nov 2023 22:27:05 +0300 Subject: [PATCH 27/72] [MIRROR] Autolathe item and UI fix [MDB IGNORE] (#25184) (#768) * Autolathe item and UI fix (#79847) ## About The Pull Request 1. Fixes #79828 The problem strictly applies to toolboxes or any items that can be printed from custom materials, that's now fixed. Another bonus fix is that it no longer greys out items like toolboxes just because they don't have fixed material requirements, it now computes the maximum amount of material present in the lathe and uses that to check how many toolboxes or any other similar type of item can be printed ![Screenshot (361)](https://github.com/tgstation/tgstation/assets/110812394/8a92f215-8e51-4e4b-8d90-5b6097b59dfe) 3. This also fixes another uncaught bug where the UI would not compute the new max number of printable items if glass/bluespace crystals were inserted. It would only update when iron was inserted which is weird but that's fixed now too. ## Changelog :cl: fix: autolathe does not diminish materials from custom material items like toolboxes when printing them in bulk. Also does not gray out that item in the UI fix: autloathe correctly updates UI after inserting items into it /:cl: * Autolathe item and UI fix --------- Co-authored-by: SkyratBot <59378654+SkyratBot@users.noreply.github.com> Co-authored-by: SyncIt21 <110812394+SyncIt21@users.noreply.github.com> --- code/game/machinery/autolathe.dm | 88 +++++++++------------ tgui/packages/tgui/interfaces/Autolathe.tsx | 37 +++++---- 2 files changed, 58 insertions(+), 67 deletions(-) diff --git a/code/game/machinery/autolathe.dm b/code/game/machinery/autolathe.dm index 946bdb6d6cb..1a62fa0261b 100644 --- a/code/game/machinery/autolathe.dm +++ b/code/game/machinery/autolathe.dm @@ -64,11 +64,17 @@ /obj/machinery/autolathe/ui_static_data(mob/user) var/list/data = materials.ui_static_data() - data["designs"] = handle_designs(stored_research.researched_designs) + var/max_available = materials.total_amount() + for(var/datum/material/container_mat as anything in materials.materials) + var/available = materials.materials[container_mat] + if(available) + max_available = max(max_available, available) + + data["designs"] = handle_designs(stored_research.researched_designs, max_available) if(imported_designs.len) - data["designs"] += handle_designs(imported_designs) + data["designs"] += handle_designs(imported_designs, max_available) if(hacked) - data["designs"] += handle_designs(stored_research.hacked_designs) + data["designs"] += handle_designs(stored_research.hacked_designs, max_available) return data @@ -83,7 +89,7 @@ return data -/obj/machinery/autolathe/proc/handle_designs(list/designs) +/obj/machinery/autolathe/proc/handle_designs(list/designs, max_available) var/list/output = list() var/datum/asset/spritesheet/research_designs/spritesheet = get_asset_datum(/datum/asset/spritesheet/research_designs) @@ -108,7 +114,13 @@ else cost[i] = design_cost - max_multiplier = min(max_multiplier, 50, round((istype(mat) ? materials.get_material_amount(i) : 0) / design_cost)) + var/mat_available + if(istype(mat)) //regular mat + mat_available = materials.get_material_amount(mat) + else //category mat means we can make it from any mat, use largest available mat + mat_available = max_available + + max_multiplier = min(max_multiplier, 50, round(mat_available / design_cost)) //create & send ui data var/icon_size = spritesheet.icon_size_id(design.id) @@ -208,6 +220,7 @@ materials.use_materials(materials_used, coeff, multiplier) to_chat(usr, span_notice("You print [multiplier] item(s) from the [src]")) update_static_data_for_all_viewers() + //print item icon_state = "autolathe_n" var/time_per_item = is_stack ? 32 : ((32 * coeff * multiplier) ** 0.8) / multiplier @@ -215,21 +228,26 @@ return TRUE +/obj/machinery/autolathe/crowbar_act(mob/living/user, obj/item/tool) + if(default_deconstruction_crowbar(tool)) + return TOOL_ACT_TOOLTYPE_SUCCESS + +/obj/machinery/autolathe/screwdriver_act_secondary(mob/living/user, obj/item/tool) + if(default_deconstruction_screwdriver(user, "autolathe_t", "autolathe", tool)) + return TOOL_ACT_TOOLTYPE_SUCCESS + /obj/machinery/autolathe/attackby(obj/item/attacking_item, mob/living/user, params) + if(user.combat_mode) //so we can hit the machine + return ..() + if(busy) balloon_alert(user, "it's busy!") return TRUE - if(default_deconstruction_crowbar(attacking_item)) - return TRUE - if(panel_open && is_wire_tool(attacking_item)) wires.interact(user) return TRUE - if(user.combat_mode) //so we can hit the machine - return ..() - if(machine_stat) return TRUE @@ -258,45 +276,16 @@ balloon_alert(user, "close the panel first!") return FALSE - if(istype(attacking_item, /obj/item/storage/bag/trash)) - for(var/obj/item/content_item in attacking_item.contents) - if(!do_after(user, 0.5 SECONDS, src)) - return FALSE - attackby(content_item, user) - return TRUE - return ..() -/obj/machinery/autolathe/attackby_secondary(obj/item/weapon, mob/living/user, params) - . = SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN - if(busy) - balloon_alert(user, "it's busy!") - return - - if(default_deconstruction_screwdriver(user, "autolathe_t", "autolathe", weapon)) - return - - if(machine_stat) - return SECONDARY_ATTACK_CALL_NORMAL - - if(panel_open) - balloon_alert(user, "close the panel first!") - return - - return SECONDARY_ATTACK_CALL_NORMAL - /obj/machinery/autolathe/proc/AfterMaterialInsert(container, obj/item/item_inserted, last_inserted_id, mats_consumed, amount_inserted, atom/context) SIGNAL_HANDLER - if(ispath(item_inserted, /obj/item/stack/ore/bluespace_crystal)) - use_power(SHEET_MATERIAL_AMOUNT / 10) - else if(item_inserted.has_material_type(/datum/material/glass)) - flick("autolathe_r", src)//plays glass insertion animation by default otherwise - else - flick("autolathe_o", src)//plays metal insertion animation + flick("autolathe_[item_inserted.has_material_type(/datum/material/glass) ? "r" : "o"]", src) - use_power(min(active_power_usage * 0.25, amount_inserted / 100)) - update_static_data_for_all_viewers() + use_power(min(active_power_usage * 0.25, amount_inserted / 100)) + + update_static_data_for_all_viewers() /obj/machinery/autolathe/MouseDrop(atom/over, src_location, over_location, src_control, over_control, params) . = ..() @@ -311,7 +300,6 @@ /obj/machinery/autolathe/proc/make_items(list/picked_materials, multiplier, is_stack, mob/user, time_per_item) var/atom/our_loc = drop_location() var/atom/drop_loc = get_step(src, drop_direction) - var/client_awarded = FALSE busy = TRUE SStgui.update_uis(src) //so ui immediatly knows its busy @@ -327,12 +315,10 @@ //custom materials for toolboxes if(length(picked_materials)) - new_item.set_custom_materials(picked_materials, 1 / multiplier) //Ensure we get the non multiplied amount - if(!client_awarded) //so we dont award the medal multiple times - for(var/datum/material/mat in picked_materials) - if(!istype(mat, /datum/material/glass) && !istype(mat, /datum/material/iron)) - user.client.give_award(/datum/award/achievement/misc/getting_an_upgrade, user) - client_awarded = TRUE + new_item.set_custom_materials(picked_materials) //Ensure we get the non multiplied amount + for(var/datum/material/mat in picked_materials) + if(!istype(mat, /datum/material/glass) && !istype(mat, /datum/material/iron)) + user.client.give_award(/datum/award/achievement/misc/getting_an_upgrade, user) //no need to call if ontop of us if(drop_direction) diff --git a/tgui/packages/tgui/interfaces/Autolathe.tsx b/tgui/packages/tgui/interfaces/Autolathe.tsx index 1436d045256..e83554e7164 100644 --- a/tgui/packages/tgui/interfaces/Autolathe.tsx +++ b/tgui/packages/tgui/interfaces/Autolathe.tsx @@ -118,18 +118,20 @@ type PrintButtonProps = { quantity: number; availableMaterials: MaterialMap; SHEET_MATERIAL_AMOUNT: number; + maxmult: number; }; const PrintButton = (props: PrintButtonProps, context) => { const { act } = useBackend(context); - const { design, quantity, availableMaterials, SHEET_MATERIAL_AMOUNT } = props; - - const canPrint = !Object.entries(design.cost).some( - ([material, amount]) => - !availableMaterials[material] || - amount * quantity > (availableMaterials[material] ?? 0) - ); + const { + design, + quantity, + availableMaterials, + SHEET_MATERIAL_AMOUNT, + maxmult, + } = props; + const canPrint = maxmult >= quantity; return ( { !canPrint && 'FabricatorRecipe__Button--disabled', ])} color={'transparent'} - onClick={() => act('make', { id: design.id, multiplier: quantity })}> + onClick={() => + canPrint && act('make', { id: design.id, multiplier: quantity }) + }> ×{quantity} @@ -163,11 +167,8 @@ const AutolatheRecipe = (props: AutolatheRecipeProps, context) => { const { act } = useBackend(context); const { design, availableMaterials, SHEET_MATERIAL_AMOUNT } = props; - const canPrint = !Object.entries(design.cost).some( - ([material, amount]) => - !availableMaterials[material] || - amount > (availableMaterials[material] ?? 0) - ); + const maxmult = design.maxmult; + const canPrint = maxmult > 0; return (
@@ -195,7 +196,9 @@ const AutolatheRecipe = (props: AutolatheRecipeProps, context) => { 'FabricatorRecipe__Title', !canPrint && 'FabricatorRecipe__Title--disabled', ])} - onClick={() => act('make', { id: design.id, multiplier: 1 })}> + onClick={() => + canPrint && act('make', { id: design.id, multiplier: 1 }) + }>
{ quantity={5} SHEET_MATERIAL_AMOUNT={SHEET_MATERIAL_AMOUNT} availableMaterials={availableMaterials} + maxmult={maxmult} /> { quantity={10} SHEET_MATERIAL_AMOUNT={SHEET_MATERIAL_AMOUNT} availableMaterials={availableMaterials} + maxmult={maxmult} />
{ !canPrint && 'FabricatorRecipe__Button--disabled', ])}> act('make', { id: design.id, From f8de57619f03d25221840ca38b984542ad187fb7 Mon Sep 17 00:00:00 2001 From: Iajret Creature <122297233+Steals-The-PRs@users.noreply.github.com> Date: Thu, 23 Nov 2023 22:27:16 +0300 Subject: [PATCH 28/72] [MIRROR] pixel perfect 4x [MDB IGNORE] (#25182) (#769) * pixel perfect 4x (#79660) ## About The Pull Request Adds pixel perfect 4x and 4.5x scaling. I tested it and it seems to work though 4.5 scaling causes very slightly distorted pixel sizes. There's also a bit of letterboxing but I think that happens with all of the pixel perfect settings. ## Why It's Good For The Game better fits 4k monitors and isn't stretch to fit ## Changelog :cl: qol: adds pixel perfect 4x, 4.5x, and 5x /:cl: * pixel perfect 4x --------- Co-authored-by: SkyratBot <59378654+SkyratBot@users.noreply.github.com> Co-authored-by: aaaa1023 <74441292+aaaa1023@users.noreply.github.com> --- code/modules/client/preferences/pixel_size.dm | 2 +- .../preferences/features/game_preferences/pixel_size.tsx | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/code/modules/client/preferences/pixel_size.dm b/code/modules/client/preferences/pixel_size.dm index cb166e0139a..ea375d91e43 100644 --- a/code/modules/client/preferences/pixel_size.dm +++ b/code/modules/client/preferences/pixel_size.dm @@ -4,7 +4,7 @@ savefile_identifier = PREFERENCE_PLAYER minimum = 0 - maximum = 3 + maximum = 5 step = 0.5 diff --git a/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/game_preferences/pixel_size.tsx b/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/game_preferences/pixel_size.tsx index 4afde6a8bb1..ed5fb9aafa7 100644 --- a/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/game_preferences/pixel_size.tsx +++ b/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/game_preferences/pixel_size.tsx @@ -9,5 +9,8 @@ export const pixel_size: Feature = { 1.5: 'Pixel Perfect 1.5x', 2: 'Pixel Perfect 2x', 3: 'Pixel Perfect 3x', + 4: 'Pixel Perfect 4x', + 4.5: 'Pixel Perfect 4.5x', + 5: 'Pixel Perfect 5x', }), }; From 5c759f12b6790f673b35ab2fd0bd6797467866b5 Mon Sep 17 00:00:00 2001 From: Iajret Creature <122297233+Steals-The-PRs@users.noreply.github.com> Date: Thu, 23 Nov 2023 22:28:08 +0300 Subject: [PATCH 29/72] [MIRROR] Fixes fullupgrade chem dispenser not spawning with all their chemicals [MDB IGNORE] (#25180) (#771) * Fixes fullupgrade chem dispenser not spawning with all their chemicals (#79858) ## About The Pull Request Fixes https://github.com/Skyrat-SS13/Skyrat-tg/issues/24911 Tin. They were spawning with only the emagged reagents. This was not an issue for the drink dispensers because they call the parent after adjusting the reagent lists. It needs to be done that way so that `RefreshParts()` gets called after adjusting the lists.
Before/after ![dreamseeker_H0sicTrScp](https://github.com/tgstation/tgstation/assets/13398309/649ab998-8308-4efa-be25-f4942ecab175) ![image](https://github.com/tgstation/tgstation/assets/13398309/9709dfa3-bf64-40f8-ab24-8508255d17ae)
## Why It's Good For The Game Fixes a bug ## Changelog :cl: fix: fullupgrade chem dispensers will now spawn with all their chems /:cl: * Fixes fullupgrade chem dispenser not spawning with all their chemicals --------- Co-authored-by: SkyratBot <59378654+SkyratBot@users.noreply.github.com> Co-authored-by: Bloop <13398309+vinylspiders@users.noreply.github.com> --- code/modules/reagents/chemistry/machinery/chem_dispenser.dm | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/code/modules/reagents/chemistry/machinery/chem_dispenser.dm b/code/modules/reagents/chemistry/machinery/chem_dispenser.dm index a4d31849cda..bc5b14614c6 100644 --- a/code/modules/reagents/chemistry/machinery/chem_dispenser.dm +++ b/code/modules/reagents/chemistry/machinery/chem_dispenser.dm @@ -136,7 +136,6 @@ //SKYRAT EDIT CHANGE END /obj/machinery/chem_dispenser/Initialize(mapload) - . = ..() if(dispensable_reagents != null && !dispensable_reagents.len) dispensable_reagents = default_dispensable_reagents if(dispensable_reagents) @@ -162,6 +161,8 @@ if(emagged_reagents) emagged_reagents = sort_list(emagged_reagents, GLOBAL_PROC_REF(cmp_reagents_asc)) + . = ..() // So that we call RefreshParts() after adjusting the lists + if(is_operational) begin_processing() update_appearance() From b157d33e62c95cced6a1d83d16861e04af4e2e66 Mon Sep 17 00:00:00 2001 From: Iajret Creature <122297233+Steals-The-PRs@users.noreply.github.com> Date: Thu, 23 Nov 2023 22:28:17 +0300 Subject: [PATCH 30/72] [MIRROR] Paraplegics can use the skillchip machine. [MDB IGNORE] (#25177) (#772) * Paraplegics can use the skillchip machine. (#79860) ## About The Pull Request Fixes #64387. Gives the Skillsoft station `INTERACT_ATOM_IGNORE_MOBILITY`, making it possible to use while lying down. This means that it can actually be used by paraplegics, or anyone else without functional legs. ## Why It's Good For The Game As this particular machine can only be used from inside, and you cannot bring a wheelchair in, it is currently impossible for paraplegic characters to use skillchips at all. There is no good reason _why_ paraplegics or people without legs should be barred from this system, and it doesn't make much sense that this machine would need legs to function - so it no longer requires them. ## Changelog :cl: fix: Skillsoft's skillchip stations are now ADA-compliant (Astronauts with Disabilities Act). Paraplegic characters can now implant themselves with skillchips, the same as anyone else. /:cl: * Paraplegics can use the skillchip machine. --------- Co-authored-by: SkyratBot <59378654+SkyratBot@users.noreply.github.com> Co-authored-by: lizardqueenlexi <105025397+lizardqueenlexi@users.noreply.github.com> --- code/modules/library/skill_learning/skill_station.dm | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/code/modules/library/skill_learning/skill_station.dm b/code/modules/library/skill_learning/skill_station.dm index d7fb5b7ff8e..697b34d742e 100644 --- a/code/modules/library/skill_learning/skill_station.dm +++ b/code/modules/library/skill_learning/skill_station.dm @@ -9,7 +9,8 @@ icon_state = "implantchair" occupant_typecache = list(/mob/living/carbon) //todo make occupant_typecache per type state_open = TRUE - interaction_flags_atom = INTERACT_ATOM_ATTACK_HAND //Don't call ui_interac by default - we only want that when inside + // Only opens UI when inside; also, you can use the machine while lying down (for paraplegics and the like) + interaction_flags_atom = INTERACT_ATOM_ATTACK_HAND | INTERACT_ATOM_IGNORE_MOBILITY circuit = /obj/item/circuitboard/machine/skill_station /// Currently implanting/removing var/working = FALSE From 219f4f8e72134c84ec81b743370d0ede0abc7a44 Mon Sep 17 00:00:00 2001 From: Yaroslav Nurkov <78199449+AnywayFarus@users.noreply.github.com> Date: Thu, 23 Nov 2023 22:32:38 +0300 Subject: [PATCH 31/72] Automatic changelog for PR #787 [ci skip] --- html/changelogs/AutoChangeLog-pr-787.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-787.yml diff --git a/html/changelogs/AutoChangeLog-pr-787.yml b/html/changelogs/AutoChangeLog-pr-787.yml new file mode 100644 index 00000000000..da74cef81fe --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-787.yml @@ -0,0 +1,4 @@ +author: "TwistedSilicon" +delete-after: True +changes: + - bugfix: "Window damage overlays have been fixed." \ No newline at end of file From fbdd28380f589032c6e0964fdb026ad0899a3a0a Mon Sep 17 00:00:00 2001 From: Iajret Creature <122297233+Steals-The-PRs@users.noreply.github.com> Date: Thu, 23 Nov 2023 22:33:36 +0300 Subject: [PATCH 32/72] [MIRROR] [Non-Modular] [TM First!] Adds Special Rules and Metaprotections to Antagonist Objective Panels (#504) * [Non-Modular] [TM First!] Adds Special Rules and Metaprotections to Antagonist Objective Panels (#24040) * The Goods * Turned 'Prettier' back on * Fixing SKYRAT EDIT tag formatting * Grammar fixes * Update tgui/packages/tgui/interfaces/AntagInfoClock.tsx Co-authored-by: GoldenAlpharex <58045821+GoldenAlpharex@users.noreply.github.com> * Update tgui/packages/tgui/interfaces/AntagInfoBlob.tsx Co-authored-by: GoldenAlpharex <58045821+GoldenAlpharex@users.noreply.github.com> * Update tgui/packages/tgui/interfaces/AntagInfoClock.tsx Co-authored-by: GoldenAlpharex <58045821+GoldenAlpharex@users.noreply.github.com> * Update tgui/packages/tgui/interfaces/AntagInfoAssaultops.tsx Co-authored-by: GoldenAlpharex <58045821+GoldenAlpharex@users.noreply.github.com> * Update tgui/packages/tgui/interfaces/AntagInfoGeneric.tsx Co-authored-by: GoldenAlpharex <58045821+GoldenAlpharex@users.noreply.github.com> * Update tgui/packages/tgui/interfaces/AntagInfoGeneric.tsx Co-authored-by: GoldenAlpharex <58045821+GoldenAlpharex@users.noreply.github.com> * Update tgui/packages/tgui/interfaces/AntagInfoGeneric.tsx Co-authored-by: GoldenAlpharex <58045821+GoldenAlpharex@users.noreply.github.com> * Update tgui/packages/tgui/interfaces/AntagInfoGeneric.tsx Co-authored-by: GoldenAlpharex <58045821+GoldenAlpharex@users.noreply.github.com> * Update tgui/packages/tgui/interfaces/AntagInfoMalf.tsx Co-authored-by: GoldenAlpharex <58045821+GoldenAlpharex@users.noreply.github.com> * Update tgui/packages/tgui/interfaces/AntagInfoMalf.tsx Co-authored-by: GoldenAlpharex <58045821+GoldenAlpharex@users.noreply.github.com> * Apply suggestions from code review Co-authored-by: GoldenAlpharex <58045821+GoldenAlpharex@users.noreply.github.com> * Overhauls to use hyperlinks * Consolidates Changes into one file (mostly) - Stack sections with hyperlinks have been condensed into a single file. - They are now imported where needed. --------- Co-authored-by: Giz <13398309+vinylspiders@users.noreply.github.com> Co-authored-by: GoldenAlpharex <58045821+GoldenAlpharex@users.noreply.github.com> * Update AntagInfoRules.tsx --------- Co-authored-by: LovliestPlant <107971606+LovliestPlant@users.noreply.github.com> Co-authored-by: Giz <13398309+vinylspiders@users.noreply.github.com> Co-authored-by: GoldenAlpharex <58045821+GoldenAlpharex@users.noreply.github.com> Co-authored-by: ReezeBL --- .../tgui/interfaces/AntagInfoAssaultops.tsx | 8 + .../tgui/interfaces/AntagInfoBlob.tsx | 4 + .../tgui/interfaces/AntagInfoChangeling.tsx | 11 +- .../tgui/interfaces/AntagInfoClock.tsx | 11 +- .../tgui/interfaces/AntagInfoGeneric.tsx | 11 +- .../tgui/interfaces/AntagInfoHeretic.tsx | 9 + .../tgui/interfaces/AntagInfoMalf.tsx | 4 + .../tgui/interfaces/AntagInfoMorph.tsx | 8 + .../tgui/interfaces/AntagInfoNightmare.tsx | 8 + .../tgui/interfaces/AntagInfoNinja.tsx | 8 + .../tgui/interfaces/AntagInfoRules.tsx | 266 ++++++++++++++++++ .../tgui/interfaces/AntagInfoTraitor.tsx | 14 +- .../tgui/interfaces/AntagInfoWizard.tsx | 11 +- 13 files changed, 368 insertions(+), 5 deletions(-) create mode 100644 tgui/packages/tgui/interfaces/AntagInfoRules.tsx diff --git a/tgui/packages/tgui/interfaces/AntagInfoAssaultops.tsx b/tgui/packages/tgui/interfaces/AntagInfoAssaultops.tsx index 46f5a07182f..332d11d63fb 100644 --- a/tgui/packages/tgui/interfaces/AntagInfoAssaultops.tsx +++ b/tgui/packages/tgui/interfaces/AntagInfoAssaultops.tsx @@ -2,6 +2,9 @@ import { useBackend, useLocalState } from '../backend'; import { LabeledList, Stack, Button, Section, ProgressBar, Box, Tabs, Divider } from '../components'; import { BooleanLike } from 'common/react'; import { Window } from '../layouts'; +// SKYRAT EDIT BEGIN +import { Rules } from './AntagInfoRules'; +// SKYRAT EDIT END type Objectives = { count: number; @@ -117,6 +120,11 @@ export const AntagInfoAssaultops = (props, context) => { {tab === 1 && } {tab === 2 && } + {/* SKYRAT EDIT ADDITION START */} + + + + {/* SKYRAT EDIT ADDITION END */} diff --git a/tgui/packages/tgui/interfaces/AntagInfoBlob.tsx b/tgui/packages/tgui/interfaces/AntagInfoBlob.tsx index e8471a6a5ac..7000b324aa9 100644 --- a/tgui/packages/tgui/interfaces/AntagInfoBlob.tsx +++ b/tgui/packages/tgui/interfaces/AntagInfoBlob.tsx @@ -1,6 +1,9 @@ import { useBackend } from '../backend'; import { Box, Collapsible, Divider, LabeledList, Section, Stack } from '../components'; import { Objective } from './common/Objectives'; +// SKYRAT EDIT BEGIN +import { Rules } from './AntagInfoRules'; +// SKYRAT EDIT END import { Window } from '../layouts'; @@ -25,6 +28,7 @@ export const AntagInfoBlob = (props, context) => { + diff --git a/tgui/packages/tgui/interfaces/AntagInfoChangeling.tsx b/tgui/packages/tgui/interfaces/AntagInfoChangeling.tsx index f3eda78c661..339c115e30c 100644 --- a/tgui/packages/tgui/interfaces/AntagInfoChangeling.tsx +++ b/tgui/packages/tgui/interfaces/AntagInfoChangeling.tsx @@ -4,6 +4,9 @@ import { useBackend, useSharedState } from '../backend'; import { Button, Dimmer, Dropdown, Section, Stack, NoticeBox } from '../components'; import { Window } from '../layouts'; import { ObjectivePrintout, Objective, ReplaceObjectivesButton } from './common/Objectives'; +// SKYRAT EDIT BEGIN +import { Rules } from './AntagInfoRules'; +// SKYRAT EDIT END const hivestyle = { fontWeight: 'bold', @@ -54,9 +57,10 @@ type Info = { can_change_objective: BooleanLike; }; +// SKYRAT EDIT change height from 750 to 900 export const AntagInfoChangeling = (props, context) => { return ( - + { + {/* SKYRAT EDIT ADDITION START */} + + + + {/* SKYRAT EDIT ADDITION END */} diff --git a/tgui/packages/tgui/interfaces/AntagInfoClock.tsx b/tgui/packages/tgui/interfaces/AntagInfoClock.tsx index 8912a666bc5..96b94c70339 100644 --- a/tgui/packages/tgui/interfaces/AntagInfoClock.tsx +++ b/tgui/packages/tgui/interfaces/AntagInfoClock.tsx @@ -1,16 +1,20 @@ import { useBackend } from '../backend'; import { Icon, Section, Stack } from '../components'; import { Window } from '../layouts'; +// SKYRAT EDIT BEGIN +import { Rules } from './AntagInfoRules'; +// SKYRAT EDIT END type Info = { antag_name: string; }; +// SKYRAT EDIT change height from 250 to 350 export const AntagInfoClock = (props, context) => { const { data } = useBackend(context); const { antag_name } = data; return ( - +
@@ -19,6 +23,11 @@ export const AntagInfoClock = (props, context) => { {' You are the ' + antag_name + '! '} + {/* SKYRAT EDIT ADDITION START */} + + + + {/* SKYRAT EDIT ADDITION END */} diff --git a/tgui/packages/tgui/interfaces/AntagInfoGeneric.tsx b/tgui/packages/tgui/interfaces/AntagInfoGeneric.tsx index 33b7623c44f..7aa7b80eea0 100644 --- a/tgui/packages/tgui/interfaces/AntagInfoGeneric.tsx +++ b/tgui/packages/tgui/interfaces/AntagInfoGeneric.tsx @@ -2,23 +2,32 @@ import { useBackend } from '../backend'; import { Section, Stack } from '../components'; import { Window } from '../layouts'; import { ObjectivePrintout, Objective } from './common/Objectives'; +// SKYRAT EDIT BEGIN +import { Rules } from './AntagInfoRules'; +// SKYRAT EDIT END type Info = { antag_name: string; objectives: Objective[]; }; +// SKYRAT EDIT increase height from 250 to 500 export const AntagInfoGeneric = (props, context) => { const { data } = useBackend(context); const { antag_name, objectives } = data; return ( - +
You are the {antag_name}! + {/* SKYRAT EDIT ADDITION START */} + + + + {/* SKYRAT EDIT ADDITION END */} diff --git a/tgui/packages/tgui/interfaces/AntagInfoHeretic.tsx b/tgui/packages/tgui/interfaces/AntagInfoHeretic.tsx index ff14419473c..367cc311403 100644 --- a/tgui/packages/tgui/interfaces/AntagInfoHeretic.tsx +++ b/tgui/packages/tgui/interfaces/AntagInfoHeretic.tsx @@ -3,6 +3,9 @@ import { Section, Stack, Box, Tabs, Button, BlockQuote } from '../components'; import { Window } from '../layouts'; import { BooleanLike } from 'common/react'; import { ObjectivePrintout, Objective, ReplaceObjectivesButton } from './common/Objectives'; +// SKYRAT EDIT BEGIN +import { Rules } from './AntagInfoRules'; +// SKYRAT EDIT END const hereticRed = { color: '#e03c3c', @@ -63,6 +66,12 @@ const IntroductionSection = (props, context) => { + {/* SKYRAT EDIT ADDITION START */} + + + + {/* SKYRAT EDIT ADDITION END */} + diff --git a/tgui/packages/tgui/interfaces/AntagInfoMalf.tsx b/tgui/packages/tgui/interfaces/AntagInfoMalf.tsx index 0344f11d2ee..76e7944cfd7 100644 --- a/tgui/packages/tgui/interfaces/AntagInfoMalf.tsx +++ b/tgui/packages/tgui/interfaces/AntagInfoMalf.tsx @@ -5,6 +5,9 @@ import { BlockQuote, Button, Section, Stack, Tabs } from '../components'; import { BooleanLike } from 'common/react'; import { Window } from '../layouts'; import { ObjectivePrintout, Objective, ReplaceObjectivesButton } from './common/Objectives'; +// SKYRAT EDIT BEGIN +import { Rules } from './AntagInfoRules'; +// SKYRAT EDIT END const allystyle = { fontWeight: 'bold', @@ -55,6 +58,7 @@ const IntroductionSection = (props, context) => { /> } /> +
diff --git a/tgui/packages/tgui/interfaces/AntagInfoMorph.tsx b/tgui/packages/tgui/interfaces/AntagInfoMorph.tsx index fb98e1aa35b..58c379ab522 100644 --- a/tgui/packages/tgui/interfaces/AntagInfoMorph.tsx +++ b/tgui/packages/tgui/interfaces/AntagInfoMorph.tsx @@ -1,5 +1,8 @@ import { BlockQuote, Stack } from '../components'; import { Window } from '../layouts'; +// SKYRAT EDIT BEGIN +import { Rules } from './AntagInfoRules'; +// SKYRAT EDIT END const goodstyle = { color: 'lightgreen', @@ -48,6 +51,11 @@ export const AntagInfoMorph = (props, context) => { {' '} + {/* SKYRAT EDIT ADDITION START */} + + + + {/* SKYRAT EDIT ADDITION END */}
diff --git a/tgui/packages/tgui/interfaces/AntagInfoNightmare.tsx b/tgui/packages/tgui/interfaces/AntagInfoNightmare.tsx index 327e114e2fd..6d4b105c498 100644 --- a/tgui/packages/tgui/interfaces/AntagInfoNightmare.tsx +++ b/tgui/packages/tgui/interfaces/AntagInfoNightmare.tsx @@ -1,5 +1,8 @@ import { BlockQuote, LabeledList, Section, Stack } from '../components'; import { Window } from '../layouts'; +// SKYRAT EDIT BEGIN +import { Rules } from './AntagInfoRules'; +// SKYRAT EDIT END const tipstyle = { color: 'white', @@ -68,6 +71,11 @@ export const AntagInfoNightmare = (props, context) => {
+ {/* SKYRAT EDIT ADDITION START */} + + + + {/* SKYRAT EDIT ADDITION END */}
diff --git a/tgui/packages/tgui/interfaces/AntagInfoNinja.tsx b/tgui/packages/tgui/interfaces/AntagInfoNinja.tsx index a537888af75..0615e46e05d 100644 --- a/tgui/packages/tgui/interfaces/AntagInfoNinja.tsx +++ b/tgui/packages/tgui/interfaces/AntagInfoNinja.tsx @@ -3,6 +3,9 @@ import { useBackend } from '../backend'; import { Icon, Section, Stack } from '../components'; import { Window } from '../layouts'; import { ObjectivePrintout, Objective, ReplaceObjectivesButton } from './common/Objectives'; +// SKYRAT EDIT BEGIN +import { Rules } from './AntagInfoRules'; +// SKYRAT EDIT END const ninja_emphasis = { color: 'red', @@ -48,6 +51,11 @@ export const AntagInfoNinja = (props, context) => { what you can do! + {/* SKYRAT EDIT ADDITION START */} + + + + {/* SKYRAT EDIT ADDITION END */} { + const { data } = useBackend(context); + const { antag_name } = data; + switch (antag_name) { + case 'Abductor Agent' || 'Abductor Scientist' || 'Abductor Solo': + return ( + + Special Rules: + + { + + Special Rules and Metaprotections! + + } + + + ); + break; + case 'Drifting Contractor': + return ( + + Special Rules: + + { + + Special Rules and Metaprotections! + + } + + + ); + break; + case 'Cortical Borer': + return ( + + Special Rules: + + { + + Special Rules and Metaprotections! + + } + + + ); + break; + case 'Venus Human Trap': + return ( + + Special Rules: + + { + + Special Rules and Metaprotections! + + } + + + ); + break; + case 'Obsessed': + return ( + + Special Rules: + + { + + Special Rules and Metaprotections! + + } + + + ); + break; + case 'Revenant': + return ( + + Special Rules: + + { + + Special Rules and Metaprotections! + + } + + + ); + break; + case 'Space Dragon': + return ( + + Special Rules: + + { + + Special Rules and Metaprotections! + + } + + + ); + break; + case 'Space Pirate': + return ( + + Special Rules: + + { + + Special Rules and Metaprotections! + + } + + + ); + break; + case 'Blob': + return ( + + Special Rules: + + { + + Special Rules and Metaprotections! + + } + + + ); + break; + case 'Changeling': + return ( + + Special Rules: + + { + + Special Rules and Metaprotections! + + } + + + ); + case 'ClockCult': + return ( + + Special Rules: + {Dont be an asshole.} + + ); + case 'AssaultOps': + return ( + + Special Rules: + + { + + Special Rules and Metaprotections! + + } + + + ); + case 'Heretic': + return ( + + Special Rules: + + { + + Special Rules and Metaprotections! + + } + + + ); + case 'Malf AI': + return ( + + Special Rules: + + { + + Special Rules and Metaprotections! + + } + + + ); + case 'Morph': + return ( + + Special Rules: + + { + + Special Rules and Metaprotections! + + } + + + ); + case 'Nightmare': + return ( + + Special Rules: + + { + + Special Rules and Metaprotections! + + } + + + ); + case 'Ninja': + return ( + + Special Rules: + + { + + Special Rules and Metaprotections! + + } + + + ); + case 'Wizard': + return ( + + Special Rules: + + { + + Special Rules and Metaprotections! + + } + + + ); + default: + return ( + + Special Rules: + + { + + Special Rules and Metaprotections! + + } + + + ); + break; + } +}; diff --git a/tgui/packages/tgui/interfaces/AntagInfoTraitor.tsx b/tgui/packages/tgui/interfaces/AntagInfoTraitor.tsx index cc62986c085..083e3b2372c 100644 --- a/tgui/packages/tgui/interfaces/AntagInfoTraitor.tsx +++ b/tgui/packages/tgui/interfaces/AntagInfoTraitor.tsx @@ -4,6 +4,9 @@ import { BlockQuote, Button, Dimmer, Section, Stack } from '../components'; import { BooleanLike } from 'common/react'; import { Window } from '../layouts'; import { ObjectivePrintout, Objective } from './common/Objectives'; +// SKYRAT EDIT BEGIN +import { Rules } from './AntagInfoRules'; +// SKYRAT EDIT END const allystyle = { fontWeight: 'bold', @@ -48,6 +51,14 @@ const IntroductionSection = (props, context) => { + {/* SKYRAT EDIT ADDITION START */} + + {/* SKYRAT EDIT ADDITION START */} + + + + + {/* SKYRAT EDIT ADDITION END */} ); @@ -218,11 +229,12 @@ const CodewordsSection = (props, context) => { ); }; +// SKYRAT EDIT: change height from 580 to 650 export const AntagInfoTraitor = (props, context) => { const { data } = useBackend(context); const { theme } = data; return ( - + diff --git a/tgui/packages/tgui/interfaces/AntagInfoWizard.tsx b/tgui/packages/tgui/interfaces/AntagInfoWizard.tsx index e5de257851a..94d528513d0 100644 --- a/tgui/packages/tgui/interfaces/AntagInfoWizard.tsx +++ b/tgui/packages/tgui/interfaces/AntagInfoWizard.tsx @@ -3,6 +3,9 @@ import { useBackend } from '../backend'; import { Box, Section, Stack } from '../components'; import { Window } from '../layouts'; import { ObjectivePrintout, Objective, ReplaceObjectivesButton } from './common/Objectives'; +// SKYRAT EDIT BEGIN +import { Rules } from './AntagInfoRules'; +// SKYRAT EDIT END const teleportstyle = { color: 'yellow', @@ -48,12 +51,13 @@ type Info = { can_change_objective: BooleanLike; }; +// SKYRAT CHANGE height from 630 to 700 export const AntagInfoWizard = (props, context) => { const { data, act } = useBackend(context); const { ritual, objectives, can_change_objective } = data; return ( - + @@ -78,6 +82,11 @@ export const AntagInfoWizard = (props, context) => { + {/* SKYRAT EDIT ADDITION START */} + + + + {/* SKYRAT EDIT ADDITION END */} From 365bf82f961830fe6c7b9cb4dcc96001963a2482 Mon Sep 17 00:00:00 2001 From: Iajret Creature <122297233+Steals-The-PRs@users.noreply.github.com> Date: Thu, 23 Nov 2023 22:36:51 +0300 Subject: [PATCH 33/72] [MIRROR] Different pen types have unique behavior when used in foam darts. [MDB IGNORE] (#25183) (#773) * Different pen types have unique behavior when used in foam darts. (#79587) ## About The Pull Request This PR makes the following changes: - Refactors inserting items into foam darts into a component on items that can be inserted into darts - Adds the aforementioned component to pens - Provides an inspection tip for how to modify a foam dart - Gives different pen types specific behavior when used in a foam dart Pens typically give a foam dart 5 brute and 50% embed chance (affected by falloff). The following types of pens give the specified properties (usually directly derived from the pen's stats and additional functions): - Red pen (and four-color pen set to red): Slightly faster dart - Captain's fountain pen: Slightly faster dart, and 75% base embed chance - Sleepypen: Tries to inject its reagents into the hit mob, but doesn't penetrate thick clothing like syringe guns do - Energy Dagger: 35 brute, 100% base embed chance, and slightly faster dart - Survival Pen: Mines rocks on impact - Fine Tip Pen (if someone somehow manages to get one): 100 bare wound bonus and 9000 demolition modifier ## Why It's Good For The Game Expands the emergent gameplay possibilities of using pens in foam darts. While there are balance risks involved with traitors being able to buy the equivalent of reusable 45u syringe shots and 35 brute bullets, you are not likely to get your pen back once it hits its target, unless you somehow have the recall spell and have bound the pen to it. There are probably more TC-efficient ways to achieve comparable projectile weaponry, but foam dart guns have an air of subtlety to them... at least until your skin is pierced by a pointy writing implement that may also be something more deadly. If maintainers still have balance concerns, please let me know. ## Changelog :cl: add: Certain types of pens now function like you expect they would when inserted into a foam dart qol: Examining a foam dart closely will show you how to modify it, or what it is modified with /:cl: * Different pen types have unique behavior when used in foam darts. --------- Co-authored-by: SkyratBot <59378654+SkyratBot@users.noreply.github.com> Co-authored-by: Y0SH1M4S73R --- code/__DEFINES/dcs/signals/signals_object.dm | 38 ++++- code/__DEFINES/traits/declarations.dm | 2 + code/__HELPERS/maths.dm | 5 + code/_globalvars/traits/_traits.dm | 3 + code/datums/components/dart_insert.dm | 161 ++++++++++++++++++ code/datums/components/embedded.dm | 1 + code/datums/elements/caseless.dm | 10 +- code/datums/mutations/tongue_spike.dm | 2 + code/game/objects/items.dm | 5 +- code/game/objects/objs.dm | 7 +- code/modules/paperwork/pen.dm | 153 ++++++++++++++++- .../modules/projectiles/ammunition/_firing.dm | 1 + .../projectiles/ammunition/ballistic/foam.dm | 47 +++-- .../guns/ballistic/bows/bow_arrows.dm | 3 +- code/modules/projectiles/projectile.dm | 4 +- .../projectile/bullets/foam_dart.dm | 13 +- .../projectiles/projectile/bullets/rifle.dm | 3 +- icons/obj/weapons/guns/toy.dmi | Bin 869 -> 2855 bytes tgstation.dme | 1 + 19 files changed, 403 insertions(+), 56 deletions(-) create mode 100644 code/datums/components/dart_insert.dm diff --git a/code/__DEFINES/dcs/signals/signals_object.dm b/code/__DEFINES/dcs/signals/signals_object.dm index 4998f10849e..c1d9e88786a 100644 --- a/code/__DEFINES/dcs/signals/signals_object.dm +++ b/code/__DEFINES/dcs/signals/signals_object.dm @@ -12,6 +12,8 @@ /// from /obj/item/toy/crayon/spraycan/afterattack: (user, spraycan, color_is_dark) #define COMSIG_OBJ_PAINTED "obj_painted" #define DONT_USE_SPRAYCAN_CHARGES (1<<0) +/// from /obj/obj_reskin: (mob/user, skin) +#define COMSIG_OBJ_RESKIN "obj_reskin" // /obj/machinery signals @@ -361,9 +363,9 @@ // /obj/projectile signals (sent to the firer) -///from base of /obj/projectile/proc/on_hit(), like COMSIG_PROJECTILE_ON_HIT but on the projectile itself and with the hit limb (if any): (atom/movable/firer, atom/target, angle, hit_limb) +///from base of /obj/projectile/proc/on_hit(), like COMSIG_PROJECTILE_ON_HIT but on the projectile itself and with the hit limb (if any): (atom/movable/firer, atom/target, angle, hit_limb, blocked) #define COMSIG_PROJECTILE_SELF_ON_HIT "projectile_self_on_hit" -///from base of /obj/projectile/proc/on_hit(): (atom/movable/firer, atom/target, angle, hit_limb) +///from base of /obj/projectile/proc/on_hit(): (atom/movable/firer, atom/target, angle, hit_limb, blocked) #define COMSIG_PROJECTILE_ON_HIT "projectile_on_hit" ///from base of /obj/projectile/proc/fire(): (obj/projectile, atom/original_target) #define COMSIG_PROJECTILE_BEFORE_FIRE "projectile_before_fire" @@ -387,6 +389,9 @@ ///sent to targets during the process_hit proc of projectiles #define COMSIG_FIRE_CASING "fire_casing" +///from the base of /obj/item/ammo_casing/ready_proj() : (atom/target, mob/living/user, quiet, zone_override, atom/fired_from) +#define COMSIG_CASING_READY_PROJECTILE "casing_ready_projectile" + ///sent to the projectile after an item is spawned by the projectile_drop element: (new_item) #define COMSIG_PROJECTILE_ON_SPAWN_DROP "projectile_on_spawn_drop" ///sent to the projectile when spawning the item (shrapnel) that may be embedded: (new_item) @@ -448,6 +453,12 @@ #define COMSIG_ITEM_AFTERATTACK_SECONDARY "item_afterattack_secondary" ///from base of obj/item/attack_qdeleted(): (atom/target, mob/user, params) #define COMSIG_ITEM_ATTACK_QDELETED "item_attack_qdeleted" +///from base of obj/item/embedded(): (atom/target, obj/item/bodypart/part) +#define COMSIG_ITEM_EMBEDDED "item_embedded" +///from base of datum/component/embedded/safeRemove(): (mob/living/carbon/victim) +#define COMSIG_ITEM_UNEMBEDDED "item_unembedded" +/// from base of obj/item/failedEmbed() +#define COMSIG_ITEM_FAILED_EMBED "item_failed_embed" ///from /obj/item/assembly/proc/pulsed(mob/pulser) #define COMSIG_ASSEMBLY_PULSED "assembly_pulsed" @@ -481,3 +492,26 @@ /// from /obj/structure/cursed_slot_machine/determine_victor() when someone finally wins. #define COMSIG_GLOB_CURSED_SLOT_MACHINE_WON "cursed_slot_machine_won" + +/// from /datum/component/dart_insert/add_to_dart() : (obj/item/ammo_casing, mob/user) +#define COMSIG_DART_INSERT_ADDED "dart_insert_added" + +/// from /datum/component/dart_insert/remove_from_dart() : (obj/ammo_casing/dart, mob/user) +#define COMSIG_DART_INSERT_REMOVED "dart_insert_removed" + +/** + * from /datum/component/dart_insert/get_dart_var_modifiers() : (list/out_modifiers) + * + * valid indices for `out_modifiers` are: + * - `damage`: number + * - `speed`: number + * - `armour_penetration`: number + * - `wound_bonus`: number + * - `bare_wound_bonus`: number + * - `demolition_mod`: number + * - `embedding`: list with embedding params + */ +#define COMSIG_DART_INSERT_GET_VAR_MODIFIERS "dart_insert_get_var_modifiers" + +/// from /datum/component/dart_insert/on_reskin() +#define COMSIG_DART_INSERT_PARENT_RESKINNED "dart_insert_parent_reskinned" diff --git a/code/__DEFINES/traits/declarations.dm b/code/__DEFINES/traits/declarations.dm index 536b1023a5a..d9db85b32da 100644 --- a/code/__DEFINES/traits/declarations.dm +++ b/code/__DEFINES/traits/declarations.dm @@ -976,4 +976,6 @@ Remember to update _globalvars/traits.dm if you're adding/removing/renaming trai /// Trait given to mobs that we do not want to mindswap #define TRAIT_NO_MINDSWAP "no_mindswap" +/// Trait given to foam darts that have an insert in them +#define TRAIT_DART_HAS_INSERT "dart_has_insert" // END TRAIT DEFINES diff --git a/code/__HELPERS/maths.dm b/code/__HELPERS/maths.dm index 116fb34fad5..c28357eb478 100644 --- a/code/__HELPERS/maths.dm +++ b/code/__HELPERS/maths.dm @@ -217,3 +217,8 @@ return max(new_value, threshold) if(sign == -1) return min(new_value, threshold * -1) + +/// Takes two values x and y, and returns 1/((1/x) + y) +/// Useful for providing an additive modifier to a value that is used as a divisor, such as `/obj/projectile/var/speed` +/proc/reciprocal_add(x, y) + return 1/((1/x)+y) diff --git a/code/_globalvars/traits/_traits.dm b/code/_globalvars/traits/_traits.dm index b1d1c5eaac3..6af47e3ab10 100644 --- a/code/_globalvars/traits/_traits.dm +++ b/code/_globalvars/traits/_traits.dm @@ -472,6 +472,9 @@ GLOBAL_LIST_INIT(traits_by_type, list( "TRAIT_UNCATCHABLE" = TRAIT_UNCATCHABLE, "TRAIT_WIELDED" = TRAIT_WIELDED, ), + /obj/item/ammo_casing = list( + "TRAIT_DART_HAS_INSERT" = TRAIT_DART_HAS_INSERT, + ), /obj/item/bodypart = list( "TRAIT_DISABLED_BY_WOUND" = TRAIT_DISABLED_BY_WOUND, "TRAIT_IGNORED_BY_LIVING_FLESH" = TRAIT_IGNORED_BY_LIVING_FLESH, diff --git a/code/datums/components/dart_insert.dm b/code/datums/components/dart_insert.dm new file mode 100644 index 00000000000..03d1d689357 --- /dev/null +++ b/code/datums/components/dart_insert.dm @@ -0,0 +1,161 @@ +/** + * Component for allowing items to be inserted into foam darts. + * The parent can register signal handlers for `COMSIG_DART_INSERT_ADDED`, + * `COMSIG_DART_INSERT_REMOVED` to define custom behavior for when the item + * is added to/removed from a dart, and `COMSIG_DART_INSERT_GET_VAR_MODIFIERS` + * to define the modifications the item makes to the vars of the fired projectile. + */ +/datum/component/dart_insert + /// List for tracking the modifications this component has made to the vars of the containing projectile + var/list/var_modifiers + /// A reference to the ammo casing this component's parent was inserted into + var/obj/item/ammo_casing/holder_casing + /// A reference to the projectile this component's parent was inserted into + var/obj/projectile/holder_projectile + /// The icon file used for the overlay applied over the containing ammo casing + var/casing_overlay_icon + /// The icon state used for the overlay applied over the containing ammo casing + var/casing_overlay_icon_state + /// The icon file used for the overlay applied over the containing projectile + var/projectile_overlay_icon + /// The icon state used for the overlay applied over the containing projectile + var/projectile_overlay_icon_state + +/datum/component/dart_insert/Initialize(_casing_overlay_icon, _casing_overlay_icon_state, _projectile_overlay_icon, _projectile_overlay_icon_state) + if(!isitem(parent)) + return COMPONENT_INCOMPATIBLE + casing_overlay_icon = _casing_overlay_icon + casing_overlay_icon_state = _casing_overlay_icon_state + projectile_overlay_icon = _projectile_overlay_icon + projectile_overlay_icon_state = _projectile_overlay_icon_state + +/datum/component/dart_insert/RegisterWithParent() + . = ..() + RegisterSignal(parent, COMSIG_ITEM_PRE_ATTACK, PROC_REF(on_preattack)) + RegisterSignal(parent, COMSIG_OBJ_RESKIN, PROC_REF(on_reskin)) + +/datum/component/dart_insert/UnregisterFromParent() + . = ..() + var/obj/item/parent_item = parent + var/parent_loc = parent_item.loc + if(parent_loc && (parent_loc == holder_casing || parent_loc == holder_projectile)) + parent_item.forceMove(get_turf(parent_item)) + remove_from_dart(holder_casing, holder_projectile) + UnregisterSignal(parent, COMSIG_ITEM_PRE_ATTACK) + +/datum/component/dart_insert/proc/on_preattack(datum/source, atom/target, mob/user, params) + SIGNAL_HANDLER + var/obj/item/ammo_casing/foam_dart/dart = target + if(!istype(dart)) + return + if(!dart.modified) + to_chat(user, span_warning("The safety cap prevents you from inserting [parent] into [dart].")) + return COMPONENT_CANCEL_ATTACK_CHAIN + if(HAS_TRAIT(dart, TRAIT_DART_HAS_INSERT)) + to_chat(user, span_warning("There's already something in [dart].")) + return COMPONENT_CANCEL_ATTACK_CHAIN + add_to_dart(dart, user) + return COMPONENT_CANCEL_ATTACK_CHAIN + +/datum/component/dart_insert/proc/on_reskin(datum/source, mob/user, skin) + SIGNAL_HANDLER + SEND_SIGNAL(parent, COMSIG_DART_INSERT_PARENT_RESKINNED) + +/datum/component/dart_insert/proc/add_to_dart(obj/item/ammo_casing/dart, mob/user) + var/obj/projectile/dart_projectile = dart.loaded_projectile + var/obj/item/parent_item = parent + if(user) + if(!user.transferItemToLoc(parent_item, dart_projectile)) + return + to_chat(user, span_notice("You insert [parent_item] into [dart].")) + else + parent_item.forceMove(dart_projectile) + ADD_TRAIT(dart, TRAIT_DART_HAS_INSERT, REF(src)) + RegisterSignal(dart, COMSIG_ITEM_ATTACK_SELF, PROC_REF(on_dart_attack_self)) + RegisterSignal(dart, COMSIG_ATOM_EXAMINE_MORE, PROC_REF(on_dart_examine_more)) + RegisterSignals(parent, list(COMSIG_QDELETING, COMSIG_MOVABLE_MOVED), PROC_REF(on_leave_dart)) + RegisterSignal(dart, COMSIG_ATOM_UPDATE_OVERLAYS, PROC_REF(on_casing_update_overlays)) + RegisterSignal(dart_projectile, COMSIG_ATOM_UPDATE_OVERLAYS, PROC_REF(on_projectile_update_overlays)) + RegisterSignals(dart_projectile, list(COMSIG_PROJECTILE_ON_SPAWN_DROP, COMSIG_PROJECTILE_ON_SPAWN_EMBEDDED), PROC_REF(on_spawn_drop)) + apply_var_modifiers(dart_projectile) + dart.harmful = dart_projectile.damage > 0 || dart_projectile.wound_bonus > 0 || dart_projectile.bare_wound_bonus > 0 + SEND_SIGNAL(parent, COMSIG_DART_INSERT_ADDED, dart) + dart.update_appearance() + dart_projectile.update_appearance() + holder_casing = dart + holder_projectile = dart_projectile + +/datum/component/dart_insert/proc/remove_from_dart(obj/item/ammo_casing/dart, obj/projectile/projectile, mob/user) + holder_casing = null + holder_projectile = null + if(istype(dart)) + UnregisterSignal(dart, list(COMSIG_ITEM_ATTACK_SELF, COMSIG_ATOM_EXAMINE_MORE, COMSIG_ATOM_UPDATE_OVERLAYS)) + REMOVE_TRAIT(dart, TRAIT_DART_HAS_INSERT, REF(src)) + dart.update_appearance() + if(istype(projectile)) + remove_var_modifiers(projectile) + UnregisterSignal(projectile, list(COMSIG_PROJECTILE_ON_SPAWN_DROP, COMSIG_PROJECTILE_ON_SPAWN_EMBEDDED, COMSIG_ATOM_UPDATE_OVERLAYS)) + if(dart?.loaded_projectile == projectile) + dart.harmful = projectile.damage > 0 || projectile.wound_bonus > 0 || projectile.bare_wound_bonus > 0 + projectile.update_appearance() + SEND_SIGNAL(parent, COMSIG_DART_INSERT_REMOVED, dart, projectile, user) + UnregisterSignal(parent, list(COMSIG_QDELETING, COMSIG_MOVABLE_MOVED)) + if(user) + INVOKE_ASYNC(user, TYPE_PROC_REF(/mob, put_in_hands), parent) + to_chat(user, span_notice("You remove [parent] from [dart].")) + +/datum/component/dart_insert/proc/on_dart_attack_self(datum/source, mob/user) + SIGNAL_HANDLER + remove_from_dart(holder_casing, holder_projectile, user) + +/datum/component/dart_insert/proc/on_dart_examine_more(datum/source, mob/user, list/examine_list) + var/obj/item/parent_item = parent + examine_list += span_notice("You can see a [parent_item.name] inserted into it.") + +/datum/component/dart_insert/proc/on_leave_dart() + SIGNAL_HANDLER + remove_from_dart(holder_casing, holder_projectile) + +/datum/component/dart_insert/proc/on_spawn_drop(datum/source, obj/item/ammo_casing/new_casing) + SIGNAL_HANDLER + UnregisterSignal(parent, list(COMSIG_QDELETING, COMSIG_MOVABLE_MOVED)) + add_to_dart(new_casing) + +/datum/component/dart_insert/proc/on_casing_update_overlays(datum/source, list/new_overlays) + SIGNAL_HANDLER + new_overlays += mutable_appearance(casing_overlay_icon, casing_overlay_icon_state) + +/datum/component/dart_insert/proc/on_projectile_update_overlays(datum/source, list/new_overlays) + SIGNAL_HANDLER + new_overlays += mutable_appearance(projectile_overlay_icon, projectile_overlay_icon_state) + +/datum/component/dart_insert/proc/apply_var_modifiers(obj/projectile/projectile) + LAZYINITLIST(var_modifiers) + SEND_SIGNAL(parent, COMSIG_DART_INSERT_GET_VAR_MODIFIERS, var_modifiers) + projectile.damage += var_modifiers["damage"] + if(var_modifiers["speed"]) + var_modifiers["speed"] = reciprocal_add(projectile.speed, var_modifiers["speed"]) - projectile.speed + projectile.speed += var_modifiers["speed"] + projectile.armour_penetration += var_modifiers["armour_penetration"] + projectile.wound_bonus += var_modifiers["wound_bonus"] + projectile.bare_wound_bonus += var_modifiers["bare_wound_bonus"] + projectile.demolition_mod += var_modifiers["demolition_mod"] + if(islist(var_modifiers["embedding"])) + var/list/embed_params = var_modifiers["embedding"] + for(var/embed_param in embed_params - "ignore_throwspeed_threshold") + LAZYADDASSOC(projectile.embedding, embed_param, embed_params[embed_param]) + projectile.updateEmbedding() + +/datum/component/dart_insert/proc/remove_var_modifiers(obj/projectile/projectile) + projectile.damage -= var_modifiers["damage"] + projectile.speed -= var_modifiers["speed"] + projectile.armour_penetration -= var_modifiers["armour_penetration"] + projectile.wound_bonus -= var_modifiers["wound_bonus"] + projectile.bare_wound_bonus -= var_modifiers["bare_wound_bonus"] + projectile.demolition_mod -= var_modifiers["demolition_mod"] + if(islist(var_modifiers["embedding"])) + var/list/embed_params = var_modifiers["embedding"] + for(var/embed_param in embed_params - "ignore_throwspeed_threshold") + LAZYADDASSOC(projectile.embedding, embed_param, -embed_params[embed_param]) + projectile.updateEmbedding() + var_modifiers.Cut() diff --git a/code/datums/components/embedded.dm b/code/datums/components/embedded.dm index f4d7b5d7369..b62121d30d0 100644 --- a/code/datums/components/embedded.dm +++ b/code/datums/components/embedded.dm @@ -228,6 +228,7 @@ limb._unembed_object(weapon) UnregisterSignal(weapon, list(COMSIG_MOVABLE_MOVED, COMSIG_QDELETING)) // have to do it here otherwise we trigger weaponDeleted() + SEND_SIGNAL(weapon, COMSIG_ITEM_UNEMBEDDED, victim) if(!weapon.unembedded()) // if it hasn't deleted itself due to drop del UnregisterSignal(weapon, list(COMSIG_MOVABLE_MOVED, COMSIG_QDELETING)) if(to_hands) diff --git a/code/datums/elements/caseless.dm b/code/datums/elements/caseless.dm index a8a1d3df3e4..587a32f2b30 100644 --- a/code/datums/elements/caseless.dm +++ b/code/datums/elements/caseless.dm @@ -13,15 +13,23 @@ if(!isammocasing(target)) return ELEMENT_INCOMPATIBLE src.reusable = reusable + RegisterSignal(target, COMSIG_CASING_READY_PROJECTILE, PROC_REF(on_ready_projectile)) RegisterSignal(target, COMSIG_FIRE_CASING, PROC_REF(on_fired_casing)) -/datum/element/caseless/proc/on_fired_casing(obj/item/ammo_casing/shell, atom/target, mob/living/user, fired_from, randomspread, spread, zone_override, params, distro, obj/projectile/proj) +/datum/element/caseless/proc/on_ready_projectile(obj/item/ammo_casing/shell, atom/target, mob/living/user, quiet, zone_override, atom/fired_from) SIGNAL_HANDLER + var/obj/projectile/proj = shell.loaded_projectile if(isnull(proj)) return if(reusable) + if(!ispath(proj.shrapnel_type)) + proj.shrapnel_type = shell.type + proj.updateEmbedding() proj.AddElement(/datum/element/projectile_drop, shell.type) +/datum/element/caseless/proc/on_fired_casing(obj/item/ammo_casing/shell, atom/target, mob/living/user, fired_from, randomspread, spread, zone_override, params, distro, obj/projectile/proj) + SIGNAL_HANDLER + if(isgun(fired_from)) var/obj/item/gun/shot_from = fired_from if(shot_from.chambered == shell) diff --git a/code/datums/mutations/tongue_spike.dm b/code/datums/mutations/tongue_spike.dm index b33b78d7d1b..e6249041250 100644 --- a/code/datums/mutations/tongue_spike.dm +++ b/code/datums/mutations/tongue_spike.dm @@ -73,6 +73,7 @@ unembedded() /obj/item/hardened_spike/embedded(atom/target) + . = ..() if(isbodypart(target)) missed = FALSE @@ -121,6 +122,7 @@ var/embedded_once_alread = FALSE /obj/item/hardened_spike/chem/embedded(mob/living/carbon/human/embedded_mob) + . = ..() if(embedded_once_alread) return embedded_once_alread = TRUE diff --git a/code/game/objects/items.dm b/code/game/objects/items.dm index d592cd0790b..55cdf19f960 100644 --- a/code/game/objects/items.dm +++ b/code/game/objects/items.dm @@ -1177,7 +1177,8 @@ return ..() /obj/item/proc/embedded(atom/embedded_target, obj/item/bodypart/part) - return + SHOULD_CALL_PARENT(TRUE) + SEND_SIGNAL(src, COMSIG_ITEM_EMBEDDED, embedded_target, part) /obj/item/proc/unembedded() if(item_flags & DROPDEL && !QDELETED(src)) @@ -1206,6 +1207,8 @@ ///In case we want to do something special (like self delete) upon failing to embed in something. /obj/item/proc/failedEmbed() + SHOULD_CALL_PARENT(TRUE) + SEND_SIGNAL(src, COMSIG_ITEM_FAILED_EMBED) if(item_flags & DROPDEL && !QDELETED(src)) qdel(src) diff --git a/code/game/objects/objs.dm b/code/game/objects/objs.dm index 1c34e75c3d1..a7263520ad8 100644 --- a/code/game/objects/objs.dm +++ b/code/game/objects/objs.dm @@ -292,7 +292,7 @@ GLOBAL_LIST_EMPTY(objects_by_id_tag) * Arguments: * * M The mob choosing a reskin option */ -/obj/proc/reskin_obj(mob/M) +/obj/proc/reskin_obj(mob/user) if(!LAZYLEN(unique_reskin)) return @@ -302,14 +302,15 @@ GLOBAL_LIST_EMPTY(objects_by_id_tag) items += list("[reskin_option]" = item_image) sort_list(items) - var/pick = show_radial_menu(M, src, items, custom_check = CALLBACK(src, PROC_REF(check_reskin_menu), M), radius = 38, require_near = TRUE) + var/pick = show_radial_menu(user, src, items, custom_check = CALLBACK(src, PROC_REF(check_reskin_menu), user), radius = 38, require_near = TRUE) if(!pick) return if(!unique_reskin[pick]) return current_skin = pick icon_state = unique_reskin[pick] - to_chat(M, "[src] is now skinned as '[pick].'") + to_chat(user, "[src] is now skinned as '[pick].'") + SEND_SIGNAL(src, COMSIG_OBJ_RESKIN, user, pick) /** * Checks if we are allowed to interact with a radial menu for reskins diff --git a/code/modules/paperwork/pen.dm b/code/modules/paperwork/pen.dm index 69af56d3419..3750acddc42 100644 --- a/code/modules/paperwork/pen.dm +++ b/code/modules/paperwork/pen.dm @@ -31,6 +31,32 @@ var/requires_gravity = TRUE // can you use this to write in zero-g embedding = list(embed_chance = 50) sharpness = SHARP_POINTY + var/dart_insert_icon = 'icons/obj/weapons/guns/toy.dmi' + var/dart_insert_casing_icon_state = "overlay_pen" + var/dart_insert_projectile_icon_state = "overlay_pen_proj" + +/obj/item/pen/Initialize(mapload) + . = ..() + AddComponent(/datum/component/dart_insert, dart_insert_icon, dart_insert_casing_icon_state, dart_insert_icon, dart_insert_projectile_icon_state) + RegisterSignal(src, COMSIG_DART_INSERT_ADDED, PROC_REF(on_inserted_into_dart)) + RegisterSignal(src, COMSIG_DART_INSERT_REMOVED, PROC_REF(on_removed_from_dart)) + RegisterSignal(src, COMSIG_DART_INSERT_GET_VAR_MODIFIERS, PROC_REF(get_dart_var_modifiers)) + +/obj/item/pen/proc/on_inserted_into_dart(datum/source, obj/projectile/dart, mob/user, embedded = FALSE) + SIGNAL_HANDLER + +/obj/item/pen/proc/get_dart_var_modifiers(datum/source, list/modifiers) + SIGNAL_HANDLER + modifiers["damage"] = max(5, throwforce) + modifiers["speed"] = max(0, throw_speed - 3) + modifiers["embedding"] = embedding + modifiers["armour_penetration"] = armour_penetration + modifiers["wound_bonus"] = wound_bonus + modifiers["bare_wound_bonus"] = bare_wound_bonus + modifiers["demolition_mod"] = demolition_mod + +/obj/item/pen/proc/on_removed_from_dart(datum/source, obj/projectile/dart, mob/user) + SIGNAL_HANDLER /obj/item/pen/suicide_act(mob/living/user) user.visible_message(span_suicide("[user] is scribbling numbers all over [user.p_them()]self with [src]! It looks like [user.p_theyre()] trying to commit sudoku...")) @@ -69,7 +95,7 @@ if("#FF0000") colour = "#00FF00" chosen_color = "green" - throw_speed = initial(throw_speed) + throw_speed-- if("#00FF00") colour = "#0000FF" chosen_color = "blue" @@ -84,6 +110,8 @@ icon_state = "pen-fountain" font = FOUNTAIN_PEN_FONT requires_gravity = FALSE // fancy spess pens + dart_insert_casing_icon_state = "overlay_fountainpen" + dart_insert_projectile_icon_state = "overlay_fountainpen_proj" /obj/item/pen/charcoal name = "charcoal stylus" @@ -113,13 +141,23 @@ custom_materials = list(/datum/material/gold = SMALL_MATERIAL_AMOUNT*7.5) sharpness = SHARP_EDGED resistance_flags = FIRE_PROOF - unique_reskin = list("Oak" = "pen-fountain-o", - "Gold" = "pen-fountain-g", - "Rosewood" = "pen-fountain-r", - "Black and Silver" = "pen-fountain-b", - "Command Blue" = "pen-fountain-cb" - ) + unique_reskin = list( + "Oak" = "pen-fountain-o", + "Gold" = "pen-fountain-g", + "Rosewood" = "pen-fountain-r", + "Black and Silver" = "pen-fountain-b", + "Command Blue" = "pen-fountain-cb" + ) embedding = list("embed_chance" = 75) + dart_insert_casing_icon_state = "overlay_fountainpen_gold" + dart_insert_projectile_icon_state = "overlay_fountainpen_gold_proj" + var/list/overlay_reskin = list( + "Oak" = "overlay_fountainpen_gold", + "Gold" = "overlay_fountainpen_gold", + "Rosewood" = "overlay_fountainpen_gold", + "Black and Silver" = "overlay_fountainpen", + "Command Blue" = "overlay_fountainpen_gold" + ) /obj/item/pen/fountain/captain/Initialize(mapload) . = ..() @@ -128,12 +166,19 @@ effectiveness = 115, \ ) //the pen is mightier than the sword + RegisterSignal(src, COMSIG_DART_INSERT_PARENT_RESKINNED, PROC_REF(reskin_dart_insert)) /obj/item/pen/fountain/captain/reskin_obj(mob/M) ..() if(current_skin) desc = "It's an expensive [current_skin] fountain pen. The nib is quite sharp." +/obj/item/pen/fountain/captain/proc/reskin_dart_insert(datum/component/dart_insert/insert_comp) + if(!istype(insert_comp)) //You really shouldn't be sending this signal from anything other than a dart_insert component + return + insert_comp.casing_overlay_icon_state = overlay_reskin[current_skin] + insert_comp.projectile_overlay_icon_state = "[overlay_reskin[current_skin]]_proj" + /obj/item/pen/attack_self(mob/living/carbon/user) . = ..() if(.) @@ -247,6 +292,23 @@ reagents.add_reagent(/datum/reagent/toxin/mutetoxin, 15) reagents.add_reagent(/datum/reagent/toxin/staminatoxin, 10) +/obj/item/pen/sleepy/on_inserted_into_dart(datum/source, obj/item/ammo_casing/dart, mob/user) + . = ..() + var/obj/projectile/proj = dart.loaded_projectile + RegisterSignal(proj, COMSIG_PROJECTILE_SELF_ON_HIT, PROC_REF(on_dart_hit)) + +/obj/item/pen/sleepy/on_removed_from_dart(datum/source, obj/item/ammo_casing/dart, obj/projectile/proj, mob/user) + . = ..() + if(istype(proj)) + UnregisterSignal(proj, COMSIG_PROJECTILE_SELF_ON_HIT) + +/obj/item/pen/sleepy/proc/on_dart_hit(datum/source, atom/movable/firer, atom/target, angle, hit_limb, blocked) + SIGNAL_HANDLER + var/mob/living/carbon/carbon_target = target + if(!istype(carbon_target) || blocked == 100) + return + if(carbon_target.can_inject(target_zone = hit_limb)) + reagents.trans_to(carbon_target, reagents.total_volume, transferred_by = firer, methods = INJECT) /* * (Alan) Edaggers */ @@ -262,6 +324,7 @@ light_power = 0.75 light_color = COLOR_SOFT_RED light_on = FALSE + dart_insert_projectile_icon_state = "overlay_edagger" /// The real name of our item when extended. var/hidden_name = "energy dagger" /// The real desc of our item when extended. @@ -287,6 +350,62 @@ RegisterSignal(src, COMSIG_TRANSFORMING_ON_TRANSFORM, PROC_REF(on_transform)) RegisterSignal(src, COMSIG_DETECTIVE_SCANNED, PROC_REF(on_scan)) +/obj/item/pen/edagger/on_inserted_into_dart(datum/source, obj/item/ammo_casing/dart, mob/user) + . = ..() + var/datum/component/transforming/transform_comp = GetComponent(/datum/component/transforming) + if(HAS_TRAIT(src, TRAIT_TRANSFORM_ACTIVE)) + transform_comp.do_transform(src, user) + RegisterSignal(dart.loaded_projectile, COMSIG_PROJECTILE_FIRE, PROC_REF(on_containing_dart_fired)) + RegisterSignal(dart.loaded_projectile, COMSIG_PROJECTILE_ON_SPAWN_DROP, PROC_REF(on_containing_dart_drop)) + RegisterSignal(dart.loaded_projectile, COMSIG_PROJECTILE_ON_SPAWN_EMBEDDED, PROC_REF(on_containing_dart_embedded)) + +/obj/item/pen/edagger/on_removed_from_dart(datum/source, obj/item/ammo_casing/dart, obj/projectile/projectile, mob/user) + . = ..() + if(istype(dart)) + UnregisterSignal(dart, list(COMSIG_ITEM_UNEMBEDDED, COMSIG_ITEM_FAILED_EMBED)) + if(istype(projectile)) + UnregisterSignal(projectile, list(COMSIG_PROJECTILE_FIRE, COMSIG_PROJECTILE_ON_SPAWN_DROP, COMSIG_PROJECTILE_ON_SPAWN_EMBEDDED)) + +/obj/item/pen/edagger/get_dart_var_modifiers(datum/source, list/modifiers) + . = ..() + var/datum/component/transforming/transform_comp = GetComponent(/datum/component/transforming) + modifiers["damage"] = max(5, transform_comp.throwforce_on) + modifiers["speed"] = max(0, transform_comp.throw_speed_on - 3) + var/list/embed_params = modifiers["embedding"] + embed_params["embed_chance"] = 100 + +/obj/item/pen/edagger/proc/on_containing_dart_fired(obj/projectile/source) + SIGNAL_HANDLER + playsound(source, 'sound/weapons/saberon.ogg', 5, TRUE) + var/datum/component/transforming/transform_comp = GetComponent(/datum/component/transforming) + source.hitsound = transform_comp.hitsound_on + source.set_light(light_range, light_power, light_color, l_on = TRUE) + +/obj/item/pen/edagger/proc/on_containing_dart_drop(datum/source, obj/item/ammo_casing/new_casing) + SIGNAL_HANDLER + playsound(new_casing, 'sound/weapons/saberoff.ogg', 5, TRUE) + +/obj/item/pen/edagger/proc/on_containing_dart_embedded(datum/source, obj/item/ammo_casing/new_casing) + SIGNAL_HANDLER + RegisterSignal(new_casing, COMSIG_ITEM_UNEMBEDDED, PROC_REF(on_embedded_removed)) + RegisterSignal(new_casing, COMSIG_ITEM_FAILED_EMBED, PROC_REF(on_containing_dart_failed_embed)) + +/obj/item/pen/edagger/proc/on_containing_dart_failed_embed(obj/item/ammo_casing/source) + SIGNAL_HANDLER + playsound(source, 'sound/weapons/saberoff.ogg', 5, TRUE) + UnregisterSignal(source, list(COMSIG_ITEM_UNEMBEDDED, COMSIG_ITEM_FAILED_EMBED)) + +/obj/item/pen/edagger/proc/on_embedded_removed(obj/item/ammo_casing/source, mob/living/carbon/victim) + SIGNAL_HANDLER + playsound(source, 'sound/weapons/saberoff.ogg', 5, TRUE) + UnregisterSignal(source, list(COMSIG_ITEM_UNEMBEDDED, COMSIG_ITEM_FAILED_EMBED)) + victim.visible_message( + message = span_warning("The blade of the [hidden_name] retracts as the [source.name] is removed from [victim]!"), + self_message = span_warning("The blade of the [hidden_name] retracts as the [source.name] is removed from you!"), + blind_message = span_warning("You hear an energy blade retract!"), + vision_distance = 1 + ) + /obj/item/pen/edagger/suicide_act(mob/living/user) if(HAS_TRAIT(src, TRAIT_TRANSFORM_ACTIVE)) user.visible_message(span_suicide("[user] forcefully rams the pen into their mouth!")) @@ -348,6 +467,25 @@ toolspeed = 10 //You will never willingly choose to use one of these over a shovel. font = FOUNTAIN_PEN_FONT colour = "#0000FF" + dart_insert_casing_icon_state = "overlay_survivalpen" + dart_insert_projectile_icon_state = "overlay_survivalpen_proj" + +/obj/item/pen/survival/on_inserted_into_dart(datum/source, obj/item/ammo_casing/dart, mob/user) + . = ..() + RegisterSignal(dart.loaded_projectile, COMSIG_PROJECTILE_SELF_ON_HIT, PROC_REF(on_dart_hit)) + +/obj/item/pen/survival/on_removed_from_dart(datum/source, obj/item/ammo_casing/dart, obj/projectile/proj, mob/user) + . = ..() + if(istype(proj)) + UnregisterSignal(proj, COMSIG_PROJECTILE_SELF_ON_HIT) + +/obj/item/pen/survival/proc/on_dart_hit(obj/projectile/source, atom/movable/firer, atom/target) + var/turf/target_turf = get_turf(target) + if(!target_turf) + target_turf = get_turf(src) + if(ismineralturf(target_turf)) + var/turf/closed/mineral/mineral_turf = target_turf + mineral_turf.gets_drilled(firer, TRUE) /obj/item/pen/destroyer name = "Fine Tipped Pen" @@ -362,6 +500,7 @@ desc = "A pen with an extendable screwdriver tip. This one has a yellow cap." icon_state = "pendriver" toolspeed = 1.2 // gotta have some downside + dart_insert_projectile_icon_state = "overlay_pendriver" /obj/item/pen/screwdriver/get_all_tool_behaviours() return list(TOOL_SCREWDRIVER) diff --git a/code/modules/projectiles/ammunition/_firing.dm b/code/modules/projectiles/ammunition/_firing.dm index dee2c087c68..009c52b227e 100644 --- a/code/modules/projectiles/ammunition/_firing.dm +++ b/code/modules/projectiles/ammunition/_firing.dm @@ -66,6 +66,7 @@ if(reagents && loaded_projectile.reagents) reagents.trans_to(loaded_projectile, reagents.total_volume, transferred_by = user) //For chemical darts/bullets qdel(reagents) + SEND_SIGNAL(src, COMSIG_CASING_READY_PROJECTILE, target, user, quiet, zone_override, fired_from) /obj/item/ammo_casing/proc/throw_proj(atom/target, turf/targloc, mob/living/user, params, spread, atom/fired_from) var/turf/curloc = get_turf(fired_from) diff --git a/code/modules/projectiles/ammunition/ballistic/foam.dm b/code/modules/projectiles/ammunition/ballistic/foam.dm index 21ceeb6918b..2895d74555b 100644 --- a/code/modules/projectiles/ammunition/ballistic/foam.dm +++ b/code/modules/projectiles/ammunition/ballistic/foam.dm @@ -9,6 +9,7 @@ custom_materials = list(/datum/material/iron = SMALL_MATERIAL_AMOUNT * 0.1125) harmful = FALSE var/modified = FALSE + var/static/list/insertable_items_hint = list(/obj/item/pen) /obj/item/ammo_casing/foam_dart/Initialize(mapload) . = ..() @@ -18,47 +19,37 @@ . = ..() if(modified) icon_state = "[base_icon_state]_empty" - loaded_projectile?.icon_state = "[base_icon_state]_empty" + loaded_projectile?.icon_state = "[loaded_projectile.base_icon_state]_empty_proj" return icon_state = "[base_icon_state]" - loaded_projectile?.icon_state = "[loaded_projectile.base_icon_state]" + loaded_projectile?.icon_state = "[loaded_projectile.base_icon_state]_proj" /obj/item/ammo_casing/foam_dart/update_desc() . = ..() desc = "It's Donk or Don't! [modified ? "... Although, this one doesn't look too safe." : "Ages 8 and up."]" -/obj/item/ammo_casing/foam_dart/attackby(obj/item/A, mob/user, params) - var/obj/projectile/bullet/foam_dart/FD = loaded_projectile - if (A.tool_behaviour == TOOL_SCREWDRIVER && !modified) +/obj/item/ammo_casing/foam_dart/examine_more(mob/user) + . = ..() + if(!HAS_TRAIT(src, TRAIT_DART_HAS_INSERT)) + var/list/type_initial_names = list() + for(var/type in insertable_items_hint) + var/obj/item/type_item = type + type_initial_names += "\a [initial(type_item.name)]" + . += span_notice("[modified ? "You can" : "If you removed the safety cap with a screwdriver, you could"] insert a small item\ + [length(type_initial_names) ? ", such as [english_list(type_initial_names, and_text = "or ", final_comma_text = ", ")]" : ""].") + + +/obj/item/ammo_casing/foam_dart/attackby(obj/item/attacking_item, mob/user, params) + var/obj/projectile/bullet/foam_dart/dart = loaded_projectile + if (attacking_item.tool_behaviour == TOOL_SCREWDRIVER && !modified) modified = TRUE - FD.modified = TRUE - FD.damage_type = BRUTE + dart.modified = TRUE + dart.damage_type = BRUTE to_chat(user, span_notice("You pop the safety cap off [src].")) update_appearance() - else if (istype(A, /obj/item/pen)) - if(modified) - if(!FD.pen) - harmful = TRUE - if(!user.transferItemToLoc(A, FD)) - return - FD.pen = A - FD.damage = 5 - to_chat(user, span_notice("You insert [A] into [src].")) - else - to_chat(user, span_warning("There's already something in [src].")) - else - to_chat(user, span_warning("The safety cap prevents you from inserting [A] into [src].")) else return ..() -/obj/item/ammo_casing/foam_dart/attack_self(mob/living/user) - var/obj/projectile/bullet/foam_dart/FD = loaded_projectile - if(FD.pen) - FD.damage = initial(FD.damage) - user.put_in_hands(FD.pen) - to_chat(user, span_notice("You remove [FD.pen] from [src].")) - FD.pen = null - /obj/item/ammo_casing/foam_dart/riot name = "riot foam dart" desc = "Whose smart idea was it to use toys as crowd control? Ages 18 and up." diff --git a/code/modules/projectiles/guns/ballistic/bows/bow_arrows.dm b/code/modules/projectiles/guns/ballistic/bows/bow_arrows.dm index a3bb54a07e0..713790049b5 100644 --- a/code/modules/projectiles/guns/ballistic/bows/bow_arrows.dm +++ b/code/modules/projectiles/guns/ballistic/bows/bow_arrows.dm @@ -32,6 +32,7 @@ damage = 50 speed = 1 range = 25 + shrapnel_type = null embedding = list( embed_chance = 90, fall_chance = 2, @@ -42,7 +43,6 @@ jostle_pain_mult = 3, rip_time = 1 SECONDS ) - shrapnel_type = /obj/item/ammo_casing/arrow /// holy arrows /obj/item/ammo_casing/arrow/holy @@ -59,7 +59,6 @@ desc = "Here it comes, cultist scum!" icon_state = "holy_arrow_projectile" damage = 20 //still a lot but this is roundstart gear so far less - shrapnel_type =/obj/item/ammo_casing/arrow/holy embedding = list( embed_chance = 50, fall_chance = 2, diff --git a/code/modules/projectiles/projectile.dm b/code/modules/projectiles/projectile.dm index 18c0b557f88..a7beb1a7102 100644 --- a/code/modules/projectiles/projectile.dm +++ b/code/modules/projectiles/projectile.dm @@ -282,8 +282,8 @@ var/mob/living/L = target hit_limb_zone = L.check_hit_limb_zone_name(def_zone) if(fired_from) - SEND_SIGNAL(fired_from, COMSIG_PROJECTILE_ON_HIT, firer, target, Angle, hit_limb_zone) - SEND_SIGNAL(src, COMSIG_PROJECTILE_SELF_ON_HIT, firer, target, Angle, hit_limb_zone) + SEND_SIGNAL(fired_from, COMSIG_PROJECTILE_ON_HIT, firer, target, Angle, hit_limb_zone, blocked) + SEND_SIGNAL(src, COMSIG_PROJECTILE_SELF_ON_HIT, firer, target, Angle, hit_limb_zone, blocked) if(QDELETED(src)) // in case one of the above signals deleted the projectile for whatever reason return BULLET_ACT_BLOCK diff --git a/code/modules/projectiles/projectile/bullets/foam_dart.dm b/code/modules/projectiles/projectile/bullets/foam_dart.dm index 6d4cffd4524..3f086166e6a 100644 --- a/code/modules/projectiles/projectile/bullets/foam_dart.dm +++ b/code/modules/projectiles/projectile/bullets/foam_dart.dm @@ -5,27 +5,24 @@ damage_type = OXY icon = 'icons/obj/weapons/guns/toy.dmi' icon_state = "foamdart_proj" - base_icon_state = "foamdart_proj" + base_icon_state = "foamdart" range = 10 + shrapnel_type = null embedding = null var/modified = FALSE var/obj/item/pen/pen = null /obj/projectile/bullet/foam_dart/Initialize(mapload) . = ..() - RegisterSignal(src, COMSIG_PROJECTILE_ON_SPAWN_DROP, PROC_REF(handle_drop)) + RegisterSignals(src, list(COMSIG_PROJECTILE_ON_SPAWN_DROP, COMSIG_PROJECTILE_ON_SPAWN_EMBEDDED), PROC_REF(handle_drop)) /obj/projectile/bullet/foam_dart/proc/handle_drop(datum/source, obj/item/ammo_casing/foam_dart/newcasing) SIGNAL_HANDLER newcasing.modified = modified + newcasing.update_appearance() var/obj/projectile/bullet/foam_dart/newdart = newcasing.loaded_projectile newdart.modified = modified newdart.damage_type = damage_type - if(pen) - newdart.pen = pen - pen.forceMove(newdart) - pen = null - newdart.damage = 5 newdart.update_appearance() /obj/projectile/bullet/foam_dart/Destroy() @@ -35,5 +32,5 @@ /obj/projectile/bullet/foam_dart/riot name = "riot foam dart" icon_state = "foamdart_riot_proj" - base_icon_state = "foamdart_riot_proj" + base_icon_state = "foamdart_riot" stamina = 25 diff --git a/code/modules/projectiles/projectile/bullets/rifle.dm b/code/modules/projectiles/projectile/bullets/rifle.dm index de7e59facc3..d76b2de9d6a 100644 --- a/code/modules/projectiles/projectile/bullets/rifle.dm +++ b/code/modules/projectiles/projectile/bullets/rifle.dm @@ -46,7 +46,7 @@ bare_wound_bonus = 80 embedding = list(embed_chance=100, fall_chance=3, jostle_chance=4, ignore_throwspeed_threshold=TRUE, pain_stam_pct=0.4, pain_mult=5, jostle_pain_mult=6, rip_time=10) wound_falloff_tile = -5 - shrapnel_type = /obj/item/ammo_casing/harpoon + shrapnel_type = null // Rebar (Rebar Crossbow) /obj/projectile/bullet/rebar @@ -75,4 +75,3 @@ embedding = list(embed_chance=80, fall_chance=1, jostle_chance=3, ignore_throwspeed_threshold=TRUE, pain_stam_pct=0.4, pain_mult=3, jostle_pain_mult=2, rip_time=14) embed_falloff_tile = -3 shrapnel_type = /obj/item/stack/rods - diff --git a/icons/obj/weapons/guns/toy.dmi b/icons/obj/weapons/guns/toy.dmi index 83a85e7e447c793b1c5e295f3d85fceeb5388302..3f7e509b699e69710cd172f4642260940dcbb3b6 100644 GIT binary patch literal 2855 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 literal 869 zcmV-r1DgDaP)005u}0{{R3yb+fl0000yP)t-sz`(#2 zSPwIg5*T|10A~L)ng3=I5`ZWuSPl*xF&bxQXCWLMHZLz67#RPVGylvp06qXTE-wH7 zGr+*WA?R{500001bW%=J06^y0W&i*HsCrabbVOxyV{&P5bZKvH004NLQ&w!zk*nG@wu6K znM5lFIff*~#2XLtEJC3P5url7YH;w8W;lL5$_lQ2F5tul0Ky@_XTVRWrvLx~BS}O- zRCt{2n(dB)Fc3wpAFv1r>-#_K;;LD@bmmrD=os%w_*I5EK^fC4n++j^q~n5=w)(?u zcLBC`3@Mn(GlKiWUcFXTf0Y$%j*WV)w(Ik+yKRu5;AuFi4Hj7sPnqzXDIz$AKH=SN zv?SQiuqD`k&*-fQPV>V%%n45O!#m6gPAlFa2oC2#ZLrAt=t6=nC|Cpvrt&K|efZvC zPH;8{O$oaBFNrfGxEX_#wjzWOLhN85zf-$MWG748&lLRbP*AU@;3o;9ZK;$`B0-ej zMGK;hy_8SR71T#`_N40dPY6ou`jo@@UG$WERdB8_`l}$n)9dpHD(NB4@AUdCg1y}R zx?0thcl;C7>N5$-=^@VVE@z1Lxdi3(5a)M#{R8N44oy%_4{`dW*FS*%D3S*GMM2KK zA_Ud?47`P)9M0kVPOr}-D2H=6ztiip2>J<~`zMIec2|zf%4uoq+n+-AehNbOP$X^c{pm^oN*#NX+Md2=jxS5JCtcgb+eVNz88>ng69y vH2;gCX#N*N(flt4=6|U$|09GDLWsu?W2#u;HO+7C00000NkvXXu0mjf Date: Thu, 23 Nov 2023 22:42:47 +0300 Subject: [PATCH 34/72] Automatic changelog for PR #786 [ci skip] --- html/changelogs/AutoChangeLog-pr-786.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-786.yml diff --git a/html/changelogs/AutoChangeLog-pr-786.yml b/html/changelogs/AutoChangeLog-pr-786.yml new file mode 100644 index 00000000000..9cb91ae6647 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-786.yml @@ -0,0 +1,4 @@ +author: "Nerev4r" +delete-after: True +changes: + - bugfix: "Chameleon mutation is toggleable again." \ No newline at end of file From e3744ec38f1d19694795ac340ed9ffffc0d4fd23 Mon Sep 17 00:00:00 2001 From: Yaroslav Nurkov <78199449+AnywayFarus@users.noreply.github.com> Date: Thu, 23 Nov 2023 22:47:39 +0300 Subject: [PATCH 35/72] Automatic changelog for PR #784 [ci skip] --- html/changelogs/AutoChangeLog-pr-784.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-784.yml diff --git a/html/changelogs/AutoChangeLog-pr-784.yml b/html/changelogs/AutoChangeLog-pr-784.yml new file mode 100644 index 00000000000..2d911e132c8 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-784.yml @@ -0,0 +1,4 @@ +author: "RatFromTheJungle" +delete-after: True +changes: + - bugfix: "fixes punches doing like triple stamina damage, by removing a 2.6x multiplier." \ No newline at end of file From 9d0cae51904c6a7d2efc4cff013dbdfa76cd0d35 Mon Sep 17 00:00:00 2001 From: Iajret Creature <122297233+Steals-The-PRs@users.noreply.github.com> Date: Thu, 23 Nov 2023 22:50:18 +0300 Subject: [PATCH 36/72] [MIRROR] Golems cannot turn into Plasmamen [MDB IGNORE] (#765) * Golems cannot turn into Plasmamen * Diffs --------- Co-authored-by: SkyratBot <59378654+SkyratBot@users.noreply.github.com> Co-authored-by: Jacquerel Co-authored-by: Giz <13398309+vinylspiders@users.noreply.github.com> Co-authored-by: Iajret --- code/__DEFINES/surgery.dm | 2 + code/__DEFINES/traits/declarations.dm | 5 ++ code/_globalvars/traits/_traits.dm | 2 + code/_globalvars/traits/admin_tooling.dm | 2 + code/game/turfs/open/lava.dm | 67 ++++++++++--------- .../basic/lavaland/legion/legion_brood.dm | 4 ++ .../basic/lavaland/lobstrosity/lobstrosity.dm | 1 - .../mob/living/basic/lavaland/mining.dm | 2 +- .../carbon/human/species_types/android.dm | 3 +- .../carbon/human/species_types/golems.dm | 3 + .../carbon/human/species_types/plasmamen.dm | 3 + .../carbon/human/species_types/skeletons.dm | 1 + .../mob/living/carbon/human/status_procs.dm | 8 --- code/modules/mob/living/status_procs.dm | 30 ++++++--- code/modules/surgery/bodyparts/_bodyparts.dm | 2 +- .../surgery/bodyparts/robot_bodyparts.dm | 12 +++- .../bodyparts/species_parts/misc_bodyparts.dm | 6 ++ .../species_parts/plasmaman_bodyparts.dm | 6 ++ 18 files changed, 104 insertions(+), 55 deletions(-) diff --git a/code/__DEFINES/surgery.dm b/code/__DEFINES/surgery.dm index dcdd1394253..6f078c28724 100644 --- a/code/__DEFINES/surgery.dm +++ b/code/__DEFINES/surgery.dm @@ -43,6 +43,8 @@ #define BODYPART_PSEUDOPART (1<<1) /// Bodypart did not match the owner's default bodypart limb_id when surgically implanted #define BODYPART_IMPLANTED (1<<2) +/// Bodypart never displays as a husk +#define BODYPART_UNHUSKABLE (1<<3) // Bodypart change blocking flags ///Bodypart does not get replaced during set_species() diff --git a/code/__DEFINES/traits/declarations.dm b/code/__DEFINES/traits/declarations.dm index d9db85b32da..bb0a65fc5d2 100644 --- a/code/__DEFINES/traits/declarations.dm +++ b/code/__DEFINES/traits/declarations.dm @@ -124,6 +124,8 @@ Remember to update _globalvars/traits.dm if you're adding/removing/renaming trai #define TRAIT_NUKEIMMUNE "nuke_immunity" /// Can't be given viruses #define TRAIT_VIRUSIMMUNE "virus_immunity" +/// Won't become a husk under any circumstances +#define TRAIT_UNHUSKABLE "trait_unhuskable" /// Reduces the chance viruses will spread to this mob, and if the mob has a virus, slows its advancement #define TRAIT_VIRUS_RESISTANCE "virus_resistance" #define TRAIT_GENELESS "geneless" @@ -536,6 +538,9 @@ Remember to update _globalvars/traits.dm if you're adding/removing/renaming trai /// Disables the floating animation. See above. #define TRAIT_NO_FLOATING_ANIM "no-floating-animation" +/// Cannot be turned into a funny skeleton by the plasma river +#define TRAIT_NO_PLASMA_TRANSFORM "no_plasma_transform" + /// Weather immunities, also protect mobs inside them. #define TRAIT_LAVA_IMMUNE "lava_immune" //Used by lava turfs and The Floor Is Lava. #define TRAIT_ASHSTORM_IMMUNE "ashstorm_immune" diff --git a/code/_globalvars/traits/_traits.dm b/code/_globalvars/traits/_traits.dm index 6af47e3ab10..7ec768e619a 100644 --- a/code/_globalvars/traits/_traits.dm +++ b/code/_globalvars/traits/_traits.dm @@ -282,6 +282,7 @@ GLOBAL_LIST_INIT(traits_by_type, list( "TRAIT_NO_DNA_SCRAMBLE" = TRAIT_NO_DNA_SCRAMBLE, "TRAIT_NO_FLOATING_ANIM" = TRAIT_NO_FLOATING_ANIM, "TRAIT_NO_GLIDE" = TRAIT_NO_GLIDE, + "TRAIT_NO_PLASMA_TRANSFORM" = TRAIT_NO_PLASMA_TRANSFORM, "TRAIT_NO_GUN_AKIMBO" = TRAIT_NO_GUN_AKIMBO, "TRAIT_NO_IMMOBILIZE" = TRAIT_NO_IMMOBILIZE, "TRAIT_NO_JUMPSUIT" = TRAIT_NO_JUMPSUIT, @@ -422,6 +423,7 @@ GLOBAL_LIST_INIT(traits_by_type, list( "TRAIT_UNBREAKABLE" = TRAIT_UNBREAKABLE, "TRAIT_UNDENSE" = TRAIT_UNDENSE, "TRAIT_UNDERWATER_BASKETWEAVING_KNOWLEDGE" = TRAIT_UNDERWATER_BASKETWEAVING_KNOWLEDGE, + "TRAIT_UNHUSKABLE" = TRAIT_UNHUSKABLE, "TRAIT_UNINTELLIGIBLE_SPEECH" = TRAIT_UNINTELLIGIBLE_SPEECH, "TRAIT_UNKNOWN" = TRAIT_UNKNOWN, "TRAIT_UNNATURAL_RED_GLOWY_EYES" = TRAIT_UNNATURAL_RED_GLOWY_EYES, diff --git a/code/_globalvars/traits/admin_tooling.dm b/code/_globalvars/traits/admin_tooling.dm index b65a31c79f7..26c419723cb 100644 --- a/code/_globalvars/traits/admin_tooling.dm +++ b/code/_globalvars/traits/admin_tooling.dm @@ -129,6 +129,7 @@ GLOBAL_LIST_INIT(admin_visible_traits, list( "TRAIT_NO_BLOOD_OVERLAY" = TRAIT_NO_BLOOD_OVERLAY, "TRAIT_NO_DNA_COPY" = TRAIT_NO_DNA_COPY, "TRAIT_NO_GLIDE" = TRAIT_NO_GLIDE, + "TRAIT_NO_PLASMA_TRANSFORM" = TRAIT_NO_PLASMA_TRANSFORM, "TRAIT_NO_SLIP_ALL" = TRAIT_NO_SLIP_ALL, "TRAIT_NO_SLIP_ICE" = TRAIT_NO_SLIP_ICE, "TRAIT_NO_SLIP_SLIDE" = TRAIT_NO_SLIP_SLIDE, @@ -214,6 +215,7 @@ GLOBAL_LIST_INIT(admin_visible_traits, list( "TRAIT_UI_BLOCKED" = TRAIT_UI_BLOCKED, "TRAIT_UNDENSE" = TRAIT_UNDENSE, "TRAIT_UNDERWATER_BASKETWEAVING_KNOWLEDGE" = TRAIT_UNDERWATER_BASKETWEAVING_KNOWLEDGE, + "TRAIT_UNHUSKABLE" = TRAIT_UNHUSKABLE, "TRAIT_UNINTELLIGIBLE_SPEECH" = TRAIT_UNINTELLIGIBLE_SPEECH, "TRAIT_UNKNOWN" = TRAIT_UNKNOWN, "TRAIT_UNNATURAL_RED_GLOWY_EYES" = TRAIT_UNNATURAL_RED_GLOWY_EYES, diff --git a/code/game/turfs/open/lava.dm b/code/game/turfs/open/lava.dm index 3b382069f58..cce5a49e993 100644 --- a/code/game/turfs/open/lava.dm +++ b/code/game/turfs/open/lava.dm @@ -368,37 +368,40 @@ /turf/open/lava/plasma/do_burn(atom/movable/burn_target, seconds_per_tick = 1) . = TRUE - if(isobj(burn_target)) - return FALSE // Does nothing against objects. Old code. + if(!isliving(burn_target)) + return FALSE var/mob/living/burn_living = burn_target - burn_living.adjustFireLoss(2) - if(QDELETED(burn_living)) - return - burn_living.adjust_fire_stacks(20) //dipping into a stream of plasma would probably make you more flammable than usual - burn_living.adjust_bodytemperature(-rand(50,65)) //its cold, man - if(!ishuman(burn_living) || SPT_PROB(65, seconds_per_tick)) + var/need_mob_update + // This is from plasma, so it should obey plasma biotype requirements + need_mob_update += burn_living.adjustToxLoss(15, updating_health = FALSE, required_biotype = MOB_ORGANIC) + need_mob_update += burn_living.adjustFireLoss(25, updating_health = FALSE) + if(need_mob_update) + burn_living.updatehealth() + + if(QDELETED(burn_living) \ + || !ishuman(burn_living) \ + || HAS_TRAIT(burn_living, TRAIT_NODISMEMBER) \ + || HAS_TRAIT(burn_living, TRAIT_NO_PLASMA_TRANSFORM) \ + || SPT_PROB(65, seconds_per_tick) \ + ) return + var/mob/living/carbon/human/burn_human = burn_living - var/datum/species/burn_species = burn_human.dna.species - if(istype(burn_species, /datum/species/plasmaman) || istype(burn_species, /datum/species/android)) //ignore plasmamen/robotic species - return - var/list/plasma_parts = list()//a list of the organic parts to be turned into plasma limbs - var/list/robo_parts = list()//keep a reference of robotic parts so we know if we can turn them into a plasmaman + var/list/immune_parts = list() // Parts we can't transform because they're not organic or can't be dismembered + var/list/transform_parts = list() // Parts we want to transform + for(var/obj/item/bodypart/burn_limb as anything in burn_human.bodyparts) - if(IS_ORGANIC_LIMB(burn_limb) && burn_limb.limb_id != SPECIES_PLASMAMAN) //getting every organic, non-plasmaman limb (augments/androids are immune to this) - plasma_parts += burn_limb - if(IS_ROBOTIC_LIMB(burn_limb)) - robo_parts += burn_limb + if(!IS_ORGANIC_LIMB(burn_limb) || !burn_limb.can_dismember()) + immune_parts += burn_limb + continue + if(burn_limb.limb_id == SPECIES_PLASMAMAN) + continue + transform_parts += burn_limb - var/need_mob_update - need_mob_update += burn_human.adjustToxLoss(15, updating_health = FALSE, required_biotype = MOB_ORGANIC) // This is from plasma, so it should obey plasma biotype requirements - need_mob_update += burn_human.adjustFireLoss(25, updating_health = FALSE) - if(need_mob_update) - burn_human.updatehealth() - if(plasma_parts.len) - var/obj/item/bodypart/burn_limb = pick(plasma_parts) //using the above-mentioned list to get a choice of limbs + if(length(transform_parts)) + var/obj/item/bodypart/burn_limb = pick_n_take(transform_parts) burn_human.emote("scream") var/obj/item/bodypart/plasmalimb switch(burn_limb.body_zone) //get plasmaman limb to swap in @@ -414,16 +417,20 @@ plasmalimb = new /obj/item/bodypart/chest/plasmaman if(BODY_ZONE_HEAD) plasmalimb = new /obj/item/bodypart/head/plasmaman + burn_human.del_and_replace_bodypart(plasmalimb) burn_human.update_body_parts() burn_human.emote("scream") burn_human.visible_message(span_warning("[burn_human]'s [burn_limb.plaintext_zone] melts down to the bone!"), \ - span_userdanger("You scream out in pain as your [burn_limb.plaintext_zone] melts down to the bone, leaving an eerie plasma-like glow where flesh used to be!")) - if(!plasma_parts.len && !robo_parts.len) //a person with no potential organic limbs left AND no robotic limbs, time to turn them into a plasmaman - burn_human.ignite_mob() - burn_human.set_species(/datum/species/plasmaman) - burn_human.visible_message(span_warning("[burn_human] bursts into a brilliant purple flame as [burn_human.p_their()] entire body is that of a skeleton!"), \ - span_userdanger("Your senses numb as all of your remaining flesh is turned into a purple slurry, sloshing off your body and leaving only your bones to show in a vibrant purple!")) + span_userdanger("You scream out in pain as your [burn_limb.plaintext_zone] melts down to the bone, held together only by strands of purple fungus!")) + + // If all of your limbs are plasma then congrats: you are plasma man + if(length(immune_parts) || length(transform_parts)) + return + burn_human.ignite_mob() + burn_human.set_species(/datum/species/plasmaman) + burn_human.visible_message(span_warning("[burn_human] bursts into flame as the last of [burn_human.p_their()] body is coated in fungus!"), \ + span_userdanger("Your senses numb as what remains of your flesh sloughs off, revealing the plasma-encrusted bone beneath!")) //mafia specific tame happy plasma (normal atmos, no slowdown) /turf/open/lava/plasma/mafia diff --git a/code/modules/mob/living/basic/lavaland/legion/legion_brood.dm b/code/modules/mob/living/basic/lavaland/legion/legion_brood.dm index 797426058a1..91edf40615c 100644 --- a/code/modules/mob/living/basic/lavaland/legion/legion_brood.dm +++ b/code/modules/mob/living/basic/lavaland/legion/legion_brood.dm @@ -95,5 +95,9 @@ icon_living = "snowlegion_head" icon_dead = "snowlegion_head" +/mob/living/basic/legion_brood/snow/Initialize(mapload) + . = ..() + ADD_TRAIT(src, TRAIT_SNOWSTORM_IMMUNE, INNATE_TRAIT) + /mob/living/basic/legion_brood/snow/get_legion_type(mob/living/target) return /mob/living/basic/mining/legion/snow diff --git a/code/modules/mob/living/basic/lavaland/lobstrosity/lobstrosity.dm b/code/modules/mob/living/basic/lavaland/lobstrosity/lobstrosity.dm index ef6d846970d..64facb5cfa3 100644 --- a/code/modules/mob/living/basic/lavaland/lobstrosity/lobstrosity.dm +++ b/code/modules/mob/living/basic/lavaland/lobstrosity/lobstrosity.dm @@ -33,7 +33,6 @@ /mob/living/basic/mining/lobstrosity/Initialize(mapload) . = ..() - ADD_TRAIT(src, TRAIT_SNOWSTORM_IMMUNE, INNATE_TRAIT) AddElement(/datum/element/mob_grabber) AddElement(/datum/element/footstep, FOOTSTEP_MOB_CLAW) AddElement(/datum/element/basic_eating, food_types = target_foods) diff --git a/code/modules/mob/living/basic/lavaland/mining.dm b/code/modules/mob/living/basic/lavaland/mining.dm index 0b6c4f321b6..3bcdd1ceaa6 100644 --- a/code/modules/mob/living/basic/lavaland/mining.dm +++ b/code/modules/mob/living/basic/lavaland/mining.dm @@ -22,7 +22,7 @@ /mob/living/basic/mining/Initialize(mapload) . = ..() - add_traits(list(TRAIT_LAVA_IMMUNE, TRAIT_ASHSTORM_IMMUNE), INNATE_TRAIT) + add_traits(list(TRAIT_LAVA_IMMUNE, TRAIT_ASHSTORM_IMMUNE, TRAIT_SNOWSTORM_IMMUNE), INNATE_TRAIT) AddElement(/datum/element/mob_killed_tally, "mobs_killed_mining") var/static/list/vulnerable_projectiles if(!vulnerable_projectiles) diff --git a/code/modules/mob/living/carbon/human/species_types/android.dm b/code/modules/mob/living/carbon/human/species_types/android.dm index af21d304cb7..dec4fd9e306 100644 --- a/code/modules/mob/living/carbon/human/species_types/android.dm +++ b/code/modules/mob/living/carbon/human/species_types/android.dm @@ -9,9 +9,11 @@ TRAIT_NOBLOOD, TRAIT_NOBREATH, TRAIT_NOCLONELOSS, + TRAIT_NOCRITDAMAGE, TRAIT_NOFIRE, TRAIT_NOHUNGER, TRAIT_NO_DNA_COPY, + TRAIT_NO_PLASMA_TRANSFORM, TRAIT_NO_UNDERWEAR, TRAIT_PIERCEIMMUNE, TRAIT_RADIMMUNE, @@ -20,7 +22,6 @@ TRAIT_RESISTHIGHPRESSURE, TRAIT_RESISTLOWPRESSURE, TRAIT_TOXIMMUNE, - TRAIT_NOCRITDAMAGE, ) inherent_biotypes = MOB_ROBOTIC|MOB_HUMANOID diff --git a/code/modules/mob/living/carbon/human/species_types/golems.dm b/code/modules/mob/living/carbon/human/species_types/golems.dm index c86b8c9a276..01451a8db36 100644 --- a/code/modules/mob/living/carbon/human/species_types/golems.dm +++ b/code/modules/mob/living/carbon/human/species_types/golems.dm @@ -12,9 +12,12 @@ TRAIT_NOFIRE, TRAIT_NO_AUGMENTS, TRAIT_NO_DNA_COPY, + TRAIT_NO_PLASMA_TRANSFORM, TRAIT_NO_UNDERWEAR, TRAIT_PIERCEIMMUNE, TRAIT_RADIMMUNE, + TRAIT_SNOWSTORM_IMMUNE, // Shared with plasma river... but I guess if you can survive a plasma river a blizzard isn't a big deal + TRAIT_UNHUSKABLE, ) mutantheart = null mutantlungs = null diff --git a/code/modules/mob/living/carbon/human/species_types/plasmamen.dm b/code/modules/mob/living/carbon/human/species_types/plasmamen.dm index 9facc517c1c..eaabee63485 100644 --- a/code/modules/mob/living/carbon/human/species_types/plasmamen.dm +++ b/code/modules/mob/living/carbon/human/species_types/plasmamen.dm @@ -10,10 +10,13 @@ TRAIT_HARDLY_WOUNDED, TRAIT_NOBLOOD, TRAIT_NO_DNA_COPY, + TRAIT_NO_PLASMA_TRANSFORM, TRAIT_RADIMMUNE, TRAIT_RESISTCOLD, + TRAIT_UNHUSKABLE, ) + inherent_biotypes = MOB_HUMANOID|MOB_MINERAL inherent_respiration_type = RESPIRATION_PLASMA mutantlungs = /obj/item/organ/internal/lungs/plasmaman diff --git a/code/modules/mob/living/carbon/human/species_types/skeletons.dm b/code/modules/mob/living/carbon/human/species_types/skeletons.dm index f2682da2eba..4120f939d51 100644 --- a/code/modules/mob/living/carbon/human/species_types/skeletons.dm +++ b/code/modules/mob/living/carbon/human/species_types/skeletons.dm @@ -22,6 +22,7 @@ TRAIT_RESISTHIGHPRESSURE, TRAIT_RESISTLOWPRESSURE, TRAIT_TOXIMMUNE, + TRAIT_UNHUSKABLE, TRAIT_XENO_IMMUNE, ) inherent_biotypes = MOB_UNDEAD|MOB_HUMANOID diff --git a/code/modules/mob/living/carbon/human/status_procs.dm b/code/modules/mob/living/carbon/human/status_procs.dm index 8f6dc8efeb9..6f4e8570099 100644 --- a/code/modules/mob/living/carbon/human/status_procs.dm +++ b/code/modules/mob/living/carbon/human/status_procs.dm @@ -30,11 +30,3 @@ . = ..() if(.) update_body_parts() - -/mob/living/carbon/human/become_husk(source) - if(istype(dna.species, /datum/species/skeleton)) //skeletons shouldn't be husks. - cure_husk() - return - . = ..() - if(.) - update_body_parts() diff --git a/code/modules/mob/living/status_procs.dm b/code/modules/mob/living/status_procs.dm index bbc37911bb1..96beb024fe9 100644 --- a/code/modules/mob/living/status_procs.dm +++ b/code/modules/mob/living/status_procs.dm @@ -497,18 +497,28 @@ /mob/living/proc/cure_husk(source) REMOVE_TRAIT(src, TRAIT_HUSK, source) - if(!HAS_TRAIT(src, TRAIT_HUSK)) - REMOVE_TRAIT(src, TRAIT_DISFIGURED, "husk") - update_body() - return TRUE + if(HAS_TRAIT(src, TRAIT_HUSK)) + return FALSE + REMOVE_TRAIT(src, TRAIT_DISFIGURED, "husk") + update_body() + UnregisterSignal(src, SIGNAL_ADDTRAIT(TRAIT_UNHUSKABLE)) + return TRUE /mob/living/proc/become_husk(source) - if(!HAS_TRAIT(src, TRAIT_HUSK)) - ADD_TRAIT(src, TRAIT_HUSK, source) - ADD_TRAIT(src, TRAIT_DISFIGURED, "husk") - update_body() - else - ADD_TRAIT(src, TRAIT_HUSK, source) + if(HAS_TRAIT(src, TRAIT_UNHUSKABLE)) + return + var/was_husk = HAS_TRAIT(src, TRAIT_HUSK) + ADD_TRAIT(src, TRAIT_HUSK, source) + if (was_husk) + return + ADD_TRAIT(src, TRAIT_DISFIGURED, "husk") + update_body() + RegisterSignal(src, SIGNAL_ADDTRAIT(TRAIT_UNHUSKABLE), PROC_REF(became_unhuskable)) + +/// Called when we become unhuskable while already husked +/mob/living/proc/became_unhuskable() + SIGNAL_HANDLER + cure_husk() /mob/living/proc/cure_fakedeath(source) remove_traits(list(TRAIT_FAKEDEATH, TRAIT_DEATHCOMA), source) diff --git a/code/modules/surgery/bodyparts/_bodyparts.dm b/code/modules/surgery/bodyparts/_bodyparts.dm index c24e9f8ceca..a9dab01c918 100644 --- a/code/modules/surgery/bodyparts/_bodyparts.dm +++ b/code/modules/surgery/bodyparts/_bodyparts.dm @@ -901,7 +901,7 @@ SHOULD_CALL_PARENT(TRUE) if(IS_ORGANIC_LIMB(src)) - if(owner && HAS_TRAIT(owner, TRAIT_HUSK)) + if(!(bodypart_flags & BODYPART_UNHUSKABLE) && owner && HAS_TRAIT(owner, TRAIT_HUSK)) dmg_overlay_type = "" //no damage overlay shown when husked is_husked = TRUE else if(owner && HAS_TRAIT(owner, TRAIT_INVISIBLE_MAN)) diff --git a/code/modules/surgery/bodyparts/robot_bodyparts.dm b/code/modules/surgery/bodyparts/robot_bodyparts.dm index f10393dd653..10195c6d98e 100644 --- a/code/modules/surgery/bodyparts/robot_bodyparts.dm +++ b/code/modules/surgery/bodyparts/robot_bodyparts.dm @@ -42,6 +42,7 @@ damage_examines = list(BRUTE = ROBOTIC_BRUTE_EXAMINE_TEXT, BURN = ROBOTIC_BURN_EXAMINE_TEXT, CLONE = DEFAULT_CLONE_EXAMINE_TEXT) disabling_threshold_percentage = 1 + bodypart_flags = BODYPART_UNHUSKABLE /obj/item/bodypart/arm/right/robot name = "cyborg right arm" @@ -75,6 +76,7 @@ biological_state = (BIO_ROBOTIC|BIO_JOINTED) damage_examines = list(BRUTE = ROBOTIC_BRUTE_EXAMINE_TEXT, BURN = ROBOTIC_BURN_EXAMINE_TEXT, CLONE = DEFAULT_CLONE_EXAMINE_TEXT) + bodypart_flags = BODYPART_UNHUSKABLE /obj/item/bodypart/leg/left/robot name = "cyborg left leg" @@ -108,6 +110,7 @@ biological_state = (BIO_ROBOTIC|BIO_JOINTED) damage_examines = list(BRUTE = ROBOTIC_BRUTE_EXAMINE_TEXT, BURN = ROBOTIC_BURN_EXAMINE_TEXT, CLONE = DEFAULT_CLONE_EXAMINE_TEXT) + bodypart_flags = BODYPART_UNHUSKABLE /obj/item/bodypart/leg/left/robot/emp_act(severity) . = ..() @@ -154,6 +157,7 @@ biological_state = (BIO_ROBOTIC|BIO_JOINTED) damage_examines = list(BRUTE = ROBOTIC_BRUTE_EXAMINE_TEXT, BURN = ROBOTIC_BURN_EXAMINE_TEXT, CLONE = DEFAULT_CLONE_EXAMINE_TEXT) + bodypart_flags = BODYPART_UNHUSKABLE /obj/item/bodypart/leg/right/robot/emp_act(severity) . = ..() @@ -197,14 +201,15 @@ biological_state = (BIO_ROBOTIC) damage_examines = list(BRUTE = ROBOTIC_BRUTE_EXAMINE_TEXT, BURN = ROBOTIC_BURN_EXAMINE_TEXT, CLONE = DEFAULT_CLONE_EXAMINE_TEXT) - - var/wired = FALSE - var/obj/item/stock_parts/cell/cell = null + bodypart_flags = BODYPART_UNHUSKABLE robotic_emp_paralyze_damage_percent_threshold = 0.6 wing_types = list(/obj/item/organ/external/wings/functional/robotic) + var/wired = FALSE + var/obj/item/stock_parts/cell/cell = null + /obj/item/bodypart/chest/robot/emp_act(severity) . = ..() if(!. || isnull(owner)) @@ -376,6 +381,7 @@ damage_examines = list(BRUTE = ROBOTIC_BRUTE_EXAMINE_TEXT, BURN = ROBOTIC_BURN_EXAMINE_TEXT, CLONE = DEFAULT_CLONE_EXAMINE_TEXT) head_flags = HEAD_EYESPRITES + bodypart_flags = BODYPART_UNHUSKABLE var/obj/item/assembly/flash/handheld/flash1 = null var/obj/item/assembly/flash/handheld/flash2 = null diff --git a/code/modules/surgery/bodyparts/species_parts/misc_bodyparts.dm b/code/modules/surgery/bodyparts/species_parts/misc_bodyparts.dm index ad3c9ce213c..f4be2fd340f 100644 --- a/code/modules/surgery/bodyparts/species_parts/misc_bodyparts.dm +++ b/code/modules/surgery/bodyparts/species_parts/misc_bodyparts.dm @@ -331,6 +331,7 @@ should_draw_greyscale = FALSE dmg_overlay_type = null head_flags = NONE + bodypart_flags = BODYPART_UNHUSKABLE /obj/item/bodypart/chest/skeleton biological_state = BIO_BONE @@ -338,6 +339,7 @@ is_dimorphic = FALSE should_draw_greyscale = FALSE dmg_overlay_type = null + bodypart_flags = BODYPART_UNHUSKABLE wing_types = list(/obj/item/organ/external/wings/functional/skeleton) /obj/item/bodypart/arm/left/skeleton @@ -345,24 +347,28 @@ limb_id = SPECIES_SKELETON should_draw_greyscale = FALSE dmg_overlay_type = null + bodypart_flags = BODYPART_UNHUSKABLE /obj/item/bodypart/arm/right/skeleton biological_state = (BIO_BONE|BIO_JOINTED) limb_id = SPECIES_SKELETON should_draw_greyscale = FALSE dmg_overlay_type = null + bodypart_flags = BODYPART_UNHUSKABLE /obj/item/bodypart/leg/left/skeleton biological_state = (BIO_BONE|BIO_JOINTED) limb_id = SPECIES_SKELETON should_draw_greyscale = FALSE dmg_overlay_type = null + bodypart_flags = BODYPART_UNHUSKABLE /obj/item/bodypart/leg/right/skeleton biological_state = (BIO_BONE|BIO_JOINTED) limb_id = SPECIES_SKELETON should_draw_greyscale = FALSE dmg_overlay_type = null + bodypart_flags = BODYPART_UNHUSKABLE ///MUSHROOM /obj/item/bodypart/head/mushroom diff --git a/code/modules/surgery/bodyparts/species_parts/plasmaman_bodyparts.dm b/code/modules/surgery/bodyparts/species_parts/plasmaman_bodyparts.dm index 8070072521f..8ba27c2cdf9 100644 --- a/code/modules/surgery/bodyparts/species_parts/plasmaman_bodyparts.dm +++ b/code/modules/surgery/bodyparts/species_parts/plasmaman_bodyparts.dm @@ -10,6 +10,7 @@ brute_modifier = 1.5 //Plasmemes are weak burn_modifier = 1.5 //Plasmemes are weak head_flags = HEAD_EYESPRITES + bodypart_flags = BODYPART_UNHUSKABLE /obj/item/bodypart/chest/plasmaman icon = 'icons/mob/human/species/plasmaman/bodyparts.dmi' @@ -22,6 +23,7 @@ dmg_overlay_type = null brute_modifier = 1.5 //Plasmemes are weak burn_modifier = 1.5 //Plasmemes are weak + bodypart_flags = BODYPART_UNHUSKABLE wing_types = NONE /obj/item/bodypart/arm/left/plasmaman @@ -34,6 +36,7 @@ dmg_overlay_type = null brute_modifier = 1.5 //Plasmemes are weak burn_modifier = 1.5 //Plasmemes are weak + bodypart_flags = BODYPART_UNHUSKABLE /obj/item/bodypart/arm/right/plasmaman icon = 'icons/mob/human/species/plasmaman/bodyparts.dmi' @@ -45,6 +48,7 @@ dmg_overlay_type = null brute_modifier = 1.5 //Plasmemes are weak burn_modifier = 1.5 //Plasmemes are weak + bodypart_flags = BODYPART_UNHUSKABLE /obj/item/bodypart/leg/left/plasmaman icon = 'icons/mob/human/species/plasmaman/bodyparts.dmi' @@ -56,6 +60,7 @@ dmg_overlay_type = null brute_modifier = 1.5 //Plasmemes are weak burn_modifier = 1.5 //Plasmemes are weak + bodypart_flags = BODYPART_UNHUSKABLE /obj/item/bodypart/leg/right/plasmaman icon = 'icons/mob/human/species/plasmaman/bodyparts.dmi' @@ -67,3 +72,4 @@ dmg_overlay_type = null brute_modifier = 1.5 //Plasmemes are weak burn_modifier = 1.5 //Plasmemes are weak + bodypart_flags = BODYPART_UNHUSKABLE From cd6dc9753ca8a8145439e4965ecd2c0f9e67fb9e Mon Sep 17 00:00:00 2001 From: Yaroslav Nurkov <78199449+AnywayFarus@users.noreply.github.com> Date: Thu, 23 Nov 2023 23:46:57 +0300 Subject: [PATCH 37/72] Automatic changelog for PR #768 [ci skip] --- html/changelogs/AutoChangeLog-pr-768.yml | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-768.yml diff --git a/html/changelogs/AutoChangeLog-pr-768.yml b/html/changelogs/AutoChangeLog-pr-768.yml new file mode 100644 index 00000000000..5cf1a7ecd62 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-768.yml @@ -0,0 +1,5 @@ +author: "SyncIt21" +delete-after: True +changes: + - bugfix: "autolathe does not diminish materials from custom material items like toolboxes when printing them in bulk. Also does not gray out that item in the UI" + - bugfix: "autloathe correctly updates UI after inserting items into it" \ No newline at end of file From b2df3bfae55ff970160fe51a01aac38a7d7cb024 Mon Sep 17 00:00:00 2001 From: Yaroslav Nurkov <78199449+AnywayFarus@users.noreply.github.com> Date: Thu, 23 Nov 2023 23:47:37 +0300 Subject: [PATCH 38/72] Automatic changelog for PR #769 [ci skip] --- html/changelogs/AutoChangeLog-pr-769.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-769.yml diff --git a/html/changelogs/AutoChangeLog-pr-769.yml b/html/changelogs/AutoChangeLog-pr-769.yml new file mode 100644 index 00000000000..eb9509a7aa4 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-769.yml @@ -0,0 +1,4 @@ +author: "aaaa1023" +delete-after: True +changes: + - qol: "adds pixel perfect 4x, 4.5x, and 5x" \ No newline at end of file From b6db921197724e9f2278ddc1b5ef37bf83a75b35 Mon Sep 17 00:00:00 2001 From: Yaroslav Nurkov <78199449+AnywayFarus@users.noreply.github.com> Date: Thu, 23 Nov 2023 23:48:32 +0300 Subject: [PATCH 39/72] Automatic changelog for PR #771 [ci skip] --- html/changelogs/AutoChangeLog-pr-771.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-771.yml diff --git a/html/changelogs/AutoChangeLog-pr-771.yml b/html/changelogs/AutoChangeLog-pr-771.yml new file mode 100644 index 00000000000..0c02064c9b3 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-771.yml @@ -0,0 +1,4 @@ +author: "vinylspiders" +delete-after: True +changes: + - bugfix: "fullupgrade chem dispensers will now spawn with all their chems" \ No newline at end of file From 71fa2fabaef2fa9355baca06f18319f237c7bc26 Mon Sep 17 00:00:00 2001 From: Yaroslav Nurkov <78199449+AnywayFarus@users.noreply.github.com> Date: Thu, 23 Nov 2023 23:49:17 +0300 Subject: [PATCH 40/72] Automatic changelog for PR #772 [ci skip] --- html/changelogs/AutoChangeLog-pr-772.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-772.yml diff --git a/html/changelogs/AutoChangeLog-pr-772.yml b/html/changelogs/AutoChangeLog-pr-772.yml new file mode 100644 index 00000000000..07ed14a6044 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-772.yml @@ -0,0 +1,4 @@ +author: "lizardqueenlexi" +delete-after: True +changes: + - bugfix: "Skillsoft's skillchip stations are now ADA-compliant (Astronauts with Disabilities Act). Paraplegic characters can now implant themselves with skillchips, the same as anyone else." \ No newline at end of file From b588fcad5869c88840ac083ec89258bc5c005c67 Mon Sep 17 00:00:00 2001 From: Yaroslav Nurkov <78199449+AnywayFarus@users.noreply.github.com> Date: Thu, 23 Nov 2023 23:50:17 +0300 Subject: [PATCH 41/72] Automatic changelog for PR #504 [ci skip] --- html/changelogs/AutoChangeLog-pr-504.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-504.yml diff --git a/html/changelogs/AutoChangeLog-pr-504.yml b/html/changelogs/AutoChangeLog-pr-504.yml new file mode 100644 index 00000000000..2c3a0bcb2e3 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-504.yml @@ -0,0 +1,4 @@ +author: "LovliestPlant" +delete-after: True +changes: + - rscadd: "Adds links to any special rules or metaprotections to antag's objective panels." \ No newline at end of file From 24838eecb95bd3dbf05f0e906dd0a5f7895ed0a7 Mon Sep 17 00:00:00 2001 From: Yaroslav Nurkov <78199449+AnywayFarus@users.noreply.github.com> Date: Thu, 23 Nov 2023 23:51:01 +0300 Subject: [PATCH 42/72] Automatic changelog for PR #773 [ci skip] --- html/changelogs/AutoChangeLog-pr-773.yml | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-773.yml diff --git a/html/changelogs/AutoChangeLog-pr-773.yml b/html/changelogs/AutoChangeLog-pr-773.yml new file mode 100644 index 00000000000..2b841d6dd8d --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-773.yml @@ -0,0 +1,5 @@ +author: "Y0SH1M4S73R" +delete-after: True +changes: + - rscadd: "Certain types of pens now function like you expect they would when inserted into a foam dart" + - qol: "Examining a foam dart closely will show you how to modify it, or what it is modified with" \ No newline at end of file From 8cd0026cd4fcc40b1a3eeeac1d49147995d89329 Mon Sep 17 00:00:00 2001 From: Iajret Creature <122297233+Steals-The-PRs@users.noreply.github.com> Date: Thu, 23 Nov 2023 23:51:58 +0300 Subject: [PATCH 43/72] [MIRROR] Kills `spec_updatehealth`, replaces it with use of `COMSIG_LIVING_HEALTH_UPDATE` [MDB IGNORE] (#766) * Kills `spec_updatehealth`, replaces it with use of `COMSIG_LIVING_HEALTH_UPDATE` * Diffs --------- Co-authored-by: SkyratBot <59378654+SkyratBot@users.noreply.github.com> Co-authored-by: MrMelbert <51863163+MrMelbert@users.noreply.github.com> Co-authored-by: Giz <13398309+vinylspiders@users.noreply.github.com> Co-authored-by: Iajret --- code/modules/admin/create_mob.dm | 4 +- .../mob/living/carbon/human/_species.dm | 3 - code/modules/mob/living/carbon/human/human.dm | 1 - .../carbon/human/species_types/ethereal.dm | 87 ++++++++++--------- 4 files changed, 46 insertions(+), 49 deletions(-) diff --git a/code/modules/admin/create_mob.dm b/code/modules/admin/create_mob.dm index 8c574d207b2..c23b37e14f1 100644 --- a/code/modules/admin/create_mob.dm +++ b/code/modules/admin/create_mob.dm @@ -32,6 +32,6 @@ human.dna.species.mutant_bodyparts = human.dna.mutant_bodyparts.Copy() human.dna.species.body_markings = human.dna.body_markings.Copy() // SKYRAT EDIT ADDITION END - // Snowflake stuff (ethereals) - human.dna.species.spec_updatehealth(human) + // Snowflake for Ethereals + human.updatehealth() human.updateappearance(mutcolor_update = TRUE) diff --git a/code/modules/mob/living/carbon/human/_species.dm b/code/modules/mob/living/carbon/human/_species.dm index 1215179d0ef..2d4518bd034 100644 --- a/code/modules/mob/living/carbon/human/_species.dm +++ b/code/modules/mob/living/carbon/human/_species.dm @@ -1130,9 +1130,6 @@ GLOBAL_LIST_EMPTY(features_by_species) // ATTACK PROCS // ////////////////// -/datum/species/proc/spec_updatehealth(mob/living/carbon/human/H) - return - /datum/species/proc/help(mob/living/carbon/human/user, mob/living/carbon/human/target, datum/martial_art/attacker_style) if(SEND_SIGNAL(target, COMSIG_CARBON_PRE_HELP, user, attacker_style) & COMPONENT_BLOCK_HELP_ACT) return TRUE diff --git a/code/modules/mob/living/carbon/human/human.dm b/code/modules/mob/living/carbon/human/human.dm index a75253e1517..be84d857ed6 100644 --- a/code/modules/mob/living/carbon/human/human.dm +++ b/code/modules/mob/living/carbon/human/human.dm @@ -999,7 +999,6 @@ /mob/living/carbon/human/updatehealth() . = ..() - dna?.species.spec_updatehealth(src) if(HAS_TRAIT(src, TRAIT_IGNOREDAMAGESLOWDOWN)) remove_movespeed_modifier(/datum/movespeed_modifier/damage_slowdown) remove_movespeed_modifier(/datum/movespeed_modifier/damage_slowdown_flying) diff --git a/code/modules/mob/living/carbon/human/species_types/ethereal.dm b/code/modules/mob/living/carbon/human/species_types/ethereal.dm index abe7d058181..7850dee6734 100644 --- a/code/modules/mob/living/carbon/human/species_types/ethereal.dm +++ b/code/modules/mob/living/carbon/human/species_types/ethereal.dm @@ -55,24 +55,24 @@ QDEL_NULL(ethereal_light) return ..() -/datum/species/ethereal/on_species_gain(mob/living/carbon/new_ethereal, datum/species/old_species, pref_load) +/datum/species/ethereal/on_species_gain(mob/living/carbon/human/new_ethereal, datum/species/old_species, pref_load) . = ..() if(!ishuman(new_ethereal)) return - var/mob/living/carbon/human/ethereal = new_ethereal - default_color = ethereal.dna.features["ethcolor"] + default_color = new_ethereal.dna.features["ethcolor"] fixed_hair_color = default_color r1 = GETREDPART(default_color) g1 = GETGREENPART(default_color) b1 = GETBLUEPART(default_color) - RegisterSignal(ethereal, COMSIG_ATOM_EMAG_ACT, PROC_REF(on_emag_act)) - RegisterSignal(ethereal, COMSIG_ATOM_EMP_ACT, PROC_REF(on_emp_act)) - RegisterSignal(ethereal, COMSIG_LIGHT_EATER_ACT, PROC_REF(on_light_eater)) - RegisterSignal(ethereal, COMSIG_HIT_BY_SABOTEUR, PROC_REF(on_saboteur)) - ethereal_light = ethereal.mob_light(light_type = /obj/effect/dummy/lighting_obj/moblight/species) - spec_updatehealth(ethereal) + RegisterSignal(new_ethereal, COMSIG_ATOM_EMAG_ACT, PROC_REF(on_emag_act)) + RegisterSignal(new_ethereal, COMSIG_ATOM_EMP_ACT, PROC_REF(on_emp_act)) + RegisterSignal(new_ethereal, COMSIG_HIT_BY_SABOTEUR, PROC_REF(on_saboteur)) + RegisterSignal(new_ethereal, COMSIG_LIGHT_EATER_ACT, PROC_REF(on_light_eater)) + RegisterSignal(new_ethereal, COMSIG_LIVING_HEALTH_UPDATE, PROC_REF(refresh_light_color)) + ethereal_light = new_ethereal.mob_light(light_type = /obj/effect/dummy/lighting_obj/moblight/species) + refresh_light_color(new_ethereal) new_ethereal.set_safe_hunger_level() - update_mail_goodies(ethereal) + update_mail_goodies(new_ethereal) var/obj/item/organ/internal/heart/ethereal/ethereal_heart = new_ethereal.get_organ_slot(ORGAN_SLOT_HEART) ethereal_heart.ethereal_color = default_color @@ -82,10 +82,13 @@ limb.update_limb(is_creating = TRUE) /datum/species/ethereal/on_species_loss(mob/living/carbon/human/former_ethereal, datum/species/new_species, pref_load) - UnregisterSignal(former_ethereal, COMSIG_ATOM_EMAG_ACT) - UnregisterSignal(former_ethereal, COMSIG_ATOM_EMP_ACT) - UnregisterSignal(former_ethereal, COMSIG_LIGHT_EATER_ACT) - UnregisterSignal(former_ethereal, COMSIG_HIT_BY_SABOTEUR) + UnregisterSignal(former_ethereal, list( + COMSIG_ATOM_EMAG_ACT, + COMSIG_ATOM_EMP_ACT, + COMSIG_HIT_BY_SABOTEUR, + COMSIG_LIGHT_EATER_ACT, + COMSIG_LIVING_HEALTH_UPDATE, + )) QDEL_NULL(ethereal_light) return ..() @@ -109,9 +112,9 @@ features["ethcolor"] = GLOB.color_list_ethereal[pick(GLOB.color_list_ethereal)] return features -/datum/species/ethereal/spec_updatehealth(mob/living/carbon/human/ethereal) - . = ..() - if(!ethereal_light) +/datum/species/ethereal/proc/refresh_light_color(mob/living/carbon/human/ethereal) + SIGNAL_HANDLER + if(isnull(ethereal_light)) return if(default_color != ethereal.dna.features["ethcolor"]) var/new_color = ethereal.dna.features["ethcolor"] @@ -138,39 +141,38 @@ ethereal.set_facial_haircolor(dead_color, override = TRUE, update = FALSE) ethereal.set_haircolor(dead_color, override = TRUE, update = TRUE) -/datum/species/ethereal/proc/on_emp_act(mob/living/carbon/human/H, severity, protection) +/datum/species/ethereal/proc/on_emp_act(mob/living/carbon/human/source, severity, protection) SIGNAL_HANDLER if(protection & EMP_PROTECT_SELF) return EMPeffect = TRUE - spec_updatehealth(H) - to_chat(H, span_notice("You feel the light of your body leave you.")) + refresh_light_color(source) + to_chat(source, span_notice("You feel the light of your body leave you.")) switch(severity) if(EMP_LIGHT) - addtimer(CALLBACK(src, PROC_REF(stop_emp), H), 10 SECONDS, TIMER_UNIQUE|TIMER_OVERRIDE) //We're out for 10 seconds + addtimer(CALLBACK(src, PROC_REF(stop_emp), source), 10 SECONDS, TIMER_UNIQUE|TIMER_OVERRIDE) //We're out for 10 seconds if(EMP_HEAVY) - addtimer(CALLBACK(src, PROC_REF(stop_emp), H), 20 SECONDS, TIMER_UNIQUE|TIMER_OVERRIDE) //We're out for 20 seconds + addtimer(CALLBACK(src, PROC_REF(stop_emp), source), 20 SECONDS, TIMER_UNIQUE|TIMER_OVERRIDE) //We're out for 20 seconds -/datum/species/ethereal/proc/on_saboteur(datum/source, disrupt_duration) +/datum/species/ethereal/proc/on_saboteur(mob/living/carbon/human/source, disrupt_duration) SIGNAL_HANDLER - var/mob/living/carbon/human/our_target = source EMPeffect = TRUE - spec_updatehealth(our_target) - to_chat(our_target, span_warning("Something inside of you crackles in a bad way.")) - our_target.take_bodypart_damage(burn = 3, wound_bonus = CANT_WOUND) - addtimer(CALLBACK(src, PROC_REF(stop_emp), our_target), disrupt_duration, TIMER_UNIQUE|TIMER_OVERRIDE) + refresh_light_color(source) + to_chat(source, span_warning("Something inside of you crackles in a bad way.")) + source.take_bodypart_damage(burn = 3, wound_bonus = CANT_WOUND) + addtimer(CALLBACK(src, PROC_REF(stop_emp), source), disrupt_duration, TIMER_UNIQUE|TIMER_OVERRIDE) return COMSIG_SABOTEUR_SUCCESS -/datum/species/ethereal/proc/on_emag_act(mob/living/carbon/human/H, mob/user) +/datum/species/ethereal/proc/on_emag_act(mob/living/carbon/human/source, mob/user) SIGNAL_HANDLER if(emageffect) return FALSE emageffect = TRUE if(user) - to_chat(user, span_notice("You tap [H] on the back with your card.")) - H.visible_message(span_danger("[H] starts flickering in an array of colors!")) - handle_emag(H) - addtimer(CALLBACK(src, PROC_REF(stop_emag), H), 2 MINUTES) //Disco mode for 2 minutes! This doesn't affect the ethereal at all besides either annoying some players, or making someone look badass. + to_chat(user, span_notice("You tap [source] on the back with your card.")) + source.visible_message(span_danger("[source] starts flickering in an array of colors!")) + handle_emag(source) + addtimer(CALLBACK(src, PROC_REF(stop_emag), source), 2 MINUTES) //Disco mode for 2 minutes! This doesn't affect the ethereal at all besides either annoying some players, or making someone look badass. return TRUE /// Special handling for getting hit with a light eater @@ -179,23 +181,22 @@ source.emp_act(EMP_LIGHT) return COMPONENT_BLOCK_LIGHT_EATER -/datum/species/ethereal/proc/stop_emp(mob/living/carbon/human/H) +/datum/species/ethereal/proc/stop_emp(mob/living/carbon/human/ethereal) EMPeffect = FALSE - spec_updatehealth(H) - to_chat(H, span_notice("You feel more energized as your shine comes back.")) - + refresh_light_color(ethereal) + to_chat(ethereal, span_notice("You feel more energized as your shine comes back.")) -/datum/species/ethereal/proc/handle_emag(mob/living/carbon/human/H) +/datum/species/ethereal/proc/handle_emag(mob/living/carbon/human/ethereal) if(!emageffect) return current_color = GLOB.color_list_ethereal[pick(GLOB.color_list_ethereal)] - spec_updatehealth(H) - addtimer(CALLBACK(src, PROC_REF(handle_emag), H), 5) //Call ourselves every 0.5 seconds to change color + refresh_light_color(ethereal) + addtimer(CALLBACK(src, PROC_REF(handle_emag), ethereal), 0.5 SECONDS) -/datum/species/ethereal/proc/stop_emag(mob/living/carbon/human/H) +/datum/species/ethereal/proc/stop_emag(mob/living/carbon/human/ethereal) emageffect = FALSE - spec_updatehealth(H) - H.visible_message(span_danger("[H] stops flickering and goes back to their normal state!")) + refresh_light_color(ethereal) + ethereal.visible_message(span_danger("[ethereal] stops flickering and goes back to their normal state!")) /datum/species/ethereal/get_features() var/list/features = ..() From 5e52651fc69bc04d1ab714401469101347925409 Mon Sep 17 00:00:00 2001 From: Yaroslav Nurkov <78199449+AnywayFarus@users.noreply.github.com> Date: Fri, 24 Nov 2023 00:06:47 +0300 Subject: [PATCH 44/72] Automatic changelog for PR #765 [ci skip] --- html/changelogs/AutoChangeLog-pr-765.yml | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-765.yml diff --git a/html/changelogs/AutoChangeLog-pr-765.yml b/html/changelogs/AutoChangeLog-pr-765.yml new file mode 100644 index 00000000000..b0dee4bb57a --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-765.yml @@ -0,0 +1,8 @@ +author: "Jacquerel" +delete-after: True +changes: + - bugfix: "The plasma river is about as deadly for animals as it is for humans." + - bugfix: "Golems can now wade in the plasma river unscathed." + - bugfix: "Undismemberable limbs will no longer be dismembered by the plasma river." + - balance: "Golems and plasmamen cannot become husked." + - image: "Robotic and Skeletal parts will remain distinct while the rest of the body is husked." \ No newline at end of file From f2961719f42aa08d7ed8bbda541d105dd98a80c4 Mon Sep 17 00:00:00 2001 From: Yaroslav Nurkov <78199449+AnywayFarus@users.noreply.github.com> Date: Fri, 24 Nov 2023 01:19:42 +0300 Subject: [PATCH 45/72] Automatic changelog for PR #766 [ci skip] --- html/changelogs/AutoChangeLog-pr-766.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-766.yml diff --git a/html/changelogs/AutoChangeLog-pr-766.yml b/html/changelogs/AutoChangeLog-pr-766.yml new file mode 100644 index 00000000000..5f68fc311e2 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-766.yml @@ -0,0 +1,4 @@ +author: "Melbert" +delete-after: True +changes: + - refactor: "Refactors how ethereals update their color when damaged." \ No newline at end of file From 495a38f8fbe4e068e797515d989e03aff1e42165 Mon Sep 17 00:00:00 2001 From: Changelogs Date: Fri, 24 Nov 2023 01:04:20 +0000 Subject: [PATCH 46/72] Automatic changelog compile [ci skip] --- html/changelogs/AutoChangeLog-pr-504.yml | 4 -- html/changelogs/AutoChangeLog-pr-764.yml | 8 ---- html/changelogs/AutoChangeLog-pr-765.yml | 8 ---- html/changelogs/AutoChangeLog-pr-766.yml | 4 -- html/changelogs/AutoChangeLog-pr-768.yml | 5 --- html/changelogs/AutoChangeLog-pr-769.yml | 4 -- html/changelogs/AutoChangeLog-pr-771.yml | 4 -- html/changelogs/AutoChangeLog-pr-772.yml | 4 -- html/changelogs/AutoChangeLog-pr-773.yml | 5 --- html/changelogs/AutoChangeLog-pr-784.yml | 4 -- html/changelogs/AutoChangeLog-pr-786.yml | 4 -- html/changelogs/AutoChangeLog-pr-787.yml | 4 -- html/changelogs/AutoChangeLog-pr-788.yml | 5 --- html/changelogs/AutoChangeLog-pr-790.yml | 4 -- html/changelogs/AutoChangeLog-pr-793.yml | 4 -- html/changelogs/AutoChangeLog-pr-794.yml | 4 -- html/changelogs/AutoChangeLog-pr-795.yml | 4 -- html/changelogs/archive/2023-11.yml | 55 ++++++++++++++++++++++++ 18 files changed, 55 insertions(+), 79 deletions(-) delete mode 100644 html/changelogs/AutoChangeLog-pr-504.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-764.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-765.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-766.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-768.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-769.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-771.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-772.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-773.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-784.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-786.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-787.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-788.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-790.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-793.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-794.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-795.yml diff --git a/html/changelogs/AutoChangeLog-pr-504.yml b/html/changelogs/AutoChangeLog-pr-504.yml deleted file mode 100644 index 2c3a0bcb2e3..00000000000 --- a/html/changelogs/AutoChangeLog-pr-504.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "LovliestPlant" -delete-after: True -changes: - - rscadd: "Adds links to any special rules or metaprotections to antag's objective panels." \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-764.yml b/html/changelogs/AutoChangeLog-pr-764.yml deleted file mode 100644 index 8a41e1c0adc..00000000000 --- a/html/changelogs/AutoChangeLog-pr-764.yml +++ /dev/null @@ -1,8 +0,0 @@ -author: "Melbert" -delete-after: True -changes: - - balance: "Transformation sting now lasts 8 minutes, down from permanent. However, the effect is paused for dead and stasis mobs, making it permanent SO LONG AS they stay dead or in stasis. The effect is also permanent if used on a monkey." - - balance: "Transformation sting now costs 33 chemicals, down from 50." - - balance: "Transformation sting now costs 2 dna points, down from 3." - - bugfix: "Transformation sting works on monkeys again." - - refactor: "Refactored a bit of human randomization." \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-765.yml b/html/changelogs/AutoChangeLog-pr-765.yml deleted file mode 100644 index b0dee4bb57a..00000000000 --- a/html/changelogs/AutoChangeLog-pr-765.yml +++ /dev/null @@ -1,8 +0,0 @@ -author: "Jacquerel" -delete-after: True -changes: - - bugfix: "The plasma river is about as deadly for animals as it is for humans." - - bugfix: "Golems can now wade in the plasma river unscathed." - - bugfix: "Undismemberable limbs will no longer be dismembered by the plasma river." - - balance: "Golems and plasmamen cannot become husked." - - image: "Robotic and Skeletal parts will remain distinct while the rest of the body is husked." \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-766.yml b/html/changelogs/AutoChangeLog-pr-766.yml deleted file mode 100644 index 5f68fc311e2..00000000000 --- a/html/changelogs/AutoChangeLog-pr-766.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "Melbert" -delete-after: True -changes: - - refactor: "Refactors how ethereals update their color when damaged." \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-768.yml b/html/changelogs/AutoChangeLog-pr-768.yml deleted file mode 100644 index 5cf1a7ecd62..00000000000 --- a/html/changelogs/AutoChangeLog-pr-768.yml +++ /dev/null @@ -1,5 +0,0 @@ -author: "SyncIt21" -delete-after: True -changes: - - bugfix: "autolathe does not diminish materials from custom material items like toolboxes when printing them in bulk. Also does not gray out that item in the UI" - - bugfix: "autloathe correctly updates UI after inserting items into it" \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-769.yml b/html/changelogs/AutoChangeLog-pr-769.yml deleted file mode 100644 index eb9509a7aa4..00000000000 --- a/html/changelogs/AutoChangeLog-pr-769.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "aaaa1023" -delete-after: True -changes: - - qol: "adds pixel perfect 4x, 4.5x, and 5x" \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-771.yml b/html/changelogs/AutoChangeLog-pr-771.yml deleted file mode 100644 index 0c02064c9b3..00000000000 --- a/html/changelogs/AutoChangeLog-pr-771.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "vinylspiders" -delete-after: True -changes: - - bugfix: "fullupgrade chem dispensers will now spawn with all their chems" \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-772.yml b/html/changelogs/AutoChangeLog-pr-772.yml deleted file mode 100644 index 07ed14a6044..00000000000 --- a/html/changelogs/AutoChangeLog-pr-772.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "lizardqueenlexi" -delete-after: True -changes: - - bugfix: "Skillsoft's skillchip stations are now ADA-compliant (Astronauts with Disabilities Act). Paraplegic characters can now implant themselves with skillchips, the same as anyone else." \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-773.yml b/html/changelogs/AutoChangeLog-pr-773.yml deleted file mode 100644 index 2b841d6dd8d..00000000000 --- a/html/changelogs/AutoChangeLog-pr-773.yml +++ /dev/null @@ -1,5 +0,0 @@ -author: "Y0SH1M4S73R" -delete-after: True -changes: - - rscadd: "Certain types of pens now function like you expect they would when inserted into a foam dart" - - qol: "Examining a foam dart closely will show you how to modify it, or what it is modified with" \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-784.yml b/html/changelogs/AutoChangeLog-pr-784.yml deleted file mode 100644 index 2d911e132c8..00000000000 --- a/html/changelogs/AutoChangeLog-pr-784.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "RatFromTheJungle" -delete-after: True -changes: - - bugfix: "fixes punches doing like triple stamina damage, by removing a 2.6x multiplier." \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-786.yml b/html/changelogs/AutoChangeLog-pr-786.yml deleted file mode 100644 index 9cb91ae6647..00000000000 --- a/html/changelogs/AutoChangeLog-pr-786.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "Nerev4r" -delete-after: True -changes: - - bugfix: "Chameleon mutation is toggleable again." \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-787.yml b/html/changelogs/AutoChangeLog-pr-787.yml deleted file mode 100644 index da74cef81fe..00000000000 --- a/html/changelogs/AutoChangeLog-pr-787.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "TwistedSilicon" -delete-after: True -changes: - - bugfix: "Window damage overlays have been fixed." \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-788.yml b/html/changelogs/AutoChangeLog-pr-788.yml deleted file mode 100644 index e9429200cfc..00000000000 --- a/html/changelogs/AutoChangeLog-pr-788.yml +++ /dev/null @@ -1,5 +0,0 @@ -author: "jjpark-kb" -delete-after: True -changes: - - rscadd: "you can craft the gutlunch trough" - - qol: "you can fill the gutlunch trough with a mining bag" \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-790.yml b/html/changelogs/AutoChangeLog-pr-790.yml deleted file mode 100644 index db441e24d90..00000000000 --- a/html/changelogs/AutoChangeLog-pr-790.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "Smol42" -delete-after: True -changes: - - rscadd: "Added four acrador snouts." \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-793.yml b/html/changelogs/AutoChangeLog-pr-793.yml deleted file mode 100644 index f375987f1c4..00000000000 --- a/html/changelogs/AutoChangeLog-pr-793.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "Xander3359" -delete-after: True -changes: - - admin: "Remove \"Make AI\" from VV dropdown" \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-794.yml b/html/changelogs/AutoChangeLog-pr-794.yml deleted file mode 100644 index 5575fc89378..00000000000 --- a/html/changelogs/AutoChangeLog-pr-794.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "SyncIt21" -delete-after: True -changes: - - bugfix: "RCD can build directional windows on top of existing grills & without them." \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-795.yml b/html/changelogs/AutoChangeLog-pr-795.yml deleted file mode 100644 index 01610a2bd18..00000000000 --- a/html/changelogs/AutoChangeLog-pr-795.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "jjpark-kb" -delete-after: True -changes: - - bugfix: "gutlunches now produce miner salve instead of milk, as well as the other reagents if fed the correct ore" \ No newline at end of file diff --git a/html/changelogs/archive/2023-11.yml b/html/changelogs/archive/2023-11.yml index 9764f72e362..2241ce8267d 100644 --- a/html/changelogs/archive/2023-11.yml +++ b/html/changelogs/archive/2023-11.yml @@ -1164,3 +1164,58 @@ - code_imp: 'The currently operating rust-g version on a live server is posted to places like the runtime.log, in the same place where the revision information and any applicable test merges already were. /:cl:' +2023-11-24: + Jacquerel: + - bugfix: The plasma river is about as deadly for animals as it is for humans. + - bugfix: Golems can now wade in the plasma river unscathed. + - bugfix: Undismemberable limbs will no longer be dismembered by the plasma river. + - balance: Golems and plasmamen cannot become husked. + - image: Robotic and Skeletal parts will remain distinct while the rest of the body + is husked. + LovliestPlant: + - rscadd: Adds links to any special rules or metaprotections to antag's objective + panels. + Melbert: + - balance: Transformation sting now lasts 8 minutes, down from permanent. However, + the effect is paused for dead and stasis mobs, making it permanent SO LONG AS + they stay dead or in stasis. The effect is also permanent if used on a monkey. + - balance: Transformation sting now costs 33 chemicals, down from 50. + - balance: Transformation sting now costs 2 dna points, down from 3. + - bugfix: Transformation sting works on monkeys again. + - refactor: Refactored a bit of human randomization. + - refactor: Refactors how ethereals update their color when damaged. + Nerev4r: + - bugfix: Chameleon mutation is toggleable again. + RatFromTheJungle: + - bugfix: fixes punches doing like triple stamina damage, by removing a 2.6x multiplier. + Smol42: + - rscadd: Added four acrador snouts. + SyncIt21: + - bugfix: autolathe does not diminish materials from custom material items like + toolboxes when printing them in bulk. Also does not gray out that item in the + UI + - bugfix: autloathe correctly updates UI after inserting items into it + - bugfix: RCD can build directional windows on top of existing grills & without + them. + TwistedSilicon: + - bugfix: Window damage overlays have been fixed. + Xander3359: + - admin: Remove "Make AI" from VV dropdown + Y0SH1M4S73R: + - rscadd: Certain types of pens now function like you expect they would when inserted + into a foam dart + - qol: Examining a foam dart closely will show you how to modify it, or what it + is modified with + aaaa1023: + - qol: adds pixel perfect 4x, 4.5x, and 5x + jjpark-kb: + - bugfix: gutlunches now produce miner salve instead of milk, as well as the other + reagents if fed the correct ore + - rscadd: you can craft the gutlunch trough + - qol: you can fill the gutlunch trough with a mining bag + lizardqueenlexi: + - bugfix: Skillsoft's skillchip stations are now ADA-compliant (Astronauts with + Disabilities Act). Paraplegic characters can now implant themselves with skillchips, + the same as anyone else. + vinylspiders: + - bugfix: fullupgrade chem dispensers will now spawn with all their chems From bd0c91bbb4c376aaa9d422b56733bf0511ea90ad Mon Sep 17 00:00:00 2001 From: Iajret Creature <122297233+Steals-The-PRs@users.noreply.github.com> Date: Fri, 24 Nov 2023 11:45:14 +0300 Subject: [PATCH 47/72] [MIRROR] Converts more js files to jsx [MDB IGNORE] (#807) * Converts more js files to jsx (#79894) --------- Co-authored-by: SkyratBot <59378654+SkyratBot@users.noreply.github.com> Co-authored-by: Jeremiah <42397676+jlsnow301@users.noreply.github.com> --- tgui/packages/tgui-panel/chat/{renderer.js => renderer.jsx} | 2 +- tgui/packages/tgui-panel/{index.js => index.jsx} | 0 .../tgui/stories/{Blink.stories.js => Blink.stories.jsx} | 0 .../stories/{BlockQuote.stories.js => BlockQuote.stories.jsx} | 0 tgui/packages/tgui/stories/{Box.stories.js => Box.stories.jsx} | 0 .../tgui/stories/{Button.stories.js => Button.stories.jsx} | 0 .../tgui/stories/{ByondUi.stories.js => ByondUi.stories.jsx} | 0 .../stories/{Collapsible.stories.js => Collapsible.stories.jsx} | 0 .../packages/tgui/stories/{Flex.stories.js => Flex.stories.jsx} | 0 .../tgui/stories/{Input.stories.js => Input.stories.jsx} | 0 .../stories/{LabeledList.stories.js => LabeledList.stories.jsx} | 0 .../tgui/stories/{Popper.stories.js => Popper.stories.jsx} | 0 .../stories/{ProgressBar.stories.js => ProgressBar.stories.jsx} | 0 .../tgui/stories/{Stack.stories.js => Stack.stories.jsx} | 0 .../tgui/stories/{Storage.stories.js => Storage.stories.jsx} | 0 .../packages/tgui/stories/{Tabs.stories.js => Tabs.stories.jsx} | 0 .../tgui/stories/{Themes.stories.js => Themes.stories.jsx} | 0 .../tgui/stories/{Tooltip.stories.js => Tooltip.stories.jsx} | 0 tgui/packages/tgui/stories/{common.js => common.jsx} | 0 19 files changed, 1 insertion(+), 1 deletion(-) rename tgui/packages/tgui-panel/chat/{renderer.js => renderer.jsx} (99%) rename tgui/packages/tgui-panel/{index.js => index.jsx} (100%) rename tgui/packages/tgui/stories/{Blink.stories.js => Blink.stories.jsx} (100%) rename tgui/packages/tgui/stories/{BlockQuote.stories.js => BlockQuote.stories.jsx} (100%) rename tgui/packages/tgui/stories/{Box.stories.js => Box.stories.jsx} (100%) rename tgui/packages/tgui/stories/{Button.stories.js => Button.stories.jsx} (100%) rename tgui/packages/tgui/stories/{ByondUi.stories.js => ByondUi.stories.jsx} (100%) rename tgui/packages/tgui/stories/{Collapsible.stories.js => Collapsible.stories.jsx} (100%) rename tgui/packages/tgui/stories/{Flex.stories.js => Flex.stories.jsx} (100%) rename tgui/packages/tgui/stories/{Input.stories.js => Input.stories.jsx} (100%) rename tgui/packages/tgui/stories/{LabeledList.stories.js => LabeledList.stories.jsx} (100%) rename tgui/packages/tgui/stories/{Popper.stories.js => Popper.stories.jsx} (100%) rename tgui/packages/tgui/stories/{ProgressBar.stories.js => ProgressBar.stories.jsx} (100%) rename tgui/packages/tgui/stories/{Stack.stories.js => Stack.stories.jsx} (100%) rename tgui/packages/tgui/stories/{Storage.stories.js => Storage.stories.jsx} (100%) rename tgui/packages/tgui/stories/{Tabs.stories.js => Tabs.stories.jsx} (100%) rename tgui/packages/tgui/stories/{Themes.stories.js => Themes.stories.jsx} (100%) rename tgui/packages/tgui/stories/{Tooltip.stories.js => Tooltip.stories.jsx} (100%) rename tgui/packages/tgui/stories/{common.js => common.jsx} (100%) diff --git a/tgui/packages/tgui-panel/chat/renderer.js b/tgui/packages/tgui-panel/chat/renderer.jsx similarity index 99% rename from tgui/packages/tgui-panel/chat/renderer.js rename to tgui/packages/tgui-panel/chat/renderer.jsx index 7a528cd4fd7..5d6337148fb 100644 --- a/tgui/packages/tgui-panel/chat/renderer.js +++ b/tgui/packages/tgui-panel/chat/renderer.jsx @@ -11,7 +11,7 @@ import { COMBINE_MAX_MESSAGES, COMBINE_MAX_TIME_WINDOW, IMAGE_RETRY_DELAY, IMAGE import { render } from 'inferno'; import { canPageAcceptType, createMessage, isSameMessage } from './model'; import { highlightNode, linkifyNode } from './replaceInTextNode'; -import { Tooltip } from '../../tgui/components'; +import { Tooltip } from 'tgui/components'; const logger = createLogger('chatRenderer'); diff --git a/tgui/packages/tgui-panel/index.js b/tgui/packages/tgui-panel/index.jsx similarity index 100% rename from tgui/packages/tgui-panel/index.js rename to tgui/packages/tgui-panel/index.jsx diff --git a/tgui/packages/tgui/stories/Blink.stories.js b/tgui/packages/tgui/stories/Blink.stories.jsx similarity index 100% rename from tgui/packages/tgui/stories/Blink.stories.js rename to tgui/packages/tgui/stories/Blink.stories.jsx diff --git a/tgui/packages/tgui/stories/BlockQuote.stories.js b/tgui/packages/tgui/stories/BlockQuote.stories.jsx similarity index 100% rename from tgui/packages/tgui/stories/BlockQuote.stories.js rename to tgui/packages/tgui/stories/BlockQuote.stories.jsx diff --git a/tgui/packages/tgui/stories/Box.stories.js b/tgui/packages/tgui/stories/Box.stories.jsx similarity index 100% rename from tgui/packages/tgui/stories/Box.stories.js rename to tgui/packages/tgui/stories/Box.stories.jsx diff --git a/tgui/packages/tgui/stories/Button.stories.js b/tgui/packages/tgui/stories/Button.stories.jsx similarity index 100% rename from tgui/packages/tgui/stories/Button.stories.js rename to tgui/packages/tgui/stories/Button.stories.jsx diff --git a/tgui/packages/tgui/stories/ByondUi.stories.js b/tgui/packages/tgui/stories/ByondUi.stories.jsx similarity index 100% rename from tgui/packages/tgui/stories/ByondUi.stories.js rename to tgui/packages/tgui/stories/ByondUi.stories.jsx diff --git a/tgui/packages/tgui/stories/Collapsible.stories.js b/tgui/packages/tgui/stories/Collapsible.stories.jsx similarity index 100% rename from tgui/packages/tgui/stories/Collapsible.stories.js rename to tgui/packages/tgui/stories/Collapsible.stories.jsx diff --git a/tgui/packages/tgui/stories/Flex.stories.js b/tgui/packages/tgui/stories/Flex.stories.jsx similarity index 100% rename from tgui/packages/tgui/stories/Flex.stories.js rename to tgui/packages/tgui/stories/Flex.stories.jsx diff --git a/tgui/packages/tgui/stories/Input.stories.js b/tgui/packages/tgui/stories/Input.stories.jsx similarity index 100% rename from tgui/packages/tgui/stories/Input.stories.js rename to tgui/packages/tgui/stories/Input.stories.jsx diff --git a/tgui/packages/tgui/stories/LabeledList.stories.js b/tgui/packages/tgui/stories/LabeledList.stories.jsx similarity index 100% rename from tgui/packages/tgui/stories/LabeledList.stories.js rename to tgui/packages/tgui/stories/LabeledList.stories.jsx diff --git a/tgui/packages/tgui/stories/Popper.stories.js b/tgui/packages/tgui/stories/Popper.stories.jsx similarity index 100% rename from tgui/packages/tgui/stories/Popper.stories.js rename to tgui/packages/tgui/stories/Popper.stories.jsx diff --git a/tgui/packages/tgui/stories/ProgressBar.stories.js b/tgui/packages/tgui/stories/ProgressBar.stories.jsx similarity index 100% rename from tgui/packages/tgui/stories/ProgressBar.stories.js rename to tgui/packages/tgui/stories/ProgressBar.stories.jsx diff --git a/tgui/packages/tgui/stories/Stack.stories.js b/tgui/packages/tgui/stories/Stack.stories.jsx similarity index 100% rename from tgui/packages/tgui/stories/Stack.stories.js rename to tgui/packages/tgui/stories/Stack.stories.jsx diff --git a/tgui/packages/tgui/stories/Storage.stories.js b/tgui/packages/tgui/stories/Storage.stories.jsx similarity index 100% rename from tgui/packages/tgui/stories/Storage.stories.js rename to tgui/packages/tgui/stories/Storage.stories.jsx diff --git a/tgui/packages/tgui/stories/Tabs.stories.js b/tgui/packages/tgui/stories/Tabs.stories.jsx similarity index 100% rename from tgui/packages/tgui/stories/Tabs.stories.js rename to tgui/packages/tgui/stories/Tabs.stories.jsx diff --git a/tgui/packages/tgui/stories/Themes.stories.js b/tgui/packages/tgui/stories/Themes.stories.jsx similarity index 100% rename from tgui/packages/tgui/stories/Themes.stories.js rename to tgui/packages/tgui/stories/Themes.stories.jsx diff --git a/tgui/packages/tgui/stories/Tooltip.stories.js b/tgui/packages/tgui/stories/Tooltip.stories.jsx similarity index 100% rename from tgui/packages/tgui/stories/Tooltip.stories.js rename to tgui/packages/tgui/stories/Tooltip.stories.jsx diff --git a/tgui/packages/tgui/stories/common.js b/tgui/packages/tgui/stories/common.jsx similarity index 100% rename from tgui/packages/tgui/stories/common.js rename to tgui/packages/tgui/stories/common.jsx From 8718b689b10d41dad315508e973ee10efe6beaee Mon Sep 17 00:00:00 2001 From: Iajret Creature <122297233+Steals-The-PRs@users.noreply.github.com> Date: Fri, 24 Nov 2023 12:06:10 +0300 Subject: [PATCH 48/72] [MIRROR] Adds INTJ skillchip [MDB IGNORE] (#803) * Adds INTJ skillchip (#79902) --------- Co-authored-by: SkyratBot <59378654+SkyratBot@users.noreply.github.com> Co-authored-by: Jacquerel --- code/__DEFINES/traits/declarations.dm | 3 +++ code/_globalvars/lists/maintenance_loot.dm | 1 + code/_globalvars/traits/_traits.dm | 1 + code/datums/components/food/edible.dm | 10 ++++++++++ code/modules/library/skill_learning/skillchip.dm | 9 +++++++++ code/modules/mob/living/brain/brain_item.dm | 1 + .../living/carbon/human/species_types/abductors.dm | 11 ++++++----- code/modules/power/supermatter/supermatter.dm | 11 +++++++++-- code/modules/reagents/reagent_containers.dm | 5 ++++- code/modules/vending/games.dm | 3 ++- 10 files changed, 46 insertions(+), 9 deletions(-) diff --git a/code/__DEFINES/traits/declarations.dm b/code/__DEFINES/traits/declarations.dm index bb0a65fc5d2..bd63f013f85 100644 --- a/code/__DEFINES/traits/declarations.dm +++ b/code/__DEFINES/traits/declarations.dm @@ -212,6 +212,9 @@ Remember to update _globalvars/traits.dm if you're adding/removing/renaming trai ///Added to mob or mind, changes the icons of the fish shown in the minigame UI depending on the possible reward. #define TRAIT_REVEAL_FISH "reveal_fish" +/// Added to a mob, allows that mob to experience flavour-based moodlets when examining food +#define TRAIT_REMOTE_TASTING "remote_tasting" + /// Stops the mob from slipping on water, or banana peels, or pretty much anything that doesn't have [GALOSHES_DONT_HELP] set #define TRAIT_NO_SLIP_WATER "noslip_water" /// Stops the mob from slipping on permafrost ice (not any other ice) (but anything with [SLIDE_ICE] set) diff --git a/code/_globalvars/lists/maintenance_loot.dm b/code/_globalvars/lists/maintenance_loot.dm index a54799b7bb1..05aa4e419a2 100644 --- a/code/_globalvars/lists/maintenance_loot.dm +++ b/code/_globalvars/lists/maintenance_loot.dm @@ -351,6 +351,7 @@ GLOBAL_LIST_INIT(rarity_loot, list(//rare: really good items /obj/item/disk/nuclear/fake = 1, /obj/item/disk/surgery/advanced_plastic_surgery = 1, /obj/item/skillchip/brainwashing = 1, + /obj/item/skillchip/intj = 1, /obj/item/tattoo_kit = 1, /obj/item/folder/ancient_paperwork = 1, ) = 1, diff --git a/code/_globalvars/traits/_traits.dm b/code/_globalvars/traits/_traits.dm index 7ec768e619a..8d445921fff 100644 --- a/code/_globalvars/traits/_traits.dm +++ b/code/_globalvars/traits/_traits.dm @@ -351,6 +351,7 @@ GLOBAL_LIST_INIT(traits_by_type, list( "TRAIT_REAGENT_SCANNER" = TRAIT_REAGENT_SCANNER, "TRAIT_RECENTLY_BLOCKED_MAGIC" = TRAIT_RECENTLY_BLOCKED_MAGIC, "TRAIT_RELAYING_ATTACKER" = TRAIT_RELAYING_ATTACKER, + "TRAIT_REMOTE_TASTING" = TRAIT_REMOTE_TASTING, "TRAIT_RESEARCH_SCANNER" = TRAIT_RESEARCH_SCANNER, "TRAIT_RESISTCOLD" = TRAIT_RESISTCOLD, "TRAIT_RESISTHEAT" = TRAIT_RESISTHEAT, diff --git a/code/datums/components/food/edible.dm b/code/datums/components/food/edible.dm index 1e724f0e404..9986b2a4d43 100644 --- a/code/datums/components/food/edible.dm +++ b/code/datums/components/food/edible.dm @@ -264,6 +264,16 @@ Behavior that's still missing from this component that original food items had t for(var/datum/reagent/reagent as anything in owner.reagents.reagent_list) examine_list += span_notice("- [reagent.name] [reagent.volume]u: [round(reagent.purity * 100)]% pure") + if(!HAS_TRAIT(user, TRAIT_REMOTE_TASTING)) + return + var/fraction = min(bite_consumption / owner.reagents.total_volume, 1) + checkLiked(fraction, user) + if (!owner.reagents.get_reagent_amount(/datum/reagent/consumable/salt)) + examine_list += span_notice("It could use a little more Sodium Chloride...") + if (isliving(user)) + var/mob/living/living_user = user + living_user.taste(owner.reagents) + /datum/component/edible/proc/UseFromHand(obj/item/source, mob/living/M, mob/living/user) SIGNAL_HANDLER diff --git a/code/modules/library/skill_learning/skillchip.dm b/code/modules/library/skill_learning/skillchip.dm index 762e8e0162c..89822976993 100644 --- a/code/modules/library/skill_learning/skillchip.dm +++ b/code/modules/library/skill_learning/skillchip.dm @@ -498,4 +498,13 @@ activate_message = span_notice("You feel the knowledge and passion of several sunbaked, seasoned fishermen burn within you.") deactivate_message = span_notice("You no longer feel like casting a fishing rod by the sunny riverside.") +/obj/item/skillchip/intj + name = "Integrated Intuitive Thinking and Judging skillchip" + auto_traits = list(TRAIT_REMOTE_TASTING) + skill_name = "Mental Flavour Calculus" + skill_description = "When examining food, you can experience the flavours just as well as if you were eating it." + skill_icon = FA_ICON_DRUMSTICK_BITE + activate_message = span_notice("You think of your favourite food and realise that you can rotate its flavour in your mind.") + deactivate_message = span_notice("You feel your food-based mind palace crumbling...") + #undef SKILLCHIP_CATEGORY_GENERAL diff --git a/code/modules/mob/living/brain/brain_item.dm b/code/modules/mob/living/brain/brain_item.dm index 9d54d95516d..8f29a7d2be7 100644 --- a/code/modules/mob/living/brain/brain_item.dm +++ b/code/modules/mob/living/brain/brain_item.dm @@ -433,6 +433,7 @@ desc = "A piece of juicy meat found in an ayy lmao's head." icon_state = "brain-x" brain_size = 1.3 + organ_traits = list(TRAIT_ADVANCEDTOOLUSER, TRAIT_CAN_STRIP, TRAIT_LITERATE, TRAIT_REMOTE_TASTING) ////////////////////////////////////TRAUMAS//////////////////////////////////////// diff --git a/code/modules/mob/living/carbon/human/species_types/abductors.dm b/code/modules/mob/living/carbon/human/species_types/abductors.dm index 345e30264ba..74d2bedf3a7 100644 --- a/code/modules/mob/living/carbon/human/species_types/abductors.dm +++ b/code/modules/mob/living/carbon/human/species_types/abductors.dm @@ -3,14 +3,15 @@ id = SPECIES_ABDUCTOR sexes = FALSE inherent_traits = list( - TRAIT_NO_UNDERWEAR, + TRAIT_CHUNKYFINGERS_IGNORE_BATON, + TRAIT_NEVER_WOUNDED, + TRAIT_NOBLOOD, TRAIT_NOBREATH, + TRAIT_NODISMEMBER, TRAIT_NOHUNGER, + TRAIT_NO_UNDERWEAR, + TRAIT_REMOTE_TASTING, TRAIT_VIRUSIMMUNE, - TRAIT_NOBLOOD, - TRAIT_CHUNKYFINGERS_IGNORE_BATON, - TRAIT_NODISMEMBER, - TRAIT_NEVER_WOUNDED ) mutanttongue = /obj/item/organ/internal/tongue/abductor mutantstomach = null diff --git a/code/modules/power/supermatter/supermatter.dm b/code/modules/power/supermatter/supermatter.dm index 580d2a66f96..c38036e6eab 100644 --- a/code/modules/power/supermatter/supermatter.dm +++ b/code/modules/power/supermatter/supermatter.dm @@ -243,8 +243,15 @@ GLOBAL_DATUM(main_supermatter_engine, /obj/machinery/power/supermatter_crystal) /obj/machinery/power/supermatter_crystal/examine(mob/user) . = ..() var/immune = HAS_MIND_TRAIT(user, TRAIT_MADNESS_IMMUNE) - if(isliving(user) && !immune && (get_dist(user, src) < SM_HALLUCINATION_RANGE(internal_energy))) - . += span_danger("You get headaches just from looking at it.") + if(isliving(user)) + if (!immune && (get_dist(user, src) < SM_HALLUCINATION_RANGE(internal_energy))) + . += span_danger("You get headaches just from looking at it.") + var/mob/living/living_user = user + if (HAS_TRAIT(user, TRAIT_REMOTE_TASTING)) + to_chat(user, span_warning("The taste is overwhelming and indescribable!")) + living_user.electrocute_act(shock_damage = 15, source = src, flags = SHOCK_KNOCKDOWN | SHOCK_NOGLOVES) + . += span_notice("It could use a little more Sodium Chloride...") + . += delamination_strategy.examine(src) return . diff --git a/code/modules/reagents/reagent_containers.dm b/code/modules/reagents/reagent_containers.dm index 5234018bbd9..d58df6a1d6b 100644 --- a/code/modules/reagents/reagent_containers.dm +++ b/code/modules/reagents/reagent_containers.dm @@ -61,13 +61,16 @@ reagents.add_reagent(/datum/reagent/blood, disease_amount, data) add_initial_reagents() -/obj/item/reagent_containers/examine() +/obj/item/reagent_containers/examine(mob/user) . = ..() if(has_variable_transfer_amount) if(possible_transfer_amounts.len > 1) . += span_notice("Left-click or right-click in-hand to increase or decrease its transfer amount.") else if(possible_transfer_amounts.len) . += span_notice("Left-click or right-click in-hand to view its transfer amount.") + if(isliving(user) && HAS_TRAIT(user, TRAIT_REMOTE_TASTING)) + var/mob/living/living_user = user + living_user.taste(reagents) /obj/item/reagent_containers/create_reagents(max_vol, flags) . = ..() diff --git a/code/modules/vending/games.dm b/code/modules/vending/games.dm index e51205c00e4..5e3d9d3b055 100644 --- a/code/modules/vending/games.dm +++ b/code/modules/vending/games.dm @@ -52,11 +52,12 @@ /obj/item/skillchip/appraiser = 2, /obj/item/skillchip/basketweaving = 2, /obj/item/skillchip/bonsai = 2, + /obj/item/skillchip/intj = 2, /obj/item/skillchip/light_remover = 2, + /obj/item/skillchip/master_angler = 2, /obj/item/skillchip/sabrage = 2, /obj/item/skillchip/useless_adapter = 5, /obj/item/skillchip/wine_taster = 2, - /obj/item/skillchip/master_angler = 2, ), ), list( From 0bfb17ff21ae080c22bc46a5e282a8f8df25812b Mon Sep 17 00:00:00 2001 From: Yaroslav Nurkov <78199449+AnywayFarus@users.noreply.github.com> Date: Fri, 24 Nov 2023 12:06:36 +0300 Subject: [PATCH 49/72] Automatic changelog for PR #803 [ci skip] --- html/changelogs/AutoChangeLog-pr-803.yml | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-803.yml diff --git a/html/changelogs/AutoChangeLog-pr-803.yml b/html/changelogs/AutoChangeLog-pr-803.yml new file mode 100644 index 00000000000..ce9dc0871e8 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-803.yml @@ -0,0 +1,5 @@ +author: "Jacquerel" +delete-after: True +changes: + - rscadd: "A new skill chip can be found in maintenance or purchased from the vendor, allowing you to experience food in new and exciting ways." + - rscadd: "Abductors also have access to this incredible power, simply using their genius level brains." \ No newline at end of file From 2f00a6964861f5b1e231c4d0c8e4f5f65960506f Mon Sep 17 00:00:00 2001 From: Iajret Creature <122297233+Steals-The-PRs@users.noreply.github.com> Date: Fri, 24 Nov 2023 12:06:59 +0300 Subject: [PATCH 50/72] [MIRROR] Android doesn't need epipen [MDB IGNORE] (#767) * Android doesn't need epipen * Merge Master, Resolve conflict --------- Co-authored-by: SkyratBot <59378654+SkyratBot@users.noreply.github.com> Co-authored-by: Xackii <120736708+Xackii@users.noreply.github.com> Co-authored-by: SomeRandomOwl <2568378+SomeRandomOwl@users.noreply.github.com> Co-authored-by: Iajret --- code/__DEFINES/traits/declarations.dm | 2 ++ code/_globalvars/traits/_traits.dm | 1 + code/modules/mob/living/carbon/human/_species.dm | 2 +- code/modules/mob/living/carbon/human/species_types/android.dm | 1 + code/modules/reagents/chemistry/holder.dm | 2 +- 5 files changed, 6 insertions(+), 2 deletions(-) diff --git a/code/__DEFINES/traits/declarations.dm b/code/__DEFINES/traits/declarations.dm index bd63f013f85..98a8df19b7c 100644 --- a/code/__DEFINES/traits/declarations.dm +++ b/code/__DEFINES/traits/declarations.dm @@ -164,6 +164,8 @@ Remember to update _globalvars/traits.dm if you're adding/removing/renaming trai #define TRAIT_NOBLOOD "noblood" /// This just means that the carbon will always have functional liverless metabolism #define TRAIT_LIVERLESS_METABOLISM "liverless_metabolism" +/// This carbon can't be overdosed by chems +#define TRAIT_OVERDOSEIMMUNE "overdose_immune" /// Humans with this trait cannot be turned into zombies #define TRAIT_NO_ZOMBIFY "no_zombify" /// Carbons with this trait can't have their DNA copied by diseases nor changelings diff --git a/code/_globalvars/traits/_traits.dm b/code/_globalvars/traits/_traits.dm index 8d445921fff..3d45a9b78bd 100644 --- a/code/_globalvars/traits/_traits.dm +++ b/code/_globalvars/traits/_traits.dm @@ -320,6 +320,7 @@ GLOBAL_LIST_INIT(traits_by_type, list( "TRAIT_NUKEIMMUNE" = TRAIT_NUKEIMMUNE, "TRAIT_OIL_FRIED" = TRAIT_OIL_FRIED, "TRAIT_ORBITING_FORBIDDEN" = TRAIT_ORBITING_FORBIDDEN, + "TRAIT_OVERDOSEIMMUNE" = TRAIT_OVERDOSEIMMUNE, "TRAIT_OVERWATCH_IMMUNE" = TRAIT_OVERWATCH_IMMUNE, "TRAIT_OVERWATCHED" = TRAIT_OVERWATCHED, "TRAIT_PACIFISM" = TRAIT_PACIFISM, diff --git a/code/modules/mob/living/carbon/human/_species.dm b/code/modules/mob/living/carbon/human/_species.dm index 2d4518bd034..48956982eb1 100644 --- a/code/modules/mob/living/carbon/human/_species.dm +++ b/code/modules/mob/living/carbon/human/_species.dm @@ -1068,7 +1068,7 @@ GLOBAL_LIST_EMPTY(features_by_species) affected.blood_volume = min(affected.blood_volume + round(chem.volume, 0.1), BLOOD_VOLUME_MAXIMUM) affected.reagents.del_reagent(chem.type) return COMSIG_MOB_STOP_REAGENT_CHECK - if(!chem.overdosed && chem.overdose_threshold && chem.volume >= chem.overdose_threshold) + if(!chem.overdosed && chem.overdose_threshold && chem.volume >= chem.overdose_threshold && !HAS_TRAIT(affected, TRAIT_OVERDOSEIMMUNE)) chem.overdosed = TRUE chem.overdose_start(affected) affected.log_message("has started overdosing on [chem.name] at [chem.volume] units.", LOG_GAME) diff --git a/code/modules/mob/living/carbon/human/species_types/android.dm b/code/modules/mob/living/carbon/human/species_types/android.dm index dec4fd9e306..5988ad3b890 100644 --- a/code/modules/mob/living/carbon/human/species_types/android.dm +++ b/code/modules/mob/living/carbon/human/species_types/android.dm @@ -15,6 +15,7 @@ TRAIT_NO_DNA_COPY, TRAIT_NO_PLASMA_TRANSFORM, TRAIT_NO_UNDERWEAR, + TRAIT_OVERDOSEIMMUNE, TRAIT_PIERCEIMMUNE, TRAIT_RADIMMUNE, TRAIT_RESISTCOLD, diff --git a/code/modules/reagents/chemistry/holder.dm b/code/modules/reagents/chemistry/holder.dm index 20d4da62f2b..5f9d7f81995 100644 --- a/code/modules/reagents/chemistry/holder.dm +++ b/code/modules/reagents/chemistry/holder.dm @@ -765,7 +765,7 @@ if(!reagent.metabolizing) reagent.metabolizing = TRUE reagent.on_mob_metabolize(owner) - if(can_overdose) + if(can_overdose && !HAS_TRAIT(owner, TRAIT_OVERDOSEIMMUNE)) if(reagent.overdose_threshold) if(reagent.volume >= reagent.overdose_threshold && !reagent.overdosed) reagent.overdosed = TRUE From 4b3b976534da632d6750109e16c477f1bdc59595 Mon Sep 17 00:00:00 2001 From: Yaroslav Nurkov <78199449+AnywayFarus@users.noreply.github.com> Date: Fri, 24 Nov 2023 12:07:22 +0300 Subject: [PATCH 51/72] Automatic changelog for PR #767 [ci skip] --- html/changelogs/AutoChangeLog-pr-767.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-767.yml diff --git a/html/changelogs/AutoChangeLog-pr-767.yml b/html/changelogs/AutoChangeLog-pr-767.yml new file mode 100644 index 00000000000..cbdde26ed49 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-767.yml @@ -0,0 +1,4 @@ +author: "Steals-The-PRs" +delete-after: True +changes: + - bugfix: "Androids cannot have overdose effect by any chems." \ No newline at end of file From 0534ce0d8641b2b21abac4d679c84ffbde8f1f6d Mon Sep 17 00:00:00 2001 From: Iajret Creature <122297233+Steals-The-PRs@users.noreply.github.com> Date: Fri, 24 Nov 2023 12:07:49 +0300 Subject: [PATCH 52/72] [MIRROR] Fix refresh button in log viewer [MDB IGNORE] (#775) * Fix refresh button in log viewer (#79520) --------- Co-authored-by: SkyratBot <59378654+SkyratBot@users.noreply.github.com> Co-authored-by: vvvv-vvvv <136390975+vvvv-vvvv@users.noreply.github.com> Co-authored-by: Bloop <13398309+vinylspiders@users.noreply.github.com> Co-authored-by: Iajret --- code/game/world.dm | 2 +- code/modules/logging/log_holder.dm | 9 +++------ 2 files changed, 4 insertions(+), 7 deletions(-) diff --git a/code/game/world.dm b/code/game/world.dm index de638624319..99cffb74ad2 100644 --- a/code/game/world.dm +++ b/code/game/world.dm @@ -190,7 +190,7 @@ GLOBAL_VAR(restart_counter) data["tick_usage"] = world.tick_usage data["tick_lag"] = world.tick_lag data["time"] = world.time - data["timestamp"] = logger.unix_timestamp_string() + data["timestamp"] = rustg_unix_timestamp() return data /world/proc/SetupLogs() diff --git a/code/modules/logging/log_holder.dm b/code/modules/logging/log_holder.dm index 7d8386e77b6..1cea0e554be 100644 --- a/code/modules/logging/log_holder.dm +++ b/code/modules/logging/log_holder.dm @@ -107,7 +107,7 @@ GENERAL_PROTECT_DATUM(/datum/log_holder) return switch(action) - if("re-render") + if("refresh") cache_ui_data() SStgui.update_uis(src) return TRUE @@ -121,7 +121,7 @@ GENERAL_PROTECT_DATUM(/datum/log_holder) CRASH("Attempted to call init_logging twice!") round_id = GLOB.round_id - logging_start_timestamp = unix_timestamp_string() + logging_start_timestamp = rustg_unix_timestamp() log_categories = list() disabled_categories = list() @@ -243,13 +243,10 @@ GENERAL_PROTECT_DATUM(/datum/log_holder) if(human_readable_enabled) rustg_file_write("\[[human_readable_timestamp()]\] Starting up round ID [round_id].\n - -------------------------\n", category_instance.get_output_file(null, "log")) -/datum/log_holder/proc/unix_timestamp_string() // pending change to rust-g - return RUSTG_CALL(RUST_G, "unix_timestamp")() - /datum/log_holder/proc/human_readable_timestamp(precision = 3) var/start = time2text(world.timeofday, "YYYY-MM-DD hh:mm:ss") // now we grab the millis from the rustg timestamp - var/rustg_stamp = unix_timestamp_string() + var/rustg_stamp = rustg_unix_timestamp() var/list/timestamp = splittext(rustg_stamp, ".") #ifdef UNIT_TESTS if(length(timestamp) != 2) From 7afb32e901652f2c9730f39c246cb861e1656712 Mon Sep 17 00:00:00 2001 From: Yaroslav Nurkov <78199449+AnywayFarus@users.noreply.github.com> Date: Fri, 24 Nov 2023 12:19:32 +0300 Subject: [PATCH 53/72] Automatic changelog for PR #775 [ci skip] --- html/changelogs/AutoChangeLog-pr-775.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-775.yml diff --git a/html/changelogs/AutoChangeLog-pr-775.yml b/html/changelogs/AutoChangeLog-pr-775.yml new file mode 100644 index 00000000000..c585c229470 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-775.yml @@ -0,0 +1,4 @@ +author: "vvvv-vvvv" +delete-after: True +changes: + - bugfix: "Fix refresh button in log viewer" \ No newline at end of file From 1e1afd86c76df859b9cb02aa53c00d335519ee42 Mon Sep 17 00:00:00 2001 From: Iajret Creature <122297233+Steals-The-PRs@users.noreply.github.com> Date: Fri, 24 Nov 2023 12:42:20 +0300 Subject: [PATCH 54/72] hammerable glass shards (for sand) (#782) * hammerable glass shards (for sand) * good point, zero points * Update modular_skyrat/modules/primitive_production/code/misc.dm * color and no meshing this sand --------- Co-authored-by: jjpark-kb <55967837+jjpark-kb@users.noreply.github.com> Co-authored-by: Bloop <13398309+vinylspiders@users.noreply.github.com> --- .../ashwalkers/code/items/ash_seedmesh.dm | 15 ++++---- .../modules/primitive_production/code/misc.dm | 35 +++++++++++++++++++ .../research/xenoarch/xenoarch_tool.dm | 1 + tgstation.dme | 1 + 4 files changed, 46 insertions(+), 6 deletions(-) create mode 100644 modular_skyrat/modules/primitive_production/code/misc.dm diff --git a/modular_skyrat/modules/ashwalkers/code/items/ash_seedmesh.dm b/modular_skyrat/modules/ashwalkers/code/items/ash_seedmesh.dm index a0882c288a1..205e357313e 100644 --- a/modular_skyrat/modules/ashwalkers/code/items/ash_seedmesh.dm +++ b/modular_skyrat/modules/ashwalkers/code/items/ash_seedmesh.dm @@ -9,23 +9,26 @@ /obj/item/seed_mesh/attackby(obj/item/attacking_item, mob/user, params) if(istype(attacking_item, /obj/item/stack/ore/glass)) - var/obj/item/stack/stack_item = attacking_item + var/obj/item/stack/ore/ore_item = attacking_item + if(ore_item.points == 0) + user.balloon_alert(user, "[ore_item] is worthless!") + return - while(stack_item.amount >= 5) + while(ore_item.amount >= 5) if(!do_after(user, 5 SECONDS, src)) user.balloon_alert(user, "have to stand still!") return - if(!stack_item.use(5)) - user.balloon_alert(user, "unable to use five of [stack_item]!") + if(!ore_item.use(5)) + user.balloon_alert(user, "unable to use five of [ore_item]!") return if(prob(70)) - user.balloon_alert(user, "[stack_item] reveals nothing!") + user.balloon_alert(user, "[ore_item] reveals nothing!") continue var/spawn_seed = pick(subtypesof(/obj/item/seeds) - seeds_blacklist) new spawn_seed(get_turf(src)) - user.balloon_alert(user, "[stack_item] revealed something!") + user.balloon_alert(user, "[ore_item] revealed something!") return ..() diff --git a/modular_skyrat/modules/primitive_production/code/misc.dm b/modular_skyrat/modules/primitive_production/code/misc.dm new file mode 100644 index 00000000000..18bcafa8664 --- /dev/null +++ b/modular_skyrat/modules/primitive_production/code/misc.dm @@ -0,0 +1,35 @@ +/obj/item/shard/attackby(obj/item/item, mob/user, params) + //xenoarch hammer, forging hammer, etc. + if(item.tool_behaviour == TOOL_HAMMER) + var/added_color + switch(src.type) + if(/obj/item/shard) + added_color = "#88cdf1" + + if(/obj/item/shard/plasma) + added_color = "#ff80f4" + + if(/obj/item/shard/plastitanium) + added_color = "#5d3369" + + if(/obj/item/shard/titanium) + added_color = "#cfbee0" + + var/obj/colored_item = new /obj/item/stack/ore/glass/zero_cost(get_turf(src)) + colored_item.add_atom_colour(added_color, FIXED_COLOUR_PRIORITY) + new /obj/effect/decal/cleanable/glass(get_turf(src)) + user.balloon_alert(user, "[src] shatters!") + playsound(src, SFX_SHATTER, 30, TRUE) + qdel(src) + return TRUE + + return ..() + +/obj/item/stack/ore/glass/zero_cost + points = 0 + merge_type = /obj/item/stack/ore/glass/zero_cost + +/obj/item/stack/ore/examine(mob/user) + . = ..() + if(points == 0) + . += span_warning("
[src] is worthless and will not reward any mining points!") diff --git a/modular_skyrat/modules/xenoarch/code/modules/research/xenoarch/xenoarch_tool.dm b/modular_skyrat/modules/xenoarch/code/modules/research/xenoarch/xenoarch_tool.dm index 50f695c2011..5d58fa29b84 100644 --- a/modular_skyrat/modules/xenoarch/code/modules/research/xenoarch/xenoarch_tool.dm +++ b/modular_skyrat/modules/xenoarch/code/modules/research/xenoarch/xenoarch_tool.dm @@ -7,6 +7,7 @@ /obj/item/xenoarch/hammer name = "parent dev item" desc = "A hammer that can be used to remove dirt from strange rocks." + tool_behaviour = TOOL_HAMMER var/dig_amount = 1 var/dig_speed = 1 SECONDS var/advanced = FALSE diff --git a/tgstation.dme b/tgstation.dme index 35b9780d62d..97709cd1a6c 100644 --- a/tgstation.dme +++ b/tgstation.dme @@ -7749,6 +7749,7 @@ #include "modular_skyrat\modules\primitive_cooking_additions\code\stone_stove.dm" #include "modular_skyrat\modules\primitive_production\code\ceramics.dm" #include "modular_skyrat\modules\primitive_production\code\glassblowing.dm" +#include "modular_skyrat\modules\primitive_production\code\misc.dm" #include "modular_skyrat\modules\primitive_production\code\production_skill.dm" #include "modular_skyrat\modules\primitive_structures\code\fencing.dm" #include "modular_skyrat\modules\primitive_structures\code\storage_structures.dm" From 9148e6c2d5be0f6b6309fa0d9f1fbfc6137fdb20 Mon Sep 17 00:00:00 2001 From: Yaroslav Nurkov <78199449+AnywayFarus@users.noreply.github.com> Date: Fri, 24 Nov 2023 12:42:47 +0300 Subject: [PATCH 55/72] Automatic changelog for PR #782 [ci skip] --- html/changelogs/AutoChangeLog-pr-782.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-782.yml diff --git a/html/changelogs/AutoChangeLog-pr-782.yml b/html/changelogs/AutoChangeLog-pr-782.yml new file mode 100644 index 00000000000..bea28e92212 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-782.yml @@ -0,0 +1,4 @@ +author: "jjpark-kb" +delete-after: True +changes: + - rscadd: "you can hammer glass shards to get back sand" \ No newline at end of file From 14b08cf6de36acb5222d1eddecc0c3b09231e0f6 Mon Sep 17 00:00:00 2001 From: Iajret Creature <122297233+Steals-The-PRs@users.noreply.github.com> Date: Fri, 24 Nov 2023 12:42:58 +0300 Subject: [PATCH 56/72] Removes Kilostation completely from the Automapper (#791) removes it Co-authored-by: The Sharkening <95130227+StrangeWeirdKitten@users.noreply.github.com> --- .../skyrat/automapper/automapper_config.toml | 33 - .../kilostation/kilostation_armory.dmm | 144 - .../kilostation/kilostation_arrivals.dmm | 357 -- .../kilostation/kilostation_cryo.dmm | 204 -- .../kilostation/kilostation_ert_bay.dmm | 3119 ----------------- 5 files changed, 3857 deletions(-) delete mode 100644 _maps/skyrat/automapper/templates/kilostation/kilostation_armory.dmm delete mode 100644 _maps/skyrat/automapper/templates/kilostation/kilostation_arrivals.dmm delete mode 100644 _maps/skyrat/automapper/templates/kilostation/kilostation_cryo.dmm delete mode 100644 _maps/skyrat/automapper/templates/kilostation/kilostation_ert_bay.dmm diff --git a/_maps/skyrat/automapper/automapper_config.toml b/_maps/skyrat/automapper/automapper_config.toml index 1683d43dae8..00c9ae33593 100644 --- a/_maps/skyrat/automapper/automapper_config.toml +++ b/_maps/skyrat/automapper/automapper_config.toml @@ -197,39 +197,6 @@ required_map = "IceBoxStation.dmm" coordinates = [202, 16, 2] trait_name = "Station" -# KILOSTATION MAP EDITS -# Kilostation Arrivals -[templates.kilostation_arrivals] -map_files = ["kilostation_arrivals.dmm"] -directory = "_maps/skyrat/automapper/templates/kilostation/" -required_map = "KiloStation.dmm" -coordinates = [151, 80, 1] -trait_name = "Station" - -# Kilostation ERT Bay and Barber -[templates.kilostation_ert_bay] -map_files = ["kilostation_ert_bay.dmm"] -directory = "_maps/skyrat/automapper/templates/kilostation/" -required_map = "KiloStation.dmm" -coordinates = [77, 151, 1] -trait_name = "Station" - -# Kilostation Cryo -[templates.kilostation_cryo] -map_files = ["kilostation_cryo.dmm"] -directory = "_maps/skyrat/automapper/templates/kilostation/" -required_map = "KiloStation.dmm" -coordinates = [59, 118, 1] -trait_name = "Station" - -# Kilostation Armory -[templates.kilostation_armory] -map_files = ["kilostation_armory.dmm"] -directory = "_maps/skyrat/automapper/templates/kilostation/" -required_map = "KiloStation.dmm" -coordinates = [81, 80, 1] -trait_name = "Station" - # TRAMSTATION MAP EDITS # Tramstation Arrivals [templates.tramstation_arrivals] diff --git a/_maps/skyrat/automapper/templates/kilostation/kilostation_armory.dmm b/_maps/skyrat/automapper/templates/kilostation/kilostation_armory.dmm deleted file mode 100644 index 229c3d31bd0..00000000000 --- a/_maps/skyrat/automapper/templates/kilostation/kilostation_armory.dmm +++ /dev/null @@ -1,144 +0,0 @@ -//MAP CONVERTED BY dmm2tgm.py THIS HEADER COMMENT PREVENTS RECONVERSION, DO NOT REMOVE -"e" = ( -/obj/effect/turf_decal/tile/neutral, -/obj/effect/turf_decal/tile/neutral{ - dir = 8 - }, -/obj/effect/turf_decal/tile/neutral{ - dir = 1 - }, -/obj/effect/turf_decal/bot, -/obj/structure/window/reinforced/spawner/directional/south, -/obj/structure/window/reinforced/spawner/directional/east, -/obj/effect/decal/cleanable/dirt, -/obj/structure/closet/secure_closet/armory_kiboko, -/turf/open/floor/iron/showroomfloor, -/area/station/ai_monitored/security/armory) -"q" = ( -/obj/effect/turf_decal/tile/neutral, -/obj/effect/turf_decal/tile/neutral{ - dir = 4 - }, -/obj/effect/turf_decal/tile/neutral{ - dir = 1 - }, -/obj/effect/turf_decal/bot, -/obj/structure/window/reinforced/spawner/directional/north, -/obj/structure/window/reinforced/spawner/directional/west, -/obj/structure/rack/gunrack, -/obj/effect/spawner/armory_spawn/microfusion, -/turf/open/floor/iron/showroomfloor, -/area/station/ai_monitored/security/armory) -"u" = ( -/obj/effect/turf_decal/tile/neutral, -/obj/effect/turf_decal/tile/neutral{ - dir = 8 - }, -/obj/effect/turf_decal/bot, -/obj/structure/rack, -/obj/item/clothing/head/helmet/sec{ - pixel_x = -3; - pixel_y = 3 - }, -/obj/item/clothing/head/helmet/sec, -/obj/item/clothing/head/helmet/sec{ - pixel_x = 3; - pixel_y = -3 - }, -/obj/item/clothing/suit/armor/vest/alt/sec{ - pixel_x = -3; - pixel_y = 3 - }, -/obj/item/clothing/suit/armor/vest/alt/sec, -/obj/item/clothing/suit/armor/vest/alt/sec{ - pixel_x = 3; - pixel_y = -3 - }, -/turf/open/floor/iron/dark, -/area/station/ai_monitored/security/armory) -"w" = ( -/obj/effect/turf_decal/tile/neutral{ - dir = 8 - }, -/obj/effect/turf_decal/tile/neutral{ - dir = 4 - }, -/obj/effect/turf_decal/tile/neutral{ - dir = 1 - }, -/obj/effect/turf_decal/bot, -/obj/structure/window/reinforced/spawner/directional/north, -/obj/structure/window/reinforced/spawner/directional/east, -/obj/structure/rack/gunrack, -/obj/effect/spawner/armory_spawn/smg, -/turf/open/floor/iron/showroomfloor, -/area/station/ai_monitored/security/armory) -"G" = ( -/obj/effect/turf_decal/tile/neutral, -/obj/effect/turf_decal/tile/neutral{ - dir = 8 - }, -/obj/effect/turf_decal/tile/neutral{ - dir = 4 - }, -/obj/effect/turf_decal/bot, -/obj/structure/window/reinforced/spawner/directional/south, -/obj/structure/window/reinforced/spawner/directional/west, -/obj/structure/rack/gunrack, -/obj/effect/spawner/armory_spawn/shotguns, -/turf/open/floor/iron/showroomfloor, -/area/station/ai_monitored/security/armory) -"N" = ( -/obj/item/clothing/mask/gas/sechailer{ - pixel_x = -3; - pixel_y = 3 - }, -/obj/item/clothing/mask/gas/sechailer, -/obj/item/clothing/mask/gas/sechailer{ - pixel_x = 3; - pixel_y = -3 - }, -/obj/item/flashlight/seclite, -/obj/item/flashlight/seclite, -/obj/item/flashlight/seclite, -/obj/effect/turf_decal/tile/neutral, -/obj/effect/decal/cleanable/cobweb, -/obj/machinery/airalarm/directional/west, -/obj/structure/table, -/obj/item/storage/barricade{ - pixel_y = -5 - }, -/obj/item/storage/barricade, -/obj/item/storage/barricade{ - pixel_y = 5 - }, -/turf/open/floor/iron/dark, -/area/station/ai_monitored/security/armory) -"S" = ( -/turf/template_noop, -/area/template_noop) - -(1,1,1) = {" -N -S -S -S -"} -(2,1,1) = {" -u -S -S -S -"} -(3,1,1) = {" -S -S -w -e -"} -(4,1,1) = {" -S -S -q -G -"} diff --git a/_maps/skyrat/automapper/templates/kilostation/kilostation_arrivals.dmm b/_maps/skyrat/automapper/templates/kilostation/kilostation_arrivals.dmm deleted file mode 100644 index dc4d9060ab2..00000000000 --- a/_maps/skyrat/automapper/templates/kilostation/kilostation_arrivals.dmm +++ /dev/null @@ -1,357 +0,0 @@ -//MAP CONVERTED BY dmm2tgm.py THIS HEADER COMMENT PREVENTS RECONVERSION, DO NOT REMOVE -"a" = ( -/turf/open/floor/plating/airless, -/area/space) -"e" = ( -/obj/effect/turf_decal/bot, -/obj/machinery/computer/shuttle/arrivals/recall{ - dir = 1 - }, -/turf/open/floor/iron/dark, -/area/station/hallway/secondary/entry) -"f" = ( -/turf/closed/wall/rust, -/area/station/hallway/secondary/entry) -"h" = ( -/obj/effect/turf_decal/tile/blue{ - dir = 8 - }, -/obj/machinery/atmospherics/components/unary/vent_scrubber/on/layer2{ - dir = 1 - }, -/obj/effect/turf_decal/box, -/turf/open/floor/iron, -/area/station/hallway/secondary/entry) -"i" = ( -/obj/effect/turf_decal/tile/blue{ - dir = 8 - }, -/obj/effect/turf_decal/tile/blue{ - dir = 4 - }, -/obj/effect/turf_decal/tile/red, -/obj/effect/turf_decal/stripes/line, -/obj/item/radio/intercom/directional/east, -/turf/open/floor/iron, -/area/station/hallway/secondary/entry) -"j" = ( -/obj/effect/turf_decal/stripes/line, -/obj/machinery/light/small/directional/west, -/obj/machinery/status_display/shuttle/directional/west{ - shuttle_id = "arrivals_shuttle" - }, -/turf/open/floor/iron, -/area/station/hallway/secondary/entry) -"k" = ( -/obj/effect/spawner/structure/window/reinforced, -/obj/structure/sign/warning/vacuum/external, -/turf/open/floor/plating, -/area/station/hallway/secondary/entry) -"n" = ( -/obj/effect/turf_decal/tile/neutral{ - dir = 4 - }, -/obj/effect/turf_decal/tile/neutral{ - dir = 1 - }, -/obj/structure/table, -/obj/item/paper_bin{ - pixel_x = -4; - pixel_y = 4 - }, -/obj/item/pen, -/obj/effect/turf_decal/loading_area{ - dir = 1 - }, -/turf/open/floor/iron/dark, -/area/station/hallway/secondary/entry) -"p" = ( -/obj/effect/turf_decal/tile/blue{ - dir = 8 - }, -/obj/effect/turf_decal/tile/red, -/obj/effect/turf_decal/stripes/corner, -/obj/effect/landmark/start/hangover, -/turf/open/floor/iron, -/area/station/hallway/secondary/entry) -"q" = ( -/turf/closed/wall, -/area/station/hallway/secondary/entry) -"r" = ( -/obj/effect/turf_decal/tile/blue{ - dir = 8 - }, -/obj/effect/turf_decal/tile/red, -/obj/effect/turf_decal/tile/red{ - dir = 1 - }, -/obj/effect/turf_decal/stripes/line, -/obj/effect/turf_decal/stripes/corner{ - dir = 1 - }, -/obj/effect/decal/cleanable/dirt, -/obj/machinery/bluespace_vendor/directional/west, -/turf/open/floor/iron, -/area/station/hallway/secondary/entry) -"s" = ( -/obj/effect/turf_decal/stripes/line, -/obj/structure/flora/bush/pale/style_random, -/obj/effect/decal/cleanable/dirt, -/turf/open/misc/asteroid/airless, -/area/space/nearstation) -"t" = ( -/obj/effect/turf_decal/stripes/line, -/obj/machinery/light/small/directional/east, -/obj/machinery/status_display/shuttle/directional/east{ - shuttle_id = "arrivals_shuttle" - }, -/turf/open/floor/iron, -/area/station/hallway/secondary/entry) -"v" = ( -/obj/effect/turf_decal/stripes/line, -/obj/structure/flora/grass/jungle/a/style_random, -/obj/effect/decal/cleanable/dirt, -/turf/open/misc/asteroid/airless, -/area/space/nearstation) -"x" = ( -/obj/effect/turf_decal/bot, -/obj/structure/closet/emcloset, -/obj/effect/turf_decal/tile/neutral{ - dir = 4 - }, -/obj/effect/turf_decal/tile/neutral{ - dir = 1 - }, -/obj/machinery/light/small/directional/south, -/obj/structure/sign/poster/contraband/random/directional/south, -/turf/open/floor/iron/dark, -/area/station/hallway/secondary/entry) -"z" = ( -/obj/effect/spawner/random/vending/colavend, -/obj/effect/turf_decal/bot, -/turf/open/floor/iron/dark, -/area/station/hallway/secondary/entry) -"A" = ( -/obj/effect/turf_decal/tile/blue{ - dir = 8 - }, -/obj/effect/turf_decal/tile/red, -/obj/effect/turf_decal/stripes/corner{ - dir = 8 - }, -/turf/open/floor/iron, -/area/station/hallway/secondary/entry) -"D" = ( -/obj/effect/turf_decal/stripes/line, -/turf/open/misc/asteroid/airless, -/area/space/nearstation) -"E" = ( -/obj/machinery/door/airlock/external{ - name = "Arrival Shuttle Airlock" - }, -/obj/effect/mapping_helpers/airlock/cyclelink_helper, -/turf/open/floor/iron/dark, -/area/station/hallway/secondary/entry) -"F" = ( -/obj/effect/spawner/structure/window/reinforced, -/turf/open/floor/plating, -/area/station/hallway/secondary/entry) -"G" = ( -/obj/machinery/door/airlock/external{ - name = "Arrival Shuttle Airlock"; - space_dir = 2 - }, -/obj/effect/mapping_helpers/airlock/cyclelink_helper{ - dir = 1 - }, -/turf/open/floor/iron/dark, -/area/station/hallway/secondary/entry) -"I" = ( -/obj/structure/sign/warning/docking, -/turf/closed/wall, -/area/station/hallway/secondary/entry) -"J" = ( -/obj/effect/turf_decal/tile/red, -/turf/open/floor/iron, -/area/station/hallway/secondary/entry) -"M" = ( -/turf/closed/mineral/random/labormineral, -/area/space/nearstation) -"O" = ( -/obj/docking_port/stationary{ - dir = 4; - dwidth = 1; - height = 13; - shuttle_id = "arrivals_stationary"; - name = "arrivals"; - width = 5 - }, -/turf/open/floor/plating/airless, -/area/space) -"S" = ( -/obj/effect/turf_decal/stripes/line, -/obj/structure/flora/grass/jungle/b/style_random, -/obj/effect/decal/cleanable/dirt, -/turf/open/misc/asteroid/airless, -/area/space/nearstation) -"T" = ( -/obj/structure/sign/warning/secure_area{ - name = "EMERGENCY STORAGE" - }, -/turf/closed/wall, -/area/station/hallway/secondary/entry) -"V" = ( -/obj/effect/turf_decal/delivery, -/obj/machinery/vending/clothing, -/turf/open/floor/iron/dark, -/area/station/hallway/secondary/entry) -"W" = ( -/obj/machinery/door/airlock/external{ - name = "Arrival Shuttle Airlock" - }, -/obj/effect/mapping_helpers/airlock/cyclelink_helper, -/obj/effect/landmark/navigate_destination, -/turf/open/floor/iron/dark, -/area/station/hallway/secondary/entry) -"X" = ( -/obj/effect/turf_decal/bot, -/obj/effect/turf_decal/tile/neutral{ - dir = 4 - }, -/obj/effect/turf_decal/tile/neutral{ - dir = 1 - }, -/obj/structure/closet/firecloset, -/turf/open/floor/iron/dark, -/area/station/hallway/secondary/entry) -"Y" = ( -/obj/effect/turf_decal/tile/neutral{ - dir = 4 - }, -/obj/effect/turf_decal/tile/neutral{ - dir = 1 - }, -/obj/effect/landmark/start/assistant, -/turf/open/floor/iron, -/area/station/hallway/secondary/entry) - -(1,1,1) = {" -x -f -M -S -a -a -a -a -"} -(2,1,1) = {" -X -q -M -v -a -O -a -a -"} -(3,1,1) = {" -T -f -q -I -a -a -a -a -"} -(4,1,1) = {" -r -E -j -G -a -a -a -a -"} -(5,1,1) = {" -A -F -F -F -a -a -a -a -"} -(6,1,1) = {" -h -n -F -s -a -a -a -a -"} -(7,1,1) = {" -Y -V -k -v -a -a -a -a -"} -(8,1,1) = {" -J -z -F -D -a -a -a -a -"} -(9,1,1) = {" -J -e -F -v -a -a -a -a -"} -(10,1,1) = {" -p -F -F -F -a -a -a -a -"} -(11,1,1) = {" -i -W -t -G -a -a -a -a -"} -(12,1,1) = {" -f -q -f -I -a -a -a -a -"} diff --git a/_maps/skyrat/automapper/templates/kilostation/kilostation_cryo.dmm b/_maps/skyrat/automapper/templates/kilostation/kilostation_cryo.dmm deleted file mode 100644 index d3035bcc07a..00000000000 --- a/_maps/skyrat/automapper/templates/kilostation/kilostation_cryo.dmm +++ /dev/null @@ -1,204 +0,0 @@ -//MAP CONVERTED BY dmm2tgm.py THIS HEADER COMMENT PREVENTS RECONVERSION, DO NOT REMOVE -"a" = ( -/turf/closed/wall, -/area/station/common/cryopods) -"c" = ( -/obj/structure/table, -/obj/item/clipboard, -/obj/item/screwdriver{ - pixel_y = 16 - }, -/turf/open/floor/iron/dark, -/area/station/maintenance/port/greater) -"d" = ( -/obj/effect/turf_decal/bot, -/obj/structure/frame/computer{ - anchored = 1; - dir = 1 - }, -/obj/structure/cable, -/turf/open/floor/iron/dark, -/area/station/maintenance/port/greater) -"e" = ( -/obj/effect/spawner/structure/window/reinforced, -/obj/machinery/door/poddoor/shutters/preopen{ - id = "greylair"; - name = "Lair Privacy Shutter" - }, -/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, -/obj/structure/cable, -/turf/open/floor/plating, -/area/station/maintenance/port/greater) -"g" = ( -/turf/open/floor/iron, -/area/station/common/cryopods) -"j" = ( -/obj/machinery/computer/cryopod/directional/east, -/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, -/turf/open/floor/iron, -/area/station/common/cryopods) -"l" = ( -/obj/effect/spawner/structure/window/reinforced, -/turf/open/floor/plating, -/area/station/common/cryopods) -"o" = ( -/obj/machinery/power/apc/auto_name/directional/west, -/obj/structure/cable, -/turf/open/floor/iron, -/area/station/common/cryopods) -"r" = ( -/obj/effect/spawner/structure/window/reinforced, -/obj/machinery/door/poddoor/shutters/preopen{ - id = "greylair"; - name = "Lair Privacy Shutter" - }, -/obj/structure/cable, -/turf/open/floor/plating, -/area/station/maintenance/port/greater) -"u" = ( -/obj/effect/turf_decal/bot, -/obj/structure/frame/computer{ - anchored = 1; - dir = 1 - }, -/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, -/turf/open/floor/iron/dark, -/area/station/maintenance/port/greater) -"x" = ( -/obj/machinery/cryopod, -/obj/effect/turf_decal/siding/white, -/obj/machinery/airalarm/directional/east, -/turf/open/floor/iron/dark, -/area/station/common/cryopods) -"z" = ( -/obj/machinery/door/airlock/public/glass{ - name = "Cryopods" - }, -/obj/effect/landmark/navigate_destination, -/turf/open/floor/iron, -/area/station/common/cryopods) -"A" = ( -/obj/machinery/cryopod, -/obj/effect/turf_decal/siding/white, -/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, -/turf/open/floor/iron/dark, -/area/station/common/cryopods) -"D" = ( -/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, -/turf/open/floor/iron, -/area/station/common/cryopods) -"J" = ( -/obj/effect/turf_decal/siding/white{ - dir = 1 - }, -/obj/machinery/atmospherics/components/unary/vent_pump/on/layer4{ - dir = 1 - }, -/obj/machinery/camera/directional/east, -/obj/machinery/time_clock/directional/east, -/obj/item/kirbyplants/random, -/turf/open/floor/iron/dark, -/area/station/common/cryopods) -"O" = ( -/obj/machinery/cryopod, -/obj/effect/turf_decal/siding/white, -/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, -/turf/open/floor/iron/dark, -/area/station/common/cryopods) -"Q" = ( -/obj/structure/table, -/obj/item/storage/briefcase/secure, -/obj/item/taperecorder, -/obj/structure/sign/warning/electric_shock/directional/south, -/turf/open/floor/iron/dark, -/area/station/maintenance/port/greater) -"R" = ( -/obj/effect/spawner/structure/window/reinforced, -/obj/machinery/door/poddoor/shutters/preopen{ - id = "greylair"; - name = "Lair Privacy Shutter" - }, -/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, -/obj/structure/cable, -/turf/open/floor/plating, -/area/station/maintenance/port/greater) -"S" = ( -/obj/machinery/cryopod{ - dir = 1 - }, -/obj/effect/turf_decal/siding/white{ - dir = 9 - }, -/turf/open/floor/iron/dark, -/area/station/common/cryopods) -"U" = ( -/turf/closed/wall, -/area/station/maintenance/port/greater) -"W" = ( -/obj/machinery/cryopod, -/obj/effect/turf_decal/siding/white, -/obj/structure/cable, -/obj/machinery/atmospherics/components/unary/vent_scrubber/on/layer2{ - dir = 4 - }, -/obj/machinery/light/directional/west, -/turf/open/floor/iron/dark, -/area/station/common/cryopods) -"X" = ( -/obj/effect/turf_decal/bot, -/obj/structure/frame/computer{ - anchored = 1; - dir = 1 - }, -/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, -/turf/open/floor/iron/dark, -/area/station/maintenance/port/greater) - -(1,1,1) = {" -Q -a -a -a -a -a -"} -(2,1,1) = {" -d -r -W -o -g -l -"} -(3,1,1) = {" -X -e -O -g -g -z -"} -(4,1,1) = {" -u -R -A -D -S -l -"} -(5,1,1) = {" -c -r -x -j -J -l -"} -(6,1,1) = {" -U -a -a -a -a -a -"} diff --git a/_maps/skyrat/automapper/templates/kilostation/kilostation_ert_bay.dmm b/_maps/skyrat/automapper/templates/kilostation/kilostation_ert_bay.dmm deleted file mode 100644 index 34e0fbcad74..00000000000 --- a/_maps/skyrat/automapper/templates/kilostation/kilostation_ert_bay.dmm +++ /dev/null @@ -1,3119 +0,0 @@ -//MAP CONVERTED BY dmm2tgm.py THIS HEADER COMMENT PREVENTS RECONVERSION, DO NOT REMOVE -"ad" = ( -/obj/structure/transit_tube/diagonal/topleft, -/obj/structure/lattice/catwalk, -/turf/open/space/basic, -/area/space/nearstation) -"an" = ( -/obj/effect/decal/cleanable/dirt, -/obj/structure/sign/poster/official/random/directional/east, -/turf/open/floor/iron, -/area/station/hallway/primary/fore) -"aK" = ( -/obj/machinery/newscaster/directional/east, -/obj/machinery/atmospherics/components/unary/vent_scrubber/on/layer2, -/turf/open/floor/carpet/executive, -/area/station/command/heads_quarters/nt_rep) -"bb" = ( -/obj/machinery/door/airlock/maintenance/external{ - name = "Transit Intersection" - }, -/obj/effect/mapping_helpers/airlock/cyclelink_helper{ - dir = 8 - }, -/obj/effect/mapping_helpers/airlock/unres{ - dir = 8 - }, -/obj/effect/mapping_helpers/airlock/access/any/medical/maintenance, -/obj/structure/cable, -/turf/open/floor/plating, -/area/station/maintenance/fore/lesser) -"bj" = ( -/obj/machinery/bluespace_vendor/directional/east, -/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, -/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, -/obj/structure/disposalpipe/segment, -/obj/machinery/door/airlock/public/glass{ - name = "Salon Hallway" - }, -/obj/machinery/door/firedoor, -/obj/effect/turf_decal/caution/stand_clear, -/turf/open/floor/iron/dark, -/area/station/hallway/primary/fore) -"bB" = ( -/obj/effect/decal/cleanable/dirt, -/obj/structure/sign/poster/contraband/random/directional/south, -/obj/structure/cable, -/obj/effect/mapping_helpers/burnt_floor, -/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, -/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, -/turf/open/floor/plating, -/area/station/maintenance/fore) -"bH" = ( -/obj/structure/transit_tube/diagonal/crossing/topleft, -/obj/structure/lattice/catwalk, -/turf/open/space/basic, -/area/space/nearstation) -"bV" = ( -/obj/structure/chair/sofa/bench/right{ - dir = 8 - }, -/obj/effect/decal/cleanable/dirt, -/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, -/obj/effect/mapping_helpers/broken_floor, -/turf/open/floor/plating, -/area/station/hallway/primary/fore) -"ca" = ( -/obj/machinery/airalarm/directional/north, -/obj/machinery/atmospherics/components/unary/vent_pump/on/layer4, -/turf/open/floor/carpet/executive, -/area/station/command/heads_quarters/nt_rep) -"cc" = ( -/obj/machinery/atmospherics/components/unary/vent_pump/on/layer4{ - dir = 4 - }, -/turf/open/floor/iron/dark, -/area/station/hallway/primary/fore) -"cf" = ( -/obj/machinery/firealarm/directional/west, -/obj/effect/decal/cleanable/dirt, -/turf/open/floor/iron, -/area/station/hallway/primary/fore) -"cm" = ( -/obj/structure/filingcabinet/employment, -/turf/open/floor/carpet/executive, -/area/station/command/heads_quarters/nt_rep) -"cW" = ( -/obj/structure/fans/tiny/forcefield{ - dir = 1 - }, -/obj/structure/sign/warning/vacuum/external/directional/east, -/obj/machinery/door/poddoor/preopen{ - name = "Dock Shutter" - }, -/turf/open/floor/plating, -/area/station/hallway/primary/fore) -"cX" = ( -/obj/structure/closet/secure_closet/nanotrasen_consultant/station, -/obj/item/assembly/flash/handheld, -/obj/machinery/status_display/ai/directional/north, -/turf/open/floor/carpet/executive, -/area/station/command/heads_quarters/nt_rep) -"df" = ( -/obj/machinery/disposal/bin, -/obj/structure/disposalpipe/trunk{ - dir = 8 - }, -/obj/effect/turf_decal/delivery, -/obj/effect/turf_decal/tile/green{ - dir = 1 - }, -/obj/structure/sign/poster/official/random/directional/north, -/turf/open/floor/iron/dark/corner{ - dir = 1 - }, -/area/station/hallway/primary/fore) -"ds" = ( -/obj/structure/chair/sofa/bench/right{ - dir = 8 - }, -/obj/effect/landmark/start/assistant, -/obj/effect/turf_decal/tile/green, -/turf/open/floor/iron/dark/corner, -/area/station/hallway/primary/fore) -"dC" = ( -/obj/effect/turf_decal/tile/purple/opposingcorners{ - dir = 8 - }, -/turf/open/floor/iron/cafeteria, -/area/station/service/barber) -"dG" = ( -/obj/machinery/camera/directional/north, -/obj/effect/decal/cleanable/dirt, -/turf/open/floor/iron, -/area/station/hallway/primary/fore) -"dV" = ( -/obj/effect/spawner/structure/window/hollow/reinforced/middle, -/obj/structure/transit_tube, -/obj/structure/disposalpipe/segment, -/turf/open/floor/plating, -/area/station/maintenance/fore/lesser) -"dY" = ( -/obj/structure/cable, -/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, -/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, -/obj/structure/disposalpipe/segment, -/obj/effect/turf_decal/tile/green{ - dir = 4 - }, -/obj/effect/turf_decal/stripes/line, -/turf/open/floor/iron/dark/corner{ - dir = 4 - }, -/area/station/hallway/primary/fore) -"dZ" = ( -/obj/structure/lattice, -/turf/open/space/basic, -/area/space/nearstation) -"ew" = ( -/obj/structure/sign/departments/custodian, -/turf/closed/wall, -/area/station/maintenance/fore) -"ey" = ( -/obj/effect/turf_decal/tile/purple/opposingcorners{ - dir = 8 - }, -/obj/machinery/vending/barbervend, -/obj/item/radio/intercom/directional/north, -/turf/open/floor/iron/cafeteria, -/area/station/service/barber) -"eL" = ( -/obj/structure/closet{ - name = "maid locker" - }, -/obj/effect/turf_decal/tile/neutral, -/obj/effect/turf_decal/tile/neutral{ - dir = 8 - }, -/obj/effect/turf_decal/bot, -/obj/effect/decal/cleanable/dirt, -/obj/item/clothing/gloves/color/white, -/obj/item/clothing/accessory/maidapron{ - pixel_x = -4; - pixel_y = -4 - }, -/obj/item/clothing/shoes/laceup, -/obj/structure/mirror/directional/north, -/turf/open/floor/iron/dark, -/area/station/maintenance/fore) -"eQ" = ( -/obj/structure/table, -/obj/effect/turf_decal/tile/neutral, -/obj/effect/turf_decal/tile/neutral{ - dir = 8 - }, -/obj/effect/decal/cleanable/dirt, -/obj/item/storage/box/mousetraps{ - pixel_x = -4; - pixel_y = 4 - }, -/obj/item/flashlight, -/obj/structure/noticeboard/directional/north, -/turf/open/floor/iron/dark, -/area/station/maintenance/fore) -"eZ" = ( -/obj/machinery/door/airlock/maintenance, -/obj/effect/mapping_helpers/airlock/abandoned, -/obj/structure/barricade/wooden/crude, -/obj/effect/decal/cleanable/dirt, -/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, -/obj/structure/cable, -/obj/effect/mapping_helpers/airlock/unres{ - dir = 4 - }, -/obj/effect/mapping_helpers/airlock/access/all/service/janitor, -/turf/open/floor/iron/dark, -/area/station/maintenance/fore) -"fb" = ( -/obj/effect/turf_decal/tile/green{ - dir = 4 - }, -/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, -/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, -/turf/open/floor/iron/dark/corner{ - dir = 4 - }, -/area/station/hallway/primary/fore) -"fc" = ( -/obj/effect/turf_decal/siding/white{ - dir = 5 - }, -/obj/machinery/vending/coffee, -/turf/open/floor/iron/dark, -/area/station/hallway/primary/fore) -"fr" = ( -/obj/machinery/light/directional/west, -/turf/open/floor/iron, -/area/station/hallway/primary/fore) -"fx" = ( -/obj/structure/cable, -/obj/machinery/light/directional/south, -/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, -/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, -/turf/open/floor/wood, -/area/station/command/heads_quarters/nt_rep) -"fA" = ( -/obj/structure/disposalpipe/segment, -/obj/structure/window/reinforced/spawner/directional/north, -/turf/open/floor/plating, -/area/station/maintenance/fore/lesser) -"fF" = ( -/obj/effect/turf_decal/siding/white{ - dir = 4 - }, -/obj/effect/spawner/random/vending/snackvend, -/turf/open/floor/iron/dark, -/area/station/hallway/primary/fore) -"fR" = ( -/obj/structure/sign/warning/secure_area, -/turf/closed/wall, -/area/space/nearstation) -"fT" = ( -/obj/effect/turf_decal/stripes/corner{ - dir = 4 - }, -/obj/effect/decal/cleanable/dirt, -/obj/structure/cable, -/obj/effect/mapping_helpers/burnt_floor, -/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, -/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, -/turf/open/floor/plating, -/area/station/maintenance/fore) -"gk" = ( -/obj/structure/disposalpipe/segment{ - dir = 4 - }, -/obj/structure/closet/firecloset, -/obj/effect/turf_decal/bot, -/obj/effect/turf_decal/tile/green{ - dir = 1 - }, -/obj/item/radio/intercom/directional/north, -/turf/open/floor/iron/dark/corner{ - dir = 1 - }, -/area/station/hallway/primary/fore) -"gv" = ( -/obj/effect/turf_decal/tile/blue{ - dir = 8 - }, -/obj/effect/turf_decal/stripes/line{ - dir = 1 - }, -/turf/open/floor/iron/dark/corner{ - dir = 8 - }, -/area/station/hallway/primary/fore) -"gw" = ( -/obj/effect/turf_decal/stripes/line{ - dir = 1 - }, -/obj/effect/decal/cleanable/dirt, -/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, -/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, -/turf/open/floor/iron, -/area/station/hallway/primary/fore) -"gx" = ( -/obj/effect/turf_decal/tile/blue{ - dir = 4 - }, -/obj/effect/turf_decal/stripes/line{ - dir = 1 - }, -/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, -/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, -/turf/open/floor/iron/dark/corner{ - dir = 4 - }, -/area/station/hallway/primary/fore) -"gy" = ( -/obj/structure/chair/sofa/bench{ - dir = 8 - }, -/obj/effect/decal/cleanable/dirt, -/turf/open/floor/iron/dark, -/area/station/hallway/primary/fore) -"gH" = ( -/obj/effect/decal/cleanable/dirt, -/obj/structure/cable, -/turf/open/floor/plating, -/area/station/maintenance/fore/lesser) -"gW" = ( -/obj/effect/turf_decal/sand/plating, -/obj/structure/disposalpipe/segment{ - dir = 10 - }, -/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, -/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, -/obj/structure/cable, -/turf/open/floor/plating/airless, -/area/space/nearstation) -"gX" = ( -/obj/effect/turf_decal/siding/wood{ - dir = 1 - }, -/obj/machinery/holopad, -/turf/open/floor/wood, -/area/station/command/heads_quarters/nt_rep) -"ha" = ( -/obj/structure/sign/departments/holy{ - pixel_y = 30 - }, -/turf/open/floor/iron/stairs/right{ - dir = 4 - }, -/area/station/hallway/primary/fore) -"hd" = ( -/obj/machinery/firealarm/directional/south, -/obj/effect/decal/cleanable/dirt, -/turf/open/floor/iron, -/area/station/hallway/primary/fore) -"hg" = ( -/obj/structure/window/reinforced/spawner/directional/south, -/turf/open/misc/asteroid/airless, -/area/space/nearstation) -"hj" = ( -/obj/effect/turf_decal/sand/plating, -/obj/structure/disposalpipe/segment{ - dir = 4 - }, -/turf/open/floor/plating/airless, -/area/space/nearstation) -"hs" = ( -/obj/machinery/light/directional/south, -/obj/effect/turf_decal/siding/white{ - dir = 4 - }, -/obj/structure/sign/poster/official/random/directional/south, -/turf/open/floor/iron/dark, -/area/station/hallway/primary/fore) -"hS" = ( -/obj/structure/transit_tube/diagonal/crossing/topleft, -/turf/open/misc/asteroid/airless, -/area/space/nearstation) -"iv" = ( -/obj/structure/cable, -/turf/open/floor/iron/stairs/old{ - dir = 8 - }, -/area/station/maintenance/fore/lesser) -"iy" = ( -/obj/machinery/door/airlock/maintenance, -/obj/effect/mapping_helpers/airlock/unres{ - dir = 8 - }, -/obj/structure/cable, -/obj/effect/mapping_helpers/airlock/cyclelink_helper{ - dir = 4 - }, -/obj/effect/mapping_helpers/airlock/access/all/engineering/maintenance, -/obj/effect/mapping_helpers/burnt_floor, -/turf/open/floor/plating, -/area/station/maintenance/fore/lesser) -"iD" = ( -/obj/effect/decal/cleanable/dirt, -/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, -/turf/open/floor/plating, -/area/station/hallway/primary/fore) -"iM" = ( -/obj/structure/fans/tiny/forcefield{ - dir = 1 - }, -/obj/machinery/door/poddoor/preopen{ - name = "Dock Shutter" - }, -/turf/open/floor/plating, -/area/station/hallway/primary/fore) -"iV" = ( -/obj/effect/turf_decal/stripes/line{ - dir = 8 - }, -/obj/machinery/atmospherics/components/unary/vent_pump/on/layer4, -/obj/effect/mapping_helpers/broken_floor, -/turf/open/floor/plating, -/area/station/hallway/primary/fore) -"jA" = ( -/obj/structure/table, -/obj/effect/turf_decal/tile/neutral, -/obj/effect/turf_decal/tile/neutral{ - dir = 8 - }, -/obj/effect/decal/cleanable/dirt, -/obj/item/storage/box/lights/mixed{ - pixel_x = -4; - pixel_y = 4 - }, -/obj/item/storage/belt/janitor, -/obj/item/storage/bag/trash, -/obj/structure/sign/poster/contraband/busty_backdoor_xeno_babes_6/directional/north, -/obj/effect/decal/cleanable/cobweb, -/turf/open/floor/iron/dark, -/area/station/maintenance/fore) -"jC" = ( -/obj/structure/chair/sofa/bench{ - dir = 8 - }, -/obj/effect/turf_decal/siding/white{ - dir = 4 - }, -/turf/open/floor/iron/dark, -/area/station/hallway/primary/fore) -"jJ" = ( -/obj/structure/transit_tube/crossing, -/obj/structure/disposalpipe/segment{ - dir = 10 - }, -/turf/open/floor/plating, -/area/station/maintenance/fore/lesser) -"jK" = ( -/obj/effect/decal/cleanable/dirt, -/turf/open/floor/iron/dark, -/area/station/hallway/primary/fore) -"jS" = ( -/obj/machinery/light/directional/north, -/obj/effect/turf_decal/siding/white{ - dir = 4 - }, -/obj/machinery/airalarm/directional/north, -/turf/open/floor/iron/dark, -/area/station/hallway/primary/fore) -"jV" = ( -/turf/open/floor/plating, -/area/station/hallway/primary/fore) -"jY" = ( -/obj/effect/landmark/carpspawn, -/turf/open/space/basic, -/area/space) -"kh" = ( -/obj/effect/turf_decal/siding/white{ - dir = 4 - }, -/turf/open/floor/plating, -/area/station/hallway/primary/fore) -"ku" = ( -/obj/machinery/camera/directional/north, -/obj/item/radio/intercom/directional/north, -/turf/open/floor/iron, -/area/station/hallway/primary/fore) -"kz" = ( -/obj/effect/spawner/structure/window/reinforced, -/obj/machinery/door/poddoor/preopen{ - name = "Privacy Shutter"; - id = "nt_rep_priv_2" - }, -/turf/open/floor/plating, -/area/station/command/heads_quarters/nt_rep) -"kE" = ( -/obj/effect/decal/cleanable/dirt, -/turf/open/floor/plating, -/area/station/hallway/primary/fore) -"kI" = ( -/obj/effect/turf_decal/siding/white{ - dir = 6 - }, -/obj/effect/spawner/random/vending/colavend, -/turf/open/floor/iron/dark, -/area/station/hallway/primary/fore) -"kP" = ( -/obj/effect/turf_decal/stripes/line{ - dir = 8 - }, -/obj/effect/decal/cleanable/dirt, -/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, -/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, -/turf/open/floor/iron, -/area/station/hallway/primary/fore) -"lr" = ( -/obj/effect/turf_decal/tile/neutral{ - dir = 4 - }, -/obj/effect/turf_decal/tile/neutral{ - dir = 1 - }, -/obj/machinery/newscaster/directional/north, -/obj/machinery/camera/directional/north{ - c_tag = "Fore Hallway Monastary Tube"; - name = "fore camera" - }, -/obj/structure/chair/sofa/bench, -/obj/effect/landmark/start/assistant, -/turf/open/floor/iron/dark/corner{ - dir = 4 - }, -/area/station/hallway/primary/fore) -"lw" = ( -/obj/structure/window/reinforced/spawner/directional/north, -/obj/structure/transit_tube/crossing, -/turf/open/floor/plating, -/area/station/maintenance/fore/lesser) -"lU" = ( -/obj/effect/turf_decal/tile/purple/opposingcorners{ - dir = 8 - }, -/obj/structure/closet/secure_closet/barber, -/obj/effect/decal/cleanable/dirt, -/obj/item/pushbroom, -/obj/item/reagent_containers/spray/cleaner, -/obj/machinery/firealarm/directional/west, -/obj/effect/decal/cleanable/cobweb, -/obj/machinery/light_switch/directional/north, -/turf/open/floor/iron/cafeteria, -/area/station/service/barber) -"mi" = ( -/obj/effect/turf_decal/stripes/line{ - dir = 4 - }, -/obj/effect/turf_decal/stripes/line{ - dir = 8 - }, -/obj/structure/grille, -/turf/open/floor/plating/airless, -/area/space/nearstation) -"mU" = ( -/obj/structure/chair/sofa/bench{ - dir = 8 - }, -/obj/effect/landmark/start/assistant, -/turf/open/floor/iron/dark, -/area/station/hallway/primary/fore) -"mZ" = ( -/turf/open/floor/carpet/executive, -/area/station/command/heads_quarters/nt_rep) -"nc" = ( -/obj/effect/turf_decal/sand/plating, -/obj/structure/disposalpipe/segment, -/obj/structure/window/reinforced/spawner/directional/south, -/turf/open/floor/plating/airless, -/area/space/nearstation) -"ne" = ( -/turf/closed/wall, -/area/space/nearstation) -"nv" = ( -/obj/machinery/airalarm/directional/east, -/turf/open/floor/iron, -/area/station/hallway/primary/fore) -"nA" = ( -/obj/effect/decal/cleanable/dirt, -/obj/effect/turf_decal/bot, -/obj/structure/sink/directional/east, -/obj/item/reagent_containers/cup/bucket, -/obj/item/mop, -/obj/effect/turf_decal/stripes/corner, -/obj/machinery/button/door/directional/south{ - id = "maidbay"; - name = "Maid Bay Toggle" - }, -/obj/structure/sign/poster/contraband/random/directional/west, -/obj/effect/mapping_helpers/broken_floor, -/turf/open/floor/plating, -/area/station/maintenance/fore) -"nE" = ( -/obj/structure/chair/sofa/bench{ - dir = 8 - }, -/obj/effect/turf_decal/siding/white{ - dir = 4 - }, -/obj/effect/landmark/start/assistant, -/obj/effect/decal/cleanable/dirt, -/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, -/turf/open/floor/iron/dark, -/area/station/hallway/primary/fore) -"nF" = ( -/obj/structure/cable, -/obj/effect/turf_decal/tile/blue{ - dir = 8 - }, -/turf/open/floor/iron/dark/corner{ - dir = 8 - }, -/area/station/hallway/primary/fore) -"nN" = ( -/obj/effect/spawner/structure/window/reinforced, -/turf/open/floor/plating, -/area/station/hallway/primary/fore) -"nS" = ( -/obj/structure/chair/sofa/bench/corner{ - dir = 8 - }, -/obj/effect/turf_decal/tile/green, -/obj/machinery/camera/directional/south, -/turf/open/floor/iron/dark/corner, -/area/station/hallway/primary/fore) -"nW" = ( -/obj/effect/decal/cleanable/dirt, -/turf/open/floor/iron, -/area/station/hallway/primary/fore) -"oi" = ( -/obj/effect/turf_decal/tile/neutral, -/obj/structure/extinguisher_cabinet/directional/east, -/obj/effect/turf_decal/tile/neutral{ - dir = 4 - }, -/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, -/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, -/obj/structure/disposalpipe/segment, -/obj/effect/turf_decal/stripes/line{ - dir = 1 - }, -/turf/open/floor/iron/dark/corner{ - dir = 4 - }, -/area/station/hallway/primary/fore) -"oR" = ( -/obj/effect/spawner/structure/window/reinforced, -/obj/machinery/door/poddoor/preopen{ - name = "Privacy Shutter"; - id = "nt_rep_priv" - }, -/turf/open/floor/plating, -/area/station/command/heads_quarters/nt_rep) -"oZ" = ( -/obj/effect/decal/cleanable/dirt, -/turf/closed/wall/r_wall/rust, -/area/station/command/heads_quarters/nt_rep) -"pf" = ( -/turf/closed/wall, -/area/station/maintenance/fore) -"qg" = ( -/obj/structure/closet/crate, -/obj/item/hand_labeler, -/obj/item/storage/crayons, -/obj/effect/decal/cleanable/cobweb/cobweb2, -/turf/open/floor/plating, -/area/station/maintenance/fore) -"qj" = ( -/obj/structure/chair/sofa/bench/right{ - dir = 8 - }, -/obj/effect/turf_decal/siding/white{ - dir = 4 - }, -/turf/open/floor/iron/dark, -/area/station/hallway/primary/fore) -"qr" = ( -/obj/effect/decal/cleanable/dirt, -/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, -/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, -/obj/structure/cable, -/obj/effect/mapping_helpers/broken_floor, -/turf/open/floor/plating, -/area/station/maintenance/fore) -"qM" = ( -/obj/machinery/button/door/directional/north{ - name = "Privacy Shutters Control"; - id = "nt_rep_priv" - }, -/obj/structure/table/wood, -/obj/item/folder/yellow{ - pixel_x = 8; - pixel_y = -1 - }, -/obj/item/folder/red{ - pixel_x = -4; - pixel_y = -2 - }, -/obj/item/folder/white{ - pixel_x = 4; - pixel_y = 3 - }, -/obj/item/folder/blue{ - pixel_y = 6; - pixel_x = -2 - }, -/turf/open/floor/wood, -/area/station/command/heads_quarters/nt_rep) -"qS" = ( -/obj/effect/turf_decal/tile/neutral{ - dir = 4 - }, -/obj/effect/turf_decal/tile/neutral{ - dir = 1 - }, -/obj/structure/noticeboard/directional/north{ - dir = 2; - name = "Chapel Notice Board" - }, -/obj/machinery/light/directional/north, -/obj/structure/chair/sofa/bench/right, -/turf/open/floor/iron/dark/corner{ - dir = 4 - }, -/area/station/hallway/primary/fore) -"qU" = ( -/obj/effect/turf_decal/tile/green, -/turf/open/floor/iron/dark/corner, -/area/station/hallway/primary/fore) -"rk" = ( -/obj/effect/turf_decal/siding/white{ - dir = 1 - }, -/obj/machinery/newscaster/directional/west, -/obj/effect/landmark/start/barber, -/turf/open/floor/iron/dark, -/area/station/service/barber) -"rt" = ( -/obj/structure/window/reinforced/spawner/directional/north, -/obj/structure/cable, -/obj/machinery/power/apc/auto_name/directional/east, -/turf/open/floor/plating, -/area/station/maintenance/fore/lesser) -"rz" = ( -/obj/structure/closet/crate/bin, -/obj/machinery/camera/directional/north, -/obj/structure/noticeboard/directional/north, -/turf/open/floor/iron/dark, -/area/station/hallway/primary/fore) -"rE" = ( -/obj/effect/turf_decal/siding/white{ - dir = 4 - }, -/obj/item/kirbyplants/random, -/turf/open/floor/iron, -/area/station/hallway/primary/fore) -"rL" = ( -/obj/effect/turf_decal/siding/wood{ - dir = 8 - }, -/obj/machinery/light_switch/directional/south, -/obj/structure/cable, -/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, -/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, -/turf/open/floor/wood, -/area/station/command/heads_quarters/nt_rep) -"rT" = ( -/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, -/turf/open/floor/iron, -/area/station/hallway/primary/fore) -"su" = ( -/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, -/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, -/obj/structure/disposalpipe/segment, -/obj/effect/turf_decal/tile/green{ - dir = 4 - }, -/turf/open/floor/iron/dark/corner{ - dir = 4 - }, -/area/station/hallway/primary/fore) -"sz" = ( -/obj/effect/turf_decal/stripes/line{ - dir = 4 - }, -/obj/effect/decal/cleanable/dirt, -/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, -/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, -/turf/open/floor/iron, -/area/station/hallway/primary/fore) -"tg" = ( -/turf/closed/wall/rust, -/area/station/maintenance/fore) -"tx" = ( -/obj/structure/transit_tube/crossing, -/obj/effect/turf_decal/sand/plating, -/obj/structure/window/reinforced/spawner/directional/south, -/turf/open/floor/plating/airless, -/area/space/nearstation) -"tz" = ( -/obj/effect/turf_decal/sand/plating, -/obj/structure/sign/warning/secure_area/directional/east, -/turf/open/floor/plating/airless, -/area/space/nearstation) -"tU" = ( -/obj/item/radio/intercom/directional/south, -/turf/open/floor/iron/dark, -/area/station/hallway/primary/fore) -"ud" = ( -/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, -/turf/open/floor/iron/dark, -/area/station/hallway/primary/fore) -"uf" = ( -/obj/effect/landmark/start/nanotrasen_consultant, -/obj/machinery/atmospherics/components/unary/vent_scrubber/on/layer2, -/turf/open/floor/wood, -/area/station/command/heads_quarters/nt_rep) -"uj" = ( -/obj/structure/lattice, -/obj/structure/grille/broken, -/turf/open/space/basic, -/area/space/nearstation) -"uI" = ( -/obj/effect/decal/cleanable/dirt, -/obj/effect/landmark/blobstart, -/obj/effect/turf_decal/stripes/line, -/obj/effect/mapping_helpers/broken_floor, -/turf/open/floor/plating, -/area/station/maintenance/fore) -"uM" = ( -/obj/effect/turf_decal/tile/blue{ - dir = 8 - }, -/obj/machinery/button/curtain{ - id = "barbershopcurtains1"; - pixel_x = -25; - pixel_y = 4 - }, -/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, -/obj/effect/decal/cleanable/dirt, -/obj/effect/landmark/start/hangover, -/turf/open/floor/iron/dark, -/area/station/service/barber) -"uX" = ( -/obj/effect/turf_decal/tile/neutral{ - dir = 4 - }, -/obj/effect/turf_decal/tile/neutral{ - dir = 1 - }, -/obj/machinery/firealarm/directional/north, -/obj/structure/chair/sofa/bench, -/obj/effect/landmark/start/assistant, -/turf/open/floor/iron/dark/corner{ - dir = 4 - }, -/area/station/hallway/primary/fore) -"vp" = ( -/obj/effect/turf_decal/stripes/line{ - dir = 8 - }, -/obj/structure/cable, -/obj/effect/mapping_helpers/burnt_floor, -/turf/open/floor/plating, -/area/station/maintenance/fore/lesser) -"vs" = ( -/obj/effect/turf_decal/sand/plating, -/obj/structure/disposalpipe/segment{ - dir = 4 - }, -/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, -/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, -/obj/structure/cable, -/turf/open/floor/plating/airless, -/area/space/nearstation) -"vE" = ( -/obj/effect/turf_decal/sand/plating, -/obj/structure/disposalpipe/segment{ - dir = 5 - }, -/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, -/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, -/obj/structure/cable, -/turf/open/floor/plating/airless, -/area/space/nearstation) -"vJ" = ( -/obj/effect/turf_decal/tile/purple/opposingcorners{ - dir = 8 - }, -/obj/machinery/airalarm/directional/west, -/obj/effect/decal/cleanable/dirt, -/turf/open/floor/iron/cafeteria, -/area/station/service/barber) -"vS" = ( -/obj/effect/turf_decal/siding/wood/corner{ - dir = 8 - }, -/obj/structure/table/wood, -/obj/item/camera_film{ - pixel_x = -5; - pixel_y = 9 - }, -/obj/item/camera_film, -/turf/open/floor/wood, -/area/station/command/heads_quarters/nt_rep) -"vV" = ( -/obj/effect/decal/cleanable/dirt, -/obj/effect/turf_decal/stripes/line, -/obj/effect/mapping_helpers/burnt_floor, -/turf/open/floor/plating, -/area/station/maintenance/fore) -"wh" = ( -/obj/effect/turf_decal/siding/white{ - dir = 4 - }, -/turf/open/floor/iron, -/area/station/hallway/primary/fore) -"wF" = ( -/turf/open/floor/iron, -/area/station/hallway/primary/fore) -"wK" = ( -/obj/machinery/door/airlock/public{ - name = "Massage Parlour" - }, -/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, -/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, -/obj/machinery/door/firedoor, -/turf/open/floor/iron, -/area/station/service/barber) -"wL" = ( -/obj/machinery/door/airlock/public/glass{ - name = "Ferry Dock" - }, -/obj/machinery/door/firedoor, -/obj/effect/turf_decal/caution/stand_clear, -/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, -/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, -/turf/open/floor/iron/dark, -/area/station/hallway/primary/fore) -"wQ" = ( -/obj/machinery/door/airlock/public/glass{ - name = "Barbershop" - }, -/obj/structure/cable, -/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, -/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, -/obj/machinery/door/firedoor, -/turf/open/floor/iron, -/area/station/service/barber) -"wT" = ( -/obj/structure/cable, -/obj/effect/turf_decal/siding/wood/corner{ - dir = 4 - }, -/obj/machinery/atmospherics/components/unary/vent_pump/on/layer4, -/turf/open/floor/wood, -/area/station/command/heads_quarters/nt_rep) -"xV" = ( -/turf/closed/wall/r_wall/rust, -/area/station/command/heads_quarters/nt_rep) -"yd" = ( -/obj/structure/chair/sofa/bench/left{ - dir = 1 - }, -/obj/effect/turf_decal/tile/green, -/turf/open/floor/iron/dark/corner, -/area/station/hallway/primary/fore) -"yC" = ( -/turf/closed/wall/rust, -/area/station/service/barber) -"yM" = ( -/obj/effect/turf_decal/sand/plating, -/obj/structure/disposalpipe/segment{ - dir = 10 - }, -/turf/open/floor/plating/airless, -/area/space/nearstation) -"zb" = ( -/turf/closed/wall/r_wall, -/area/station/command/heads_quarters/nt_rep) -"ze" = ( -/obj/machinery/light/directional/south, -/obj/effect/turf_decal/stripes/corner{ - dir = 8 - }, -/turf/open/floor/iron, -/area/station/hallway/primary/fore) -"zf" = ( -/obj/structure/lattice, -/obj/structure/sign/warning/secure_area/directional/south, -/turf/open/space/basic, -/area/space/nearstation) -"zu" = ( -/obj/machinery/light/directional/east, -/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, -/turf/open/floor/carpet/executive, -/area/station/command/heads_quarters/nt_rep) -"zF" = ( -/obj/structure/table/wood, -/obj/item/paper_bin{ - pixel_y = 4 - }, -/obj/item/pen/fountain, -/turf/open/floor/carpet/executive, -/area/station/command/heads_quarters/nt_rep) -"zR" = ( -/obj/effect/spawner/structure/window, -/obj/structure/curtain/cloth/fancy/mechanical{ - id = "barbershopcurtains1"; - name = "Massage Parlour Drapes" - }, -/turf/open/floor/plating, -/area/station/service/barber) -"zZ" = ( -/obj/effect/decal/cleanable/dirt, -/turf/open/floor/iron/grimy, -/area/station/hallway/primary/fore) -"Ag" = ( -/turf/closed/wall/rust, -/area/station/maintenance/fore/lesser) -"AB" = ( -/obj/effect/turf_decal/stripes/line{ - dir = 4 - }, -/obj/effect/decal/cleanable/dirt, -/obj/machinery/atmospherics/components/unary/vent_pump/on/layer4, -/turf/open/floor/iron, -/area/station/hallway/primary/fore) -"Be" = ( -/obj/effect/turf_decal/tile/blue{ - dir = 8 - }, -/obj/structure/bed/pod, -/obj/machinery/firealarm/directional/north, -/obj/machinery/camera/directional/west, -/turf/open/floor/iron/dark, -/area/station/service/barber) -"Bs" = ( -/obj/effect/turf_decal/siding/wood{ - dir = 1 - }, -/obj/machinery/camera/directional/east{ - c_tag = "NT Consultant's Office"; - name = "command camera" - }, -/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, -/turf/open/floor/wood, -/area/station/command/heads_quarters/nt_rep) -"Bx" = ( -/obj/structure/disposalpipe/segment{ - dir = 6 - }, -/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, -/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, -/turf/open/floor/iron, -/area/station/hallway/primary/fore) -"BU" = ( -/obj/effect/turf_decal/siding/white{ - dir = 1 - }, -/obj/machinery/atmospherics/components/unary/vent_pump/on/layer4{ - dir = 1 - }, -/obj/effect/landmark/start/barber, -/turf/open/floor/iron/dark, -/area/station/service/barber) -"BZ" = ( -/obj/structure/transit_tube/diagonal/crossing/topleft, -/turf/open/space/basic, -/area/space/nearstation) -"Ce" = ( -/obj/effect/turf_decal/tile/neutral{ - dir = 4 - }, -/obj/effect/turf_decal/stripes/line{ - dir = 1 - }, -/turf/open/floor/iron/dark/corner{ - dir = 4 - }, -/area/station/hallway/primary/fore) -"Cf" = ( -/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, -/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, -/obj/machinery/firealarm/directional/south, -/turf/open/floor/wood, -/area/station/command/heads_quarters/nt_rep) -"Cm" = ( -/obj/structure/flora/rock/style_random, -/turf/open/misc/asteroid/airless, -/area/space/nearstation) -"Da" = ( -/obj/structure/chair/sofa/bench/left{ - dir = 8 - }, -/obj/effect/turf_decal/siding/white{ - dir = 4 - }, -/obj/effect/decal/cleanable/dirt, -/turf/open/floor/iron/dark, -/area/station/hallway/primary/fore) -"Dh" = ( -/obj/effect/turf_decal/stripes/corner{ - dir = 4 - }, -/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, -/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, -/turf/open/floor/iron, -/area/station/hallway/primary/fore) -"Dl" = ( -/turf/open/misc/asteroid/airless, -/area/space/nearstation) -"Dp" = ( -/obj/effect/decal/cleanable/dirt, -/obj/item/radio/intercom/directional/east, -/obj/machinery/camera/directional/east, -/turf/open/floor/iron, -/area/station/hallway/primary/fore) -"DC" = ( -/obj/machinery/door/airlock/public/glass{ - name = "Salon Hallway" - }, -/obj/machinery/door/firedoor, -/obj/effect/turf_decal/caution/stand_clear, -/turf/open/floor/iron/dark, -/area/station/hallway/primary/fore) -"DJ" = ( -/turf/closed/wall/rust, -/area/station/command/heads_quarters/nt_rep) -"Ef" = ( -/obj/machinery/light/directional/north, -/obj/effect/turf_decal/stripes/line{ - dir = 4 - }, -/turf/open/floor/iron, -/area/station/hallway/primary/fore) -"Eg" = ( -/turf/closed/wall, -/area/station/hallway/primary/fore) -"Eh" = ( -/obj/structure/cable, -/obj/effect/turf_decal/tile/blue{ - dir = 8 - }, -/obj/effect/turf_decal/stripes/line, -/turf/open/floor/iron/dark/corner{ - dir = 8 - }, -/area/station/hallway/primary/fore) -"Ek" = ( -/obj/effect/turf_decal/stripes/line{ - dir = 1 - }, -/obj/effect/decal/cleanable/dirt, -/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, -/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, -/obj/structure/cable, -/obj/effect/mapping_helpers/broken_floor, -/turf/open/floor/plating, -/area/station/maintenance/fore) -"En" = ( -/obj/machinery/door/airlock/public/glass{ - name = "Ferry Dock" - }, -/obj/machinery/door/firedoor, -/obj/effect/turf_decal/caution/stand_clear, -/turf/open/floor/iron/dark, -/area/station/hallway/primary/fore) -"Ev" = ( -/obj/structure/chair/office, -/obj/effect/landmark/start/nanotrasen_consultant, -/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, -/turf/open/floor/carpet/executive, -/area/station/command/heads_quarters/nt_rep) -"EG" = ( -/obj/effect/turf_decal/siding/wood{ - dir = 1 - }, -/obj/structure/chair/office{ - dir = 1 - }, -/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, -/turf/open/floor/wood, -/area/station/command/heads_quarters/nt_rep) -"EI" = ( -/obj/effect/turf_decal/tile/purple/opposingcorners{ - dir = 8 - }, -/obj/machinery/power/apc/auto_name/directional/west, -/obj/structure/cable, -/obj/machinery/atmospherics/components/unary/vent_scrubber/on/layer2{ - dir = 4 - }, -/obj/effect/decal/cleanable/dirt, -/obj/machinery/camera/directional/west, -/turf/open/floor/iron/cafeteria, -/area/station/service/barber) -"EO" = ( -/obj/structure/transit_tube/curved/flipped, -/turf/open/space/basic, -/area/space/nearstation) -"EP" = ( -/obj/effect/decal/cleanable/dirt, -/obj/effect/mapping_helpers/broken_floor, -/turf/open/floor/plating, -/area/station/hallway/primary/fore) -"EX" = ( -/obj/structure/table/wood, -/obj/item/stamp{ - pixel_y = 8; - pixel_x = -6 - }, -/obj/item/stamp/denied{ - pixel_x = -6; - pixel_y = 2 - }, -/obj/item/stamp/centcom{ - pixel_x = 6; - pixel_y = 4 - }, -/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, -/turf/open/floor/carpet/executive, -/area/station/command/heads_quarters/nt_rep) -"Fg" = ( -/obj/structure/cable, -/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, -/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, -/obj/effect/turf_decal/tile/blue{ - dir = 8 - }, -/turf/open/floor/iron/dark/corner{ - dir = 8 - }, -/area/station/hallway/primary/fore) -"Fi" = ( -/turf/closed/wall, -/area/station/service/barber) -"Fl" = ( -/obj/effect/turf_decal/stripes/line{ - dir = 4 - }, -/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, -/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, -/turf/open/floor/iron, -/area/station/hallway/primary/fore) -"Fz" = ( -/obj/effect/spawner/structure/window/reinforced, -/turf/open/floor/plating, -/area/station/maintenance/fore/lesser) -"FM" = ( -/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, -/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, -/obj/structure/disposalpipe/segment, -/obj/effect/turf_decal/tile/green{ - dir = 4 - }, -/obj/structure/cable, -/turf/open/floor/iron/dark/corner{ - dir = 4 - }, -/area/station/hallway/primary/fore) -"FQ" = ( -/obj/effect/turf_decal/stripes/line, -/turf/open/floor/iron, -/area/station/hallway/primary/fore) -"FU" = ( -/obj/effect/turf_decal/tile/purple/opposingcorners{ - dir = 8 - }, -/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, -/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, -/obj/effect/decal/cleanable/dirt, -/turf/open/floor/iron/cafeteria, -/area/station/service/barber) -"Gh" = ( -/turf/open/space/basic, -/area/space) -"Gw" = ( -/obj/structure/chair/sofa/bench/left, -/obj/effect/turf_decal/tile/neutral{ - dir = 4 - }, -/obj/effect/turf_decal/stripes/corner{ - dir = 4 - }, -/turf/open/floor/iron/dark/corner{ - dir = 4 - }, -/area/station/hallway/primary/fore) -"GN" = ( -/obj/effect/decal/cleanable/dirt, -/obj/machinery/door/airlock/maintenance, -/obj/effect/mapping_helpers/airlock/unres{ - dir = 4 - }, -/obj/structure/cable, -/obj/effect/mapping_helpers/airlock/cyclelink_helper{ - dir = 8 - }, -/obj/effect/mapping_helpers/airlock/access/all/engineering/maintenance, -/obj/effect/mapping_helpers/burnt_floor, -/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, -/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, -/turf/open/floor/plating, -/area/station/maintenance/fore) -"GU" = ( -/obj/effect/decal/cleanable/dirt, -/obj/structure/sign/poster/random/directional/north, -/obj/structure/cable, -/obj/effect/mapping_helpers/broken_floor, -/turf/open/floor/plating, -/area/station/maintenance/fore/lesser) -"GX" = ( -/obj/effect/turf_decal/tile/blue{ - dir = 8 - }, -/turf/open/floor/iron/dark/corner{ - dir = 8 - }, -/area/station/hallway/primary/fore) -"Ho" = ( -/obj/effect/turf_decal/tile/blue{ - dir = 8 - }, -/obj/item/radio/intercom/directional/west, -/obj/machinery/atmospherics/components/unary/vent_pump/on/layer4{ - dir = 4 - }, -/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, -/obj/effect/decal/cleanable/dirt, -/obj/machinery/light/small/directional/south, -/turf/open/floor/iron/dark, -/area/station/service/barber) -"HJ" = ( -/obj/machinery/light/directional/south, -/obj/effect/turf_decal/stripes/corner, -/obj/structure/noticeboard/directional/south, -/turf/open/floor/iron, -/area/station/hallway/primary/fore) -"HV" = ( -/obj/effect/turf_decal/tile/blue{ - dir = 4 - }, -/obj/structure/table/reinforced/rglass, -/obj/item/hairbrush{ - pixel_x = 6; - pixel_y = 9 - }, -/obj/item/clothing/gloves/latex, -/turf/open/floor/iron/dark, -/area/station/service/barber) -"HW" = ( -/obj/effect/turf_decal/stripes/line{ - dir = 1 - }, -/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, -/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, -/turf/open/floor/iron, -/area/station/hallway/primary/fore) -"Ia" = ( -/obj/effect/decal/cleanable/dirt, -/obj/machinery/atmospherics/components/unary/vent_scrubber/on/layer2{ - dir = 8 - }, -/turf/open/floor/iron, -/area/station/hallway/primary/fore) -"Ib" = ( -/turf/closed/wall, -/area/station/maintenance/fore/lesser) -"Iv" = ( -/obj/machinery/light/directional/north, -/obj/effect/turf_decal/stripes/line{ - dir = 8 - }, -/turf/open/floor/iron, -/area/station/hallway/primary/fore) -"IX" = ( -/obj/structure/table/wood, -/obj/item/taperecorder{ - pixel_y = 5; - pixel_x = 5 - }, -/obj/item/camera{ - pixel_x = -4 - }, -/turf/open/floor/wood, -/area/station/command/heads_quarters/nt_rep) -"Ja" = ( -/obj/effect/decal/cleanable/dirt, -/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, -/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, -/obj/effect/landmark/event_spawn, -/obj/structure/cable, -/obj/effect/mapping_helpers/burnt_floor, -/turf/open/floor/plating, -/area/station/maintenance/fore) -"Jl" = ( -/obj/effect/turf_decal/stripes/line{ - dir = 4 - }, -/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, -/turf/open/floor/iron, -/area/station/hallway/primary/fore) -"Jm" = ( -/obj/structure/cable, -/obj/machinery/status_display/ai/directional/south, -/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, -/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, -/turf/open/floor/wood, -/area/station/command/heads_quarters/nt_rep) -"Jn" = ( -/obj/structure/chair/sofa/bench{ - dir = 8 - }, -/obj/effect/turf_decal/siding/white{ - dir = 4 - }, -/obj/effect/landmark/start/assistant, -/turf/open/floor/iron/dark, -/area/station/hallway/primary/fore) -"Jq" = ( -/obj/effect/turf_decal/stripes/line{ - dir = 8 - }, -/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, -/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, -/turf/open/floor/iron, -/area/station/hallway/primary/fore) -"JP" = ( -/obj/machinery/camera/directional/south, -/obj/effect/decal/cleanable/dirt, -/obj/item/radio/intercom/directional/south, -/turf/open/floor/iron, -/area/station/hallway/primary/fore) -"KA" = ( -/obj/machinery/photocopier, -/obj/machinery/button/door/directional/north{ - id = "nt_rep_priv_2"; - name = "Privacy Shutters Control" - }, -/turf/open/floor/carpet/executive, -/area/station/command/heads_quarters/nt_rep) -"KE" = ( -/obj/effect/turf_decal/stripes/line{ - dir = 8 - }, -/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, -/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, -/obj/effect/mapping_helpers/broken_floor, -/turf/open/floor/plating, -/area/station/hallway/primary/fore) -"KL" = ( -/obj/effect/decal/cleanable/dirt, -/obj/effect/turf_decal/stripes/corner{ - dir = 4 - }, -/obj/effect/turf_decal/bot, -/obj/structure/reagent_dispensers/fueltank, -/obj/effect/mapping_helpers/broken_floor, -/turf/open/floor/plating, -/area/station/maintenance/fore) -"Lw" = ( -/obj/structure/transit_tube/diagonal/topleft, -/turf/open/space/basic, -/area/space/nearstation) -"LI" = ( -/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, -/turf/open/floor/iron/dark, -/area/station/hallway/primary/fore) -"Me" = ( -/obj/structure/lattice, -/obj/structure/grille, -/turf/open/space/basic, -/area/space/nearstation) -"Mt" = ( -/turf/closed/wall/rust, -/area/station/hallway/primary/fore) -"Mu" = ( -/obj/structure/flora/rock/pile/style_2, -/turf/open/misc/asteroid/airless, -/area/space/nearstation) -"Mw" = ( -/obj/effect/turf_decal/tile/purple/opposingcorners{ - dir = 8 - }, -/obj/structure/cable, -/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, -/obj/effect/decal/cleanable/dirt, -/turf/open/floor/iron/cafeteria, -/area/station/service/barber) -"MG" = ( -/obj/effect/decal/cleanable/dirt, -/obj/machinery/atmospherics/components/unary/vent_scrubber/on/layer2{ - dir = 4 - }, -/turf/open/floor/iron, -/area/station/hallway/primary/fore) -"MO" = ( -/obj/effect/turf_decal/stripes/line{ - dir = 1 - }, -/obj/effect/decal/cleanable/dirt, -/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, -/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, -/turf/open/floor/plating, -/area/station/hallway/primary/fore) -"MP" = ( -/turf/closed/wall/rust, -/area/space/nearstation) -"Ng" = ( -/obj/machinery/power/apc/auto_name/directional/north, -/obj/structure/cable, -/obj/effect/turf_decal/siding/wood{ - dir = 4 - }, -/obj/structure/filingcabinet/chestdrawer, -/turf/open/floor/wood, -/area/station/command/heads_quarters/nt_rep) -"Nu" = ( -/obj/effect/decal/cleanable/dirt, -/obj/machinery/atmospherics/components/unary/vent_pump/on/layer4{ - dir = 8 - }, -/obj/effect/landmark/generic_maintenance_landmark, -/turf/open/floor/plating, -/area/station/maintenance/fore) -"NU" = ( -/obj/effect/turf_decal/tile/blue{ - dir = 4 - }, -/obj/effect/turf_decal/stripes/line, -/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, -/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, -/turf/open/floor/iron/dark/corner{ - dir = 4 - }, -/area/station/hallway/primary/fore) -"Op" = ( -/obj/machinery/light/directional/east, -/obj/effect/decal/cleanable/dirt, -/turf/open/floor/iron, -/area/station/hallway/primary/fore) -"Oq" = ( -/obj/docking_port/stationary{ - dheight = 3; - dir = 8; - dwidth = 8; - height = 11; - shuttle_id = "ferry_home"; - name = "Port Bay 2"; - width = 20 - }, -/turf/open/floor/plating, -/area/station/hallway/primary/fore) -"Oy" = ( -/obj/effect/turf_decal/tile/blue{ - dir = 8 - }, -/obj/effect/turf_decal/stripes/line, -/turf/open/floor/iron/dark/corner{ - dir = 8 - }, -/area/station/hallway/primary/fore) -"OJ" = ( -/obj/effect/turf_decal/sand/plating, -/obj/structure/disposalpipe/segment, -/turf/open/floor/plating/airless, -/area/space/nearstation) -"OO" = ( -/obj/structure/disposalpipe/segment{ - dir = 4 - }, -/obj/machinery/light/directional/north, -/obj/structure/closet/emcloset, -/obj/effect/turf_decal/bot, -/obj/effect/turf_decal/tile/green{ - dir = 1 - }, -/turf/open/floor/iron/dark/corner{ - dir = 1 - }, -/area/station/hallway/primary/fore) -"OR" = ( -/obj/machinery/modular_computer/preset/command{ - dir = 4 - }, -/turf/open/floor/carpet/executive, -/area/station/command/heads_quarters/nt_rep) -"OY" = ( -/obj/effect/decal/cleanable/dirt, -/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, -/obj/effect/turf_decal/stripes/line{ - dir = 4 - }, -/obj/structure/cable, -/obj/effect/mapping_helpers/broken_floor, -/turf/open/floor/plating, -/area/station/maintenance/fore) -"Pd" = ( -/obj/effect/turf_decal/tile/blue{ - dir = 8 - }, -/obj/structure/sign/poster/official/random/directional/west, -/turf/open/floor/iron/dark/corner{ - dir = 8 - }, -/area/station/hallway/primary/fore) -"Po" = ( -/obj/structure/table/reinforced/rglass, -/obj/item/reagent_containers/dropper, -/obj/item/hairbrush/comb{ - pixel_y = 10 - }, -/obj/machinery/button/curtain{ - id = "barbershopcurtains"; - pixel_x = 10; - pixel_y = -26 - }, -/turf/open/floor/iron/dark, -/area/station/service/barber) -"Pt" = ( -/obj/structure/fans/tiny/forcefield{ - dir = 1 - }, -/obj/structure/sign/warning/vacuum/external/directional/west, -/obj/machinery/door/poddoor/preopen{ - name = "Dock Shutter" - }, -/turf/open/floor/plating, -/area/station/hallway/primary/fore) -"Pw" = ( -/obj/structure/transit_tube, -/obj/effect/turf_decal/sand/plating, -/turf/open/floor/plating/airless, -/area/space/nearstation) -"PD" = ( -/obj/effect/decal/cleanable/dirt, -/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, -/obj/structure/cable, -/obj/effect/mapping_helpers/burnt_floor, -/turf/open/floor/plating, -/area/station/maintenance/fore) -"Qy" = ( -/obj/effect/turf_decal/stripes/line{ - dir = 8 - }, -/obj/effect/decal/cleanable/dirt, -/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, -/turf/open/floor/iron, -/area/station/hallway/primary/fore) -"Re" = ( -/obj/effect/turf_decal/tile/purple/opposingcorners{ - dir = 8 - }, -/obj/structure/cable, -/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, -/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, -/turf/open/floor/iron/cafeteria, -/area/station/service/barber) -"Rf" = ( -/obj/structure/chair/sofa/bench{ - dir = 8 - }, -/obj/effect/turf_decal/siding/white{ - dir = 4 - }, -/obj/effect/landmark/start/assistant, -/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, -/turf/open/floor/iron/dark, -/area/station/hallway/primary/fore) -"Rj" = ( -/obj/effect/decal/cleanable/dirt, -/obj/machinery/atmospherics/components/unary/vent_scrubber/on/layer2{ - dir = 4 - }, -/turf/open/floor/iron/dark, -/area/station/hallway/primary/fore) -"Ry" = ( -/obj/effect/turf_decal/stripes/corner{ - dir = 1 - }, -/obj/effect/decal/cleanable/dirt, -/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, -/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, -/turf/open/floor/iron, -/area/station/hallway/primary/fore) -"RA" = ( -/obj/structure/disposalpipe/segment{ - dir = 5 - }, -/obj/effect/decal/cleanable/dirt, -/turf/open/floor/plating, -/area/station/maintenance/fore/lesser) -"Sa" = ( -/obj/structure/chair/sofa/bench/left{ - dir = 8 - }, -/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, -/turf/open/floor/iron/dark, -/area/station/hallway/primary/fore) -"Sg" = ( -/obj/effect/turf_decal/stripes/line{ - dir = 8 - }, -/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, -/turf/open/floor/iron, -/area/station/hallway/primary/fore) -"SC" = ( -/obj/effect/turf_decal/tile/blue{ - dir = 4 - }, -/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, -/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, -/turf/open/floor/iron/dark, -/area/station/service/barber) -"SH" = ( -/obj/effect/turf_decal/siding/wood{ - dir = 1 - }, -/obj/structure/chair/office{ - dir = 1 - }, -/turf/open/floor/wood, -/area/station/command/heads_quarters/nt_rep) -"Th" = ( -/obj/effect/decal/cleanable/dirt, -/obj/item/radio/intercom/directional/east, -/turf/open/floor/iron, -/area/station/hallway/primary/fore) -"TD" = ( -/obj/structure/transit_tube, -/obj/structure/disposalpipe/segment, -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/cobweb, -/turf/open/floor/iron/grimy, -/area/station/hallway/primary/fore) -"TG" = ( -/obj/effect/turf_decal/stripes/line, -/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, -/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, -/turf/open/floor/iron, -/area/station/hallway/primary/fore) -"TS" = ( -/turf/template_noop, -/area/template_noop) -"TU" = ( -/obj/structure/table/reinforced/rglass, -/obj/item/razor{ - pixel_x = -6 - }, -/obj/item/reagent_containers/spray/barbers_aid{ - pixel_x = 6 - }, -/obj/machinery/light/directional/south, -/turf/open/floor/iron/dark, -/area/station/service/barber) -"Uc" = ( -/obj/structure/transit_tube/diagonal/topleft, -/turf/open/misc/asteroid/airless, -/area/space/nearstation) -"Ul" = ( -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/food/pie_smudge, -/obj/effect/mapping_helpers/broken_floor, -/turf/open/floor/plating, -/area/station/maintenance/fore) -"Um" = ( -/obj/structure/flora/rock/pile/style_random, -/turf/open/misc/asteroid/airless, -/area/space/nearstation) -"Uw" = ( -/turf/open/floor/iron/dark, -/area/station/hallway/primary/fore) -"UZ" = ( -/obj/effect/turf_decal/tile/green{ - dir = 4 - }, -/obj/effect/turf_decal/stripes/line{ - dir = 1 - }, -/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, -/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, -/turf/open/floor/iron/dark/corner{ - dir = 4 - }, -/area/station/hallway/primary/fore) -"Vp" = ( -/obj/structure/chair/comfy/barber_chair, -/obj/effect/turf_decal/siding/white{ - dir = 1 - }, -/obj/effect/landmark/start/hangover, -/turf/open/floor/iron/dark, -/area/station/service/barber) -"VG" = ( -/obj/effect/mapping_helpers/broken_floor, -/turf/open/floor/plating, -/area/station/hallway/primary/fore) -"Wi" = ( -/obj/effect/turf_decal/stripes/line{ - dir = 1 - }, -/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, -/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, -/turf/open/floor/plating, -/area/station/hallway/primary/fore) -"WA" = ( -/obj/effect/spawner/structure/window, -/obj/structure/curtain/cloth/fancy/mechanical{ - id = "barbershopcurtains"; - name = "Barber Shop Drapes" - }, -/turf/open/floor/plating, -/area/station/service/barber) -"WE" = ( -/obj/machinery/door/airlock/corporate{ - name = "NT Consultant's Office" - }, -/obj/effect/mapping_helpers/airlock/access/all/cent_com/rep_door, -/obj/structure/cable, -/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, -/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, -/obj/machinery/door/firedoor, -/turf/open/floor/iron/dark/corner{ - dir = 4 - }, -/area/station/command/heads_quarters/nt_rep) -"WY" = ( -/obj/effect/turf_decal/tile/blue{ - dir = 4 - }, -/obj/structure/chair/office/light{ - dir = 8 - }, -/obj/machinery/atmospherics/components/unary/vent_scrubber/on/layer2{ - dir = 8 - }, -/obj/effect/landmark/start/barber, -/turf/open/floor/iron/dark, -/area/station/service/barber) -"Xo" = ( -/obj/structure/disposalpipe/segment, -/obj/machinery/firealarm/directional/east, -/obj/effect/turf_decal/tile/green{ - dir = 4 - }, -/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, -/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, -/turf/open/floor/iron/dark/corner{ - dir = 4 - }, -/area/station/hallway/primary/fore) -"Xp" = ( -/obj/machinery/atmospherics/components/unary/vent_pump/on/layer4{ - dir = 8 - }, -/turf/open/floor/iron, -/area/station/hallway/primary/fore) -"XI" = ( -/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, -/turf/open/floor/iron, -/area/station/hallway/primary/fore) -"XJ" = ( -/obj/effect/turf_decal/stripes/corner{ - dir = 1 - }, -/obj/effect/decal/cleanable/dirt, -/obj/effect/turf_decal/stripes/corner, -/obj/effect/spawner/random/structure/crate, -/obj/effect/mapping_helpers/broken_floor, -/turf/open/floor/plating, -/area/station/maintenance/fore) -"XL" = ( -/turf/closed/mineral/random/labormineral, -/area/space/nearstation) -"XP" = ( -/obj/effect/turf_decal/sand/plating, -/turf/open/floor/plating/airless, -/area/space/nearstation) -"Yl" = ( -/obj/structure/table/reinforced/rglass, -/obj/structure/mirror/directional/south, -/obj/item/lipstick/random{ - pixel_x = -6; - pixel_y = -5 - }, -/obj/item/lipstick/random, -/obj/item/reagent_containers/spray/quantum_hair_dye{ - pixel_x = 9 - }, -/turf/open/floor/iron/dark, -/area/station/service/barber) -"YD" = ( -/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, -/turf/open/floor/wood, -/area/station/command/heads_quarters/nt_rep) -"YS" = ( -/obj/effect/turf_decal/sand/plating, -/obj/structure/disposalpipe/segment{ - dir = 5 - }, -/turf/open/floor/plating/airless, -/area/space/nearstation) -"Zb" = ( -/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, -/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, -/turf/open/floor/wood, -/area/station/command/heads_quarters/nt_rep) -"Ze" = ( -/obj/structure/transit_tube/crossing, -/obj/effect/turf_decal/sand/plating, -/turf/open/floor/plating/airless, -/area/space/nearstation) -"Zv" = ( -/obj/structure/disposalpipe/segment, -/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, -/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, -/turf/open/floor/iron, -/area/station/hallway/primary/fore) -"ZN" = ( -/obj/structure/table/wood, -/turf/open/floor/carpet/executive, -/area/station/command/heads_quarters/nt_rep) - -(1,1,1) = {" -Gh -Gh -Gh -Gh -Gh -Gh -Gh -Gh -Gh -jY -Gh -Gh -Gh -Gh -Gh -Gh -Gh -Gh -Gh -Gh -Gh -BZ -dZ -Gh -Gh -Gh -Gh -Dl -Dl -vs -XL -TS -TS -TS -TS -TS -TS -TS -TS -TS -TS -TS -"} -(2,1,1) = {" -XL -Gh -Gh -Gh -Gh -Dl -Dl -Gh -Gh -Gh -nN -nN -nN -nN -nN -nN -Gh -Gh -Gh -Gh -Gh -Gh -ad -dZ -dZ -dZ -dZ -dZ -XP -gW -vE -TS -TS -TS -TS -TS -TS -TS -TS -TS -TS -TS -"} -(3,1,1) = {" -XL -Dl -Gh -Gh -Dl -Dl -Dl -Dl -Gh -nN -nN -rE -wh -kh -rE -nN -nN -Gh -Gh -Gh -Gh -Gh -Gh -Lw -Dl -Dl -Dl -Dl -Dl -Dl -hj -TS -TS -TS -TS -TS -TS -TS -TS -TS -TS -TS -"} -(4,1,1) = {" -XL -Dl -Dl -Gh -Mu -Dl -Dl -Dl -Dl -nN -Uw -Rj -jK -jK -cc -Uw -nN -Dl -Dl -Dl -Dl -Gh -Dl -Dl -hS -Dl -Dl -Dl -Dl -Dl -hj -TS -TS -TS -TS -TS -TS -TS -TS -TS -TS -TS -"} -(5,1,1) = {" -Dl -Dl -Dl -Dl -Dl -Dl -Dl -Dl -nN -nN -jK -bV -mU -gy -Sa -jV -nN -nN -Dl -Mu -Dl -Dl -Dl -Dl -Dl -Uc -Dl -Dl -Dl -XL -hj -TS -TS -TS -TS -TS -TS -TS -TS -TS -TS -TS -"} -(6,1,1) = {" -Dl -Dl -Dl -Dl -Dl -Dl -Dl -Dl -Eg -rz -jK -LI -Uw -jK -ud -Uw -tU -Eg -Dl -Dl -Dl -Dl -Dl -Dl -Dl -Dl -Uc -Dl -Gh -Gh -yM -OJ -YS -TS -TS -TS -TS -TS -TS -TS -TS -TS -"} -(7,1,1) = {" -Dl -Dl -Mt -Mt -Eg -nN -nN -nN -Eg -jS -qj -Rf -Jn -jC -nE -Da -hs -Mt -Mt -nN -nN -nN -Eg -Eg -nN -Eg -Gh -bH -dZ -dZ -dZ -fR -hj -TS -TS -TS -TS -TS -TS -TS -TS -TS -"} -(8,1,1) = {" -Gh -Gh -Eg -ku -cf -EP -nW -MG -nW -nW -wF -rT -wF -wF -XI -nW -nW -jV -fc -fF -kI -wF -fr -EP -nW -nN -Gh -dZ -Lw -Gh -Gh -dZ -hj -TS -TS -TS -TS -TS -TS -TS -TS -TS -"} -(9,1,1) = {" -Gh -Gh -Eg -Ef -AB -Jl -Jl -Fl -Fl -Fl -sz -sz -Fl -Fl -Fl -sz -sz -Fl -Fl -Fl -Fl -Fl -Fl -Dh -MG -nN -Gh -dZ -dZ -Lw -Gh -XP -yM -OJ -OJ -OJ -OJ -nc -fA -RA -TS -TS -"} -(10,1,1) = {" -Gh -Gh -Pt -jV -jV -jV -jV -jV -jV -jV -jV -jV -jV -jV -jV -jV -jV -jV -jV -jV -jV -jV -jV -HW -iD -nN -Gh -Gh -dZ -dZ -EO -Ze -Pw -Pw -Ze -Pw -Pw -tx -lw -jJ -dV -TD -"} -(11,1,1) = {" -Gh -Gh -iM -jV -jV -jV -jV -jV -jV -jV -jV -jV -jV -jV -jV -jV -jV -jV -jV -jV -jV -jV -jV -HW -hd -Eg -dZ -dZ -dZ -dZ -dZ -XP -tz -Dl -Dl -Dl -Dl -hg -rt -gH -Fz -zZ -"} -(12,1,1) = {" -Gh -Gh -iM -jV -jV -jV -jV -jV -jV -jV -jV -jV -jV -jV -jV -jV -jV -jV -jV -jV -jV -jV -jV -HW -JP -Eg -Gh -Gh -dZ -Gh -dZ -dZ -Fi -Fi -yC -Fi -Fi -yC -Ib -bb -Ag -ha -"} -(13,1,1) = {" -Gh -Gh -iM -jV -jV -jV -jV -jV -jV -jV -jV -jV -jV -jV -jV -jV -jV -jV -jV -jV -jV -jV -jV -Wi -kE -nN -Gh -Gh -Fi -yC -Fi -yC -yC -lU -EI -vJ -rk -Po -Ib -vp -Ib -qS -"} -(14,1,1) = {" -Gh -Gh -iM -jV -jV -jV -jV -jV -jV -jV -jV -jV -jV -jV -jV -jV -jV -jV -jV -jV -jV -jV -jV -MO -nW -nN -Gh -Gh -yC -Be -uM -Ho -yC -ey -Mw -dC -Vp -Yl -Ib -iv -Ag -uX -"} -(15,1,1) = {" -Gh -Gh -iM -jV -jV -jV -jV -jV -jV -jV -jV -jV -jV -jV -jV -jV -jV -jV -jV -jV -jV -jV -jV -gw -nW -nN -Gh -Gh -yC -HV -WY -SC -wK -FU -Re -Re -BU -TU -Ib -GU -Ib -lr -"} -(16,1,1) = {" -Gh -Gh -iM -jV -jV -jV -jV -jV -jV -jV -jV -jV -jV -jV -jV -jV -jV -jV -jV -jV -jV -jV -jV -gw -HJ -Eg -nN -nN -Fi -zR -zR -zR -Fi -WA -WA -wQ -WA -WA -Ag -iy -Ib -Gw -"} -(17,1,1) = {" -Gh -Gh -iM -jV -jV -jV -jV -jV -jV -jV -jV -jV -jV -jV -Oq -jV -jV -jV -jV -jV -jV -jV -jV -HW -FQ -En -gv -Oy -En -gv -GX -GX -Pd -GX -GX -Fg -nF -nF -nF -Eh -DC -Ce -"} -(18,1,1) = {" -Gh -Gh -iM -jV -jV -jV -jV -jV -jV -jV -jV -jV -jV -jV -jV -jV -jV -jV -jV -jV -jV -jV -jV -gw -TG -wL -gx -NU -wL -UZ -fb -Bx -Zv -Zv -Xo -su -su -FM -su -dY -bj -oi -"} -(19,1,1) = {" -Gh -Gh -iM -jV -jV -jV -jV -jV -jV -jV -jV -jV -jV -jV -jV -jV -jV -jV -jV -jV -jV -jV -jV -gw -ze -Eg -nN -nN -Eg -Eg -Eg -OO -wF -qU -zb -oR -oR -WE -oZ -GN -pf -tg -"} -(20,1,1) = {" -Gh -Gh -cW -jV -jV -jV -jV -jV -jV -jV -jV -jV -jV -jV -jV -jV -jV -jV -jV -jV -jV -jV -jV -gw -VG -nN -Dl -Dl -Dl -Dl -Mt -gk -wF -yd -xV -qM -vS -rL -zb -bB -pf -qg -"} -(21,1,1) = {" -Gh -Gh -Eg -Iv -iV -Sg -Sg -Qy -Qy -Qy -kP -Jq -kP -kP -kP -kP -Jq -Jq -Jq -KE -Jq -Jq -Jq -Ry -wF -nN -Dl -Dl -Dl -Um -Mt -df -ds -nS -zb -IX -uf -Jm -xV -fT -pf -pf -"} -(22,1,1) = {" -Gh -Gh -Eg -dG -nW -nW -Th -an -kE -nW -Ia -Op -wF -wF -wF -wF -nv -Dp -nW -nW -kE -wF -Op -Xp -wF -nN -Dl -Dl -Dl -Dl -Eg -Mt -xV -kz -xV -Ng -wT -fx -zb -Ek -Ja -qr -"} -(23,1,1) = {" -Gh -Gh -Mt -nN -nN -nN -Eg -Mt -nN -nN -nN -Eg -Eg -nN -nN -nN -Eg -Eg -nN -nN -nN -Eg -Eg -nN -nN -Mt -Dl -Dl -Gh -XL -XL -XL -xV -KA -OR -ZN -gX -Zb -zb -XJ -OY -KL -"} -(24,1,1) = {" -Gh -Gh -Gh -Gh -Gh -Dl -Dl -Dl -Dl -Dl -Dl -Dl -Cm -Dl -Dl -Dl -Dl -Dl -Dl -Dl -Dl -Dl -Dl -Dl -Dl -Dl -Dl -Gh -Gh -XL -XL -XL -zb -ca -Ev -EX -EG -Cf -xV -ew -eZ -pf -"} -(25,1,1) = {" -Gh -Gh -Gh -Gh -Gh -Dl -Dl -Dl -Dl -Dl -Dl -Dl -Dl -Dl -Dl -Dl -Dl -Dl -Dl -Gh -Gh -Gh -Gh -Gh -Gh -Gh -Gh -Gh -jY -Gh -XL -XL -DJ -cX -mZ -zF -SH -YD -zb -jA -PD -nA -"} -(26,1,1) = {" -Gh -Gh -Gh -Gh -Dl -Dl -Dl -Um -XL -XL -Dl -Dl -Dl -Dl -Dl -Dl -Gh -Gh -Gh -Gh -Gh -Gh -Gh -Gh -Gh -Gh -Gh -Gh -Gh -Gh -Gh -XL -zb -cm -aK -zu -Bs -YD -zb -eL -Nu -vV -"} -(27,1,1) = {" -Gh -Gh -Gh -Gh -Dl -Dl -XL -XL -XL -MP -mi -fR -XL -Dl -Um -XL -fR -dZ -uj -Me -Me -Me -dZ -fR -dZ -uj -Me -Me -Me -Me -zf -ne -xV -zb -zb -zb -zb -zb -xV -eQ -Ul -uI -"} From ae02eba4190a533aba33f23bb8eee5f48a79e9d8 Mon Sep 17 00:00:00 2001 From: Iajret Creature <122297233+Steals-The-PRs@users.noreply.github.com> Date: Fri, 24 Nov 2023 12:44:35 +0300 Subject: [PATCH 57/72] [MIRROR] [READY] The Tackleling: Unarmed bonuses and features contribute to tackle success and failure, significant outcome overhaul, among other things [MDB IGNORE] (#776) * [READY] The Tackleling: Unarmed bonuses and features contribute to tackle success and failure, significant outcome overhaul, among other things * Update tackle.dm * Update living.dm * Update tackle.dm --------- Co-authored-by: SkyratBot <59378654+SkyratBot@users.noreply.github.com> Co-authored-by: necromanceranne <40847847+necromanceranne@users.noreply.github.com> Co-authored-by: Bloop <13398309+vinylspiders@users.noreply.github.com> --- code/__DEFINES/combat.dm | 6 +- code/__DEFINES/status_effects.dm | 5 + code/datums/components/tackle.dm | 235 +++++++++++++----- .../status_effects/debuffs/staggered.dm | 41 +++ code/game/objects/items/storage/garment.dm | 1 + .../objects/structures/beds_chairs/chair.dm | 5 +- .../crates_lockers/closets/secure/security.dm | 1 + code/modules/clothing/gloves/tacklers.dm | 2 +- code/modules/clothing/shoes/_shoes.dm | 4 +- code/modules/clothing/suits/armor.dm | 5 +- .../mob/living/carbon/carbon_defense.dm | 19 +- .../mob/living/carbon/human/_species.dm | 14 +- code/modules/mob/living/living.dm | 3 +- code/modules/movespeed/modifiers/mobs.dm | 4 +- code/modules/vending/security.dm | 2 +- tgstation.dme | 1 + 16 files changed, 249 insertions(+), 99 deletions(-) create mode 100644 code/datums/status_effects/debuffs/staggered.dm diff --git a/code/__DEFINES/combat.dm b/code/__DEFINES/combat.dm index d619da64d48..5df4128be62 100644 --- a/code/__DEFINES/combat.dm +++ b/code/__DEFINES/combat.dm @@ -171,9 +171,9 @@ DEFINE_BITFIELD(status_flags, list( #define SHOVE_KNOCKDOWN_TABLE 20 #define SHOVE_KNOCKDOWN_COLLATERAL 1 #define SHOVE_CHAIN_PARALYZE 30 -//Shove slowdown -#define SHOVE_SLOWDOWN_LENGTH 30 -#define SHOVE_SLOWDOWN_STRENGTH 0.85 //multiplier +//Staggered slowdown, an effect caused by shoving and a few other features, such as tackling +#define STAGGERED_SLOWDOWN_LENGTH 30 +#define STAGGERED_SLOWDOWN_STRENGTH 0.85 //multiplier //Shove disarming item list GLOBAL_LIST_INIT(shove_disarming_types, typecacheof(list( /obj/item/gun))) diff --git a/code/__DEFINES/status_effects.dm b/code/__DEFINES/status_effects.dm index 03a3bf49ebb..768f1faa514 100644 --- a/code/__DEFINES/status_effects.dm +++ b/code/__DEFINES/status_effects.dm @@ -114,6 +114,11 @@ #define set_dizzy(duration) set_timed_status_effect(duration, /datum/status_effect/dizziness) #define set_dizzy_if_lower(duration) set_timed_status_effect(duration, /datum/status_effect/dizziness, TRUE) +#define adjust_staggered(duration) adjust_timed_status_effect(duration, /datum/status_effect/staggered) +#define adjust_staggered_up_to(duration, up_to) adjust_timed_status_effect(duration, /datum/status_effect/staggered, up_to) +#define set_staggered(duration) set_timed_status_effect(duration, /datum/status_effect/staggered) +#define set_staggered_if_lower(duration) set_timed_status_effect(duration, /datum/status_effect/staggered, TRUE) + #define adjust_jitter(duration) adjust_timed_status_effect(duration, /datum/status_effect/jitter) #define adjust_jitter_up_to(duration, up_to) adjust_timed_status_effect(duration, /datum/status_effect/jitter, up_to) #define set_jitter(duration) set_timed_status_effect(duration, /datum/status_effect/jitter) diff --git a/code/datums/components/tackle.dm b/code/datums/components/tackle.dm index a5b5606bf72..1148e2b5993 100644 --- a/code/datums/components/tackle.dm +++ b/code/datums/components/tackle.dm @@ -96,7 +96,7 @@ to_chat(user, span_warning("You're not ready to tackle!")) return - if(user.has_movespeed_modifier(/datum/movespeed_modifier/shove)) // can't tackle if you just got shoved + if(user.get_timed_status_effect_duration(/datum/status_effect/staggered)) // can't tackle if you're staggered to_chat(user, span_warning("You're too off balance to tackle!")) return @@ -131,12 +131,9 @@ * Check [rollTackle()][/datum/component/tackler/proc/rollTackle] for a more thorough explanation on the modifiers at play. * * Then, we figure out what effect we want, and we get to work! Note that with standard gripper gloves and no modifiers, the range of rolls is (-3, 3). The results are as follows, based on what we rolled: - * * -inf to -5: Seriously botched tackle, tackler suffers a concussion, brute damage, and a 3 second paralyze, target suffers nothing - * * -4 to -2: weak tackle, tackler gets 3 second knockdown, target gets shove slowdown but is otherwise fine - * * -1 to 0: decent tackle, tackler gets up a bit quicker than the target - * * 1: solid tackle, tackler has more of an advantage getting up quicker - * * 2 to 4: expert tackle, tackler has sizeable advantage and lands on their feet with a free passive grab - * * 5 to inf: MONSTER tackle, tackler gets up immediately and gets a free aggressive grab, target takes sizeable stamina damage from the hit and is paralyzed for one and a half seconds and knocked down for three seconds + * * -inf to -1: We have a negative roll result, which means something unfortunate or less than ideal happens to our sacker! Could mean just getting knocked down, but it could also mean they get a concussion. Ouch. + * * 0: We get a relatively neutral result, mildly favouring the tackler. + * * 1 to inf: We get a positive roll result, which means we get a reasonable to significant advantage against the target! * * Finally, we return a bitflag to [COMSIG_MOVABLE_IMPACT] that forces the hitpush to false so that we don't knock them away. */ @@ -155,53 +152,74 @@ return var/mob/living/carbon/target = hit - var/mob/living/carbon/human/T = target - var/mob/living/carbon/human/S = user - var/tackle_word = isfeline(user) ? "pounce" : "tackle" //If cat, "pounce" instead of "tackle". // SKYRAT EDIT - FELINE TRAITS. Was: isfelinid(user) + var/tackle_word = isfeline(user) ? "pounce" : "tackle" //If cat, "pounce" instead of "tackle". // SKYRAT EDIT - FELINE TRAITS - ORIGINAL : var/tackle_word = isfelinid(user) ? "pounce" : "tackle" + + if(target.check_block(user, 0, user.name, attack_type = LEAP_ATTACK)) + user.visible_message(span_danger("[user]'s tackle is blocked by [target], softening the effect!"), span_userdanger("Your tackle is blocked by [target], softening the effect!"), ignored_mobs = target) + to_chat(target, span_userdanger("[target] blocks [user]'s tackle attempt, softening the effect!")) + neutral_outcome(user, target, tackle_word) //Forces a neutral outcome so you're not screwed too much from being blocked while tackling + return var/roll = rollTackle(target) tackling = FALSE tackle.gentle = TRUE switch(roll) - if(-INFINITY to -5) - user.visible_message(span_danger("[user] botches [user.p_their()] [tackle_word] and slams [user.p_their()] head into [target], knocking [user.p_them()]self silly!"), span_userdanger("You botch your [tackle_word] and slam your head into [target], knocking yourself silly!"), ignored_mobs = target) - to_chat(target, span_userdanger("[user] botches [user.p_their()] [tackle_word] and slams [user.p_their()] head into you, knocking [user.p_them()]self silly!")) + if(-INFINITY to -1) + negative_outcome(user, target, roll, tackle_word) //OOF - user.Paralyze(3 SECONDS) - var/obj/item/bodypart/head/hed = user.get_bodypart(BODY_ZONE_HEAD) - if(hed) - hed.receive_damage(brute = 15, updating_health = TRUE, wound_bonus = CANT_WOUND) - user.gain_trauma(/datum/brain_trauma/mild/concussion) + if(0) //nothing good, nothing bad + neutral_outcome(user, target, tackle_word) - if(-4 to -2) // glancing blow at best - user.visible_message(span_warning("[user] lands a weak [tackle_word] on [target], briefly knocking [target.p_them()] off-balance!"), span_userdanger("You land a weak [tackle_word] on [target], briefly knocking [target.p_them()] off-balance!"), ignored_mobs = target) - to_chat(target, span_userdanger("[user] lands a weak [tackle_word] on you, briefly knocking you off-balance!")) + if(1 to INFINITY) + positive_outcome(user, target, roll, tackle_word) - user.Knockdown(30) - if(ishuman(target) && !T.has_movespeed_modifier(/datum/movespeed_modifier/shove)) - T.add_movespeed_modifier(/datum/movespeed_modifier/shove) // maybe define a slightly more severe/longer slowdown for this - addtimer(CALLBACK(T, TYPE_PROC_REF(/mob/living/carbon, clear_shove_slowdown)), SHOVE_SLOWDOWN_LENGTH * 2) + return COMPONENT_MOVABLE_IMPACT_FLIP_HITPUSH - if(-1 to 0) // decent hit, both parties are about equally inconvenienced - user.visible_message(span_warning("[user] lands a passable [tackle_word] on [target], sending them both tumbling!"), span_userdanger("You land a passable [tackle_word] on [target], sending you both tumbling!"), ignored_mobs = target) - to_chat(target, span_userdanger("[user] lands a passable [tackle_word] on you, sending you both tumbling!")) +/** + * Our positive tackling outcomes. + * + * We pass our tackle result here to determine the potential outcome of the tackle. Typically, this results in a very poor state for the tackled, and a positive outcome for the tackler. + * + * First, we determine severity by taking our roll result, multiplying it by 10, and then rolling within that value. + * + * If our target is human, their armor will reduce the severity of the roll. We pass along any MELEE armor as a percentage reduction. + * If they're not human (such as a carbon), we give them a small grace of a 10% reduction. + * + * Finally, we figure out what effect our target receives. Note that all positive outcomes inflict staggered, resulting in a much harder time escaping the potential grab: + * * 1 to 20: Our target is briefly stunned and knocked down. suffers 30 stamina damage, and our tackler is also knocked down. + * * 21 to 49: Our target is knocked down, dealt 40 stamina damage, and put into a passive grab. Given they are staggered, this means the target must resist to escape! + * * 50 to inf: Our target is hit with a significant chunk of stamina damage, put into an aggressive grab, and knocked down. They're probably not escaping after this. If our tackler is stamcrit when they land this, so is our target. +*/ - target.adjustStaminaLoss(stamina_cost) - target.Paralyze(0.5 SECONDS) - user.Knockdown(2 SECONDS) - target.Knockdown(2.5 SECONDS) +/datum/component/tackler/proc/positive_outcome(mob/living/carbon/user, mob/living/carbon/target, roll = 1, tackle_word = "tackle") + var/potential_outcome = (roll * 10) - if(1 to 2) // solid hit, tackler has a slight advantage + if(ishuman(target)) + var/mob/living/carbon/human/human_target = target + var/target_armor = human_target.run_armor_check(BODY_ZONE_CHEST, MELEE) + potential_outcome *= ((100 - target_armor) /100) + else + potential_outcome *= 0.9 + + var/mob/living/carbon/human/human_target = target + var/mob/living/carbon/human/human_sacker = user + + switch(potential_outcome) + if(-INFINITY to 0) //I don't want to know how this has happened, okay? + neutral_outcome(user, target, roll, tackle_word) //Default to neutral + + if(1 to 20) user.visible_message(span_warning("[user] lands a solid [tackle_word] on [target], knocking them both down hard!"), span_userdanger("You land a solid [tackle_word] on [target], knocking you both down hard!"), ignored_mobs = target) to_chat(target, span_userdanger("[user] lands a solid [tackle_word] on you, knocking you both down hard!")) - target.adjustStaminaLoss(30) + target.apply_damage(30, STAMINA) target.Paralyze(0.5 SECONDS) user.Knockdown(1 SECONDS) target.Knockdown(2 SECONDS) + target.adjust_staggered_up_to(STAGGERED_SLOWDOWN_LENGTH * 2, 10 SECONDS) - if(3 to 4) // really good hit, the target is definitely worse off here. Without positive modifiers, this is as good a tackle as you can land + if(21 to 49) // really good hit, the target is definitely worse off here. Without positive modifiers, this is as good a tackle as you can land user.visible_message(span_warning("[user] lands an expert [tackle_word] on [target], knocking [target.p_them()] down hard while landing on [user.p_their()] feet with a passive grip!"), span_userdanger("You land an expert [tackle_word] on [target], knocking [target.p_them()] down hard while landing on your feet with a passive grip!"), ignored_mobs = target) to_chat(target, span_userdanger("[user] lands an expert [tackle_word] on you, knocking you down hard and maintaining a passive grab!")) @@ -209,22 +227,24 @@ user.SetKnockdown(0, ignore_canstun = TRUE) user.get_up(TRUE) user.forceMove(get_turf(target)) - target.adjustStaminaLoss(40) + target.apply_damage(40, STAMINA) target.Paralyze(0.5 SECONDS) target.Knockdown(3 SECONDS) + target.adjust_staggered_up_to(STAGGERED_SLOWDOWN_LENGTH * 2, 10 SECONDS) if(ishuman(target) && ishuman(user)) - INVOKE_ASYNC(S.dna.species, TYPE_PROC_REF(/datum/species, grab), S, T) - S.setGrabState(GRAB_PASSIVE) + INVOKE_ASYNC(human_sacker.dna.species, TYPE_PROC_REF(/datum/species, grab), human_sacker, human_target) + human_sacker.setGrabState(GRAB_PASSIVE) - if(5 to INFINITY) // absolutely BODIED + if(50 to INFINITY) // absolutely BODIED var/stamcritted_user = HAS_TRAIT_FROM(user, TRAIT_INCAPACITATED, STAMINA) - if(stamcritted_user) // in case the user went into stamcrit from the tackle itself and cannot actually aggro grab (since they will be crit) we make the tackle a bit more effective on the target + if(stamcritted_user) // in case the user went into stamcrit from the tackle itself and cannot actually aggro grab (since they will be crit) we make the tackle effectivelly mutually assured...stamina crit user.visible_message(span_warning("[user] lands a monsterly reckless [tackle_word] on [target], knocking both of them senseless!"), span_userdanger("You land a monsterly reckless [tackle_word] on [target], knocking both of you senseless!"), ignored_mobs = target) to_chat(target, span_userdanger("[user] lands a monsterly reckless [tackle_word] on you, knocking the both of you senseless!")) user.forceMove(get_turf(target)) - target.adjustStaminaLoss(60) + target.apply_damage(100, STAMINA) // CRASHING THIS PLANE WITH NO SURVIVORS target.Paralyze(1 SECONDS) target.Knockdown(5 SECONDS) + target.adjust_staggered_up_to(STAGGERED_SLOWDOWN_LENGTH * 3, 10 SECONDS) else user.visible_message(span_warning("[user] lands a monster [tackle_word] on [target], knocking [target.p_them()] senseless and applying an aggressive pin!"), span_userdanger("You land a monster [tackle_word] on [target], knocking [target.p_them()] senseless and applying an aggressive pin!"), ignored_mobs = target) to_chat(target, span_userdanger("[user] lands a monster [tackle_word] on you, knocking you senseless and aggressively pinning you!")) @@ -233,15 +253,90 @@ user.SetKnockdown(0, ignore_canstun = TRUE) user.get_up(TRUE) user.forceMove(get_turf(target)) - target.adjustStaminaLoss(40) + target.apply_damage(60, STAMINA) target.Paralyze(0.5 SECONDS) target.Knockdown(3 SECONDS) + target.adjust_staggered_up_to(STAGGERED_SLOWDOWN_LENGTH * 3, 10 SECONDS) if(ishuman(target) && ishuman(user)) - INVOKE_ASYNC(S.dna.species, TYPE_PROC_REF(/datum/species, grab), S, T) - S.setGrabState(GRAB_AGGRESSIVE) + INVOKE_ASYNC(human_sacker.dna.species, TYPE_PROC_REF(/datum/species, grab), human_sacker, human_target) + human_sacker.setGrabState(GRAB_AGGRESSIVE) +/** + * Our neutral tackling outcome. + * + * Our tackler and our target are staggered. The target longer than the tackler. However, the tackler stands up after this outcome. This is maybe less neutral than it appears, but the tackler initiated, so... + * This outcome also occurs when our target has blocked the tackle in some way, preventing situations where someone tackling into a blocker is too severely punished as a result. Hence, this has its own proc. +*/ - return COMPONENT_MOVABLE_IMPACT_FLIP_HITPUSH +/datum/component/tackler/proc/neutral_outcome(mob/living/carbon/user, mob/living/carbon/target, roll = 1, tackle_word = "tackle") + + + user.visible_message(span_warning("[user] lands a [tackle_word] on [target], briefly staggering them both!"), span_userdanger("You land a [tackle_word] on [target], briefly staggering [target.p_them()] and yourself!"), ignored_mobs = target) + to_chat(target, span_userdanger("[user] lands a [tackle_word] on you, briefly staggering you both!")) + + user.get_up(TRUE) + user.adjust_staggered_up_to(STAGGERED_SLOWDOWN_LENGTH, 10 SECONDS) + target.adjust_staggered_up_to(STAGGERED_SLOWDOWN_LENGTH * 2, 10 SECONDS) //okay maybe slightly good for the sacker, it's a mild benefit okay? + +/** + * Our negative tackling outcomes. + * + * We pass our tackle result here to determine the potential outcome of the tackle. Typically, this results in a very poor state for the tackler, and a mostly okay outcome for the tackled. + * + * First, we determine severity by taking our roll result, multiplying it by -10, and then rolling within that value. + * + * If our tackler is human, their armor will reduce the severity of the roll. We pass along any MELEE armor as a percentage reduction. + * If they're not human (such as a carbon), we give them a small grace of a 10% reduction. + * + * Finally, we figure out what effect our target receives and what our tackler receives: + * * 1 to 20: Our tackler is knocked down and become staggered, and our target suffers stamina damage and is knocked staggered. So not all bad, but the target most likely can punish you for this. + * * 21 to 49: Our tackler is knocked down, suffers stamina damage, and is staggered. Ouch. + * * 50 to inf: Our tackler suffers a catastrophic failure, receiving significant stamina damage, a concussion, and is paralyzed for 3 seconds. Oh, and they're staggered for a LONG time. +*/ + +/datum/component/tackler/proc/negative_outcome(mob/living/carbon/user, mob/living/carbon/target, roll = -1, tackle_word = "tackle") + var/potential_roll_outcome = (roll * -10) + + if(ishuman(user)) + var/mob/living/carbon/human/human_sacker = target + var/attacker_armor = human_sacker.run_armor_check(BODY_ZONE_CHEST, MELEE) + potential_roll_outcome *= ((100 - attacker_armor) /100) + else + potential_roll_outcome *= 0.9 + + var/actual_roll = rand(1, potential_roll_outcome) + + switch(actual_roll) + + if(-INFINITY to 0) //I don't want to know how this has happened, okay? + neutral_outcome(user, target, roll, tackle_word) //Default to neutral + + if(1 to 20) // It's not completely terrible! But you are somewhat vulernable for doing it. + user.visible_message(span_warning("[user] lands a weak [tackle_word] on [target], briefly staggering [target.p_them()]!"), span_userdanger("You land a weak [tackle_word] on [target], briefly staggering [target.p_them()]!"), ignored_mobs = target) + to_chat(target, span_userdanger("[user] lands a weak [tackle_word] on you, staggering you!")) + + user.Knockdown(1 SECONDS) + user.adjust_staggered_up_to(STAGGERED_SLOWDOWN_LENGTH * 2, 10 SECONDS) + target.apply_damage(20, STAMINA) + target.adjust_staggered_up_to(STAGGERED_SLOWDOWN_LENGTH * 2, 10 SECONDS) + + if(21 to 49) // oughe + user.visible_message(span_warning("[user] lands a dreadful [tackle_word] on [target], briefly knocking [user.p_them()] to the ground!"), span_userdanger("You land a dreadful [tackle_word] on [target], briefly knocking you to the ground!"), ignored_mobs = target) + to_chat(target, span_userdanger("[user] lands a dreadful [tackle_word] on you, briefly knocking [user.p_them()] to the ground!")) + + user.Knockdown(3 SECONDS) + user.apply_damage(40, STAMINA) + user.adjust_staggered_up_to(STAGGERED_SLOWDOWN_LENGTH * 2, 10 SECONDS) + + if(50 to INFINITY) // It has been decided that you will suffer + user.visible_message(span_danger("[user] botches [user.p_their()] [tackle_word] and slams [user.p_their()] head into [target], knocking [user.p_them()]self silly!"), span_userdanger("You botch your [tackle_word] and slam your head into [target], knocking yourself silly!"), ignored_mobs = target) + to_chat(target, span_userdanger("[user] botches [user.p_their()] [tackle_word] and slams [user.p_their()] head into you, knocking [user.p_them()]self silly!")) + + user.Paralyze(3 SECONDS) + user.apply_damage(80, STAMINA) + user.apply_damage(20, BRUTE, BODY_ZONE_HEAD) + user.gain_trauma(/datum/brain_trauma/mild/concussion) + user.adjust_staggered_up_to(STAGGERED_SLOWDOWN_LENGTH * 3, 10 SECONDS) /** * This handles all of the modifiers for the actual carbon-on-carbon tackling, and gets its own proc because of how many there are (with plenty more in mind!) @@ -266,14 +361,21 @@ else if(target_drunkenness > 30) defense_mod -= 1 + //Arms contribute a great deal to potential tackling prowess and defense. Better arms = better bonus + var/obj/item/bodypart/arm/defender_arm = target.get_active_hand() + + if(defender_arm) //the target may not actually have arms + defense_mod += (defender_arm.unarmed_effectiveness/10) + else //sucks to be you if you don't though haha + defense_mod -= 2 + if(HAS_TRAIT(target, TRAIT_CLUMSY)) defense_mod -= 2 if(HAS_TRAIT(target, TRAIT_FAT)) // chonkers are harder to knock over defense_mod += 1 if(HAS_TRAIT(target, TRAIT_GRABWEAKNESS)) defense_mod -= 2 - if(HAS_TRAIT(target, TRAIT_DWARF)) - defense_mod -= 2 + if(HAS_TRAIT(target, TRAIT_GIANT)) defense_mod += 2 if(target.get_organic_health() < 50) @@ -289,15 +391,15 @@ if(ishuman(target)) var/mob/living/carbon/human/tackle_target = target + if(tackle_target.get_mob_height() <= HUMAN_HEIGHT_SHORTEST) //WHO ARE YOU CALLING SHORT? + defense_mod -= 2 + if(isnull(tackle_target.wear_suit) && isnull(tackle_target.w_uniform)) // who honestly puts all of their effort into tackling a naked guy? defense_mod += 2 if(tackle_target.mob_negates_gravity()) defense_mod += 1 if(tackle_target.is_shove_knockdown_blocked()) // riot armor and such defense_mod += 5 - if(tackle_target.is_holding_item_of_type(/obj/item/shield)) - defense_mod += 2 - var/obj/item/organ/external/tail/lizard/el_tail = tackle_target.get_organ_slot(ORGAN_SLOT_EXTERNAL_TAIL) if(HAS_TRAIT(tackle_target, TRAIT_TACKLING_TAILED_DEFENDER) && !el_tail) @@ -308,6 +410,15 @@ // OF-FENSE var/mob/living/carbon/sacker = parent var/sacker_drunkenness = sacker.get_drunk_amount() + + //Arms contribute a great deal to potential tackling prowess and defense. Better arms = better bonus + var/obj/item/bodypart/arm/sacker_arm = sacker.get_active_hand() + + if(sacker_arm) //I have no idea how you would be tackling without hands, but just in case + attack_mod += (sacker_arm.unarmed_effectiveness/10) + else //I don't want to know how you got to this point but if you have, fuck you, good luck tackling without ARMS + attack_mod -= 4 + if(sacker_drunkenness > 60) // you're far too drunk to hold back! attack_mod += 1 else if(sacker_drunkenness > 30) // if you're only a bit drunk though, you're just sloppy @@ -315,10 +426,10 @@ if(HAS_TRAIT(sacker, TRAIT_CLUMSY)) attack_mod -= 2 - if(HAS_TRAIT(sacker, TRAIT_DWARF)) - attack_mod -= 2 if(HAS_TRAIT(sacker, TRAIT_GIANT)) attack_mod += 2 + if(HAS_TRAIT(sacker, TRAIT_NOGUNS)) //Those dedicated to martial combat are particularly skilled tacklers + attack_mod += 2 if(HAS_TRAIT(sacker, TRAIT_TACKLING_WINGED_ATTACKER)) var/obj/item/organ/external/wings/moth/sacker_moth_wing = sacker.get_organ_slot(ORGAN_SLOT_EXTERNAL_WINGS) @@ -328,16 +439,22 @@ if(sacker_wing) attack_mod += 2 - if(ishuman(target)) - var/mob/living/carbon/human/S = sacker + if(ishuman(sacker)) + var/mob/living/carbon/human/human_sacker = sacker - var/suit_slot = S.get_item_by_slot(ITEM_SLOT_OCLOTHING) - if(suit_slot && (istype(suit_slot,/obj/item/clothing/suit/armor/riot))) // tackling in riot armor is more effective, but tiring + if(human_sacker.get_mob_height() <= HUMAN_HEIGHT_SHORTEST) //JUST YOU WAIT TILL I FIND A CHAIR, BUDDY, THEN YOU'LL BE SORRY + attack_mod -= 2 + + if(human_sacker.mob_mood.sanity_level == SANITY_INSANE) //I've gone COMPLETELY INSANE + attack_mod += 15 + human_sacker.adjustStaminaLoss(100) //AHAHAHAHAHAHAHAHA + + if(human_sacker.is_shove_knockdown_blocked()) // tackling with riot specialized armor, like riot armor, is effective but tiring attack_mod += 2 - sacker.adjustStaminaLoss(20) + human_sacker.adjustStaminaLoss(20) - var/r = rand(-3, 3) - defense_mod + attack_mod + skill_mod - return r + var/randomized_tackle_roll = rand(-3, 3) - defense_mod + attack_mod + skill_mod + return randomized_tackle_roll /** diff --git a/code/datums/status_effects/debuffs/staggered.dm b/code/datums/status_effects/debuffs/staggered.dm new file mode 100644 index 00000000000..5723bc16013 --- /dev/null +++ b/code/datums/status_effects/debuffs/staggered.dm @@ -0,0 +1,41 @@ +/datum/status_effect/staggered + id = "staggered" + tick_interval = 0.5 SECONDS + alert_type = null + remove_on_fullheal = TRUE + +/datum/status_effect/staggered/on_creation(mob/living/new_owner, duration = 10 SECONDS) + src.duration = duration + return ..() + +/datum/status_effect/staggered/on_apply() + + //a very mild animation, but you can't stagger the dead. + if(owner.stat == DEAD) + owner.do_stagger_animation(duration / 10) + return FALSE + + RegisterSignal(owner, COMSIG_LIVING_DEATH, PROC_REF(clear_staggered)) + owner.add_movespeed_modifier(/datum/movespeed_modifier/staggered) + return TRUE + +/datum/status_effect/staggered/on_remove() + UnregisterSignal(owner, COMSIG_LIVING_DEATH) + owner.remove_movespeed_modifier(/datum/movespeed_modifier/staggered) + // Resetting both X on remove so we're back to normal + owner.pixel_x = owner.base_pixel_x + +/// Signal proc that self deletes our staggered effect +/datum/status_effect/staggered/proc/clear_staggered(datum/source) + SIGNAL_HANDLER + + qdel(src) + +/datum/status_effect/staggered/tick(seconds_between_ticks) + owner.do_stagger_animation() + +/// Helper proc that causes the mob to do a stagger animation. +/// Doesn't change significantly, just meant to represent swaying back and forth +/mob/living/proc/do_stagger_animation() + animate(src, pixel_x = 4, time = 0.2 SECONDS, loop = 6, flags = ANIMATION_RELATIVE|ANIMATION_PARALLEL) + animate(pixel_x = -4, time = 0.2 SECONDS, flags = ANIMATION_RELATIVE) diff --git a/code/game/objects/items/storage/garment.dm b/code/game/objects/items/storage/garment.dm index 9398b675b1b..e9ff2f28ce1 100644 --- a/code/game/objects/items/storage/garment.dm +++ b/code/game/objects/items/storage/garment.dm @@ -82,6 +82,7 @@ new /obj/item/clothing/under/rank/security/head_of_security/grey(src) new /obj/item/clothing/under/rank/security/head_of_security/parade(src) new /obj/item/clothing/under/rank/security/head_of_security/parade/female(src) + new /obj/item/clothing/gloves/tackler/combat(src) new /obj/item/clothing/suit/armor/hos(src) new /obj/item/clothing/suit/armor/hos/hos_formal(src) new /obj/item/clothing/suit/armor/hos/trenchcoat/winter(src) diff --git a/code/game/objects/structures/beds_chairs/chair.dm b/code/game/objects/structures/beds_chairs/chair.dm index b9c80fd7f6c..ddb588db782 100644 --- a/code/game/objects/structures/beds_chairs/chair.dm +++ b/code/game/objects/structures/beds_chairs/chair.dm @@ -380,11 +380,8 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/structure/chair/stool/bar, 0) new /obj/item/stack/rods(get_turf(loc), 2) qdel(src) - - - /obj/item/chair/hit_reaction(mob/living/carbon/human/owner, atom/movable/hitby, attack_text = "the attack", final_block_chance = 0, damage = 0, attack_type = MELEE_ATTACK, damage_type = BRUTE) - if(attack_type == UNARMED_ATTACK && prob(hit_reaction_chance)) + if(attack_type == UNARMED_ATTACK && prob(hit_reaction_chance) || attack_type == LEAP_ATTACK && prob(hit_reaction_chance)) owner.visible_message(span_danger("[owner] fends off [attack_text] with [src]!")) return TRUE return FALSE diff --git a/code/game/objects/structures/crates_lockers/closets/secure/security.dm b/code/game/objects/structures/crates_lockers/closets/secure/security.dm index f25c9cfec5d..3a2b54b74f5 100755 --- a/code/game/objects/structures/crates_lockers/closets/secure/security.dm +++ b/code/game/objects/structures/crates_lockers/closets/secure/security.dm @@ -109,6 +109,7 @@ new /obj/item/radio/headset/headset_sec/alt(src) new /obj/item/clothing/glasses/hud/security/sunglasses(src) new /obj/item/flashlight/seclite(src) + new /obj/item/clothing/gloves/tackler(src) /obj/structure/closet/secure_closet/security/sec diff --git a/code/modules/clothing/gloves/tacklers.dm b/code/modules/clothing/gloves/tacklers.dm index 888ecac39ee..986d8356b1a 100644 --- a/code/modules/clothing/gloves/tacklers.dm +++ b/code/modules/clothing/gloves/tacklers.dm @@ -21,7 +21,7 @@ /// See: [/datum/component/tackler/var/speed] var/tackle_speed = 1 /// See: [/datum/component/tackler/var/skill_mod] - var/skill_mod = 0 + var/skill_mod = 1 /obj/item/clothing/gloves/tackler/Destroy() tackler = null diff --git a/code/modules/clothing/shoes/_shoes.dm b/code/modules/clothing/shoes/_shoes.dm index 118c28c0e51..e7d87f34bca 100644 --- a/code/modules/clothing/shoes/_shoes.dm +++ b/code/modules/clothing/shoes/_shoes.dm @@ -254,9 +254,7 @@ if(14 to 25) // 1.3ish% chance to stumble and be a bit off balance (like being disarmed) to_chat(our_guy, span_danger("You stumble a bit on your untied shoelaces!")) - if(!our_guy.has_movespeed_modifier(/datum/movespeed_modifier/shove)) - our_guy.add_movespeed_modifier(/datum/movespeed_modifier/shove) - addtimer(CALLBACK(our_guy, TYPE_PROC_REF(/mob/living/carbon, clear_shove_slowdown)), SHOVE_SLOWDOWN_LENGTH) + our_guy.adjust_staggered_up_to(STAGGERED_SLOWDOWN_LENGTH, 10 SECONDS) if(26 to 1000) wiser = FALSE diff --git a/code/modules/clothing/suits/armor.dm b/code/modules/clothing/suits/armor.dm index e2af151e49d..ae8b786fbef 100644 --- a/code/modules/clothing/suits/armor.dm +++ b/code/modules/clothing/suits/armor.dm @@ -369,13 +369,14 @@ /obj/item/clothing/suit/armor/swat name = "MK.I SWAT Suit" - desc = "A tactical suit first developed in a joint effort by the defunct IS-ERI and Nanotrasen in 2321 for military operations. It has a minor slowdown, but offers decent protection." + desc = "A tactical suit first developed in a joint effort by the defunct IS-ERI and Nanotrasen in 2321 for military operations. \ + It has a minor slowdown, but offers decent protection and helps the wearer resist shoving in close quarters." icon_state = "heavy" inhand_icon_state = "swat_suit" armor_type = /datum/armor/armor_swat strip_delay = 120 resistance_flags = FIRE_PROOF | ACID_PROOF - clothing_flags = THICKMATERIAL + clothing_flags = BLOCKS_SHOVE_KNOCKDOWN | THICKMATERIAL cold_protection = CHEST | GROIN | LEGS | FEET | ARMS | HANDS min_cold_protection_temperature = SPACE_SUIT_MIN_TEMP_PROTECT_OFF heat_protection = CHEST | GROIN | LEGS | FEET | ARMS | HANDS diff --git a/code/modules/mob/living/carbon/carbon_defense.dm b/code/modules/mob/living/carbon/carbon_defense.dm index 2032eb511ff..0eb3945af8c 100644 --- a/code/modules/mob/living/carbon/carbon_defense.dm +++ b/code/modules/mob/living/carbon/carbon_defense.dm @@ -383,21 +383,14 @@ if(!is_type_in_typecache(target_held_item, GLOB.shove_disarming_types)) //It's too expensive we'll get caught target_held_item = null - if(!target.has_movespeed_modifier(/datum/movespeed_modifier/shove)) - target.add_movespeed_modifier(/datum/movespeed_modifier/shove) - target.emote("sway") - if(target_held_item) - append_message = "loosening [target.p_their()] grip on [target_held_item]" - target.visible_message(span_danger("[target.name]'s grip on \the [target_held_item] loosens!"), //He's already out what are you doing - span_warning("Your grip on \the [target_held_item] loosens!"), null, COMBAT_MESSAGE_RANGE) - addtimer(CALLBACK(target, TYPE_PROC_REF(/mob/living/carbon, clear_shove_slowdown)), SHOVE_SLOWDOWN_LENGTH) - - else if(target_held_item) + if(target_held_item && target.get_timed_status_effect_duration(/datum/status_effect/staggered)) target.dropItemToGround(target_held_item) append_message = "causing [target.p_them()] to drop [target_held_item]" target.visible_message(span_danger("[target.name] drops \the [target_held_item]!"), span_warning("You drop \the [target_held_item]!"), null, COMBAT_MESSAGE_RANGE) + target.adjust_staggered_up_to(STAGGERED_SLOWDOWN_LENGTH, 10 SECONDS) + log_combat(src, target, "shoved", append_message) /mob/living/carbon/proc/is_shove_knockdown_blocked() //If you want to add more things that block shove knockdown, extend this @@ -406,12 +399,6 @@ return TRUE return FALSE -/mob/living/carbon/proc/clear_shove_slowdown() - remove_movespeed_modifier(/datum/movespeed_modifier/shove) - var/active_item = get_active_held_item() - if(is_type_in_typecache(active_item, GLOB.shove_disarming_types)) - visible_message(span_warning("[name] regains their grip on \the [active_item]!"), span_warning("You regain your grip on \the [active_item]"), null, COMBAT_MESSAGE_RANGE) - /mob/living/carbon/blob_act(obj/structure/blob/B) if (stat == DEAD) return diff --git a/code/modules/mob/living/carbon/human/_species.dm b/code/modules/mob/living/carbon/human/_species.dm index 48956982eb1..a5a41ef0b1f 100644 --- a/code/modules/mob/living/carbon/human/_species.dm +++ b/code/modules/mob/living/carbon/human/_species.dm @@ -1175,14 +1175,14 @@ GLOBAL_LIST_EMPTY(features_by_species) return FALSE user.do_attack_animation(target, atk_effect) - //has our target been shoved recently? If so, they're off-balance and we get an easy hit. - var/off_balance = FALSE + //has our target been shoved recently? If so, they're staggered and we get an easy hit. + var/staggered = FALSE //Someone in a grapple is much more vulnerable to being harmed by punches. var/grappled = FALSE - if(target.has_movespeed_modifier(/datum/movespeed_modifier/shove)) - off_balance = TRUE + if(target.get_timed_status_effect_duration(/datum/status_effect/staggered)) + staggered = TRUE if(target.pulledby && target.pulledby.grab_state >= GRAB_AGGRESSIVE) grappled = TRUE @@ -1194,7 +1194,7 @@ GLOBAL_LIST_EMPTY(features_by_species) var/miss_chance = 100//calculate the odds that a punch misses entirely. considers stamina and brute damage of the puncher. punches miss by default to prevent weird cases if(attacking_bodypart.unarmed_damage_low) - if((target.body_position == LYING_DOWN) || HAS_TRAIT(user, TRAIT_PERFECT_ATTACKER) || off_balance) //kicks and attacks against off-balance targets never miss (provided your species deals more than 0 damage) + if((target.body_position == LYING_DOWN) || HAS_TRAIT(user, TRAIT_PERFECT_ATTACKER) || staggered) //kicks and attacks against staggered targets never miss (provided your species deals more than 0 damage) miss_chance = 0 else miss_chance = clamp(UNARMED_MISS_CHANCE_BASE - limb_accuracy + user.getStaminaLoss() + (user.getBruteLoss()*0.5), 0, UNARMED_MISS_CHANCE_MAX) //Limb miss chance + various damage. capped at 80 so there is at least a chance to land a hit. @@ -1237,8 +1237,8 @@ GLOBAL_LIST_EMPTY(features_by_species) target.force_say() log_combat(user, target, "punched") - //If we rolled a punch high enough to hit our stun threshold, or our target is off-balance and they have at least 40 damage+stamina loss, we knock them down - if((target.stat != DEAD) && prob(limb_accuracy) || (target.stat != DEAD) && off_balance && (target.getStaminaLoss() + user.getBruteLoss()) >= 40) + //If we rolled a punch high enough to hit our stun threshold, or our target is staggered and they have at least 40 damage+stamina loss, we knock them down + if((target.stat != DEAD) && prob(limb_accuracy) || (target.stat != DEAD) && staggered && (target.getStaminaLoss() + user.getBruteLoss()) >= 40) target.visible_message(span_danger("[user] knocks [target] down!"), \ span_userdanger("You're knocked down by [user]!"), span_hear("You hear aggressive shuffling followed by a loud thud!"), COMBAT_MESSAGE_RANGE, user) to_chat(user, span_danger("You knock [target] down!")) diff --git a/code/modules/mob/living/living.dm b/code/modules/mob/living/living.dm index 5e4a564125c..8611bf85eb4 100644 --- a/code/modules/mob/living/living.dm +++ b/code/modules/mob/living/living.dm @@ -1163,7 +1163,8 @@ /mob/living/resist_grab(moving_resist) . = TRUE - if(pulledby.grab_state || body_position == LYING_DOWN || HAS_TRAIT(src, TRAIT_GRABWEAKNESS) || has_movespeed_modifier(/datum/movespeed_modifier/shove) && getStaminaLoss() > STAMINA_THRESHOLD_HARD_RESIST) //SKYRAT EDIT CHANGE - ORIGINAL : if(pulledby.grab_state || body_position == LYING_DOWN || HAS_TRAIT(src, TRAIT_GRABWEAKNESS) || has_movespeed_modifier(/datum/movespeed_modifier/shove) && getStaminaLoss() >= 30) + //If we're in an aggressive grab or higher, we're lying down, we're vulnerable to grabs, or we're staggered and we have some amount of stamina loss, we must resist + if(pulledby.grab_state || body_position == LYING_DOWN || HAS_TRAIT(src, TRAIT_GRABWEAKNESS) || get_timed_status_effect_duration(/datum/status_effect/staggered) && getStaminaLoss() > STAMINA_THRESHOLD_HARD_RESIST) //SKYRAT EDIT CHANGE - ORIGINAL : if(pulledby.grab_state || body_position == LYING_DOWN || HAS_TRAIT(src, TRAIT_GRABWEAKNESS) || get_timed_status_effect_duration(/datum/status_effect/staggered) && getStaminaLoss() >= 30) var/altered_grab_state = pulledby.grab_state if(body_position == LYING_DOWN || HAS_TRAIT(src, TRAIT_GRABWEAKNESS) && pulledby.grab_state < GRAB_KILL) //If prone, resisting out of a grab is equivalent to 1 grab state higher. won't make the grab state exceed the normal max, however - SKYRAT EDIT CHANGE: if((resting || HAS_TRAIT(src, TRAIT_GRABWEAKNESS)) && pulledby.grab_state < GRAB_KILL) //If resting, resisting out of a grab is equivalent to 1 grab state higher. won't make the grab state exceed the normal max, however altered_grab_state++ diff --git a/code/modules/movespeed/modifiers/mobs.dm b/code/modules/movespeed/modifiers/mobs.dm index 49358223e35..b782f2fc959 100644 --- a/code/modules/movespeed/modifiers/mobs.dm +++ b/code/modules/movespeed/modifiers/mobs.dm @@ -81,8 +81,8 @@ blacklisted_movetypes = FLOATING variable = TRUE -/datum/movespeed_modifier/shove - multiplicative_slowdown = SHOVE_SLOWDOWN_STRENGTH +/datum/movespeed_modifier/staggered + multiplicative_slowdown = STAGGERED_SLOWDOWN_STRENGTH /datum/movespeed_modifier/human_carry multiplicative_slowdown = HUMAN_CARRY_SLOWDOWN diff --git a/code/modules/vending/security.dm b/code/modules/vending/security.dm index b54edffe4c0..feae0499655 100644 --- a/code/modules/vending/security.dm +++ b/code/modules/vending/security.dm @@ -16,6 +16,7 @@ /obj/item/storage/box/evidence = 6, /obj/item/flashlight/seclite = 4, /obj/item/restraints/legcuffs/bola/energy = 7, + /obj/item/clothing/gloves/tackler = 5, ) contraband = list( /obj/item/clothing/glasses/sunglasses = 2, @@ -26,7 +27,6 @@ /obj/item/coin/antagtoken = 1, /obj/item/clothing/head/helmet/blueshirt = 1, /obj/item/clothing/suit/armor/vest/blueshirt = 1, - /obj/item/clothing/gloves/tackler = 5, /obj/item/grenade/stingbang = 1, /obj/item/watertank/pepperspray = 2, /obj/item/storage/belt/holster/energy = 4, diff --git a/tgstation.dme b/tgstation.dme index 97709cd1a6c..feefc44cb28 100644 --- a/tgstation.dme +++ b/tgstation.dme @@ -1850,6 +1850,7 @@ #include "code\datums\status_effects\debuffs\slimed.dm" #include "code\datums\status_effects\debuffs\spacer.dm" #include "code\datums\status_effects\debuffs\speech_debuffs.dm" +#include "code\datums\status_effects\debuffs\staggered.dm" #include "code\datums\status_effects\debuffs\static_vision.dm" #include "code\datums\status_effects\debuffs\strandling.dm" #include "code\datums\status_effects\debuffs\terrified.dm" From aa3b263ec29573f06a4df6efa76a55cd9c3e26d2 Mon Sep 17 00:00:00 2001 From: Iajret Creature <122297233+Steals-The-PRs@users.noreply.github.com> Date: Fri, 24 Nov 2023 12:44:59 +0300 Subject: [PATCH 58/72] [PORT] Gives Synths Internal Computers (& One Other Thing) (#792) * initial d * wew * amazing * you got it boss * thanks * blackpilled once again * Apply suggestions from code review * Apply suggestions from code review * Update brain.dm * Apply suggestions from code review * Update modular_skyrat/modules/synths/code/bodyparts/internal_computer/internal_computer.dm * swag * yee * Apply suggestions from code review * Update modular_skyrat/modules/synths/code/bodyparts/internal_computer/internal_computer.dm * Update modular_skyrat/modules/synths/code/bodyparts/internal_computer/internal_computer.dm --------- Co-authored-by: Nerevar <12636964+Nerev4r@users.noreply.github.com> Co-authored-by: Snakebittenn <12636964+Snakebittenn@users.noreply.github.com> Co-authored-by: Bloop <13398309+vinylspiders@users.noreply.github.com> --- .../code/bodyparts/internal_computer/brain.dm | 11 ++ .../internal_computer/internal_computer.dm | 117 ++++++++++++++++++ tgstation.dme | 2 + 3 files changed, 130 insertions(+) create mode 100644 modular_skyrat/modules/synths/code/bodyparts/internal_computer/brain.dm create mode 100644 modular_skyrat/modules/synths/code/bodyparts/internal_computer/internal_computer.dm diff --git a/modular_skyrat/modules/synths/code/bodyparts/internal_computer/brain.dm b/modular_skyrat/modules/synths/code/bodyparts/internal_computer/brain.dm new file mode 100644 index 00000000000..9b65b3f6772 --- /dev/null +++ b/modular_skyrat/modules/synths/code/bodyparts/internal_computer/brain.dm @@ -0,0 +1,11 @@ +/obj/item/organ/internal/brain/synth + var/obj/item/modular_computer/pda/synth/internal_computer + actions_types = list(/datum/action/item_action/synth/open_internal_computer) + +/obj/item/organ/internal/brain/synth/Initialize(mapload) + . = ..() + internal_computer = new(src) + +/obj/item/organ/internal/brain/synth/Destroy() + QDEL_NULL(internal_computer) + return ..() diff --git a/modular_skyrat/modules/synths/code/bodyparts/internal_computer/internal_computer.dm b/modular_skyrat/modules/synths/code/bodyparts/internal_computer/internal_computer.dm new file mode 100644 index 00000000000..89f24cdcede --- /dev/null +++ b/modular_skyrat/modules/synths/code/bodyparts/internal_computer/internal_computer.dm @@ -0,0 +1,117 @@ +/// Custom computer for synth brains +/obj/item/modular_computer/pda/synth + name = "virtual persocom" + + base_active_power_usage = 0 + base_idle_power_usage = 0 + + long_ranged = TRUE //Synths have good antennae + + max_idle_programs = 3 + + max_capacity = 32 + +/obj/item/modular_computer/pda/synth/Initialize(mapload) + . = ..() + + // prevent these from being created outside of synth brains + if(!istype(loc, /obj/item/organ/internal/brain/synth)) + return INITIALIZE_HINT_QDEL + +/datum/action/item_action/synth/open_internal_computer + name = "Open persocom emulation" + desc = "Accesses your built-in virtual machine." + check_flags = AB_CHECK_CONSCIOUS + +/datum/action/item_action/synth/open_internal_computer/Trigger(trigger_flags) + . = ..() + var/obj/item/organ/internal/brain/synth/targetmachine = target + targetmachine.internal_computer.interact(owner) + +/obj/item/modular_computer/pda/synth/ui_state(mob/user) + return GLOB.default_state + +/obj/item/modular_computer/pda/synth/ui_status(mob/user) + var/obj/item/organ/internal/brain/synth/brain_loc = loc + if(!istype(brain_loc)) + return UI_CLOSE + + if(!QDELETED(brain_loc.owner)) + if(brain_loc.owner == user) + return min( + ui_status_user_is_abled(user, src), + ui_status_only_living(user), + ) + else return UI_CLOSE + return ..() + +/obj/item/modular_computer/pda/synth/RemoveID(mob/user) + var/obj/item/organ/internal/brain/synth/brain_loc = loc + if(!istype(brain_loc)) + return ..() + + if(!computer_id_slot) + return ..() + + if(crew_manifest_update) + GLOB.manifest.modify(computer_id_slot.registered_name, computer_id_slot.assignment, computer_id_slot.get_trim_assignment()) + + if(user && !issilicon(user) && in_range(brain_loc.owner || brain_loc, user)) + user.put_in_hands(computer_id_slot) + else + computer_id_slot.forceMove(brain_loc.owner ? brain_loc.owner.drop_location() : brain_loc.drop_location()) //We actually update the physical on brain removal/insert + + computer_id_slot = null + playsound(src, 'sound/machines/terminal_insert_disc.ogg', 50, FALSE) + balloon_alert(user, "removed ID") + +/obj/item/modular_computer/pda/synth/get_ntnet_status() + . = NTNET_NO_SIGNAL + // NTNet is down and we are not connected via wired connection. The synth is no more + var/obj/item/organ/internal/brain/synth/brain_loc = loc + if(!istype(brain_loc)) + return + if(!find_functional_ntnet_relay() || isnull(brain_loc.owner)) + return + var/turf/current_turf = get_turf(brain_loc.owner || brain_loc) + if(is_station_level(current_turf.z)) + return NTNET_GOOD_SIGNAL + else if(long_ranged && !is_centcom_level(current_turf.z)) // Centcom is excluded because cafe + return NTNET_LOW_SIGNAL + +/* +So, I am not snowflaking more code.. except this +Attacking a synth with an id loads it into its slot.. pain and probably shitcode +*/ + +/obj/item/card/id/attack(mob/living/target_mob, mob/living/user, params) + var/mob/living/carbon/human/targetmachine = target_mob + if(!istype(targetmachine)) + return ..() + + var/obj/item/organ/internal/brain/synth/robotbrain = targetmachine.get_organ_slot(ORGAN_SLOT_BRAIN) + if(istype(robotbrain)) + if(user.zone_selected == BODY_ZONE_PRECISE_EYES) + balloon_alert(user, "Inserting ID into persocom slot...") + if(do_after(user, 5 SECONDS)) + balloon_alert(user, "ID slot interface registered!") + to_chat(targetmachine, span_notice("[user] inserts [src] into your persocom's card slot.")) + robotbrain.internal_computer.InsertID(src, user) + return + return ..() + +/obj/item/modular_computer/pda/attack(mob/living/target_mob, mob/living/user, params) + var/mob/living/carbon/human/targetmachine = target_mob + if(!istype(targetmachine)) + return ..() + + var/obj/item/organ/internal/brain/synth/robotbrain = targetmachine.get_organ_slot(ORGAN_SLOT_BRAIN) + if(istype(robotbrain)) + if(user.zone_selected == BODY_ZONE_PRECISE_EYES) + balloon_alert(user, "Establishing SSH login with persocom...") + if(do_after(user, 5 SECONDS)) + balloon_alert(user, "Connection established!") + to_chat(targetmachine, span_notice("[user] establishes an SSH connection between [src] and your persocom emulation.")) + robotbrain.internal_computer.interact(user) + return + return ..() diff --git a/tgstation.dme b/tgstation.dme index feefc44cb28..76e55f89a08 100644 --- a/tgstation.dme +++ b/tgstation.dme @@ -7869,6 +7869,8 @@ #include "modular_skyrat\modules\synths\code\bodyparts\silicon_alt_brains.dm" #include "modular_skyrat\modules\synths\code\bodyparts\stomach.dm" #include "modular_skyrat\modules\synths\code\bodyparts\tongue.dm" +#include "modular_skyrat\modules\synths\code\bodyparts\internal_computer\brain.dm" +#include "modular_skyrat\modules\synths\code\bodyparts\internal_computer\internal_computer.dm" #include "modular_skyrat\modules\synths\code\reagents\blood_pack.dm" #include "modular_skyrat\modules\synths\code\reagents\pill.dm" #include "modular_skyrat\modules\synths\code\reagents\pill_bottles.dm" From b2b96e54b98922d823a372d3749259e00b4741aa Mon Sep 17 00:00:00 2001 From: Iajret Creature <122297233+Steals-The-PRs@users.noreply.github.com> Date: Fri, 24 Nov 2023 12:45:28 +0300 Subject: [PATCH 59/72] [MIRROR] Fixes hearing messages from speakers on another z level (515 fix) [MDB IGNORE] (#799) * Fixes hearing messages from speakers on another z level (515 fix) (#79888) --------- Co-authored-by: SkyratBot <59378654+SkyratBot@users.noreply.github.com> Co-authored-by: Emmett Gaines --- code/__DEFINES/dcs/signals/signals_object.dm | 2 ++ code/game/machinery/telecomms/broadcasting.dm | 2 +- .../game/objects/items/devices/radio/radio.dm | 3 +- code/modules/mob/living/living_say.dm | 2 +- code/modules/unit_tests/say.dm | 31 +++++++++++++++++-- 5 files changed, 34 insertions(+), 6 deletions(-) diff --git a/code/__DEFINES/dcs/signals/signals_object.dm b/code/__DEFINES/dcs/signals/signals_object.dm index c1d9e88786a..1f17b3646da 100644 --- a/code/__DEFINES/dcs/signals/signals_object.dm +++ b/code/__DEFINES/dcs/signals/signals_object.dm @@ -310,6 +310,8 @@ #define COMSIG_RADIO_NEW_FREQUENCY "radio_new_frequency" ///called from base of /obj/item/radio/proc/talk_into(): (atom/movable/M, message, channel) #define COMSIG_RADIO_NEW_MESSAGE "radio_new_message" +///called from base of /obj/item/radio/proc/on_receive_messgae(): (list/data) +#define COMSIG_RADIO_RECEIVE_MESSAGE "radio_receive_message" // /obj/item/pen signals diff --git a/code/game/machinery/telecomms/broadcasting.dm b/code/game/machinery/telecomms/broadcasting.dm index 97ecd19e470..e8ecb72393f 100644 --- a/code/game/machinery/telecomms/broadcasting.dm +++ b/code/game/machinery/telecomms/broadcasting.dm @@ -155,7 +155,7 @@ radios += independent_radio for(var/obj/item/radio/called_radio as anything in radios) - called_radio.on_recieve_message() + called_radio.on_recieve_message(data) // From the list of radios, find all mobs who can hear those. var/list/receive = get_hearers_in_radio_ranges(radios) diff --git a/code/game/objects/items/devices/radio/radio.dm b/code/game/objects/items/devices/radio/radio.dm index 1bc96c35122..1a356686a74 100644 --- a/code/game/objects/items/devices/radio/radio.dm +++ b/code/game/objects/items/devices/radio/radio.dm @@ -388,7 +388,8 @@ return TRUE return FALSE -/obj/item/radio/proc/on_recieve_message() +/obj/item/radio/proc/on_recieve_message(list/data) + SEND_SIGNAL(src, COMSIG_RADIO_RECEIVE_MESSAGE, data) flick_overlay_view(overlay_speaker_active, 5 SECONDS) /obj/item/radio/ui_state(mob/user) diff --git a/code/modules/mob/living/living_say.dm b/code/modules/mob/living/living_say.dm index 50b4abf8035..de01642f0c6 100644 --- a/code/modules/mob/living/living_say.dm +++ b/code/modules/mob/living/living_say.dm @@ -283,7 +283,7 @@ GLOBAL_LIST_INIT(message_modes_stat_limits, list( var/dist = get_dist(speaker, src) - message_range if(dist > 0 && dist <= EAVESDROP_EXTRA_RANGE && !HAS_TRAIT(src, TRAIT_GOOD_HEARING) && !isobserver(src)) // ghosts can hear all messages clearly raw_message = stars(raw_message) - if (dist > EAVESDROP_EXTRA_RANGE && !HAS_TRAIT(src, TRAIT_GOOD_HEARING) && !isobserver(src)) + if (message_range != INFINITY && dist > EAVESDROP_EXTRA_RANGE && !HAS_TRAIT(src, TRAIT_GOOD_HEARING) && !isobserver(src)) return FALSE // Too far away and don't have good hearing, you can't hear anything // we need to send this signal before compose_message() is used since other signals need to modify diff --git a/code/modules/unit_tests/say.dm b/code/modules/unit_tests/say.dm index 3ae55a12e37..ec58dcedc88 100644 --- a/code/modules/unit_tests/say.dm +++ b/code/modules/unit_tests/say.dm @@ -58,12 +58,15 @@ /// This runs some simple speech tests on a speaker and listener and determines if a person can hear whispering or speaking as they are moved a distance away /datum/unit_test/speech - var/list/handle_speech_result = null - var/list/handle_hearing_result = null var/mob/living/carbon/human/speaker var/mob/living/carbon/human/listener + var/list/handle_speech_result = null + var/list/handle_hearing_result = null + var/obj/item/radio/speaker_radio var/obj/item/radio/listener_radio + var/speaker_radio_heard_message = FALSE + var/listener_radio_received_message = FALSE /datum/unit_test/speech/proc/handle_speech(datum/source, list/speech_args) SIGNAL_HANDLER @@ -99,6 +102,16 @@ handle_hearing_result = list() handle_hearing_result += hearing_args +/datum/unit_test/speech/proc/handle_radio_hearing(datum/source, mob/living/user, message, channel) + SIGNAL_HANDLER + + speaker_radio_heard_message = TRUE + +/datum/unit_test/speech/proc/handle_radio_speech(datum/source, list/data) + SIGNAL_HANDLER + + listener_radio_received_message = TRUE + /datum/unit_test/speech/Run() speaker = allocate(/mob/living/carbon/human/consistent) // Name changes to make understanding breakpoints easier @@ -114,7 +127,10 @@ listener.mock_client = mock_client RegisterSignal(speaker, COMSIG_MOB_SAY, PROC_REF(handle_speech)) + RegisterSignal(speaker_radio, COMSIG_RADIO_NEW_MESSAGE, PROC_REF(handle_radio_hearing)) + RegisterSignal(listener, COMSIG_MOVABLE_HEAR, PROC_REF(handle_hearing)) + RegisterSignal(listener_radio, COMSIG_RADIO_RECEIVE_MESSAGE, PROC_REF(handle_radio_speech)) // speaking and whispering should be hearable conversation(distance = 1) @@ -169,6 +185,9 @@ handle_hearing_result = null /datum/unit_test/speech/proc/radio_test() + speaker_radio_heard_message = FALSE + listener_radio_received_message = FALSE + speaker.forceMove(run_loc_floor_bottom_left) listener.forceMove(locate((run_loc_floor_bottom_left.x + 10), run_loc_floor_bottom_left.y, run_loc_floor_bottom_left.z)) @@ -186,11 +205,15 @@ speaker.say(pangram_quote) TEST_ASSERT(handle_speech_result, "Handle speech signal was not fired (radio test)") - TEST_ASSERT(islist(handle_hearing_result), "Listener failed to hear radio message (radio test)") + TEST_ASSERT(speaker_radio_heard_message, "Speaker's radio did not hear them speak (radio test)") TEST_ASSERT_EQUAL(speaker_radio.get_frequency(), listener_radio.get_frequency(), "Radio frequencies were not equal (radio test)") + TEST_ASSERT(listener_radio_received_message, "Listener's radio did not receive the broadcast (radio test)") + TEST_ASSERT(islist(handle_hearing_result), "Listener failed to hear radio message (radio test)") handle_speech_result = null handle_hearing_result = null + speaker_radio_heard_message = FALSE + listener_radio_received_message = FALSE speaker_radio.set_frequency(FREQ_CTF_RED) speaker.say(pangram_quote) @@ -200,6 +223,8 @@ handle_speech_result = null handle_hearing_result = null + speaker_radio_heard_message = FALSE + listener_radio_received_message = FALSE speaker_radio.set_broadcasting(FALSE) #undef NORMAL_HEARING_RANGE From 3e17fce319ada9d0f777f7f316f4eac926db9ad6 Mon Sep 17 00:00:00 2001 From: Iajret Creature <122297233+Steals-The-PRs@users.noreply.github.com> Date: Fri, 24 Nov 2023 12:45:45 +0300 Subject: [PATCH 60/72] [MIRROR] Gives roundstart prisoners a key memory of what their crime is [MDB IGNORE] (#805) * Gives roundstart prisoners a key memory of what their crime is (#79881) --------- Co-authored-by: SkyratBot <59378654+SkyratBot@users.noreply.github.com> Co-authored-by: die_amond <58376695+dieamond13@users.noreply.github.com> --- code/datums/memory/key_memories.dm | 22 ++++++++++++++++++++++ code/modules/jobs/job_types/prisoner.dm | 2 +- 2 files changed, 23 insertions(+), 1 deletion(-) diff --git a/code/datums/memory/key_memories.dm b/code/datums/memory/key_memories.dm index 5cc581f14c7..d777df72e38 100644 --- a/code/datums/memory/key_memories.dm +++ b/code/datums/memory/key_memories.dm @@ -191,3 +191,25 @@ "[protagonist_name] being implanted by a scientist.", "[protagonist_name] having surgery done on them by a scientist.", ) + +/datum/memory/key/permabrig_crimes + var/crimes + +/datum/memory/key/permabrig_crimes/New( + datum/mind/memorizer_mind, + atom/protagonist, + atom/deuteragonist, + atom/antagonist, + crimes, +) + src.crimes = crimes + return ..() + +/datum/memory/key/permabrig_crimes/get_names() + return list("[protagonist_name]'s crime of \"[crimes]\".") + +/datum/memory/key/permabrig_crimes/get_starts() + return list( + "[protagonist_name] being arrested by security for [crimes].", + "[protagonist_name] committing the crimes of [crimes].", + ) diff --git a/code/modules/jobs/job_types/prisoner.dm b/code/modules/jobs/job_types/prisoner.dm index 33369d44ce4..cf4c9f65910 100644 --- a/code/modules/jobs/job_types/prisoner.dm +++ b/code/modules/jobs/job_types/prisoner.dm @@ -45,6 +45,7 @@ var/datum/crime/past_crime = new(crime.name, crime.desc, "Central Command", "Indefinite.") target_record.crimes += past_crime to_chat(crewmember, span_warning("You are imprisoned for \"[crime_name]\".")) + crewmember.add_mob_memory(/datum/memory/key/permabrig_crimes, crimes = crime_name) /datum/outfit/job/prisoner name = "Prisoner" @@ -69,7 +70,6 @@ if(!crime_name) return var/datum/prisoner_crime/crime = GLOB.prisoner_crimes[crime_name] - var/list/limbs_to_tat = new_prisoner.bodyparts.Copy() for(var/i in 1 to crime.tattoos) if(!length(SSpersistence.prison_tattoos_to_use) || visualsOnly) From fce4f6fb267f17175abe9c05c7568a1095e91a34 Mon Sep 17 00:00:00 2001 From: Iajret Creature <122297233+Steals-The-PRs@users.noreply.github.com> Date: Fri, 24 Nov 2023 12:46:08 +0300 Subject: [PATCH 61/72] [MIRROR] [NO GBP] Makes dart insert projectile var modification code slightly better [MDB IGNORE] (#800) * [NO GBP] Makes dart insert projectile var modification code slightly better (#79886) --------- Co-authored-by: SkyratBot <59378654+SkyratBot@users.noreply.github.com> Co-authored-by: Y0SH1M4S73R --- code/__DEFINES/dcs/signals/signals_object.dm | 14 -------- code/datums/components/dart_insert.dm | 8 +++-- code/modules/paperwork/pen.dm | 36 ++++++++++++-------- 3 files changed, 26 insertions(+), 32 deletions(-) diff --git a/code/__DEFINES/dcs/signals/signals_object.dm b/code/__DEFINES/dcs/signals/signals_object.dm index 1f17b3646da..903182b21db 100644 --- a/code/__DEFINES/dcs/signals/signals_object.dm +++ b/code/__DEFINES/dcs/signals/signals_object.dm @@ -501,19 +501,5 @@ /// from /datum/component/dart_insert/remove_from_dart() : (obj/ammo_casing/dart, mob/user) #define COMSIG_DART_INSERT_REMOVED "dart_insert_removed" -/** - * from /datum/component/dart_insert/get_dart_var_modifiers() : (list/out_modifiers) - * - * valid indices for `out_modifiers` are: - * - `damage`: number - * - `speed`: number - * - `armour_penetration`: number - * - `wound_bonus`: number - * - `bare_wound_bonus`: number - * - `demolition_mod`: number - * - `embedding`: list with embedding params - */ -#define COMSIG_DART_INSERT_GET_VAR_MODIFIERS "dart_insert_get_var_modifiers" - /// from /datum/component/dart_insert/on_reskin() #define COMSIG_DART_INSERT_PARENT_RESKINNED "dart_insert_parent_reskinned" diff --git a/code/datums/components/dart_insert.dm b/code/datums/components/dart_insert.dm index 03d1d689357..19eea67ab3a 100644 --- a/code/datums/components/dart_insert.dm +++ b/code/datums/components/dart_insert.dm @@ -20,14 +20,17 @@ var/projectile_overlay_icon /// The icon state used for the overlay applied over the containing projectile var/projectile_overlay_icon_state + /// Optional callback to invoke when acquiring projectile var modifiers + var/datum/callback/modifier_getter -/datum/component/dart_insert/Initialize(_casing_overlay_icon, _casing_overlay_icon_state, _projectile_overlay_icon, _projectile_overlay_icon_state) +/datum/component/dart_insert/Initialize(_casing_overlay_icon, _casing_overlay_icon_state, _projectile_overlay_icon, _projectile_overlay_icon_state, datum/callback/_modifier_getter) if(!isitem(parent)) return COMPONENT_INCOMPATIBLE casing_overlay_icon = _casing_overlay_icon casing_overlay_icon_state = _casing_overlay_icon_state projectile_overlay_icon = _projectile_overlay_icon projectile_overlay_icon_state = _projectile_overlay_icon_state + modifier_getter = _modifier_getter /datum/component/dart_insert/RegisterWithParent() . = ..() @@ -130,8 +133,7 @@ new_overlays += mutable_appearance(projectile_overlay_icon, projectile_overlay_icon_state) /datum/component/dart_insert/proc/apply_var_modifiers(obj/projectile/projectile) - LAZYINITLIST(var_modifiers) - SEND_SIGNAL(parent, COMSIG_DART_INSERT_GET_VAR_MODIFIERS, var_modifiers) + var_modifiers = istype(modifier_getter) ? modifier_getter.Invoke() : list() projectile.damage += var_modifiers["damage"] if(var_modifiers["speed"]) var_modifiers["speed"] = reciprocal_add(projectile.speed, var_modifiers["speed"]) - projectile.speed diff --git a/code/modules/paperwork/pen.dm b/code/modules/paperwork/pen.dm index 3750acddc42..40e99eefe6a 100644 --- a/code/modules/paperwork/pen.dm +++ b/code/modules/paperwork/pen.dm @@ -37,23 +37,29 @@ /obj/item/pen/Initialize(mapload) . = ..() - AddComponent(/datum/component/dart_insert, dart_insert_icon, dart_insert_casing_icon_state, dart_insert_icon, dart_insert_projectile_icon_state) + AddComponent(/datum/component/dart_insert, \ + dart_insert_icon, \ + dart_insert_casing_icon_state, \ + dart_insert_icon, \ + dart_insert_projectile_icon_state, \ + CALLBACK(src, PROC_REF(get_dart_var_modifiers))\ + ) RegisterSignal(src, COMSIG_DART_INSERT_ADDED, PROC_REF(on_inserted_into_dart)) RegisterSignal(src, COMSIG_DART_INSERT_REMOVED, PROC_REF(on_removed_from_dart)) - RegisterSignal(src, COMSIG_DART_INSERT_GET_VAR_MODIFIERS, PROC_REF(get_dart_var_modifiers)) /obj/item/pen/proc/on_inserted_into_dart(datum/source, obj/projectile/dart, mob/user, embedded = FALSE) SIGNAL_HANDLER -/obj/item/pen/proc/get_dart_var_modifiers(datum/source, list/modifiers) - SIGNAL_HANDLER - modifiers["damage"] = max(5, throwforce) - modifiers["speed"] = max(0, throw_speed - 3) - modifiers["embedding"] = embedding - modifiers["armour_penetration"] = armour_penetration - modifiers["wound_bonus"] = wound_bonus - modifiers["bare_wound_bonus"] = bare_wound_bonus - modifiers["demolition_mod"] = demolition_mod +/obj/item/pen/proc/get_dart_var_modifiers() + return list( + "damage" = max(5, throwforce), + "speed" = max(0, throw_speed - 3), + "embedding" = embedding, + "armour_penetration" = armour_penetration, + "wound_bonus" = wound_bonus, + "bare_wound_bonus" = bare_wound_bonus, + "demolition_mod" = demolition_mod, + ) /obj/item/pen/proc/on_removed_from_dart(datum/source, obj/projectile/dart, mob/user) SIGNAL_HANDLER @@ -366,12 +372,12 @@ if(istype(projectile)) UnregisterSignal(projectile, list(COMSIG_PROJECTILE_FIRE, COMSIG_PROJECTILE_ON_SPAWN_DROP, COMSIG_PROJECTILE_ON_SPAWN_EMBEDDED)) -/obj/item/pen/edagger/get_dart_var_modifiers(datum/source, list/modifiers) +/obj/item/pen/edagger/get_dart_var_modifiers() . = ..() var/datum/component/transforming/transform_comp = GetComponent(/datum/component/transforming) - modifiers["damage"] = max(5, transform_comp.throwforce_on) - modifiers["speed"] = max(0, transform_comp.throw_speed_on - 3) - var/list/embed_params = modifiers["embedding"] + .["damage"] = max(5, transform_comp.throwforce_on) + .["speed"] = max(0, transform_comp.throw_speed_on - 3) + var/list/embed_params = .["embedding"] embed_params["embed_chance"] = 100 /obj/item/pen/edagger/proc/on_containing_dart_fired(obj/projectile/source) From a2a34af6ce6803bd96266045f9dec57eec6dff78 Mon Sep 17 00:00:00 2001 From: Iajret Creature <122297233+Steals-The-PRs@users.noreply.github.com> Date: Fri, 24 Nov 2023 12:46:32 +0300 Subject: [PATCH 62/72] [MIRROR] Updates the Mafia UI [MDB IGNORE] (#801) * Updates the Mafia UI (#79856) --------- Co-authored-by: SkyratBot <59378654+SkyratBot@users.noreply.github.com> Co-authored-by: John Willard <53777086+JohnFulpWillard@users.noreply.github.com> Co-authored-by: Jeremiah <42397676+jlsnow301@ users.noreply.github.com> --- code/modules/mafia/controller_ui.dm | 7 +++++ tgui/packages/tgui/interfaces/MafiaPanel.tsx | 32 ++++++++++++++------ 2 files changed, 29 insertions(+), 10 deletions(-) diff --git a/code/modules/mafia/controller_ui.dm b/code/modules/mafia/controller_ui.dm index cc901392d22..578555d21f4 100644 --- a/code/modules/mafia/controller_ui.dm +++ b/code/modules/mafia/controller_ui.dm @@ -29,6 +29,8 @@ if(turn) data["turn"] = " - Day [turn]" + if(phase == MAFIA_PHASE_JUDGEMENT) + data["person_voted_up_ref"] = REF(on_trial) if(phase == MAFIA_PHASE_SETUP) data["lobbydata"] = list() for(var/key in GLOB.mafia_signup + GLOB.mafia_bad_signup + GLOB.pda_mafia_signup) @@ -41,8 +43,10 @@ data["timeleft"] = next_phase_timer ? timeleft(next_phase_timer) : 0 var/datum/mafia_role/user_role = get_role_player(user) + if(user_role) data["user_notes"] = user_role.written_notes + data["player_voted_up"] = (user_role == on_trial) var/list/ui_messages = list() for(var/i = user_role.role_messages.len to 1 step -1) ui_messages.Add(list(list( @@ -56,6 +60,9 @@ player_info["name"] = role.body.real_name player_info["ref"] = REF(role) player_info["alive"] = role.game_status == MAFIA_ALIVE + player_info["role_revealed"] = FALSE + if(role.role_flags & ROLE_REVEALED) + player_info["role_revealed"] = role.name player_info["possible_actions"] = list() if(user_role) //not observer diff --git a/tgui/packages/tgui/interfaces/MafiaPanel.tsx b/tgui/packages/tgui/interfaces/MafiaPanel.tsx index ee63d105dd1..23b4b45a27a 100644 --- a/tgui/packages/tgui/interfaces/MafiaPanel.tsx +++ b/tgui/packages/tgui/interfaces/MafiaPanel.tsx @@ -16,6 +16,7 @@ type RoleInfo = { type PlayerInfo = { name: string; + role_revealed: string; is_you: BooleanLike; ref: string; alive: string; @@ -49,11 +50,13 @@ type MafiaData = { is_observer: boolean; all_roles: string[]; admin_controls: boolean; + person_voted_up_ref: string; + player_voted_up: BooleanLike; }; export const MafiaPanelData = (props, context) => { const { act, data } = useBackend(context); - const { phase, roleinfo, admin_controls, messages } = data; + const { phase, roleinfo, admin_controls, messages, player_voted_up } = data; const [mafia_tab, setMafiaMode] = useLocalState( context, 'mafia_tab', @@ -90,7 +93,7 @@ export const MafiaPanelData = (props, context) => { - {phase === 'Judgment' && ( + {phase === 'Judgment' && !player_voted_up && ( @@ -401,17 +404,20 @@ const MafiaJudgement = (props, context) => { const { act, data } = useBackend(context); return (
- + +