From 9c58d7d1b9bd9cd447289cb02d0c49772b75a24a Mon Sep 17 00:00:00 2001 From: LemonInTheDark <58055496+LemonInTheDark@users.noreply.github.com> Date: Sun, 19 May 2024 12:41:14 -0700 Subject: [PATCH 001/103] Unfucks status displays (#83296) ## About The Pull Request These things fuckin SUCK right now. Every time they update they delete their current overlay object and create a new one. We constantly update when shuttles are active. So every 2 seconds we're deleting and creating 150 objects. stupid. Even more stupid all these objects are the exact same. There is no reason we can't reuse them, so let's build a static list and use a use count to manage their lifetimes. Oh also while I'm here DO NOT FUCKING CREATE A FONT DATUM EVERY TIME YOU WANT ONE. THEY ARE STATIC. This is what god invented globals for. --- code/game/machinery/status_display.dm | 114 +++++++++++++++++--------- 1 file changed, 75 insertions(+), 39 deletions(-) diff --git a/code/game/machinery/status_display.dm b/code/game/machinery/status_display.dm index c1be0917bf352..52ae94e48a2d6 100644 --- a/code/game/machinery/status_display.dm +++ b/code/game/machinery/status_display.dm @@ -8,7 +8,7 @@ #define LINE1_Y -4 #define LINE2_X 1 #define LINE2_Y -11 -#define STATUS_DISPLAY_FONT_DATUM /datum/font/tiny_unicode/size_12pt +GLOBAL_DATUM_INIT(status_font, /datum/font, new /datum/font/tiny_unicode/size_12pt()) /// Status display which can show images and scrolling text. /obj/machinery/status_display @@ -22,8 +22,11 @@ density = FALSE layer = ABOVE_WINDOW_LAYER - var/obj/effect/overlay/status_display_text/message1_overlay - var/obj/effect/overlay/status_display_text/message2_overlay + // We store overlays as keys, so multiple displays can use the same object safely + /// String key we use to index the first effect overlay displayed on us + var/message_key_1 + /// String key we use to index the second effect overlay displayed on us + var/message_key_2 var/current_picture = "" var/current_mode = SD_BLANK var/message1 = "" @@ -109,10 +112,26 @@ * Don't call this in subclasses. */ /obj/machinery/status_display/proc/remove_messages() - if(message1_overlay) - QDEL_NULL(message1_overlay) - if(message2_overlay) - QDEL_NULL(message2_overlay) + var/obj/effect/overlay/status_display_text/overlay_1 = get_status_text(message_key_1) + message_key_1 = null + overlay_1?.disown(src) + var/obj/effect/overlay/status_display_text/overlay_2 = get_status_text(message_key_2) + message_key_2 = null + overlay_2?.disown(src) + +// List in the form key -> status display that shows said key +GLOBAL_LIST_EMPTY(key_to_status_display) + +/proc/generate_status_text(line_y, message, x_offset, text_color, header_text_color, line_pair) + var/key = "[line_y]-[message]-[x_offset]-[text_color]-[header_text_color]-[line_pair]" + var/obj/effect/overlay/status_display_text/new_overlay = GLOB.key_to_status_display[key] + if(!new_overlay) + new_overlay = new(null, line_y, message, text_color, header_text_color, x_offset, line_pair, key) + GLOB.key_to_status_display[key] = new_overlay + return new_overlay + +/proc/get_status_text(key) + return GLOB.key_to_status_display[key] /** * Create/update message overlay. @@ -125,19 +144,16 @@ * * message - the new message text. * Returns new /obj/effect/overlay/status_display_text or null if unchanged. */ -/obj/machinery/status_display/proc/update_message(obj/effect/overlay/status_display_text/overlay, line_y, message, x_offset, line_pair) - if(overlay && message == overlay.message) - return null +/obj/machinery/status_display/proc/update_message(current_key, line_y, message, x_offset, line_pair) + var/obj/effect/overlay/status_display_text/current_overlay = get_status_text(current_key) + var/obj/effect/overlay/status_display_text/new_overlay = generate_status_text(line_y, message, text_color, header_text_color, x_offset, line_pair) - if(overlay) - qdel(overlay) + if(current_overlay == new_overlay) + return current_key - var/obj/effect/overlay/status_display_text/new_status_display_text = new(src, line_y, message, text_color, header_text_color, x_offset, line_pair) - // Draw our object visually "in front" of this display, taking advantage of sidemap - new_status_display_text.pixel_y = -32 - new_status_display_text.pixel_z = 32 - vis_contents += new_status_display_text - return new_status_display_text + current_overlay?.disown(src) + new_overlay.own(src) + return new_overlay.status_key /obj/machinery/status_display/update_appearance(updates=ALL) . = ..() @@ -171,17 +187,12 @@ var/line1_metric var/line2_metric var/line_pair - var/datum/font/display_font = new STATUS_DISPLAY_FONT_DATUM() - line1_metric = display_font.get_metrics(message1) - line2_metric = display_font.get_metrics(message2) + line1_metric = GLOB.status_font.get_metrics(message1) + line2_metric = GLOB.status_font.get_metrics(message2) line_pair = (line1_metric > line2_metric ? line1_metric : line2_metric) - var/overlay = update_message(message1_overlay, LINE1_Y, message1, LINE1_X, line_pair) - if(overlay) - message1_overlay = overlay - overlay = update_message(message2_overlay, LINE2_Y, message2, LINE2_X, line_pair) - if(overlay) - message2_overlay = overlay + message_key_1 = update_message(message_key_1, LINE1_Y, message1, LINE1_X, line_pair) + message_key_2 = update_message(message_key_2, LINE2_Y, message2, LINE2_X, line_pair) // Turn off backlight if message is blank if(message1 == "" && message2 == "") @@ -215,6 +226,8 @@ /obj/machinery/status_display/examine(mob/user) . = ..() + var/obj/effect/overlay/status_display_text/message1_overlay = get_status_text(message_key_1) + var/obj/effect/overlay/status_display_text/message2_overlay = get_status_text(message_key_2) if (message1_overlay || message2_overlay) . += "The display says:" if (message1_overlay.message) @@ -247,30 +260,37 @@ /obj/effect/overlay/status_display_text icon = 'icons/obj/machines/status_display.dmi' vis_flags = VIS_INHERIT_LAYER | VIS_INHERIT_PLANE | VIS_INHERIT_ID + // physically shift down to render correctly + pixel_y = -32 + pixel_z = 32 /// The message this overlay is displaying. var/message + /// Amount of usage this overlay is getting + var/use_count = 0 + /// The status key we represent + var/status_key // If the line is short enough to not marquee, and it matches this, it's a header. var/static/regex/header_regex = regex("^-.*-$") -/obj/effect/overlay/status_display_text/Initialize(mapload, yoffset, line, text_color, header_text_color, xoffset = 0, line_pair) +/obj/effect/overlay/status_display_text/Initialize(mapload, maptext_y, message, text_color, header_text_color, xoffset = 0, line_pair, status_key) . = ..() - maptext_y = yoffset - message = line + src.maptext_y = maptext_y + src.message = message + src.status_key = status_key - var/datum/font/display_font = new STATUS_DISPLAY_FONT_DATUM() - var/line_width = display_font.get_metrics(line) + var/line_width = GLOB.status_font.get_metrics(message) if(line_width > MAX_STATIC_WIDTH) // Marquee text - var/marquee_message = "[line] [line] [line]" + var/marquee_message = "[message] [message] [message]" // Width of full content. Must of these is never revealed unless the user inputted a single character. - var/full_marquee_width = display_font.get_metrics("[marquee_message] ") + var/full_marquee_width = GLOB.status_font.get_metrics("[marquee_message] ") // We loop after only this much has passed. - var/looping_marquee_width = (display_font.get_metrics("[line] ]") - SCROLL_PADDING) + var/looping_marquee_width = (GLOB.status_font.get_metrics("[message] ]") - SCROLL_PADDING) maptext = generate_text(marquee_message, center = FALSE, text_color = text_color) maptext_width = full_marquee_width @@ -285,10 +305,28 @@ animate(maptext_x = MAX_STATIC_WIDTH, time = 0) else // Centered text - var/color = header_regex.Find(line) ? header_text_color : text_color - maptext = generate_text(line, center = TRUE, text_color = color) + var/color = header_regex.Find(message) ? header_text_color : text_color + maptext = generate_text(message, center = TRUE, text_color = color) maptext_x = xoffset //Defaults to 0, this would be centered unless overided +/obj/effect/overlay/status_display_text/Destroy(force) + GLOB.key_to_status_display -= status_key + return ..() + +/// Status displays are static, shared by everyone who needs them +/// This marks us as being used by one more guy +/obj/effect/overlay/status_display_text/proc/own(atom/movable/owned_by) + owned_by.vis_contents += src + use_count += 1 + +/// Status displays are static, shared by everyone who needs them +/// This marks us as no longer being used by a guy +/obj/effect/overlay/status_display_text/proc/disown(atom/movable/disowned_by) + disowned_by.vis_contents -= src + use_count -= 1 + if(use_count <= 0) + qdel(src) + /** * Generate the actual maptext. * Arguments: @@ -562,6 +600,4 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/machinery/status_display/random_message, 32) #undef LINE1_Y #undef LINE2_X #undef LINE2_Y -#undef STATUS_DISPLAY_FONT_DATUM - #undef SCROLL_PADDING From 90ab32949ae44dc3a6794773ac6412deb5122304 Mon Sep 17 00:00:00 2001 From: MrMelbert <51863163+MrMelbert@users.noreply.github.com> Date: Sun, 19 May 2024 22:29:45 -0500 Subject: [PATCH 002/103] `*Me` invoked via verb defaults to visible | audible, rather than just audible (#83283) ## About The Pull Request `*me` emotes invoked via the verb (or TGUI say) now default to visible | audible, rather than just audible Also adds a description on how to set your `*me` emotes to the verb. (Doesn't work for TGUI say unfortunately) ## Why It's Good For The Game I don't know why these are set to audible by default, that's just kinda weird considering 95% of custom emotes are not audible Both is best of both worlds, ensures deaf and blind people can see their own custom emotes at the very least. ## Changelog :cl: Melbert qol: Custom emotes now default to both visible and audible rather than just audible qol: Invoking the custom emote verb now explains how to set your custom emote to visible or audible /:cl: --- code/modules/mob/living/emote.dm | 4 +++- code/modules/mob/mob_say.dm | 3 ++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/code/modules/mob/living/emote.dm b/code/modules/mob/living/emote.dm index 570cf1ec30458..395c4f343dc3d 100644 --- a/code/modules/mob/living/emote.dm +++ b/code/modules/mob/living/emote.dm @@ -663,13 +663,15 @@ return copytext(sanitize(input("Choose an emote to display.") as text|null), 1, MAX_MESSAGE_LEN) /datum/emote/living/custom/proc/get_custom_emote_type_from_user() - var/type = input("Is this a visible or hearable emote?") as null|anything in list("Visible", "Hearable") + var/type = input("Is this a visible or hearable emote?") as null|anything in list("Visible", "Hearable", "Both") switch(type) if("Visible") return EMOTE_VISIBLE if("Hearable") return EMOTE_AUDIBLE + if("Both") + return EMOTE_VISIBLE | EMOTE_AUDIBLE else tgui_alert(usr,"Unable to use this emote, must be either hearable or visible.") return FALSE diff --git a/code/modules/mob/mob_say.dm b/code/modules/mob/mob_say.dm index e2a840d569b64..7caa4489095ff 100644 --- a/code/modules/mob/mob_say.dm +++ b/code/modules/mob/mob_say.dm @@ -42,6 +42,7 @@ /mob/verb/me_verb(message as text) set name = "Me" set category = "IC" + set desc = "Perform a custom emote. Leave blank to pick between an audible or a visible emote (Defaults to visible)." if(GLOB.say_disabled) //This is here to try to identify lag problems to_chat(usr, span_danger("Speech is currently admin-disabled.")) @@ -49,7 +50,7 @@ message = trim(copytext_char(sanitize(message), 1, MAX_MESSAGE_LEN)) - QUEUE_OR_CALL_VERB_FOR(VERB_CALLBACK(src, TYPE_PROC_REF(/mob, emote), "me", 1, message, TRUE), SSspeech_controller) + QUEUE_OR_CALL_VERB_FOR(VERB_CALLBACK(src, TYPE_PROC_REF(/mob, emote), "me", EMOTE_VISIBLE|EMOTE_AUDIBLE, message, TRUE), SSspeech_controller) /mob/try_speak(message, ignore_spam = FALSE, forced = null, filterproof = FALSE) var/list/filter_result From 2f3978773e2c328db67819293aacee8fd4451f4d Mon Sep 17 00:00:00 2001 From: Ben10Omintrix <138636438+Ben10Omintrix@users.noreply.github.com> Date: Mon, 20 May 2024 06:29:59 +0300 Subject: [PATCH 003/103] [no gbp] raptors with the playful trait now play with their owners (#83294) ## About The Pull Request i forgot to add this behavior to playful raptors, currently this trait does nothing. raptors will now play with their owners and tease them if they are nearby ## Why It's Good For The Game adds more personality to raptors with the playful trait. also this behavior can now be given to any other tameable mobs ## Changelog :cl: fix: playful raptors now correctly play with owners /:cl: --- code/__DEFINES/ai/ai_blackboard.dm | 5 +++++ .../basic_subtrees/play_with_owners.dm | 21 +++++++++++++++++++ .../lavaland/raptor/raptor_ai_controller.dm | 9 +++++++- .../lavaland/raptor/raptor_ai_subtrees.dm | 4 ++++ tgstation.dme | 1 + 5 files changed, 39 insertions(+), 1 deletion(-) create mode 100644 code/datums/ai/basic_mobs/basic_subtrees/play_with_owners.dm diff --git a/code/__DEFINES/ai/ai_blackboard.dm b/code/__DEFINES/ai/ai_blackboard.dm index 1a2b19740f612..a65b5ebd40758 100644 --- a/code/__DEFINES/ai/ai_blackboard.dm +++ b/code/__DEFINES/ai/ai_blackboard.dm @@ -19,6 +19,11 @@ ///can this mob heal? #define BB_BASIC_MOB_HEALER "BB_basic_mob_healer" +///the owner we will try to play with +#define BB_OWNER_TARGET "BB_owner_target" +///the list of interactions we can have with the owner +#define BB_INTERACTIONS_WITH_OWNER "BB_interactions_with_owner" + /// Store a single or list of emotes at this key #define BB_EMOTE_KEY "BB_emotes" diff --git a/code/datums/ai/basic_mobs/basic_subtrees/play_with_owners.dm b/code/datums/ai/basic_mobs/basic_subtrees/play_with_owners.dm new file mode 100644 index 0000000000000..e27e984e70649 --- /dev/null +++ b/code/datums/ai/basic_mobs/basic_subtrees/play_with_owners.dm @@ -0,0 +1,21 @@ +/datum/ai_planning_subtree/find_and_hunt_target/play_with_owner + target_key = BB_OWNER_TARGET + hunting_behavior = /datum/ai_behavior/hunt_target/play_with_owner + finding_behavior = /datum/ai_behavior/find_hunt_target/find_owner + hunt_targets = list(/mob/living) + hunt_chance = 80 + hunt_range = 9 + +/datum/ai_behavior/find_hunt_target/find_owner + action_cooldown = 1 MINUTES + behavior_flags = AI_BEHAVIOR_CAN_PLAN_DURING_EXECUTION + +/datum/ai_behavior/find_hunt_target/find_owner/valid_dinner(mob/living/source, atom/friend, radius, datum/ai_controller/controller, seconds_per_tick) + return (friend != source) && (source.faction.Find(REF(friend))) && can_see(source, friend, radius) + +/datum/ai_behavior/hunt_target/play_with_owner + +/datum/ai_behavior/hunt_target/play_with_owner/target_caught(mob/living/hunter, atom/hunted) + var/list/interactions_list = hunter.ai_controller.blackboard[BB_INTERACTIONS_WITH_OWNER] + var/interaction_message = length(interactions_list) ? pick(interactions_list) : "Plays with" + hunter.manual_emote("[interaction_message] [hunted]!") diff --git a/code/modules/mob/living/basic/lavaland/raptor/raptor_ai_controller.dm b/code/modules/mob/living/basic/lavaland/raptor/raptor_ai_controller.dm index 40c2d836554b1..323f8422d2fd0 100644 --- a/code/modules/mob/living/basic/lavaland/raptor/raptor_ai_controller.dm +++ b/code/modules/mob/living/basic/lavaland/raptor/raptor_ai_controller.dm @@ -2,6 +2,12 @@ /datum/ai_controller/basic_controller/raptor blackboard = list( + BB_INTERACTIONS_WITH_OWNER = list( + "Pecks", + "Nuzzles", + "Wags tail against", + "Playfully leans against" + ), BB_TARGETING_STRATEGY = /datum/targeting_strategy/basic/raptor, BB_PET_TARGETING_STRATEGY = /datum/targeting_strategy/basic/raptor, BB_BABIES_PARTNER_TYPES = list(/mob/living/basic/mining/raptor), @@ -25,6 +31,7 @@ /datum/ai_planning_subtree/make_babies, /datum/ai_planning_subtree/find_and_hunt_target/raptor_start_trouble, /datum/ai_planning_subtree/express_happiness, + /datum/ai_planning_subtree/find_and_hunt_target/play_with_owner/raptor, ) /datum/ai_controller/basic_controller/raptor/TryPossessPawn(atom/new_pawn) @@ -39,7 +46,7 @@ /datum/targeting_strategy/basic/raptor -//dont attack anyone with the neutral faction. +//dont attack anyone with the neutral faction. /datum/targeting_strategy/basic/raptor/faction_check(datum/ai_controller/controller, mob/living/living_mob, mob/living/the_target) return (the_target.faction.Find(FACTION_NEUTRAL) || the_target.faction.Find(FACTION_RAPTOR)) diff --git a/code/modules/mob/living/basic/lavaland/raptor/raptor_ai_subtrees.dm b/code/modules/mob/living/basic/lavaland/raptor/raptor_ai_subtrees.dm index 2d23268d35c81..9dcb360c65d82 100644 --- a/code/modules/mob/living/basic/lavaland/raptor/raptor_ai_subtrees.dm +++ b/code/modules/mob/living/basic/lavaland/raptor/raptor_ai_subtrees.dm @@ -60,3 +60,7 @@ return return ..() +/datum/ai_planning_subtree/find_and_hunt_target/play_with_owner/raptor/SelectBehaviors(datum/ai_controller/controller, seconds_per_tick) + if(!controller.blackboard[BB_RAPTOR_PLAYFUL]) + return + return ..() diff --git a/tgstation.dme b/tgstation.dme index 2e7b8532db0ff..4cdb2cb189616 100644 --- a/tgstation.dme +++ b/tgstation.dme @@ -909,6 +909,7 @@ #include "code\datums\ai\basic_mobs\basic_subtrees\mine_walls.dm" #include "code\datums\ai\basic_mobs\basic_subtrees\move_to_cardinal.dm" #include "code\datums\ai\basic_mobs\basic_subtrees\opportunistic_ventcrawler.dm" +#include "code\datums\ai\basic_mobs\basic_subtrees\play_with_owners.dm" #include "code\datums\ai\basic_mobs\basic_subtrees\prepare_travel_to_destination.dm" #include "code\datums\ai\basic_mobs\basic_subtrees\ranged_skirmish.dm" #include "code\datums\ai\basic_mobs\basic_subtrees\run_emote.dm" From a500d386852f71c11ac5a916e7ddd22cbf750a86 Mon Sep 17 00:00:00 2001 From: orange man <61334995+comfyorange@users.noreply.github.com> Date: Mon, 20 May 2024 15:30:03 +1200 Subject: [PATCH 004/103] Automatic changelog for PR #83283 [ci skip] --- html/changelogs/AutoChangeLog-pr-83283.yml | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-83283.yml diff --git a/html/changelogs/AutoChangeLog-pr-83283.yml b/html/changelogs/AutoChangeLog-pr-83283.yml new file mode 100644 index 0000000000000..855531a30258d --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-83283.yml @@ -0,0 +1,5 @@ +author: "Melbert" +delete-after: True +changes: + - qol: "Custom emotes now default to both visible and audible rather than just audible" + - qol: "Invoking the custom emote verb now explains how to set your custom emote to visible or audible" \ No newline at end of file From 68f5643ccc377f44f16b1ed844d74261d2541e4b Mon Sep 17 00:00:00 2001 From: orange man <61334995+comfyorange@users.noreply.github.com> Date: Mon, 20 May 2024 15:30:17 +1200 Subject: [PATCH 005/103] Automatic changelog for PR #83294 [ci skip] --- html/changelogs/AutoChangeLog-pr-83294.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-83294.yml diff --git a/html/changelogs/AutoChangeLog-pr-83294.yml b/html/changelogs/AutoChangeLog-pr-83294.yml new file mode 100644 index 0000000000000..908e790bee223 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-83294.yml @@ -0,0 +1,4 @@ +author: "Ben10Omintrix" +delete-after: True +changes: + - bugfix: "playful raptors now correctly play with owners" \ No newline at end of file From 2900efbff57a818dd62ef1442203f9b5dfa1bd13 Mon Sep 17 00:00:00 2001 From: Afevis Date: Sun, 19 May 2024 23:32:02 -0400 Subject: [PATCH 006/103] Fixes balloons being invisible when held (#83321) Fixes #83306 :cl: ShizCalev fix: Balloons are no longer invisible when held. /:cl: --- code/game/objects/items/toys.dm | 47 +++++++++++++++++++-------------- 1 file changed, 27 insertions(+), 20 deletions(-) diff --git a/code/game/objects/items/toys.dm b/code/game/objects/items/toys.dm index b2cc7544e1077..7f0e28c95e670 100644 --- a/code/game/objects/items/toys.dm +++ b/code/game/objects/items/toys.dm @@ -127,10 +127,6 @@ throw_range = 7 force = 0 var/random_color = TRUE - /// the string of the dmi state the balloon has while on the floor. - var/world_state - /// the string of the dmi state the balloon has while in your inventory. - var/storage_state /// the string describing the name of balloon's current colour. var/current_color @@ -159,13 +155,6 @@ list("orange", "purple") = /obj/item/toy/balloon_animal/plasmaman, ) -/obj/item/toy/balloon/Moved(atom/old_loc, movement_dir, forced, list/old_locs, momentum_change) - . = ..() - if(isturf(loc)) - icon_state = "[world_state]" - else - icon_state = "[storage_state]" - update_appearance() /obj/item/toy/balloon/long/attackby(obj/item/attacking_item, mob/living/user, params) if(!istype(attacking_item, /obj/item/toy/balloon/long) || !HAS_TRAIT(user, TRAIT_BALLOON_SUTRA)) @@ -217,14 +206,30 @@ /obj/item/toy/balloon/Initialize(mapload) . = ..() - if(random_color) - var/chosen_balloon_color = pick(BALLOON_COLORS) - current_color = "[chosen_balloon_color]" - name = "[chosen_balloon_color] [name]" - icon_state = "[icon_state]_[chosen_balloon_color]" - inhand_icon_state = icon_state - world_state = "[icon_state]" - storage_state = "[icon_state]_storage" + AddElement(/datum/element/update_icon_updates_onmob) + if(!random_color) + return + current_color = pick(BALLOON_COLORS) + update_appearance() + +/obj/item/toy/balloon/update_name(updates) + . = ..() + name = "[current_color ? "[current_color] ":null][initial(name)]" + +/obj/item/toy/balloon/vv_edit_var(vname, vval) + . = ..() + if(vname == NAMEOF(src, current_color)) + update_appearance() + +/obj/item/toy/balloon/update_icon_state() + . = ..() + var/new_icon = "[initial(icon_state)][current_color ? "_[current_color]":null]" + inhand_icon_state = new_icon + icon_state = "[new_icon][isturf(loc) ? null : "_storage"]" + +/obj/item/toy/balloon/Moved(atom/old_loc, movement_dir, forced, list/old_locs, momentum_change) + . = ..() + update_appearance() /obj/item/toy/balloon/corgi name = "corgi balloon" @@ -280,7 +285,9 @@ name = "balloon animal" desc = "You shouldn't have this." icon = 'icons/obj/toys/balloons.dmi' - icon_state = "balloon_guy" + inhand_icon_state = "balloon" + lefthand_file = 'icons/mob/inhands/items/balloons_lefthand.dmi' + righthand_file = 'icons/mob/inhands/items/balloons_righthand.dmi' throwforce = 0 throw_speed = 2 throw_range = 5 From b4ca32441eb5caeeb7c0b64bf73947b251917fdd Mon Sep 17 00:00:00 2001 From: orange man <61334995+comfyorange@users.noreply.github.com> Date: Mon, 20 May 2024 15:32:21 +1200 Subject: [PATCH 007/103] Automatic changelog for PR #83321 [ci skip] --- html/changelogs/AutoChangeLog-pr-83321.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-83321.yml diff --git a/html/changelogs/AutoChangeLog-pr-83321.yml b/html/changelogs/AutoChangeLog-pr-83321.yml new file mode 100644 index 0000000000000..2e6ee1aaf6f61 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-83321.yml @@ -0,0 +1,4 @@ +author: "ShizCalev" +delete-after: True +changes: + - bugfix: "Balloons are no longer invisible when held." \ No newline at end of file From b4d5a74722e2da3a0526f16c11a444be8608e385 Mon Sep 17 00:00:00 2001 From: Afevis Date: Sun, 19 May 2024 23:33:24 -0400 Subject: [PATCH 008/103] malf AI fixes (#83268) Fixes #83254 :cl: ShizCalev fix: Malf AI can now properly interact with APCs under their control fix: Malf AI & their slaved cyborgs won't be told that access is denied when trying to right-click lock/unlock APCs. /:cl: --- code/_onclick/ai.dm | 6 ++---- code/modules/power/apc/apc_attack.dm | 8 +++----- code/modules/power/apc/apc_tool_act.dm | 2 +- 3 files changed, 6 insertions(+), 10 deletions(-) diff --git a/code/_onclick/ai.dm b/code/_onclick/ai.dm index 13b0e5c3c1335..ec76dee9c8e22 100644 --- a/code/_onclick/ai.dm +++ b/code/_onclick/ai.dm @@ -255,10 +255,8 @@ return CLICK_ACTION_SUCCESS /obj/machinery/power/apc/attack_ai_secondary(mob/living/silicon/user, list/modifiers) - if(!can_use(user, loud = TRUE)) - return - - togglelock(user) + if(can_use(user, loud = TRUE)) + togglelock(user) return SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN /* AI Turrets */ diff --git a/code/modules/power/apc/apc_attack.dm b/code/modules/power/apc/apc_attack.dm index acaaac1bd3eec..8c9715f1dcb1c 100644 --- a/code/modules/power/apc/apc_attack.dm +++ b/code/modules/power/apc/apc_attack.dm @@ -111,13 +111,11 @@ if(!HAS_SILICON_ACCESS(user)) return TRUE . = TRUE - var/mob/living/silicon/ai/AI = user - var/mob/living/silicon/robot/robot = user - if(istype(AI) || istype(robot)) + if(isAI(user) || iscyborg(user)) if(aidisabled) . = FALSE - else if(istype(malfai) && (malfai != AI || !(robot in malfai.connected_robots))) - . = FALSE + else if(istype(malfai) && !(malfai == user || (user in malfai.connected_robots))) + . = FALSE if (!. && !loud) balloon_alert(user, "it's disabled!") return . diff --git a/code/modules/power/apc/apc_tool_act.dm b/code/modules/power/apc/apc_tool_act.dm index 0116205fdd4ca..a82ce2f8f0d50 100644 --- a/code/modules/power/apc/apc_tool_act.dm +++ b/code/modules/power/apc/apc_tool_act.dm @@ -484,7 +484,7 @@ else if(machine_stat & (BROKEN|MAINT)) balloon_alert(user, "nothing happens!") else - if(allowed(usr) && !wires.is_cut(WIRE_IDSCAN) && !malfhack && !remote_control_user) + if(allowed(usr) && !wires.is_cut(WIRE_IDSCAN) && ((!malfhack && !remote_control_user) || (malfhack && (malfai == user || (user in malfai.connected_robots))))) locked = !locked balloon_alert(user, locked ? "locked" : "unlocked") update_appearance() From 5738b072b09d8e923cff8811667d9bf295c9e678 Mon Sep 17 00:00:00 2001 From: orange man <61334995+comfyorange@users.noreply.github.com> Date: Mon, 20 May 2024 15:33:43 +1200 Subject: [PATCH 009/103] Automatic changelog for PR #83268 [ci skip] --- html/changelogs/AutoChangeLog-pr-83268.yml | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-83268.yml diff --git a/html/changelogs/AutoChangeLog-pr-83268.yml b/html/changelogs/AutoChangeLog-pr-83268.yml new file mode 100644 index 0000000000000..ddd5581fc79d2 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-83268.yml @@ -0,0 +1,5 @@ +author: "ShizCalev" +delete-after: True +changes: + - bugfix: "Malf AI can now properly interact with APCs under their control" + - bugfix: "Malf AI & their slaved cyborgs won't be told that access is denied when trying to right-click lock/unlock APCs." \ No newline at end of file From a7c6c4720d19007e5d6d89c82682eaa1ac603c32 Mon Sep 17 00:00:00 2001 From: Fikou <23585223+Fikou@users.noreply.github.com> Date: Mon, 20 May 2024 05:34:43 +0200 Subject: [PATCH 010/103] carps now properly stop floating when you kill them (#83293) ## About The Pull Request they forced their movement type to FLYING when all this stuff is supposed to be handled by the simple flying element, so even though they would lose the flying trait they would keep doing the flying animation and had movement type flying (would go over chasms and shit) as a side note - ground movement probably shouldnt exist (nothing really checks for it and you get goofy shit like GROUND|FLYING all the time) but i cant be assed to remove it because of how it interacts with speed modifiers ## Why It's Good For The Game Got damned! ## Changelog :cl: fix: carps now properly stop floating when you kill them /:cl: --- code/modules/mob/living/basic/space_fauna/carp/carp.dm | 1 - .../mob/living/basic/space_fauna/space_dragon/space_dragon.dm | 1 - .../living/simple_animal/hostile/megafauna/blood_drunk_miner.dm | 1 - 3 files changed, 3 deletions(-) diff --git a/code/modules/mob/living/basic/space_fauna/carp/carp.dm b/code/modules/mob/living/basic/space_fauna/carp/carp.dm index ee2073987dae2..816bb7cd838e1 100644 --- a/code/modules/mob/living/basic/space_fauna/carp/carp.dm +++ b/code/modules/mob/living/basic/space_fauna/carp/carp.dm @@ -20,7 +20,6 @@ icon_gib = "carp_gib" gold_core_spawnable = HOSTILE_SPAWN mob_biotypes = MOB_ORGANIC | MOB_BEAST - movement_type = FLYING health = 25 maxHealth = 25 pressure_resistance = 200 diff --git a/code/modules/mob/living/basic/space_fauna/space_dragon/space_dragon.dm b/code/modules/mob/living/basic/space_fauna/space_dragon/space_dragon.dm index bbefe37606b96..be31e121249a6 100644 --- a/code/modules/mob/living/basic/space_fauna/space_dragon/space_dragon.dm +++ b/code/modules/mob/living/basic/space_fauna/space_dragon/space_dragon.dm @@ -28,7 +28,6 @@ damage_coeff = list(BRUTE = 1, BURN = 1, TOX = 1, STAMINA = 0.5, OXY = 1) combat_mode = TRUE speed = 0 - movement_type = FLYING attack_verb_continuous = "chomps" attack_verb_simple = "chomp" attack_sound = 'sound/magic/demon_attack1.ogg' diff --git a/code/modules/mob/living/simple_animal/hostile/megafauna/blood_drunk_miner.dm b/code/modules/mob/living/simple_animal/hostile/megafauna/blood_drunk_miner.dm index 4c6605cd8393d..37649ceb3c5cf 100644 --- a/code/modules/mob/living/simple_animal/hostile/megafauna/blood_drunk_miner.dm +++ b/code/modules/mob/living/simple_animal/hostile/megafauna/blood_drunk_miner.dm @@ -29,7 +29,6 @@ Difficulty: Medium health_doll_icon = "miner" mob_biotypes = MOB_ORGANIC|MOB_HUMANOID light_color = COLOR_LIGHT_GRAYISH_RED - movement_type = GROUND speak_emote = list("roars") speed = 3 move_to_delay = 3 From 471be05aae134f3ef24c45b8162670a8a22d008b Mon Sep 17 00:00:00 2001 From: orange man <61334995+comfyorange@users.noreply.github.com> Date: Mon, 20 May 2024 15:35:02 +1200 Subject: [PATCH 011/103] Automatic changelog for PR #83293 [ci skip] --- html/changelogs/AutoChangeLog-pr-83293.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-83293.yml diff --git a/html/changelogs/AutoChangeLog-pr-83293.yml b/html/changelogs/AutoChangeLog-pr-83293.yml new file mode 100644 index 0000000000000..77a688e3d9d28 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-83293.yml @@ -0,0 +1,4 @@ +author: "Fikou" +delete-after: True +changes: + - bugfix: "carps now properly stop floating when you kill them" \ No newline at end of file From 063ac8b983066ce6ded9e5105c6c5f7b1a052285 Mon Sep 17 00:00:00 2001 From: Jacquerel Date: Mon, 20 May 2024 05:57:26 +0100 Subject: [PATCH 012/103] Adds logging for Legion Tumour interactions (#83302) ## About The Pull Request Adds logs to three events: - Receiving a Legion Tumour organ (logs victim). - Being transformed by having a Legion Tumour organ for too long (logs victim). - A Critically Wounded person being clicked with a Legion Tumour and turned into a Legion (logs attacker and victim). ## Why It's Good For The Game It hasn't happened _often_ but I've seen these various interactions confuse admins (or players) every so often and it's good to log things that aren't obvious (and many things which are). This usually comes up in the case of someone getting one from a Bioscrambler and then later experiencing a surprise transformation. ## Changelog :cl: admin: Various bad things that can happen as a result of Legion organs are now logged /:cl: --- .../mob/living/basic/lavaland/legion/legion_tumour.dm | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/code/modules/mob/living/basic/lavaland/legion/legion_tumour.dm b/code/modules/mob/living/basic/lavaland/legion/legion_tumour.dm index 55c1e6426b360..3e6931917ed29 100644 --- a/code/modules/mob/living/basic/lavaland/legion/legion_tumour.dm +++ b/code/modules/mob/living/basic/lavaland/legion/legion_tumour.dm @@ -55,6 +55,10 @@ stage = 0 elapsed_time = 0 +/obj/item/organ/internal/legion_tumour/on_mob_insert(mob/living/carbon/organ_owner, special, movement_flags) + . = ..() + owner.log_message("has received [src] which will eventually turn them into a Legion.", LOG_VICTIM) + /obj/item/organ/internal/legion_tumour/attack(mob/living/target, mob/living/user, params) if (try_apply(target, user)) qdel(src) @@ -79,6 +83,7 @@ if (!ishuman(target)) return FALSE + log_combat(user, target, "used a Legion Tumour on", src, "as they are in crit, this will turn them into a Legion.") target.visible_message(span_boldwarning("[user] splatters [target] with [src]... and it springs into horrible life!")) var/mob/living/basic/legion_brood/skull = new(target.loc) skull.melee_attack(target) @@ -143,6 +148,7 @@ /obj/item/organ/internal/legion_tumour/proc/infest() if (QDELETED(src) || QDELETED(owner)) return + owner.log_message("has been turned into a Legion by their tumour.", LOG_VICTIM) owner.visible_message(span_boldwarning("Black tendrils burst from [owner]'s flesh, covering them in amorphous flesh!")) var/mob/living/basic/mining/legion/new_legion = new spawn_type(owner.loc) new_legion.consume(owner) From 9c54757c2c5ff12f368deec83dce7f1f92372fa7 Mon Sep 17 00:00:00 2001 From: orange man <61334995+comfyorange@users.noreply.github.com> Date: Mon, 20 May 2024 16:57:45 +1200 Subject: [PATCH 013/103] Automatic changelog for PR #83302 [ci skip] --- html/changelogs/AutoChangeLog-pr-83302.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-83302.yml diff --git a/html/changelogs/AutoChangeLog-pr-83302.yml b/html/changelogs/AutoChangeLog-pr-83302.yml new file mode 100644 index 0000000000000..0cd0e16936891 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-83302.yml @@ -0,0 +1,4 @@ +author: "Jacquerel" +delete-after: True +changes: + - admin: "Various bad things that can happen as a result of Legion organs are now logged" \ No newline at end of file From 3a2fa13e7b67ff25cc643678195a768767be3570 Mon Sep 17 00:00:00 2001 From: Sadboysuss <96586172+Sadboysuss@users.noreply.github.com> Date: Mon, 20 May 2024 07:57:57 +0300 Subject: [PATCH 014/103] adds sgt.araneus to birdshot (#83298) ## About The Pull Request All other stations have a pet for the hos, why doesn't birdshot? ## Why It's Good For The Game HoS should have a pet like on other maps ## Changelog :cl: fix: HoS on birdshot now has a pet like on all other maps /:cl: --- _maps/map_files/Birdshot/birdshot.dmm | 1 + 1 file changed, 1 insertion(+) diff --git a/_maps/map_files/Birdshot/birdshot.dmm b/_maps/map_files/Birdshot/birdshot.dmm index 811ea64f9b4c1..03a999b509995 100644 --- a/_maps/map_files/Birdshot/birdshot.dmm +++ b/_maps/map_files/Birdshot/birdshot.dmm @@ -76062,6 +76062,7 @@ }, /obj/effect/decal/cleanable/dirt, /obj/machinery/light/small/directional/north, +/mob/living/basic/spider/giant/sgt_araneus, /turf/open/floor/stone, /area/station/command/heads_quarters/hos) "yaG" = ( From c9cd0ff650177e6360fa2477ed5eb6c33abc837a Mon Sep 17 00:00:00 2001 From: orange man <61334995+comfyorange@users.noreply.github.com> Date: Mon, 20 May 2024 16:58:15 +1200 Subject: [PATCH 015/103] Automatic changelog for PR #83298 [ci skip] --- html/changelogs/AutoChangeLog-pr-83298.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-83298.yml diff --git a/html/changelogs/AutoChangeLog-pr-83298.yml b/html/changelogs/AutoChangeLog-pr-83298.yml new file mode 100644 index 0000000000000..ed255d8f9095f --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-83298.yml @@ -0,0 +1,4 @@ +author: "Sadboysuss" +delete-after: True +changes: + - bugfix: "HoS on birdshot now has a pet like on all other maps" \ No newline at end of file From 8ef96bb755eb8036ff7673f0fd286727155da472 Mon Sep 17 00:00:00 2001 From: Sadboysuss <96586172+Sadboysuss@users.noreply.github.com> Date: Mon, 20 May 2024 08:00:23 +0300 Subject: [PATCH 016/103] [NO GBP] Fix jumpsuit quick toggle sensors (#83299) ## About The Pull Request I made an oopsie after a review and didn't test it ## Why It's Good For The Game bug fix ## Changelog :cl: fix: jumpsuit sensors quick maxing now works /:cl: --- code/modules/clothing/under/_under.dm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/modules/clothing/under/_under.dm b/code/modules/clothing/under/_under.dm index 8b80a28dd4af1..fd8512c3eb83f 100644 --- a/code/modules/clothing/under/_under.dm +++ b/code/modules/clothing/under/_under.dm @@ -340,7 +340,7 @@ /obj/item/clothing/under/CtrlClick(mob/user) . = ..() - if(!.) + if(.) return if(!can_toggle_sensors(user)) return From d7c2cd74949209bf53f3fe0cc8b67d77bd55e414 Mon Sep 17 00:00:00 2001 From: orange man <61334995+comfyorange@users.noreply.github.com> Date: Mon, 20 May 2024 17:00:40 +1200 Subject: [PATCH 017/103] Automatic changelog for PR #83299 [ci skip] --- html/changelogs/AutoChangeLog-pr-83299.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-83299.yml diff --git a/html/changelogs/AutoChangeLog-pr-83299.yml b/html/changelogs/AutoChangeLog-pr-83299.yml new file mode 100644 index 0000000000000..5616c75e5e75c --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-83299.yml @@ -0,0 +1,4 @@ +author: "Sadboysuss" +delete-after: True +changes: + - bugfix: "jumpsuit sensors quick maxing now works" \ No newline at end of file From d011185fdc84efdf43460697d26418c5aa4efdeb Mon Sep 17 00:00:00 2001 From: EnterTheJake <102721711+EnterTheJake@users.noreply.github.com> Date: Mon, 20 May 2024 07:01:03 +0200 Subject: [PATCH 018/103] Fixes The description of Pulse Of Entropy to display the correct reagents. (#83288) ## About The Pull Request Fixes a typo on the description of Pulse of Entropy ## Why It's Good For The Game When i made my pr to rework rust heretic, i kinda forgot to update the description on the recipe for Pulse of Entropy to include the garbage item, this fixes that. ## Changelog :cl: spellcheck: Pulse of entropy description now displays the correct reagents for the ritual /:cl: --- code/modules/antagonists/heretic/knowledge/side_rust_cosmos.dm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/modules/antagonists/heretic/knowledge/side_rust_cosmos.dm b/code/modules/antagonists/heretic/knowledge/side_rust_cosmos.dm index 453b030611bdd..671e01603c5c7 100644 --- a/code/modules/antagonists/heretic/knowledge/side_rust_cosmos.dm +++ b/code/modules/antagonists/heretic/knowledge/side_rust_cosmos.dm @@ -20,7 +20,7 @@ /datum/heretic_knowledge/entropy_pulse name = "Pulse of Entropy" - desc = "Allows you to transmute 10 iron sheets to fill the surrounding vicinity of the rune with rust." + desc = "Allows you to transmute 10 iron sheets and a garbage item to fill the surrounding vicinity of the rune with rust." gain_text = "Reality begins to whisper to me. To give it its entropic end." required_atoms = list( /obj/item/stack/sheet/iron = 10, From 03a03d97084898a11b0bb2f1cf94f0ff753bd555 Mon Sep 17 00:00:00 2001 From: orange man <61334995+comfyorange@users.noreply.github.com> Date: Mon, 20 May 2024 17:01:21 +1200 Subject: [PATCH 019/103] Automatic changelog for PR #83288 [ci skip] --- html/changelogs/AutoChangeLog-pr-83288.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-83288.yml diff --git a/html/changelogs/AutoChangeLog-pr-83288.yml b/html/changelogs/AutoChangeLog-pr-83288.yml new file mode 100644 index 0000000000000..ddc929033878a --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-83288.yml @@ -0,0 +1,4 @@ +author: "EnterTheJake" +delete-after: True +changes: + - spellcheck: "Pulse of entropy description now displays the correct reagents for the ritual" \ No newline at end of file From 22f5ab3cc85bee3f2e7a1add7f2c91a5220f0a31 Mon Sep 17 00:00:00 2001 From: Pickle-Coding <58013024+Pickle-Coding@users.noreply.github.com> Date: Mon, 20 May 2024 06:01:48 +0100 Subject: [PATCH 020/103] Cargo ripley starts at full charge. (#83287) ## About The Pull Request Cargo ripley starts at 100% charge instead of 25% charge. ## Why It's Good For The Game Because charging a cell actually requires a significant amount of energy now, the roundstart ripley starting almost uncharged causes quite a significant roundstart load since it's next to the recharger. This makes it start fully charged so the roundstart power rush is less extreme. ## Changelog :cl: balance: Cargo ripley's cell starts fully charged. /:cl: --- code/modules/vehicles/mecha/working/ripley.dm | 2 -- 1 file changed, 2 deletions(-) diff --git a/code/modules/vehicles/mecha/working/ripley.dm b/code/modules/vehicles/mecha/working/ripley.dm index a4872289e962c..1bed2350f08c8 100644 --- a/code/modules/vehicles/mecha/working/ripley.dm +++ b/code/modules/vehicles/mecha/working/ripley.dm @@ -265,8 +265,6 @@ GLOBAL_DATUM(cargo_ripley, /obj/vehicle/sealed/mecha/ripley/cargo) /obj/vehicle/sealed/mecha/ripley/cargo/Initialize(mapload) . = ..() - if(cell) - cell.charge = FLOOR(cell.charge * 0.25, 1) //Starts at very low charge //Attach hydraulic clamp ONLY var/obj/item/mecha_parts/mecha_equipment/hydraulic_clamp/HC = new From 8b9913e38fe6cbf75fa7c240b5d90c187204bf2b Mon Sep 17 00:00:00 2001 From: orange man <61334995+comfyorange@users.noreply.github.com> Date: Mon, 20 May 2024 17:02:08 +1200 Subject: [PATCH 021/103] Automatic changelog for PR #83287 [ci skip] --- html/changelogs/AutoChangeLog-pr-83287.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-83287.yml diff --git a/html/changelogs/AutoChangeLog-pr-83287.yml b/html/changelogs/AutoChangeLog-pr-83287.yml new file mode 100644 index 0000000000000..b22a2e037283b --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-83287.yml @@ -0,0 +1,4 @@ +author: "Pickle-Coding" +delete-after: True +changes: + - balance: "Cargo ripley's cell starts fully charged." \ No newline at end of file From 925419fbe9d0c6496e469416dc369aaf45f7ebf3 Mon Sep 17 00:00:00 2001 From: Afevis Date: Mon, 20 May 2024 01:02:18 -0400 Subject: [PATCH 022/103] Fixes icecream vats eating borg beakers (#83279) Fixes #83257 :cl: ShizCalev fix: Icecream vats will no longer eat cyborg beakers. /:cl: --- .../food_and_drinks/machinery/icecream_vat.dm | 20 ++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/code/modules/food_and_drinks/machinery/icecream_vat.dm b/code/modules/food_and_drinks/machinery/icecream_vat.dm index cae1b26024933..eba5ff63f3f8c 100644 --- a/code/modules/food_and_drinks/machinery/icecream_vat.dm +++ b/code/modules/food_and_drinks/machinery/icecream_vat.dm @@ -110,26 +110,27 @@ . = ..() if(.) return - if(!beaker || !istype(beaker) || !beaker.reagents || (beaker.item_flags & ABSTRACT) || !beaker.is_open_container()) + if(!istype(beaker) || !beaker.reagents || (beaker.item_flags & ABSTRACT) || !beaker.is_open_container()) return if(custom_ice_cream_beaker) - if(beaker.forceMove(src)) + if(user.transferItemToLoc(beaker, src)) try_put_in_hand(custom_ice_cream_beaker, user) balloon_alert(user, "beakers swapped") custom_ice_cream_beaker = beaker else balloon_alert(user, "beaker slot full!") return - if(beaker.forceMove(src)) - balloon_alert(user, "beaker inserted") - custom_ice_cream_beaker = beaker + if(!user.transferItemToLoc(beaker, src)) + return + balloon_alert(user, "beaker inserted") + custom_ice_cream_beaker = beaker /obj/machinery/icecream_vat/attackby_secondary(obj/item/reagent_containers/beaker, mob/user, params) . = ..() if(. == SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN) return - if(!beaker || !istype(beaker) || !beaker.reagents || (beaker.item_flags & ABSTRACT) || !beaker.is_open_container()) + if(!istype(beaker) || !beaker.reagents || (beaker.item_flags & ABSTRACT) || !beaker.is_open_container()) return SECONDARY_ATTACK_CONTINUE_CHAIN var/added_reagents = FALSE for(var/datum/reagent/beaker_reagents in beaker.reagents.reagent_list) @@ -211,9 +212,10 @@ return ice_cream_icon /obj/machinery/icecream_vat/on_deconstruction(disassembled = TRUE) - new /obj/item/stack/sheet/iron(loc, 4) - if(custom_ice_cream_beaker) - custom_ice_cream_beaker.forceMove(loc) + var/atom/drop_location = drop_location() + + new /obj/item/stack/sheet/iron(drop_location, 4) + custom_ice_cream_beaker?.forceMove(drop_location) ///Makes an ice cream cone of the make_type, using ingredients list as reagents used to make it. Puts in user's hand if possible. /obj/machinery/icecream_vat/proc/make_cone(mob/user, make_type, list/ingredients) From 07dbbc72a34dac6bfa6f6b950941d1742e947b3c Mon Sep 17 00:00:00 2001 From: orange man <61334995+comfyorange@users.noreply.github.com> Date: Mon, 20 May 2024 17:02:35 +1200 Subject: [PATCH 023/103] Automatic changelog for PR #83279 [ci skip] --- html/changelogs/AutoChangeLog-pr-83279.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-83279.yml diff --git a/html/changelogs/AutoChangeLog-pr-83279.yml b/html/changelogs/AutoChangeLog-pr-83279.yml new file mode 100644 index 0000000000000..d1f3631f57b3d --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-83279.yml @@ -0,0 +1,4 @@ +author: "ShizCalev" +delete-after: True +changes: + - bugfix: "Icecream vats will no longer eat cyborg beakers." \ No newline at end of file From 49dccad3a0daada04573778134dc79c2d1059b1b Mon Sep 17 00:00:00 2001 From: Fikou <23585223+Fikou@users.noreply.github.com> Date: Mon, 20 May 2024 07:03:59 +0200 Subject: [PATCH 024/103] unhardcodes modsuit parts (#82905) ## About The Pull Request see #70061 but i almost finished it, i only need to go through every single module and assign it a fitting part ## Changelog :cl: refactor: modsuits have been refactored if you see bugs report them fix: admin cargo tech modsuit outfit now works correctly /:cl: --------- Co-authored-by: Andrew --- code/__DEFINES/dcs/signals/signals_mod.dm | 8 +- code/__DEFINES/mod.dm | 22 +- code/__HELPERS/mobs.dm | 43 ++ .../bitrunning/antagonists/cyber_tac.dm | 77 -- .../jobs/job_types/cargo_technician.dm | 1 + code/modules/mod/adding_new_mod.md | 71 +- code/modules/mod/mod_activation.dm | 110 ++- code/modules/mod/mod_control.dm | 238 ++---- code/modules/mod/mod_paint.dm | 14 +- code/modules/mod/mod_part.dm | 22 + code/modules/mod/mod_theme.dm | 706 +++++++++++++----- code/modules/mod/mod_types.dm | 20 +- code/modules/mod/mod_ui.dm | 13 +- code/modules/mod/modules/_module.dm | 70 +- code/modules/mod/modules/module_kinesis.dm | 4 +- code/modules/mod/modules/module_pathfinder.dm | 1 + code/modules/mod/modules/modules_antag.dm | 67 +- .../mod/modules/modules_engineering.dm | 32 +- code/modules/mod/modules/modules_general.dm | 135 ++-- code/modules/mod/modules/modules_maint.dm | 48 +- code/modules/mod/modules/modules_medical.dm | 11 +- code/modules/mod/modules/modules_ninja.dm | 32 +- code/modules/mod/modules/modules_science.dm | 21 +- code/modules/mod/modules/modules_security.dm | 50 +- code/modules/mod/modules/modules_service.dm | 42 +- code/modules/mod/modules/modules_supply.dm | 49 +- code/modules/mod/modules/modules_timeline.dm | 27 +- code/modules/mod/modules/modules_visor.dm | 7 +- code/modules/unit_tests/modsuit.dm | 5 +- code/modules/unit_tests/suit_storage_icons.dm | 6 +- tgstation.dme | 1 + tgui/packages/tgui/interfaces/MODsuit.tsx | 37 +- 32 files changed, 1155 insertions(+), 835 deletions(-) create mode 100644 code/modules/mod/mod_part.dm diff --git a/code/__DEFINES/dcs/signals/signals_mod.dm b/code/__DEFINES/dcs/signals/signals_mod.dm index c4007d1296910..d3439cf857291 100644 --- a/code/__DEFINES/dcs/signals/signals_mod.dm +++ b/code/__DEFINES/dcs/signals/signals_mod.dm @@ -1,10 +1,14 @@ //MODsuit signals /// Called when a module is selected to be the active one from on_select(obj/item/mod/module/module) #define COMSIG_MOD_MODULE_SELECTED "mod_module_selected" -/// Called when a MOD deploys one or more of its parts. +/// Called when a MOD user deploys one or more of its parts. #define COMSIG_MOD_DEPLOYED "mod_deployed" -/// Called when a MOD retracts one or more of its parts. +/// Called when a MOD user retracts one or more of its parts. #define COMSIG_MOD_RETRACTED "mod_retracted" +/// Called when a MOD deploys a part. +#define COMSIG_MOD_PART_DEPLOYED "mod_part_deployed" +/// Called when a MOD retracts a part. +#define COMSIG_MOD_PART_RETRACTED "mod_part_retracted" /// Called when a MOD is finished toggling itself. #define COMSIG_MOD_TOGGLED "mod_toggled" /// Called when a MOD activation is called from toggle_activate(mob/user) diff --git a/code/__DEFINES/mod.dm b/code/__DEFINES/mod.dm index be59793927f07..8257e1969bedb 100644 --- a/code/__DEFINES/mod.dm +++ b/code/__DEFINES/mod.dm @@ -4,7 +4,7 @@ /// The default cell drain of a modsuit. The standard modsuit active power usage drains this much energy per modsuit second. #define DEFAULT_CHARGE_DRAIN (0.005 * STANDARD_CELL_CHARGE) // A standard cell lasts 200 seconds with this on active power usage, while a high power one lasts 2,000 seconds. -/// Default time for a part to seal +/// Default time for a part of the suit to seal. #define MOD_ACTIVATION_STEP_TIME (2 SECONDS) /// Passive module, just acts when put in naturally. @@ -23,14 +23,8 @@ /// This module can be used while the suit is off #define MODULE_ALLOW_INACTIVE (1<<2) -//Defines used by the theme for clothing flags and similar -#define CONTROL_LAYER "control_layer" -#define HELMET_FLAGS "helmet_flags" -#define CHESTPLATE_FLAGS "chestplate_flags" -#define GAUNTLETS_FLAGS "gauntlets_flags" -#define BOOTS_FLAGS "boots_flags" - #define UNSEALED_LAYER "unsealed_layer" +#define SEALED_LAYER "sealed_layer" #define UNSEALED_CLOTHING "unsealed_clothing" #define SEALED_CLOTHING "sealed_clothing" #define UNSEALED_INVISIBILITY "unsealed_invisibility" @@ -38,6 +32,8 @@ #define UNSEALED_COVER "unsealed_cover" #define SEALED_COVER "sealed_cover" #define CAN_OVERSLOT "can_overslot" +#define UNSEALED_MESSAGE "unsealed_message" +#define SEALED_MESSAGE "sealed_message" //Defines used to override MOD clothing's icon and worn icon files in the skin. #define MOD_ICON_OVERRIDE "mod_icon_override" @@ -49,6 +45,16 @@ #define MODLINK_FREQ_CHARLIE "CHRL" #define MODLINK_FREQ_CENTCOM "CC" +//Default text for different messages for the user. +#define HELMET_UNSEAL_MESSAGE "hisses open" +#define HELMET_SEAL_MESSAGE "hisses closed" +#define CHESTPLATE_UNSEAL_MESSAGE "releases your chest" +#define CHESTPLATE_SEAL_MESSAGE "cinches tightly around your chest" +#define GAUNTLET_UNSEAL_MESSAGE "become loose around your fingers" +#define GAUNTLET_SEAL_MESSAGE "tighten around your fingers and wrists" +#define BOOT_UNSEAL_MESSAGE "relax their grip on your legs" +#define BOOT_SEAL_MESSAGE "seal around your feet" + /// Global list of all /datum/mod_theme GLOBAL_LIST_INIT(mod_themes, setup_mod_themes()) /// Global list of all ids associated to a /datum/mod_link instance diff --git a/code/__HELPERS/mobs.dm b/code/__HELPERS/mobs.dm index d623a707b8855..eb7fa2c3aa36b 100644 --- a/code/__HELPERS/mobs.dm +++ b/code/__HELPERS/mobs.dm @@ -632,6 +632,49 @@ GLOBAL_LIST_INIT(skin_tone_names, list( else return precise_zone +///Returns a list of strings for a given slot flag. +/proc/parse_slot_flags(slot_flags) + var/list/slot_strings = list() + if(slot_flags & ITEM_SLOT_BACK) + slot_strings += "back" + if(slot_flags & ITEM_SLOT_MASK) + slot_strings += "mask" + if(slot_flags & ITEM_SLOT_NECK) + slot_strings += "neck" + if(slot_flags & ITEM_SLOT_HANDCUFFED) + slot_strings += "handcuff" + if(slot_flags & ITEM_SLOT_LEGCUFFED) + slot_strings += "legcuff" + if(slot_flags & ITEM_SLOT_BELT) + slot_strings += "belt" + if(slot_flags & ITEM_SLOT_ID) + slot_strings += "id" + if(slot_flags & ITEM_SLOT_EARS) + slot_strings += "ear" + if(slot_flags & ITEM_SLOT_EYES) + slot_strings += "glasses" + if(slot_flags & ITEM_SLOT_GLOVES) + slot_strings += "glove" + if(slot_flags & ITEM_SLOT_HEAD) + slot_strings += "head" + if(slot_flags & ITEM_SLOT_FEET) + slot_strings += "shoe" + if(slot_flags & ITEM_SLOT_OCLOTHING) + slot_strings += "oversuit" + if(slot_flags & ITEM_SLOT_ICLOTHING) + slot_strings += "undersuit" + if(slot_flags & ITEM_SLOT_SUITSTORE) + slot_strings += "suit storage" + if(slot_flags & (ITEM_SLOT_LPOCKET|ITEM_SLOT_RPOCKET)) + slot_strings += "pocket" + if(slot_flags & ITEM_SLOT_HANDS) + slot_strings += "hand" + if(slot_flags & ITEM_SLOT_DEX_STORAGE) + slot_strings += "dextrous storage" + if(slot_flags & ITEM_SLOT_BACKPACK) + slot_strings += "backpack" + return slot_strings + ///Returns the direction that the initiator and the target are facing /proc/check_target_facings(mob/living/initiator, mob/living/target) /*This can be used to add additional effects on interactions between mobs depending on how the mobs are facing each other, such as adding a crit damage to blows to the back of a guy's head. diff --git a/code/modules/bitrunning/antagonists/cyber_tac.dm b/code/modules/bitrunning/antagonists/cyber_tac.dm index 26ad05081e89d..a45fdb345d304 100644 --- a/code/modules/bitrunning/antagonists/cyber_tac.dm +++ b/code/modules/bitrunning/antagonists/cyber_tac.dm @@ -29,80 +29,3 @@ var/obj/item/implant/weapons_auth/auth = new(user) auth.implant(user) - -/obj/item/mod/control/pre_equipped/glitch - theme = /datum/mod_theme/glitch - applied_cell = /obj/item/stock_parts/cell/bluespace - applied_modules = list( - /obj/item/mod/module/storage, - /obj/item/mod/module/magnetic_harness, - /obj/item/mod/module/jetpack/advanced, - /obj/item/mod/module/jump_jet, - /obj/item/mod/module/flashlight, - ) - default_pins = list( - /obj/item/mod/module/armor_booster, - /obj/item/mod/module/jetpack/advanced, - /obj/item/mod/module/jump_jet, - ) - starting_frequency = null - -/datum/armor/mod_theme_glitch - melee = 15 - bullet = 20 - laser = 35 - bomb = 65 - bio = 100 - fire = 100 - acid = 100 - wound = 100 - -/datum/mod_theme/glitch - name = "glitch" - desc = "A modsuit outfitted for elite Cyber Authority units to track, capture, and eliminate organic intruders." - extended_desc = "The Cyber Authority function as a digital police force, patrolling the digital realm and enforcing the law. Cyber Tac units are the elite of the elite, outfitted with lethal weaponry and fast mobility specially designed to quell organic uprisings." - default_skin = "glitch" - armor_type = /datum/armor/mod_theme_glitch - resistance_flags = FIRE_PROOF|ACID_PROOF - atom_flags = PREVENT_CONTENTS_EXPLOSION_1 - max_heat_protection_temperature = FIRE_IMMUNITY_MAX_TEMP_PROTECT - complexity_max = DEFAULT_MAX_COMPLEXITY + 3 - siemens_coefficient = 0 - slowdown_inactive = 1 - slowdown_active = 0.5 - ui_theme = "terminal" - inbuilt_modules = list(/obj/item/mod/module/armor_booster) - allowed_suit_storage = list( - /obj/item/ammo_box, - /obj/item/ammo_casing, - /obj/item/restraints/handcuffs, - /obj/item/assembly/flash, - ) - skins = list( - "glitch" = list( - HELMET_FLAGS = list( - UNSEALED_LAYER = null, - UNSEALED_CLOTHING = SNUG_FIT, - SEALED_CLOTHING = THICKMATERIAL|STOPSPRESSUREDAMAGE|BLOCK_GAS_SMOKE_EFFECT|HEADINTERNALS, - UNSEALED_INVISIBILITY = HIDEFACIALHAIR, - SEALED_INVISIBILITY = HIDEMASK|HIDEEARS|HIDEEYES|HIDEFACE|HIDEHAIR|HIDESNOUT, - SEALED_COVER = HEADCOVERSMOUTH|HEADCOVERSEYES|PEPPERPROOF, - ), - CHESTPLATE_FLAGS = list( - UNSEALED_CLOTHING = THICKMATERIAL, - SEALED_CLOTHING = STOPSPRESSUREDAMAGE, - SEALED_INVISIBILITY = HIDEJUMPSUIT, - ), - GAUNTLETS_FLAGS = list( - UNSEALED_CLOTHING = THICKMATERIAL, - SEALED_CLOTHING = STOPSPRESSUREDAMAGE, - CAN_OVERSLOT = TRUE, - ), - BOOTS_FLAGS = list( - UNSEALED_CLOTHING = THICKMATERIAL, - SEALED_CLOTHING = STOPSPRESSUREDAMAGE, - CAN_OVERSLOT = TRUE, - ), - ), - ) - diff --git a/code/modules/jobs/job_types/cargo_technician.dm b/code/modules/jobs/job_types/cargo_technician.dm index dd269bc7e3736..008ddd6df0db5 100644 --- a/code/modules/jobs/job_types/cargo_technician.dm +++ b/code/modules/jobs/job_types/cargo_technician.dm @@ -54,3 +54,4 @@ name = "Cargo Technician (MODsuit)" back = /obj/item/mod/control/pre_equipped/loader + suit = null diff --git a/code/modules/mod/adding_new_mod.md b/code/modules/mod/adding_new_mod.md index b0bf12486c14a..8252822cf6c25 100644 --- a/code/modules/mod/adding_new_mod.md +++ b/code/modules/mod/adding_new_mod.md @@ -82,16 +82,15 @@ So, now that we have our theme, we want to add a skin to it (or another theme of armor_type = /datum/armor/modtheme_psychological complexity_max = DEFAULT_MAX_COMPLEXITY - 7 charge_drain = DEFAULT_CHARGE_DRAIN * 0.5 - skins = list( + variants = list( "psychological" = list( - HELMET_LAYER = null, - HELMET_FLAGS = list( + /obj/item/clothing/head/mod = list( ), - CHESTPLATE_FLAGS = list( + /obj/item/clothing/suit/mod = list( ), - GAUNTLETS_FLAGS = list( + /obj/item/clothing/gloves/mod = list( ), - BOOTS_FLAGS = list( + /obj/item/clothing/shoes/mod = list( ), ), ) @@ -101,8 +100,7 @@ We now have a psychological skin, this will apply the psychological icons to eve For example, if our helmet's icon covers the full head (like the research skin), we want to do something like this. ```dm - HELMET_LAYER = null, - HELMET_FLAGS = list( + /obj/item/clothing/head/mod = list( UNSEALED_CLOTHING = SNUG_FIT|THICKMATERIAL, SEALED_CLOTHING = STOPSPRESSUREDAMAGE|BLOCK_GAS_SMOKE_EFFECT, UNSEALED_INVISIBILITY = HIDEFACIALHAIR|HIDEMASK|HIDEEARS|HIDEEYES|HIDEFACE|HIDEHAIR|HIDESNOUT, @@ -113,8 +111,8 @@ For example, if our helmet's icon covers the full head (like the research skin), Otherwise, with an open helmet that becomes closed (like the engineering skin), we'd do this. ```dm - HELMET_LAYER = NECK_LAYER, - HELMET_FLAGS = list( + /obj/item/clothing/head/mod = list( + UNSEALED_LAYER = NECK_LAYER UNSEALED_CLOTHING = SNUG_FIT, SEALED_CLOTHING = THICKMATERIAL|STOPSPRESSUREDAMAGE, UNSEALED_INVISIBILITY = HIDEFACIALHAIR, @@ -137,47 +135,46 @@ There are specific cases of helmets that semi-cover the head, like the cosmohonk armor_type = /datum/armor/modtheme_psychological complexity_max = DEFAULT_MAX_COMPLEXITY - 7 charge_drain = DEFAULT_CHARGE_DRAIN * 0.5 - skins = list( + variants = list( "psychological" = list( - HELMET_LAYER = NECK_LAYER, - HELMET_FLAGS = list( + /obj/item/clothing/head/mod = list( + UNSEALED_LAYER = NECK_LAYER UNSEALED_CLOTHING = SNUG_FIT, SEALED_CLOTHING = THICKMATERIAL|STOPSPRESSUREDAMAGE, UNSEALED_INVISIBILITY = HIDEFACIALHAIR, SEALED_INVISIBILITY = HIDEMASK|HIDEEARS|HIDEEYES|HIDEFACE|HIDEHAIR|HIDESNOUT, SEALED_COVER = HEADCOVERSMOUTH|HEADCOVERSEYES|PEPPERPROOF, ), - CHESTPLATE_FLAGS = list( + /obj/item/clothing/suit/mod = list( UNSEALED_CLOTHING = THICKMATERIAL, SEALED_CLOTHING = STOPSPRESSUREDAMAGE, SEALED_INVISIBILITY = HIDEJUMPSUIT, ), - GAUNTLETS_FLAGS = list( + /obj/item/clothing/gloves/mod = list( UNSEALED_CLOTHING = THICKMATERIAL, SEALED_CLOTHING = STOPSPRESSUREDAMAGE, ), - BOOTS_FLAGS = list( + /obj/item/clothing/shoes/mod = list( UNSEALED_CLOTHING = THICKMATERIAL, SEALED_CLOTHING = STOPSPRESSUREDAMAGE, ), "psychotherapeutic" = list( - HELMET_LAYER = null, - HELMET_FLAGS = list( + /obj/item/clothing/head/mod = list( UNSEALED_CLOTHING = SNUG_FIT|THICKMATERIAL, SEALED_CLOTHING = STOPSPRESSUREDAMAGE, UNSEALED_INVISIBILITY = HIDEFACIALHAIR|HIDEMASK|HIDEEARS|HIDEEYES|HIDEFACE|HIDEHAIR|HIDESNOUT, UNSEALED_COVER = HEADCOVERSMOUTH|HEADCOVERSEYES|PEPPERPROOF, ), - CHESTPLATE_FLAGS = list( + /obj/item/clothing/suit/mod = list( UNSEALED_CLOTHING = THICKMATERIAL, SEALED_CLOTHING = STOPSPRESSUREDAMAGE, SEALED_INVISIBILITY = HIDEJUMPSUIT, ), - GAUNTLETS_FLAGS = list( + /obj/item/clothing/gloves/mod = list( UNSEALED_CLOTHING = THICKMATERIAL, SEALED_CLOTHING = STOPSPRESSUREDAMAGE, ), - BOOTS_FLAGS = list( + /obj/item/clothing/shoes/mod = list( UNSEALED_CLOTHING = THICKMATERIAL, SEALED_CLOTHING = STOPSPRESSUREDAMAGE, ), @@ -207,7 +204,7 @@ As we want this effect to be on demand, we probably want this to be an usable mo - Usable: You can use these for a one time effect. - Active: You can only have one selected at a time. It gives you a special click effect. -As we have an usable module, we want to set a cooldown time. All modules are also incompatible with themselves, have a specific power cost and complexity varying on how powerful they are, so let's update our definition, and also add a new variable for how much brain damage we'll heal. +As we have an usable module, we want to set a cooldown time. All modules are also incompatible with themselves, have a specific power cost and complexity varying on how powerful they are, and are equippable to certain slots, so let's update our definition, and also add a new variable for how much brain damage we'll heal. ```dm /obj/item/mod/module/neuron_healer @@ -220,25 +217,20 @@ As we have an usable module, we want to set a cooldown time. All modules are als use_energy_cost = DEFAULT_CHARGE_DRAIN incompatible_modules = list(/obj/item/mod/module/neuron_healer) cooldown_time = 15 SECONDS + required_slot = list(ITEM_SLOT_HEAD) var/brain_damage_healed = 25 ``` -Now, we want to override the on_use proc for our new effect. We want to make sure the use checks passed from parent. You can read about most procs and variables by reading [this](modules/_module.dm) +Now, we want to override the on_use proc for our new effect. You can read about most procs and variables by reading [this](modules/_module.dm) ```dm /obj/item/mod/module/neuron_healer/on_use() - . = ..() - if(!.) - return ``` After this, we want to put our special code, a basic effect of healing all mobs nearby for their brain damage and creating a beam to them. ```dm /obj/item/mod/module/neuron_healer/on_use() - . = ..() - if(!.) - return for(var/mob/living/carbon/carbon_mob in range(5, src)) if(carbon_mob == mod.wearer) continue @@ -272,47 +264,46 @@ Now we want to add it to the psychological theme, which is very simple, finishin complexity_max = DEFAULT_MAX_COMPLEXITY - 7 charge_drain = DEFAULT_CHARGE_DRAIN * 0.5 inbuilt_modules = list(/obj/item/mod/module/neuron_healer/advanced) - skins = list( + variants = list( "psychological" = list( - HELMET_LAYER = NECK_LAYER, - HELMET_FLAGS = list( + /obj/item/clothing/head/mod = list( + UNSEALED_LAYER = NECK_LAYER UNSEALED_CLOTHING = SNUG_FIT, SEALED_CLOTHING = THICKMATERIAL|STOPSPRESSUREDAMAGE, UNSEALED_INVISIBILITY = HIDEFACIALHAIR, SEALED_INVISIBILITY = HIDEMASK|HIDEEARS|HIDEEYES|HIDEFACE|HIDEHAIR|HIDESNOUT, SEALED_COVER = HEADCOVERSMOUTH|HEADCOVERSEYES|PEPPERPROOF, ), - CHESTPLATE_FLAGS = list( + /obj/item/clothing/suit/mod = list( UNSEALED_CLOTHING = THICKMATERIAL, SEALED_CLOTHING = STOPSPRESSUREDAMAGE, SEALED_INVISIBILITY = HIDEJUMPSUIT, ), - GAUNTLETS_FLAGS = list( + /obj/item/clothing/gloves/mod = list( UNSEALED_CLOTHING = THICKMATERIAL, SEALED_CLOTHING = STOPSPRESSUREDAMAGE, ), - BOOTS_FLAGS = list( + /obj/item/clothing/shoes/mod = list( UNSEALED_CLOTHING = THICKMATERIAL, SEALED_CLOTHING = STOPSPRESSUREDAMAGE, ), "psychotherapeutic" = list( - HELMET_LAYER = null, - HELMET_FLAGS = list( + /obj/item/clothing/head/mod = list( UNSEALED_CLOTHING = SNUG_FIT|THICKMATERIAL, SEALED_CLOTHING = STOPSPRESSUREDAMAGE, UNSEALED_INVISIBILITY = HIDEFACIALHAIR|HIDEMASK|HIDEEARS|HIDEEYES|HIDEFACE|HIDEHAIR|HIDESNOUT, UNSEALED_COVER = HEADCOVERSMOUTH|HEADCOVERSEYES|PEPPERPROOF, ), - CHESTPLATE_FLAGS = list( + /obj/item/clothing/suit/mod = list( UNSEALED_CLOTHING = THICKMATERIAL, SEALED_CLOTHING = STOPSPRESSUREDAMAGE, SEALED_INVISIBILITY = HIDEJUMPSUIT, ), - GAUNTLETS_FLAGS = list( + /obj/item/clothing/gloves/mod = list( UNSEALED_CLOTHING = THICKMATERIAL, SEALED_CLOTHING = STOPSPRESSUREDAMAGE, ), - BOOTS_FLAGS = list( + /obj/item/clothing/shoes/mod = list( UNSEALED_CLOTHING = THICKMATERIAL, SEALED_CLOTHING = STOPSPRESSUREDAMAGE, ), diff --git a/code/modules/mod/mod_activation.dm b/code/modules/mod/mod_activation.dm index 0d150c15fe61a..237e151bcb2c0 100644 --- a/code/modules/mod/mod_activation.dm +++ b/code/modules/mod/mod_activation.dm @@ -6,7 +6,8 @@ return var/list/display_names = list() var/list/items = list() - for(var/obj/item/part as anything in mod_parts) + var/list/parts = get_parts() + for(var/obj/item/part as anything in parts) display_names[part.name] = REF(part) var/image/part_image = image(icon = part.icon, icon_state = part.icon_state) if(part.loc != src) @@ -16,17 +17,17 @@ if(!pick) return var/part_reference = display_names[pick] - var/obj/item/part = locate(part_reference) in mod_parts + var/obj/item/part = locate(part_reference) in parts if(!istype(part) || user.incapacitated()) return if(active || activating) balloon_alert(user, "deactivate the suit first!") playsound(src, 'sound/machines/scanbuzz.ogg', 25, TRUE, SILENCED_SOUND_EXTRARANGE) return - var/parts_to_check = mod_parts - part + var/parts_to_check = parts - part if(part.loc == src) deploy(user, part) - on_mod_deployed(user) + SEND_SIGNAL(src, COMSIG_MOD_DEPLOYED, user) for(var/obj/item/checking_part as anything in parts_to_check) if(checking_part.loc != src) continue @@ -34,7 +35,7 @@ break else retract(user, part) - on_mod_retracted(user) + SEND_SIGNAL(src, COMSIG_MOD_RETRACTED, user) for(var/obj/item/checking_part as anything in parts_to_check) if(checking_part.loc == src) continue @@ -48,28 +49,29 @@ playsound(src, 'sound/machines/scanbuzz.ogg', 25, TRUE, SILENCED_SOUND_EXTRARANGE) return FALSE var/deploy = TRUE - for(var/obj/item/part as anything in mod_parts) + for(var/obj/item/part as anything in get_parts()) if(part.loc == src) continue deploy = FALSE break - for(var/obj/item/part as anything in mod_parts) + for(var/obj/item/part as anything in get_parts()) if(deploy && part.loc == src) deploy(null, part) else if(!deploy && part.loc != src) retract(null, part) - wearer.visible_message(span_notice("[wearer]'s [src] [deploy ? "deploys" : "retracts"] its' parts with a mechanical hiss."), - span_notice("[src] [deploy ? "deploys" : "retracts"] its' parts with a mechanical hiss."), + wearer.visible_message(span_notice("[wearer]'s [src] [deploy ? "deploys" : "retracts"] its parts with a mechanical hiss."), + span_notice("[src] [deploy ? "deploys" : "retracts"] its parts with a mechanical hiss."), span_hear("You hear a mechanical hiss.")) playsound(src, 'sound/mecha/mechmove03.ogg', 25, TRUE, SHORT_RANGE_SOUND_EXTRARANGE) if(deploy) - on_mod_deployed(user) + SEND_SIGNAL(src, COMSIG_MOD_DEPLOYED, user) else - on_mod_retracted(user) + SEND_SIGNAL(src, COMSIG_MOD_RETRACTED, user) return TRUE /// Deploys a part of the suit onto the user. /obj/item/mod/control/proc/deploy(mob/user, obj/item/part) + var/datum/mod_part/part_datum = get_part_datum(part) if(!wearer) playsound(src, 'sound/machines/scanbuzz.ogg', 25, TRUE, SILENCED_SOUND_EXTRARANGE) return FALSE // pAI is trying to deploy it from your hands @@ -78,10 +80,10 @@ return FALSE balloon_alert(user, "[part.name] already deployed!") playsound(src, 'sound/machines/scanbuzz.ogg', 25, TRUE, SILENCED_SOUND_EXTRARANGE) - if(part in overslotting_parts) + if(part_datum.can_overslot) var/obj/item/overslot = wearer.get_item_by_slot(part.slot_flags) if(overslot) - overslotting_parts[part] = overslot + part_datum.overslotting = overslot wearer.transferItemToLoc(overslot, part, force = TRUE) RegisterSignal(part, COMSIG_ATOM_EXITED, PROC_REF(on_overslot_exit)) if(wearer.equip_to_slot_if_possible(part, part.slot_flags, qdel_on_fail = FALSE, disable_warning = TRUE)) @@ -92,6 +94,7 @@ span_notice("[part] deploy[part.p_s()] with a mechanical hiss."), span_hear("You hear a mechanical hiss.")) playsound(src, 'sound/mecha/mechmove03.ogg', 25, TRUE, SHORT_RANGE_SOUND_EXTRARANGE) + SEND_SIGNAL(src, COMSIG_MOD_PART_DEPLOYED, user, part) return TRUE else if(!user) @@ -102,6 +105,7 @@ /// Retract a part of the suit from the user. /obj/item/mod/control/proc/retract(mob/user, obj/item/part) + var/datum/mod_part/part_datum = get_part_datum(part) if(part.loc == src) if(!user) return FALSE @@ -109,12 +113,13 @@ playsound(src, 'sound/machines/scanbuzz.ogg', 25, TRUE, SILENCED_SOUND_EXTRARANGE) REMOVE_TRAIT(part, TRAIT_NODROP, MOD_TRAIT) wearer.transferItemToLoc(part, src, force = TRUE) - if(overslotting_parts[part]) + if(part_datum.overslotting) UnregisterSignal(part, COMSIG_ATOM_EXITED) - var/obj/item/overslot = overslotting_parts[part] - if(!wearer.equip_to_slot_if_possible(overslot, overslot.slot_flags, qdel_on_fail = FALSE, disable_warning = TRUE)) + var/obj/item/overslot = part_datum.overslotting + if(!QDELING(wearer) && !wearer.equip_to_slot_if_possible(overslot, overslot.slot_flags, qdel_on_fail = FALSE, disable_warning = TRUE)) wearer.dropItemToGround(overslot, force = TRUE, silent = TRUE) - overslotting_parts[part] = null + part_datum.overslotting = null + SEND_SIGNAL(src, COMSIG_MOD_PART_RETRACTED, user, part) if(!user) return wearer.visible_message(span_notice("[wearer]'s [part.name] retract[part.p_s()] back into [src] with a mechanical hiss."), @@ -122,7 +127,7 @@ span_hear("You hear a mechanical hiss.")) playsound(src, 'sound/mecha/mechmove03.ogg', 25, TRUE, SHORT_RANGE_SOUND_EXTRARANGE) -/// Starts the activation sequence, where parts of the suit activate one by one until the whole suit is on +/// Starts the activation sequence, where parts of the suit activate one by one until the whole suit is on. /obj/item/mod/control/proc/toggle_activate(mob/user, force_deactivate = FALSE) if(!wearer) if(!force_deactivate) @@ -132,7 +137,7 @@ if(!force_deactivate && (SEND_SIGNAL(src, COMSIG_MOD_ACTIVATE, user) & MOD_CANCEL_ACTIVATE)) playsound(src, 'sound/machines/scanbuzz.ogg', 25, TRUE, SILENCED_SOUND_EXTRARANGE) return FALSE - for(var/obj/item/part as anything in mod_parts) + for(var/obj/item/part as anything in get_parts()) if(!force_deactivate && part.loc == src) balloon_alert(user, "deploy all parts first!") playsound(src, 'sound/machines/scanbuzz.ogg', 25, TRUE, SILENCED_SOUND_EXTRARANGE) @@ -157,33 +162,21 @@ for(var/obj/item/mod/module/module as anything in modules) if(!module.active || (module.allow_flags & MODULE_ALLOW_INACTIVE)) continue - module.on_deactivation(display_message = FALSE) - mod_link.end_call() + module.deactivate(display_message = FALSE) activating = TRUE + mod_link.end_call() to_chat(wearer, span_notice("MODsuit [active ? "shutting down" : "starting up"].")) - if (ai_assistant) - to_chat(ai_assistant, span_notice("MODsuit [active ? "shutting down" : "starting up"].")) - if(do_after(wearer, activation_step_time, wearer, MOD_ACTIVATION_STEP_FLAGS, extra_checks = CALLBACK(src, PROC_REF(has_wearer)), hidden = TRUE)) - to_chat(wearer, span_notice("[boots] [active ? "relax their grip on your legs" : "seal around your feet"].")) - playsound(src, 'sound/mecha/mechmove03.ogg', 25, TRUE, SHORT_RANGE_SOUND_EXTRARANGE) - seal_part(boots, seal = !active) - if(do_after(wearer, activation_step_time, wearer, MOD_ACTIVATION_STEP_FLAGS, extra_checks = CALLBACK(src, PROC_REF(has_wearer)), hidden = TRUE)) - to_chat(wearer, span_notice("[gauntlets] [active ? "become loose around your fingers" : "tighten around your fingers and wrists"].")) - playsound(src, 'sound/mecha/mechmove03.ogg', 25, TRUE, SHORT_RANGE_SOUND_EXTRARANGE) - seal_part(gauntlets, seal = !active) - if(do_after(wearer, activation_step_time, wearer, MOD_ACTIVATION_STEP_FLAGS, extra_checks = CALLBACK(src, PROC_REF(has_wearer)), hidden = TRUE)) - to_chat(wearer, span_notice("[chestplate] [active ? "releases your chest" : "cinches tightly against your chest"].")) - playsound(src, 'sound/mecha/mechmove03.ogg', 25, TRUE, SHORT_RANGE_SOUND_EXTRARANGE) - seal_part(chestplate, seal = !active) - if(do_after(wearer, activation_step_time, wearer, MOD_ACTIVATION_STEP_FLAGS, extra_checks = CALLBACK(src, PROC_REF(has_wearer)), hidden = TRUE)) - to_chat(wearer, span_notice("[helmet] hisses [active ? "open" : "closed"].")) - playsound(src, 'sound/mecha/mechmove03.ogg', 25, TRUE, SHORT_RANGE_SOUND_EXTRARANGE) - seal_part(helmet, seal = !active) - if(do_after(wearer, activation_step_time, wearer, MOD_ACTIVATION_STEP_FLAGS, extra_checks = CALLBACK(src, PROC_REF(has_wearer)), hidden = TRUE)) + for(var/obj/item/part as anything in get_parts()) + var/datum/mod_part/part_datum = get_part_datum(part) + if(do_after(wearer, activation_step_time, wearer, MOD_ACTIVATION_STEP_FLAGS, extra_checks = CALLBACK(src, PROC_REF(get_wearer)), hidden = TRUE)) + to_chat(wearer, span_notice("[part] [active ? part_datum.unsealed_message : part_datum.sealed_message].")) + playsound(src, 'sound/mecha/mechmove03.ogg', 25, TRUE, SHORT_RANGE_SOUND_EXTRARANGE) + seal_part(part, is_sealed = !active) + if(do_after(wearer, activation_step_time, wearer, MOD_ACTIVATION_STEP_FLAGS, extra_checks = CALLBACK(src, PROC_REF(get_wearer)), hidden = TRUE)) to_chat(wearer, span_notice("Systems [active ? "shut down. Parts unsealed. Goodbye" : "started up. Parts sealed. Welcome"], [wearer].")) if(ai_assistant) to_chat(ai_assistant, span_notice("SYSTEMS [active ? "DEACTIVATED. GOODBYE" : "ACTIVATED. WELCOME"]: \"[ai_assistant]\"")) - finish_activation(on = !active) + finish_activation(is_on = !active) if(active) playsound(src, 'sound/machines/synth_yes.ogg', 50, TRUE, SHORT_RANGE_SOUND_EXTRARANGE, frequency = 6000) if(!malfunctioning) @@ -194,16 +187,18 @@ SEND_SIGNAL(src, COMSIG_MOD_TOGGLED, user) return TRUE -///Seals or unseals the given part -/obj/item/mod/control/proc/seal_part(obj/item/clothing/part, seal) - if(seal) +///Seals or unseals the given part. +/obj/item/mod/control/proc/seal_part(obj/item/clothing/part, is_sealed) + var/datum/mod_part/part_datum = get_part_datum(part) + part_datum.sealed = is_sealed + if(part_datum.sealed) part.icon_state = "[skin]-[part.base_icon_state]-sealed" part.clothing_flags |= part.visor_flags part.flags_inv |= part.visor_flags_inv part.flags_cover |= part.visor_flags_cover part.heat_protection = initial(part.heat_protection) part.cold_protection = initial(part.cold_protection) - part.alternate_worn_layer = null + part.alternate_worn_layer = part_datum.sealed_layer else part.icon_state = "[skin]-[part.base_icon_state]" part.flags_cover &= ~part.visor_flags_cover @@ -211,15 +206,17 @@ part.clothing_flags &= ~part.visor_flags part.heat_protection = NONE part.cold_protection = NONE - part.alternate_worn_layer = mod_parts[part] + part.alternate_worn_layer = part_datum.unsealed_layer wearer.update_clothing(part.slot_flags) wearer.update_obscured_slots(part.visor_flags_inv) if((part.clothing_flags & (MASKINTERNALS|HEADINTERNALS)) && wearer.invalid_internals()) wearer.cutoff_internals() /// Finishes the suit's activation -/obj/item/mod/control/proc/finish_activation(on) - active = on +/obj/item/mod/control/proc/finish_activation(is_on) + var/datum/mod_part/part_datum = get_part_datum(src) + part_datum.sealed = is_on + active = is_on if(active) for(var/obj/item/mod/module/module as anything in modules) module.on_suit_activation() @@ -234,22 +231,13 @@ /// Quickly deploys all the suit parts and if successful, seals them and turns on the suit. Intended mostly for outfits. /obj/item/mod/control/proc/quick_activation() var/seal = TRUE - for(var/obj/item/part as anything in mod_parts) + for(var/obj/item/part as anything in get_parts()) if(!deploy(null, part)) seal = FALSE if(!seal) return - for(var/obj/item/part as anything in mod_parts) - seal_part(part, seal = TRUE) - finish_activation(on = TRUE) - -/obj/item/mod/control/proc/has_wearer() - return wearer - -/obj/item/mod/control/proc/on_mod_deployed(mob/user) - SEND_SIGNAL(src, COMSIG_MOD_DEPLOYED, user) - -/obj/item/mod/control/proc/on_mod_retracted(mob/user) - SEND_SIGNAL(src, COMSIG_MOD_RETRACTED, user) + for(var/obj/item/part as anything in get_parts()) + seal_part(part, is_sealed = TRUE) + finish_activation(is_on = TRUE) #undef MOD_ACTIVATION_STEP_FLAGS diff --git a/code/modules/mod/mod_control.dm b/code/modules/mod/mod_control.dm index 1dd7fceae3dd2..4fd168cee044a 100644 --- a/code/modules/mod/mod_control.dm +++ b/code/modules/mod/mod_control.dm @@ -64,20 +64,10 @@ var/activation_step_time = MOD_ACTIVATION_STEP_TIME /// Extended description of the theme. var/extended_desc - /// MOD helmet. - var/obj/item/clothing/head/mod/helmet - /// MOD chestplate. - var/obj/item/clothing/suit/mod/chestplate - /// MOD gauntlets. - var/obj/item/clothing/gloves/mod/gauntlets - /// MOD boots. - var/obj/item/clothing/shoes/mod/boots /// MOD core. var/obj/item/mod/core/core - /// Associated list of parts (helmet, chestplate, gauntlets, boots) to their unsealed worn layer. + /// List of MODsuit part datums. var/list/mod_parts = list() - /// Associated list of parts that can overslot to their overslot (overslot means the part can cover another layer of clothing). - var/list/overslotting_parts = list() /// Modules the MOD currently possesses. var/list/modules = list() /// Currently used module. @@ -102,43 +92,14 @@ if(new_theme) theme = new_theme theme = GLOB.mod_themes[theme] - slot_flags = theme.slot_flags - extended_desc = theme.extended_desc - slowdown_inactive = theme.slowdown_inactive - slowdown_active = theme.slowdown_active - activation_step_time = theme.activation_step_time - complexity_max = theme.complexity_max - ui_theme = theme.ui_theme - charge_drain = theme.charge_drain + theme.set_up_parts(src, new_skin) + for(var/obj/item/part as anything in get_parts()) + RegisterSignal(part, COMSIG_ATOM_DESTRUCTION, PROC_REF(on_part_destruction)) + RegisterSignal(part, COMSIG_QDELETING, PROC_REF(on_part_deletion)) set_wires(new /datum/wires/mod(src)) if(length(req_access)) locked = TRUE new_core?.install(src) - helmet = new /obj/item/clothing/head/mod(src) - mod_parts += helmet - chestplate = new /obj/item/clothing/suit/mod(src) - chestplate.allowed += theme.allowed_suit_storage - mod_parts += chestplate - gauntlets = new /obj/item/clothing/gloves/mod(src) - mod_parts += gauntlets - boots = new /obj/item/clothing/shoes/mod(src) - mod_parts += boots - var/list/all_parts = mod_parts + src - for(var/obj/item/part as anything in all_parts) - part.name = "[theme.name] [part.name]" - part.desc = "[part.desc] [theme.desc]" - part.set_armor(theme.armor_type) - part.resistance_flags = theme.resistance_flags - part.flags_1 |= theme.atom_flags //flags like initialization or admin spawning are here, so we cant set, have to add - part.heat_protection = NONE - part.cold_protection = NONE - part.max_heat_protection_temperature = theme.max_heat_protection_temperature - part.min_cold_protection_temperature = theme.min_cold_protection_temperature - part.siemens_coefficient = theme.siemens_coefficient - for(var/obj/item/part as anything in mod_parts) - RegisterSignal(part, COMSIG_ATOM_DESTRUCTION, PROC_REF(on_part_destruction)) - RegisterSignal(part, COMSIG_QDELETING, PROC_REF(on_part_deletion)) - set_mod_skin(new_skin || theme.default_skin) update_speed() RegisterSignal(src, COMSIG_ATOM_EXITED, PROC_REF(on_exit)) RegisterSignal(src, COMSIG_SPEED_POTION_APPLIED, PROC_REF(on_potion)) @@ -151,44 +112,21 @@ STOP_PROCESSING(SSobj, src) for(var/obj/item/mod/module/module as anything in modules) uninstall(module, deleting = TRUE) - for(var/obj/item/part as anything in mod_parts) - overslotting_parts -= part - var/atom/deleting_atom - if(!QDELETED(helmet)) - deleting_atom = helmet - helmet = null - mod_parts -= deleting_atom - qdel(deleting_atom) - if(!QDELETED(chestplate)) - deleting_atom = chestplate - chestplate = null - mod_parts -= deleting_atom - qdel(deleting_atom) - if(!QDELETED(gauntlets)) - deleting_atom = gauntlets - gauntlets = null - mod_parts -= deleting_atom - qdel(deleting_atom) - if(!QDELETED(boots)) - deleting_atom = boots - boots = null - mod_parts -= deleting_atom - qdel(deleting_atom) if(core) QDEL_NULL(core) QDEL_NULL(wires) QDEL_NULL(mod_link) + for(var/datum/mod_part/part_datum as anything in get_part_datums(all = TRUE)) + part_datum.part_item = null + part_datum.overslotting = null return ..() /obj/item/mod/control/atom_destruction(damage_flag) + if(wearer) + wearer.visible_message(span_danger("[src] fall[p_s()] apart, completely destroyed!"), vision_distance = COMBAT_MESSAGE_RANGE) + clean_up() for(var/obj/item/mod/module/module as anything in modules) uninstall(module) - for(var/obj/item/part as anything in mod_parts) - if(!overslotting_parts[part]) - continue - var/obj/item/overslot = overslotting_parts[part] - overslot.forceMove(drop_location()) - overslotting_parts[part] = null if(ai_assistant) if(ispAI(ai_assistant)) INVOKE_ASYNC(src, PROC_REF(remove_pai), /* user = */ null, /* forced = */ TRUE) // async to appease spaceman DMM because the branch we don't run has a do_after @@ -245,11 +183,10 @@ subtract_charge((charge_drain + malfunctioning_charge_drain) * seconds_per_tick) for(var/obj/item/mod/module/module as anything in modules) if(malfunctioning && module.active && SPT_PROB(5, seconds_per_tick)) - module.on_deactivation(display_message = TRUE) + module.deactivate(display_message = TRUE) module.on_process(seconds_per_tick) -/obj/item/mod/control/equipped(mob/user, slot) - ..() +/obj/item/mod/control/visual_equipped(mob/user, slot, initial = FALSE) //needs to be visual because we wanna show it in select equipment if(slot & slot_flags) set_wearer(user) else if(wearer) @@ -281,7 +218,7 @@ /obj/item/mod/control/allow_attack_hand_drop(mob/user) if(user != wearer) return ..() - for(var/obj/item/part as anything in mod_parts) + for(var/obj/item/part as anything in get_parts()) if(part.loc != src) balloon_alert(user, "retract parts first!") playsound(src, 'sound/machines/scanbuzz.ogg', 25, FALSE, SILENCED_SOUND_EXTRARANGE) @@ -290,7 +227,7 @@ /obj/item/mod/control/MouseDrop(atom/over_object) if(usr != wearer || !istype(over_object, /atom/movable/screen/inventory/hand)) return ..() - for(var/obj/item/part as anything in mod_parts) + for(var/obj/item/part as anything in get_parts()) if(part.loc != src) balloon_alert(wearer, "retract parts first!") playsound(src, 'sound/machines/scanbuzz.ogg', 25, FALSE, SILENCED_SOUND_EXTRARANGE) @@ -433,16 +370,12 @@ to_chat(wearer, span_notice("[severity > 1 ? "Light" : "Strong"] electromagnetic pulse detected!")) if(. & EMP_PROTECT_CONTENTS) return - selected_module?.on_deactivation(display_message = TRUE) + selected_module?.deactivate(display_message = TRUE) wearer.apply_damage(5 / severity, BURN, spread_damage=TRUE) to_chat(wearer, span_danger("You feel [src] heat up from the EMP, burning you slightly.")) if(wearer.stat < UNCONSCIOUS && prob(10)) wearer.emote("scream") -/obj/item/mod/control/visual_equipped(mob/user, slot, initial = FALSE) - if(slot & slot_flags) - set_wearer(user) - /obj/item/mod/control/on_outfit_equip(mob/living/carbon/human/outfit_wearer, visuals_only, item_slot) . = ..() quick_activation() @@ -450,7 +383,7 @@ /obj/item/mod/control/doStrip(mob/stripper, mob/owner) if(active && !toggle_activate(stripper, force_deactivate = TRUE)) return - for(var/obj/item/part as anything in mod_parts) + for(var/obj/item/part as anything in get_parts()) if(part.loc == src) continue retract(null, part) @@ -460,14 +393,44 @@ icon_state = "[skin]-[base_icon_state][active ? "-sealed" : ""]" return ..() +/obj/item/mod/control/proc/get_parts(all = FALSE) + . = list() + for(var/key in mod_parts) + var/datum/mod_part/part = mod_parts[key] + if(!all && part.part_item == src) + continue + . += part.part_item + +/obj/item/mod/control/proc/get_part_datums(all = FALSE) + . = list() + for(var/key in mod_parts) + var/datum/mod_part/part = mod_parts[key] + if(!all && part.part_item == src) + continue + . += part + +/obj/item/mod/control/proc/get_part_datum(obj/item/part) + RETURN_TYPE(/datum/mod_part) + var/datum/mod_part/potential_part = mod_parts["[part.slot_flags]"] + if(potential_part?.part_item == part) + return potential_part + for(var/datum/mod_part/mod_part in get_part_datums()) + if(mod_part.part_item == part) + return mod_part + CRASH("get_part_datum called with incorrect item [part] passed.") + +/obj/item/mod/control/proc/get_part_from_slot(slot) + slot = "[slot]" + for(var/part_slot in mod_parts) + if(slot != part_slot) + continue + var/datum/mod_part/part = mod_parts[part_slot] + return part.part_item + /obj/item/mod/control/proc/set_wearer(mob/living/carbon/human/user) - if (wearer == user) - // This should also not happen. - // This path is hit when equipping an outfit with visualsOnly, but only sometimes, and this eventually gets called twice. - // I'm not sure this proc should ever be being called by visualsOnly, but it is, - // and this was an emergency patch. - return - else if (!isnull(wearer)) + if(wearer == user) + CRASH("set_wearer() was called with the new wearer being the current wearer: [wearer]") + else if(!isnull(wearer)) stack_trace("set_wearer() was called with a new wearer without unset_wearer() being called") wearer = user @@ -487,17 +450,20 @@ wearer = null /obj/item/mod/control/proc/clean_up() + if(QDELING(src)) + unset_wearer() + return if(active || activating) for(var/obj/item/mod/module/module as anything in modules) if(!module.active) continue - module.on_deactivation(display_message = FALSE) - for(var/obj/item/part as anything in mod_parts) - seal_part(part, seal = FALSE) - for(var/obj/item/part as anything in mod_parts) + module.deactivate(display_message = FALSE) + for(var/obj/item/part as anything in get_parts()) + seal_part(part, is_sealed = FALSE) + for(var/obj/item/part as anything in get_parts()) retract(null, part) if(active) - finish_activation(on = FALSE) + finish_activation(is_on = FALSE) mod_link?.end_call() var/mob/old_wearer = wearer unset_wearer() @@ -506,8 +472,7 @@ /obj/item/mod/control/proc/on_species_gain(datum/source, datum/species/new_species, datum/species/old_species) SIGNAL_HANDLER - var/list/all_parts = mod_parts + src - for(var/obj/item/part in all_parts) + for(var/obj/item/part in get_parts(all = TRUE)) if(!(new_species.no_equip_flags & part.slot_flags) || is_type_in_list(new_species, part.species_exception)) continue forceMove(drop_location()) @@ -565,6 +530,11 @@ balloon_alert(user, "[new_module] would make [src] too complex!") playsound(src, 'sound/machines/scanbuzz.ogg', 25, TRUE, SILENCED_SOUND_EXTRARANGE) return + if(!new_module.has_required_parts(mod_parts)) + if(user) + balloon_alert(user, "[new_module] incompatible with [src]'s parts!") + playsound(src, 'sound/machines/scanbuzz.ogg', 25, TRUE, SILENCED_SOUND_EXTRARANGE) + return new_module.forceMove(src) modules += new_module complexity += new_module.complexity @@ -587,7 +557,7 @@ if(active) old_module.on_suit_deactivation(deleting = deleting) if(old_module.active) - old_module.on_deactivation(display_message = !deleting, deleting = deleting) + old_module.deactivate(display_message = !deleting, deleting = deleting) old_module.UnregisterSignal(src, COMSIG_ITEM_GET_WORN_OVERLAYS) old_module.on_uninstall(deleting = deleting) QDEL_LIST_ASSOC_VAL(old_module.pinned_to) @@ -643,9 +613,8 @@ wearer.update_spacesuit_hud_icon(state_to_use || "0") /obj/item/mod/control/proc/update_speed() - var/list/all_parts = mod_parts + src - for(var/obj/item/part as anything in all_parts) - part.slowdown = (active ? slowdown_active : slowdown_inactive) / length(all_parts) + for(var/obj/item/part as anything in get_parts(all = TRUE)) + part.slowdown = (active ? slowdown_active : slowdown_inactive) / length(mod_parts) wearer?.update_equipment_speed_mods() /obj/item/mod/control/proc/power_off() @@ -653,52 +622,11 @@ toggle_activate(wearer, force_deactivate = TRUE) /obj/item/mod/control/proc/set_mod_color(new_color) - var/list/all_parts = mod_parts + src - for(var/obj/item/part as anything in all_parts) + for(var/obj/item/part as anything in get_parts(all = TRUE)) part.remove_atom_colour(WASHABLE_COLOUR_PRIORITY) part.add_atom_colour(new_color, FIXED_COLOUR_PRIORITY) wearer?.regenerate_icons() -/obj/item/mod/control/proc/set_mod_skin(new_skin) - if(active) - CRASH("[src] tried to set skin while active!") - skin = new_skin - var/list/used_skin = theme.skins[new_skin] - if(used_skin[CONTROL_LAYER]) - alternate_worn_layer = used_skin[CONTROL_LAYER] - var/list/skin_updating = mod_parts + src - for(var/obj/item/part as anything in skin_updating) - part.icon = used_skin[MOD_ICON_OVERRIDE] || 'icons/obj/clothing/modsuit/mod_clothing.dmi' - part.worn_icon = used_skin[MOD_WORN_ICON_OVERRIDE] || 'icons/mob/clothing/modsuit/mod_clothing.dmi' - part.icon_state = "[skin]-[part.base_icon_state]" - for(var/obj/item/clothing/part as anything in mod_parts) - var/used_category - if(part == helmet) - used_category = HELMET_FLAGS - if(part == chestplate) - used_category = CHESTPLATE_FLAGS - if(part == gauntlets) - used_category = GAUNTLETS_FLAGS - if(part == boots) - used_category = BOOTS_FLAGS - var/list/category = used_skin[used_category] - part.clothing_flags = category[UNSEALED_CLOTHING] || NONE - part.visor_flags = category[SEALED_CLOTHING] || NONE - part.flags_inv = category[UNSEALED_INVISIBILITY] || NONE - part.visor_flags_inv = category[SEALED_INVISIBILITY] || NONE - part.flags_cover = category[UNSEALED_COVER] || NONE - part.visor_flags_cover = category[SEALED_COVER] || NONE - part.alternate_worn_layer = category[UNSEALED_LAYER] - mod_parts[part] = part.alternate_worn_layer - if(!category[CAN_OVERSLOT]) - if(overslotting_parts[part]) - var/obj/item/overslot = overslotting_parts[part] - overslot.forceMove(drop_location()) - overslotting_parts -= part - continue - overslotting_parts |= part - wearer?.regenerate_icons() - /obj/item/mod/control/proc/on_exit(datum/source, atom/movable/part, direction) SIGNAL_HANDLER @@ -712,7 +640,9 @@ if(part in modules) uninstall(part) return - if(part in mod_parts) + if(part in get_parts()) + if(isnull(part.loc)) + return if(!wearer) part.forceMove(src) return @@ -723,27 +653,25 @@ /obj/item/mod/control/proc/on_part_destruction(obj/item/part, damage_flag) SIGNAL_HANDLER - if(overslotting_parts[part]) - var/obj/item/overslot = overslotting_parts[part] - overslot.forceMove(drop_location()) - overslotting_parts[part] = null - if(QDELETED(src)) + if(QDELING(src)) return atom_destruction(damage_flag) -/obj/item/mod/control/proc/on_part_deletion(obj/item/part) //the part doesnt count as being qdeleted, so our destroying does an infinite loop, fix later +/obj/item/mod/control/proc/on_part_deletion(obj/item/part) SIGNAL_HANDLER - if(QDELETED(src)) + if(QDELING(src)) return + part.moveToNullspace() qdel(src) -/obj/item/mod/control/proc/on_overslot_exit(datum/source, atom/movable/overslot, direction) +/obj/item/mod/control/proc/on_overslot_exit(obj/item/part, atom/movable/overslot, direction) SIGNAL_HANDLER - if(overslot != overslotting_parts[source]) + var/datum/mod_part/part_datum = get_part_datum(part) + if(overslot != part_datum.overslotting) return - overslotting_parts[source] = null + part_datum.overslotting = null /obj/item/mod/control/proc/on_potion(atom/movable/source, obj/item/slimepotion/speed/speed_potion, mob/living/user) SIGNAL_HANDLER diff --git a/code/modules/mod/mod_paint.dm b/code/modules/mod/mod_paint.dm index 240c0897b33a1..1402a4aebc6bc 100644 --- a/code/modules/mod/mod_paint.dm +++ b/code/modules/mod/mod_paint.dm @@ -140,18 +140,18 @@ SStgui.close_uis(src) /obj/item/mod/paint/proc/paint_skin(obj/item/mod/control/mod, mob/user) - if(length(mod.theme.skins) <= 1) + if(length(mod.theme.variants) <= 1) balloon_alert(user, "no alternate skins!") return var/list/skins = list() - for(var/mod_skin_name in mod.theme.skins) - var/list/mod_skin = mod.theme.skins[mod_skin_name] + for(var/mod_skin_name in mod.theme.variants) + var/list/mod_skin = mod.theme.variants[mod_skin_name] skins[mod_skin_name] = image(icon = mod_skin[MOD_ICON_OVERRIDE] || mod.icon, icon_state = "[mod_skin_name]-control") var/pick = show_radial_menu(user, mod, skins, custom_check = CALLBACK(src, PROC_REF(check_menu), mod, user), require_near = TRUE) if(!pick) balloon_alert(user, "no skin picked!") return - mod.set_mod_skin(pick) + mod.theme.set_skin(pick) /obj/item/mod/paint/proc/check_menu(obj/item/mod/control/mod, mob/user) if(user.incapacitated() || !user.is_holding(src) || !mod || mod.active || mod.activating) @@ -171,7 +171,6 @@ icon = 'icons/obj/clothing/modsuit/mod_construction.dmi' icon_state = "skinapplier" var/skin = "civilian" - var/compatible_theme = /datum/mod_theme /obj/item/mod/skin_applier/Initialize(mapload) . = ..() @@ -184,14 +183,13 @@ if(mod.active || mod.activating) balloon_alert(user, "suit is active!") return TRUE - if(!istype(mod.theme, compatible_theme)) + if(!(skin in mod.theme.variants)) balloon_alert(user, "incompatible theme!") return TRUE - mod.set_mod_skin(skin) + mod.theme.set_skin(skin) balloon_alert(user, "skin applied") qdel(src) return TRUE /obj/item/mod/skin_applier/honkerative skin = "honkerative" - compatible_theme = /datum/mod_theme/syndicate diff --git a/code/modules/mod/mod_part.dm b/code/modules/mod/mod_part.dm new file mode 100644 index 0000000000000..88f8024628dc5 --- /dev/null +++ b/code/modules/mod/mod_part.dm @@ -0,0 +1,22 @@ +/// Datum to handle interactions between a MODsuit and its parts. +/datum/mod_part + /// The actual item we handle. + var/obj/item/part_item = null + /// Are we sealed? + var/sealed = FALSE + /// Message to user when unsealed. + var/unsealed_message + /// Message to user when sealed. + var/sealed_message + /// The layer the item will render on when unsealed. + var/unsealed_layer + /// The layer the item will render on when sealed. + var/sealed_layer + /// Can our part overslot over others? + var/can_overslot = FALSE + /// What are we overslotting over? + var/obj/item/overslotting = null + +/datum/mod_part/Destroy() + part_item = null + return ..() diff --git a/code/modules/mod/mod_theme.dm b/code/modules/mod/mod_theme.dm index c4c8839bd82a6..ecfa570dde160 100644 --- a/code/modules/mod/mod_theme.dm +++ b/code/modules/mod/mod_theme.dm @@ -49,58 +49,155 @@ var/list/inbuilt_modules = list() /// Allowed items in the chestplate's suit storage. var/list/allowed_suit_storage = list() - /// List of skins with their appropriate clothing flags. - var/list/skins = list( + /// List of variants and items created by them, with the flags we set. + var/list/variants = list( "standard" = list( - HELMET_FLAGS = list( + /obj/item/clothing/head/mod = list( UNSEALED_LAYER = NECK_LAYER, UNSEALED_CLOTHING = SNUG_FIT, SEALED_CLOTHING = THICKMATERIAL|STOPSPRESSUREDAMAGE|HEADINTERNALS, - SEALED_INVISIBILITY = HIDEFACIALHAIR|HIDEMASK|HIDEEARS|HIDEEYES|HIDEFACE|HIDEHAIR|HIDESNOUT, + SEALED_INVISIBILITY = HIDEFACIALHAIR|HIDEMASK|HIDEEARS|HIDEEYES|HIDEFACE|HIDEHAIR|HIDESNOUT, SEALED_COVER = HEADCOVERSMOUTH|HEADCOVERSEYES|PEPPERPROOF, + UNSEALED_MESSAGE = HELMET_UNSEAL_MESSAGE, + SEALED_MESSAGE = HELMET_SEAL_MESSAGE, ), - CHESTPLATE_FLAGS = list( + /obj/item/clothing/suit/mod = list( UNSEALED_CLOTHING = THICKMATERIAL, SEALED_CLOTHING = STOPSPRESSUREDAMAGE, SEALED_INVISIBILITY = HIDEJUMPSUIT, + UNSEALED_MESSAGE = CHESTPLATE_UNSEAL_MESSAGE, + SEALED_MESSAGE = CHESTPLATE_SEAL_MESSAGE, ), - GAUNTLETS_FLAGS = list( + /obj/item/clothing/gloves/mod = list( UNSEALED_CLOTHING = THICKMATERIAL, SEALED_CLOTHING = STOPSPRESSUREDAMAGE, CAN_OVERSLOT = TRUE, + UNSEALED_MESSAGE = GAUNTLET_UNSEAL_MESSAGE, + SEALED_MESSAGE = GAUNTLET_SEAL_MESSAGE, ), - BOOTS_FLAGS = list( + /obj/item/clothing/shoes/mod = list( UNSEALED_CLOTHING = THICKMATERIAL, SEALED_CLOTHING = STOPSPRESSUREDAMAGE, CAN_OVERSLOT = TRUE, + UNSEALED_MESSAGE = BOOT_UNSEAL_MESSAGE, + SEALED_MESSAGE = BOOT_SEAL_MESSAGE, ), ), "civilian" = list( - HELMET_FLAGS = list( - UNSEALED_LAYER = null, + /obj/item/clothing/head/mod = list( UNSEALED_CLOTHING = SNUG_FIT|THICKMATERIAL, SEALED_CLOTHING = STOPSPRESSUREDAMAGE|HEADINTERNALS, UNSEALED_INVISIBILITY = HIDEFACIALHAIR|HIDEMASK|HIDEEARS|HIDEEYES|HIDEFACE|HIDEHAIR|HIDESNOUT, UNSEALED_COVER = HEADCOVERSMOUTH|HEADCOVERSEYES|PEPPERPROOF, + UNSEALED_MESSAGE = HELMET_UNSEAL_MESSAGE, + SEALED_MESSAGE = HELMET_SEAL_MESSAGE, ), - CHESTPLATE_FLAGS = list( + /obj/item/clothing/suit/mod = list( UNSEALED_CLOTHING = THICKMATERIAL, SEALED_CLOTHING = STOPSPRESSUREDAMAGE, SEALED_INVISIBILITY = HIDEJUMPSUIT, + UNSEALED_MESSAGE = CHESTPLATE_UNSEAL_MESSAGE, + SEALED_MESSAGE = CHESTPLATE_SEAL_MESSAGE, ), - GAUNTLETS_FLAGS = list( + /obj/item/clothing/gloves/mod = list( UNSEALED_CLOTHING = THICKMATERIAL, SEALED_CLOTHING = STOPSPRESSUREDAMAGE, CAN_OVERSLOT = TRUE, + UNSEALED_MESSAGE = GAUNTLET_UNSEAL_MESSAGE, + SEALED_MESSAGE = GAUNTLET_SEAL_MESSAGE, ), - BOOTS_FLAGS = list( + /obj/item/clothing/shoes/mod = list( UNSEALED_CLOTHING = THICKMATERIAL, SEALED_CLOTHING = STOPSPRESSUREDAMAGE, CAN_OVERSLOT = TRUE, + UNSEALED_MESSAGE = BOOT_UNSEAL_MESSAGE, + SEALED_MESSAGE = BOOT_SEAL_MESSAGE, ), ), ) +#ifdef UNIT_TESTS +/datum/mod_theme/New() + var/list/skin_parts = list() + for(var/variant in variants) + skin_parts += list(assoc_to_keys(variants[variant])) + for(var/skin in skin_parts) + for(var/compared_skin in skin_parts) + if(skin ~! compared_skin) + stack_trace("[type] variants [skin] and [compared_skin] aren't made of the same parts.") + skin_parts -= skin +#endif + +/// Create parts of the suit and modify them using the theme's variables. +/datum/mod_theme/proc/set_up_parts(obj/item/mod/control/mod, skin) + var/list/parts = list(mod) + mod.slot_flags = slot_flags + mod.extended_desc = extended_desc + mod.slowdown_inactive = slowdown_inactive + mod.slowdown_active = slowdown_active + mod.activation_step_time = activation_step_time + mod.complexity_max = complexity_max + mod.ui_theme = ui_theme + mod.charge_drain = charge_drain + var/datum/mod_part/control_part_datum = new() + control_part_datum.part_item = mod + mod.mod_parts["[mod.slot_flags]"] = control_part_datum + for(var/path in variants[default_skin]) + var/obj/item/mod_part = new path(mod) + if(mod_part.slot_flags == ITEM_SLOT_OCLOTHING && isclothing(mod_part)) + var/obj/item/clothing/chestplate = mod_part + chestplate.allowed |= allowed_suit_storage + var/datum/mod_part/part_datum = new() + part_datum.part_item = mod_part + mod.mod_parts["[mod_part.slot_flags]"] = part_datum + parts += mod_part + for(var/obj/item/part as anything in parts) + part.name = "[name] [part.name]" + part.desc = "[part.desc] [desc]" + part.set_armor(armor_type) + part.resistance_flags = resistance_flags + part.flags_1 |= atom_flags //flags like initialization or admin spawning are here, so we cant set, have to add + part.heat_protection = NONE + part.cold_protection = NONE + part.max_heat_protection_temperature = max_heat_protection_temperature + part.min_cold_protection_temperature = min_cold_protection_temperature + part.siemens_coefficient = siemens_coefficient + set_skin(mod, skin || default_skin) + +/datum/mod_theme/proc/set_skin(obj/item/mod/control/mod, skin) + mod.skin = skin + var/list/used_skin = variants[skin] + var/list/parts = mod.get_parts() + for(var/obj/item/clothing/part as anything in parts) + var/list/category = used_skin[part.type] + var/datum/mod_part/part_datum = mod.get_part_datum(part) + part_datum.unsealed_layer = category[UNSEALED_LAYER] + part_datum.sealed_layer = category[SEALED_LAYER] + part_datum.unsealed_message = category[UNSEALED_MESSAGE] || "No unseal message set! Tell a coder!" + part_datum.sealed_message = category[SEALED_MESSAGE] || "No seal message set! Tell a coder!" + part_datum.can_overslot = category[CAN_OVERSLOT] || FALSE + part.clothing_flags = category[UNSEALED_CLOTHING] || NONE + part.visor_flags = category[SEALED_CLOTHING] || NONE + part.flags_inv = category[UNSEALED_INVISIBILITY] || NONE + part.visor_flags_inv = category[SEALED_INVISIBILITY] || NONE + part.flags_cover = category[UNSEALED_COVER] || NONE + part.visor_flags_cover = category[SEALED_COVER] || NONE + if(mod.get_part_datum(part).sealed) + part.clothing_flags |= part.visor_flags + part.flags_inv |= part.visor_flags_inv + part.flags_cover |= part.visor_flags_cover + part.alternate_worn_layer = part_datum.sealed_layer + else + part.alternate_worn_layer = part_datum.unsealed_layer + if(!part_datum.can_overslot && part_datum.overslotting) + var/obj/item/overslot = part_datum.overslotting + overslot.forceMove(mod.drop_location()) + for(var/obj/item/part as anything in parts + mod) + part.icon = used_skin[MOD_ICON_OVERRIDE] || 'icons/obj/clothing/modsuit/mod_clothing.dmi' + part.worn_icon = used_skin[MOD_WORN_ICON_OVERRIDE] || 'icons/mob/clothing/modsuit/mod_clothing.dmi' + part.icon_state = "[skin]-[part.base_icon_state][mod.get_part_datum(part).sealed ? "-sealed" : ""]" + mod.wearer?.update_clothing(part.slot_flags) + /datum/armor/mod_theme melee = 10 bullet = 5 @@ -108,7 +205,7 @@ energy = 5 bio = 100 fire = 25 - acid =25 + acid = 25 wound = 5 /datum/mod_theme/engineering @@ -131,30 +228,38 @@ /obj/item/fireaxe/metal_h2_axe, /obj/item/storage/bag/construction, ) - skins = list( + variants = list( "engineering" = list( - HELMET_FLAGS = list( + /obj/item/clothing/head/mod = list( UNSEALED_LAYER = NECK_LAYER, UNSEALED_CLOTHING = SNUG_FIT, SEALED_CLOTHING = THICKMATERIAL|STOPSPRESSUREDAMAGE|HEADINTERNALS, UNSEALED_INVISIBILITY = HIDEFACIALHAIR, SEALED_INVISIBILITY = HIDEMASK|HIDEEARS|HIDEEYES|HIDEFACE|HIDEHAIR|HIDESNOUT, SEALED_COVER = HEADCOVERSMOUTH|HEADCOVERSEYES|PEPPERPROOF, + UNSEALED_MESSAGE = HELMET_UNSEAL_MESSAGE, + SEALED_MESSAGE = HELMET_SEAL_MESSAGE, ), - CHESTPLATE_FLAGS = list( + /obj/item/clothing/suit/mod = list( UNSEALED_CLOTHING = THICKMATERIAL, SEALED_CLOTHING = STOPSPRESSUREDAMAGE, SEALED_INVISIBILITY = HIDEJUMPSUIT, + UNSEALED_MESSAGE = CHESTPLATE_UNSEAL_MESSAGE, + SEALED_MESSAGE = CHESTPLATE_SEAL_MESSAGE, ), - GAUNTLETS_FLAGS = list( + /obj/item/clothing/gloves/mod = list( UNSEALED_CLOTHING = THICKMATERIAL, SEALED_CLOTHING = STOPSPRESSUREDAMAGE, CAN_OVERSLOT = TRUE, + UNSEALED_MESSAGE = GAUNTLET_UNSEAL_MESSAGE, + SEALED_MESSAGE = GAUNTLET_SEAL_MESSAGE, ), - BOOTS_FLAGS = list( + /obj/item/clothing/shoes/mod = list( UNSEALED_CLOTHING = THICKMATERIAL, SEALED_CLOTHING = STOPSPRESSUREDAMAGE, CAN_OVERSLOT = TRUE, + UNSEALED_MESSAGE = BOOT_UNSEAL_MESSAGE, + SEALED_MESSAGE = BOOT_SEAL_MESSAGE, ), ), ) @@ -190,9 +295,9 @@ /obj/item/pipe_dispenser, /obj/item/t_scanner, ) - skins = list( + variants = list( "atmospheric" = list( - HELMET_FLAGS = list( + /obj/item/clothing/head/mod = list( UNSEALED_LAYER = NECK_LAYER, UNSEALED_CLOTHING = SNUG_FIT, SEALED_CLOTHING = THICKMATERIAL|STOPSPRESSUREDAMAGE|BLOCK_GAS_SMOKE_EFFECT|HEADINTERNALS, @@ -200,21 +305,29 @@ SEALED_INVISIBILITY = HIDEMASK|HIDEEARS|HIDEEYES|HIDEFACE|HIDEHAIR, UNSEALED_COVER = HEADCOVERSMOUTH, SEALED_COVER = HEADCOVERSEYES|PEPPERPROOF, + UNSEALED_MESSAGE = HELMET_UNSEAL_MESSAGE, + SEALED_MESSAGE = HELMET_SEAL_MESSAGE, ), - CHESTPLATE_FLAGS = list( + /obj/item/clothing/suit/mod = list( UNSEALED_CLOTHING = THICKMATERIAL, SEALED_CLOTHING = STOPSPRESSUREDAMAGE, SEALED_INVISIBILITY = HIDEJUMPSUIT, + UNSEALED_MESSAGE = CHESTPLATE_UNSEAL_MESSAGE, + SEALED_MESSAGE = CHESTPLATE_SEAL_MESSAGE, ), - GAUNTLETS_FLAGS = list( + /obj/item/clothing/gloves/mod = list( UNSEALED_CLOTHING = THICKMATERIAL, SEALED_CLOTHING = STOPSPRESSUREDAMAGE, CAN_OVERSLOT = TRUE, + UNSEALED_MESSAGE = GAUNTLET_UNSEAL_MESSAGE, + SEALED_MESSAGE = GAUNTLET_SEAL_MESSAGE, ), - BOOTS_FLAGS = list( + /obj/item/clothing/shoes/mod = list( UNSEALED_CLOTHING = THICKMATERIAL, SEALED_CLOTHING = STOPSPRESSUREDAMAGE, CAN_OVERSLOT = TRUE, + UNSEALED_MESSAGE = BOOT_UNSEAL_MESSAGE, + SEALED_MESSAGE = BOOT_SEAL_MESSAGE, ), ), ) @@ -255,30 +368,38 @@ /obj/item/storage/bag/construction, /obj/item/t_scanner, ) - skins = list( + variants = list( "advanced" = list( - HELMET_FLAGS = list( + /obj/item/clothing/head/mod = list( UNSEALED_LAYER = NECK_LAYER, UNSEALED_CLOTHING = SNUG_FIT, SEALED_CLOTHING = THICKMATERIAL|STOPSPRESSUREDAMAGE|BLOCK_GAS_SMOKE_EFFECT|HEADINTERNALS, UNSEALED_INVISIBILITY = HIDEFACIALHAIR, SEALED_INVISIBILITY = HIDEMASK|HIDEEARS|HIDEEYES|HIDEFACE|HIDEHAIR|HIDESNOUT, SEALED_COVER = HEADCOVERSMOUTH|HEADCOVERSEYES|PEPPERPROOF, + UNSEALED_MESSAGE = HELMET_UNSEAL_MESSAGE, + SEALED_MESSAGE = HELMET_SEAL_MESSAGE, ), - CHESTPLATE_FLAGS = list( + /obj/item/clothing/suit/mod = list( UNSEALED_CLOTHING = THICKMATERIAL, SEALED_CLOTHING = STOPSPRESSUREDAMAGE, SEALED_INVISIBILITY = HIDEJUMPSUIT, + UNSEALED_MESSAGE = CHESTPLATE_UNSEAL_MESSAGE, + SEALED_MESSAGE = CHESTPLATE_SEAL_MESSAGE, ), - GAUNTLETS_FLAGS = list( + /obj/item/clothing/gloves/mod = list( UNSEALED_CLOTHING = THICKMATERIAL, SEALED_CLOTHING = STOPSPRESSUREDAMAGE, CAN_OVERSLOT = TRUE, + UNSEALED_MESSAGE = GAUNTLET_UNSEAL_MESSAGE, + SEALED_MESSAGE = GAUNTLET_SEAL_MESSAGE, ), - BOOTS_FLAGS = list( + /obj/item/clothing/shoes/mod = list( UNSEALED_CLOTHING = THICKMATERIAL, SEALED_CLOTHING = STOPSPRESSUREDAMAGE, CAN_OVERSLOT = TRUE, + UNSEALED_MESSAGE = BOOT_UNSEAL_MESSAGE, + SEALED_MESSAGE = BOOT_SEAL_MESSAGE, ), ), ) @@ -332,55 +453,69 @@ /obj/item/gun/energy/recharge/kinetic_accelerator, ) inbuilt_modules = list(/obj/item/mod/module/ash_accretion, /obj/item/mod/module/sphere_transform) - skins = list( + variants = list( "mining" = list( - HELMET_FLAGS = list( - UNSEALED_LAYER = null, + /obj/item/clothing/head/mod = list( UNSEALED_CLOTHING = SNUG_FIT, SEALED_CLOTHING = THICKMATERIAL|STOPSPRESSUREDAMAGE|HEADINTERNALS, UNSEALED_INVISIBILITY = HIDEEARS|HIDEHAIR, SEALED_INVISIBILITY = HIDEMASK|HIDEEYES|HIDEFACE|HIDEFACIALHAIR|HIDESNOUT, SEALED_COVER = HEADCOVERSMOUTH|HEADCOVERSEYES|PEPPERPROOF, + UNSEALED_MESSAGE = HELMET_UNSEAL_MESSAGE, + SEALED_MESSAGE = HELMET_SEAL_MESSAGE, ), - CHESTPLATE_FLAGS = list( + /obj/item/clothing/suit/mod = list( UNSEALED_CLOTHING = THICKMATERIAL, SEALED_CLOTHING = STOPSPRESSUREDAMAGE, SEALED_INVISIBILITY = HIDEJUMPSUIT, + UNSEALED_MESSAGE = CHESTPLATE_UNSEAL_MESSAGE, + SEALED_MESSAGE = CHESTPLATE_SEAL_MESSAGE, ), - GAUNTLETS_FLAGS = list( + /obj/item/clothing/gloves/mod = list( UNSEALED_CLOTHING = THICKMATERIAL, SEALED_CLOTHING = STOPSPRESSUREDAMAGE, CAN_OVERSLOT = TRUE, + UNSEALED_MESSAGE = GAUNTLET_UNSEAL_MESSAGE, + SEALED_MESSAGE = GAUNTLET_SEAL_MESSAGE, ), - BOOTS_FLAGS = list( + /obj/item/clothing/shoes/mod = list( UNSEALED_CLOTHING = THICKMATERIAL, SEALED_CLOTHING = STOPSPRESSUREDAMAGE, CAN_OVERSLOT = TRUE, + UNSEALED_MESSAGE = BOOT_UNSEAL_MESSAGE, + SEALED_MESSAGE = BOOT_SEAL_MESSAGE, ), ), "asteroid" = list( - HELMET_FLAGS = list( - UNSEALED_LAYER = null, + /obj/item/clothing/head/mod = list( UNSEALED_CLOTHING = SNUG_FIT|THICKMATERIAL, SEALED_CLOTHING = STOPSPRESSUREDAMAGE|HEADINTERNALS, UNSEALED_INVISIBILITY = HIDEFACIALHAIR|HIDEEARS|HIDEHAIR|HIDESNOUT, SEALED_INVISIBILITY = HIDEMASK|HIDEEYES|HIDEFACE, SEALED_COVER = HEADCOVERSMOUTH|HEADCOVERSEYES|PEPPERPROOF, + UNSEALED_MESSAGE = HELMET_UNSEAL_MESSAGE, + SEALED_MESSAGE = HELMET_SEAL_MESSAGE, ), - CHESTPLATE_FLAGS = list( + /obj/item/clothing/suit/mod = list( UNSEALED_CLOTHING = THICKMATERIAL, SEALED_CLOTHING = STOPSPRESSUREDAMAGE, SEALED_INVISIBILITY = HIDEJUMPSUIT, + UNSEALED_MESSAGE = CHESTPLATE_UNSEAL_MESSAGE, + SEALED_MESSAGE = CHESTPLATE_SEAL_MESSAGE, ), - GAUNTLETS_FLAGS = list( + /obj/item/clothing/gloves/mod = list( UNSEALED_CLOTHING = THICKMATERIAL, SEALED_CLOTHING = STOPSPRESSUREDAMAGE, CAN_OVERSLOT = TRUE, + UNSEALED_MESSAGE = GAUNTLET_UNSEAL_MESSAGE, + SEALED_MESSAGE = GAUNTLET_SEAL_MESSAGE, ), - BOOTS_FLAGS = list( + /obj/item/clothing/shoes/mod = list( UNSEALED_CLOTHING = THICKMATERIAL, SEALED_CLOTHING = STOPSPRESSUREDAMAGE, CAN_OVERSLOT = TRUE, + UNSEALED_MESSAGE = BOOT_UNSEAL_MESSAGE, + SEALED_MESSAGE = BOOT_SEAL_MESSAGE, ), ), ) @@ -423,23 +558,26 @@ /obj/item/storage/bag/mail, ) inbuilt_modules = list(/obj/item/mod/module/hydraulic, /obj/item/mod/module/clamp/loader, /obj/item/mod/module/magnet) - skins = list( + variants = list( "loader" = list( - HELMET_FLAGS = list( - UNSEALED_LAYER = null, + /obj/item/clothing/head/mod = list( UNSEALED_CLOTHING = SNUG_FIT|THICKMATERIAL, UNSEALED_INVISIBILITY = HIDEEARS|HIDEHAIR, SEALED_INVISIBILITY = HIDEFACIALHAIR|HIDEMASK|HIDEEYES|HIDEFACE|HIDESNOUT, SEALED_COVER = HEADCOVERSMOUTH|HEADCOVERSEYES|PEPPERPROOF, + UNSEALED_MESSAGE = HELMET_UNSEAL_MESSAGE, + SEALED_MESSAGE = HELMET_SEAL_MESSAGE, ), - CHESTPLATE_FLAGS = list( + /obj/item/clothing/suit/mod = list( UNSEALED_CLOTHING = THICKMATERIAL, + UNSEALED_MESSAGE = CHESTPLATE_UNSEAL_MESSAGE, + SEALED_MESSAGE = CHESTPLATE_SEAL_MESSAGE, ), - GAUNTLETS_FLAGS = list( + /obj/item/clothing/gloves/mod = list( SEALED_CLOTHING = THICKMATERIAL, CAN_OVERSLOT = TRUE, ), - BOOTS_FLAGS = list( + /obj/item/clothing/shoes/mod = list( SEALED_CLOTHING = THICKMATERIAL, CAN_OVERSLOT = TRUE, ), @@ -486,55 +624,71 @@ /obj/item/storage/bag/chemistry, /obj/item/storage/bag/bio, ) - skins = list( + variants = list( "medical" = list( - HELMET_FLAGS = list( + /obj/item/clothing/head/mod = list( UNSEALED_LAYER = NECK_LAYER, UNSEALED_CLOTHING = SNUG_FIT, SEALED_CLOTHING = THICKMATERIAL|STOPSPRESSUREDAMAGE|BLOCK_GAS_SMOKE_EFFECT|HEADINTERNALS, UNSEALED_INVISIBILITY = HIDEFACIALHAIR, SEALED_INVISIBILITY = HIDEMASK|HIDEEARS|HIDEEYES|HIDEFACE|HIDEHAIR|HIDESNOUT, SEALED_COVER = HEADCOVERSMOUTH|HEADCOVERSEYES|PEPPERPROOF, + UNSEALED_MESSAGE = HELMET_UNSEAL_MESSAGE, + SEALED_MESSAGE = HELMET_SEAL_MESSAGE, ), - CHESTPLATE_FLAGS = list( + /obj/item/clothing/suit/mod = list( UNSEALED_CLOTHING = THICKMATERIAL, SEALED_CLOTHING = STOPSPRESSUREDAMAGE, SEALED_INVISIBILITY = HIDEJUMPSUIT, + UNSEALED_MESSAGE = CHESTPLATE_UNSEAL_MESSAGE, + SEALED_MESSAGE = CHESTPLATE_SEAL_MESSAGE, ), - GAUNTLETS_FLAGS = list( + /obj/item/clothing/gloves/mod = list( UNSEALED_CLOTHING = THICKMATERIAL, SEALED_CLOTHING = STOPSPRESSUREDAMAGE, CAN_OVERSLOT = TRUE, + UNSEALED_MESSAGE = GAUNTLET_UNSEAL_MESSAGE, + SEALED_MESSAGE = GAUNTLET_SEAL_MESSAGE, ), - BOOTS_FLAGS = list( + /obj/item/clothing/shoes/mod = list( UNSEALED_CLOTHING = THICKMATERIAL, SEALED_CLOTHING = STOPSPRESSUREDAMAGE, CAN_OVERSLOT = TRUE, + UNSEALED_MESSAGE = BOOT_UNSEAL_MESSAGE, + SEALED_MESSAGE = BOOT_SEAL_MESSAGE, ), ), "corpsman" = list( - HELMET_FLAGS = list( + /obj/item/clothing/head/mod = list( UNSEALED_LAYER = NECK_LAYER, UNSEALED_CLOTHING = SNUG_FIT, SEALED_CLOTHING = THICKMATERIAL|STOPSPRESSUREDAMAGE|BLOCK_GAS_SMOKE_EFFECT|HEADINTERNALS, UNSEALED_INVISIBILITY = HIDEFACIALHAIR, SEALED_INVISIBILITY = HIDEMASK|HIDEEARS|HIDEEYES|HIDEFACE|HIDEHAIR|HIDESNOUT, SEALED_COVER = HEADCOVERSMOUTH|HEADCOVERSEYES|PEPPERPROOF, + UNSEALED_MESSAGE = HELMET_UNSEAL_MESSAGE, + SEALED_MESSAGE = HELMET_SEAL_MESSAGE, ), - CHESTPLATE_FLAGS = list( + /obj/item/clothing/suit/mod = list( UNSEALED_CLOTHING = THICKMATERIAL, SEALED_CLOTHING = STOPSPRESSUREDAMAGE, SEALED_INVISIBILITY = HIDEJUMPSUIT, + UNSEALED_MESSAGE = CHESTPLATE_UNSEAL_MESSAGE, + SEALED_MESSAGE = CHESTPLATE_SEAL_MESSAGE, ), - GAUNTLETS_FLAGS = list( + /obj/item/clothing/gloves/mod = list( UNSEALED_CLOTHING = THICKMATERIAL, SEALED_CLOTHING = STOPSPRESSUREDAMAGE, CAN_OVERSLOT = TRUE, + UNSEALED_MESSAGE = GAUNTLET_UNSEAL_MESSAGE, + SEALED_MESSAGE = GAUNTLET_SEAL_MESSAGE, ), - BOOTS_FLAGS = list( + /obj/item/clothing/shoes/mod = list( UNSEALED_CLOTHING = THICKMATERIAL, SEALED_CLOTHING = STOPSPRESSUREDAMAGE, CAN_OVERSLOT = TRUE, + UNSEALED_MESSAGE = BOOT_UNSEAL_MESSAGE, + SEALED_MESSAGE = BOOT_SEAL_MESSAGE, ), ), ) @@ -583,30 +737,38 @@ /obj/item/storage/bag/bio, /obj/item/melee/baton/telescopic, ) - skins = list( + variants = list( "rescue" = list( - HELMET_FLAGS = list( + /obj/item/clothing/head/mod = list( UNSEALED_LAYER = NECK_LAYER, UNSEALED_CLOTHING = SNUG_FIT, SEALED_CLOTHING = THICKMATERIAL|STOPSPRESSUREDAMAGE|BLOCK_GAS_SMOKE_EFFECT|HEADINTERNALS, UNSEALED_INVISIBILITY = HIDEFACIALHAIR, SEALED_INVISIBILITY = HIDEMASK|HIDEEARS|HIDEEYES|HIDEFACE|HIDEHAIR|HIDESNOUT, SEALED_COVER = HEADCOVERSMOUTH|HEADCOVERSEYES|PEPPERPROOF, + UNSEALED_MESSAGE = HELMET_UNSEAL_MESSAGE, + SEALED_MESSAGE = HELMET_SEAL_MESSAGE, ), - CHESTPLATE_FLAGS = list( + /obj/item/clothing/suit/mod = list( UNSEALED_CLOTHING = THICKMATERIAL, SEALED_CLOTHING = STOPSPRESSUREDAMAGE, SEALED_INVISIBILITY = HIDEJUMPSUIT, + UNSEALED_MESSAGE = CHESTPLATE_UNSEAL_MESSAGE, + SEALED_MESSAGE = CHESTPLATE_SEAL_MESSAGE, ), - GAUNTLETS_FLAGS = list( + /obj/item/clothing/gloves/mod = list( UNSEALED_CLOTHING = THICKMATERIAL, SEALED_CLOTHING = STOPSPRESSUREDAMAGE, CAN_OVERSLOT = TRUE, + UNSEALED_MESSAGE = GAUNTLET_UNSEAL_MESSAGE, + SEALED_MESSAGE = GAUNTLET_SEAL_MESSAGE, ), - BOOTS_FLAGS = list( + /obj/item/clothing/shoes/mod = list( UNSEALED_CLOTHING = THICKMATERIAL, SEALED_CLOTHING = STOPSPRESSUREDAMAGE, CAN_OVERSLOT = TRUE, + UNSEALED_MESSAGE = BOOT_UNSEAL_MESSAGE, + SEALED_MESSAGE = BOOT_SEAL_MESSAGE, ), ), ) @@ -649,29 +811,36 @@ /obj/item/storage/bag/bio, /obj/item/melee/baton/telescopic, ) - skins = list( + variants = list( "research" = list( - HELMET_FLAGS = list( - UNSEALED_LAYER = null, + /obj/item/clothing/head/mod = list( UNSEALED_CLOTHING = SNUG_FIT|THICKMATERIAL, SEALED_CLOTHING = STOPSPRESSUREDAMAGE|BLOCK_GAS_SMOKE_EFFECT|HEADINTERNALS, UNSEALED_INVISIBILITY = HIDEFACIALHAIR|HIDEMASK|HIDEEARS|HIDEEYES|HIDEFACE|HIDEHAIR|HIDESNOUT, UNSEALED_COVER = HEADCOVERSMOUTH|HEADCOVERSEYES|PEPPERPROOF, + UNSEALED_MESSAGE = HELMET_UNSEAL_MESSAGE, + SEALED_MESSAGE = HELMET_SEAL_MESSAGE, ), - CHESTPLATE_FLAGS = list( + /obj/item/clothing/suit/mod = list( UNSEALED_CLOTHING = THICKMATERIAL, SEALED_CLOTHING = STOPSPRESSUREDAMAGE, SEALED_INVISIBILITY = HIDEJUMPSUIT, + UNSEALED_MESSAGE = CHESTPLATE_UNSEAL_MESSAGE, + SEALED_MESSAGE = CHESTPLATE_SEAL_MESSAGE, ), - GAUNTLETS_FLAGS = list( + /obj/item/clothing/gloves/mod = list( UNSEALED_CLOTHING = THICKMATERIAL, SEALED_CLOTHING = STOPSPRESSUREDAMAGE, CAN_OVERSLOT = TRUE, + UNSEALED_MESSAGE = GAUNTLET_UNSEAL_MESSAGE, + SEALED_MESSAGE = GAUNTLET_SEAL_MESSAGE, ), - BOOTS_FLAGS = list( + /obj/item/clothing/shoes/mod = list( UNSEALED_CLOTHING = THICKMATERIAL, SEALED_CLOTHING = STOPSPRESSUREDAMAGE, CAN_OVERSLOT = TRUE, + UNSEALED_MESSAGE = BOOT_UNSEAL_MESSAGE, + SEALED_MESSAGE = BOOT_SEAL_MESSAGE, ), ), ) @@ -707,31 +876,38 @@ /obj/item/assembly/flash, /obj/item/melee/baton, ) - skins = list( + variants = list( "security" = list( - HELMET_FLAGS = list( - UNSEALED_LAYER = null, + /obj/item/clothing/head/mod = list( UNSEALED_CLOTHING = SNUG_FIT|THICKMATERIAL, SEALED_CLOTHING = STOPSPRESSUREDAMAGE|HEADINTERNALS, UNSEALED_INVISIBILITY = HIDEFACIALHAIR|HIDEEARS|HIDEHAIR|HIDESNOUT, SEALED_INVISIBILITY = HIDEMASK|HIDEEYES|HIDEFACE, UNSEALED_COVER = HEADCOVERSMOUTH, SEALED_COVER = HEADCOVERSEYES|PEPPERPROOF, + UNSEALED_MESSAGE = HELMET_UNSEAL_MESSAGE, + SEALED_MESSAGE = HELMET_SEAL_MESSAGE, ), - CHESTPLATE_FLAGS = list( + /obj/item/clothing/suit/mod = list( UNSEALED_CLOTHING = THICKMATERIAL, SEALED_CLOTHING = STOPSPRESSUREDAMAGE, SEALED_INVISIBILITY = HIDEJUMPSUIT, + UNSEALED_MESSAGE = CHESTPLATE_UNSEAL_MESSAGE, + SEALED_MESSAGE = CHESTPLATE_SEAL_MESSAGE, ), - GAUNTLETS_FLAGS = list( + /obj/item/clothing/gloves/mod = list( UNSEALED_CLOTHING = THICKMATERIAL, SEALED_CLOTHING = STOPSPRESSUREDAMAGE, CAN_OVERSLOT = TRUE, + UNSEALED_MESSAGE = GAUNTLET_UNSEAL_MESSAGE, + SEALED_MESSAGE = GAUNTLET_SEAL_MESSAGE, ), - BOOTS_FLAGS = list( + /obj/item/clothing/shoes/mod = list( UNSEALED_CLOTHING = THICKMATERIAL, SEALED_CLOTHING = STOPSPRESSUREDAMAGE, CAN_OVERSLOT = TRUE, + UNSEALED_MESSAGE = BOOT_UNSEAL_MESSAGE, + SEALED_MESSAGE = BOOT_SEAL_MESSAGE, ), ), ) @@ -769,29 +945,36 @@ /obj/item/assembly/flash, /obj/item/melee/baton, ) - skins = list( + variants = list( "safeguard" = list( - HELMET_FLAGS = list( - UNSEALED_LAYER = null, + /obj/item/clothing/head/mod = list( UNSEALED_CLOTHING = SNUG_FIT|THICKMATERIAL, SEALED_CLOTHING = STOPSPRESSUREDAMAGE|HEADINTERNALS, UNSEALED_INVISIBILITY = HIDEFACIALHAIR|HIDEMASK|HIDEEARS|HIDEEYES|HIDEFACE|HIDEHAIR|HIDESNOUT, UNSEALED_COVER = HEADCOVERSMOUTH|HEADCOVERSEYES|PEPPERPROOF, + UNSEALED_MESSAGE = HELMET_UNSEAL_MESSAGE, + SEALED_MESSAGE = HELMET_SEAL_MESSAGE, ), - CHESTPLATE_FLAGS = list( + /obj/item/clothing/suit/mod = list( UNSEALED_CLOTHING = THICKMATERIAL, SEALED_CLOTHING = STOPSPRESSUREDAMAGE, SEALED_INVISIBILITY = HIDEJUMPSUIT, + UNSEALED_MESSAGE = CHESTPLATE_UNSEAL_MESSAGE, + SEALED_MESSAGE = CHESTPLATE_SEAL_MESSAGE, ), - GAUNTLETS_FLAGS = list( + /obj/item/clothing/gloves/mod = list( UNSEALED_CLOTHING = THICKMATERIAL, SEALED_CLOTHING = STOPSPRESSUREDAMAGE, CAN_OVERSLOT = TRUE, + UNSEALED_MESSAGE = GAUNTLET_UNSEAL_MESSAGE, + SEALED_MESSAGE = GAUNTLET_SEAL_MESSAGE, ), - BOOTS_FLAGS = list( + /obj/item/clothing/shoes/mod = list( UNSEALED_CLOTHING = THICKMATERIAL, SEALED_CLOTHING = STOPSPRESSUREDAMAGE, CAN_OVERSLOT = TRUE, + UNSEALED_MESSAGE = BOOT_UNSEAL_MESSAGE, + SEALED_MESSAGE = BOOT_SEAL_MESSAGE, ), ), ) @@ -833,30 +1016,38 @@ /obj/item/assembly/flash, /obj/item/melee/baton, ) - skins = list( + variants = list( "magnate" = list( - HELMET_FLAGS = list( + /obj/item/clothing/head/mod = list( UNSEALED_LAYER = NECK_LAYER, UNSEALED_CLOTHING = SNUG_FIT, SEALED_CLOTHING = THICKMATERIAL|STOPSPRESSUREDAMAGE|HEADINTERNALS, UNSEALED_INVISIBILITY = HIDEFACIALHAIR, SEALED_INVISIBILITY = HIDEMASK|HIDEEARS|HIDEEYES|HIDEFACE|HIDEHAIR|HIDESNOUT, SEALED_COVER = HEADCOVERSMOUTH|HEADCOVERSEYES|PEPPERPROOF, + UNSEALED_MESSAGE = HELMET_UNSEAL_MESSAGE, + SEALED_MESSAGE = HELMET_SEAL_MESSAGE, ), - CHESTPLATE_FLAGS = list( + /obj/item/clothing/suit/mod = list( UNSEALED_CLOTHING = THICKMATERIAL, SEALED_CLOTHING = STOPSPRESSUREDAMAGE, SEALED_INVISIBILITY = HIDEJUMPSUIT, + UNSEALED_MESSAGE = CHESTPLATE_UNSEAL_MESSAGE, + SEALED_MESSAGE = CHESTPLATE_SEAL_MESSAGE, ), - GAUNTLETS_FLAGS = list( + /obj/item/clothing/gloves/mod = list( UNSEALED_CLOTHING = THICKMATERIAL, SEALED_CLOTHING = STOPSPRESSUREDAMAGE, CAN_OVERSLOT = TRUE, + UNSEALED_MESSAGE = GAUNTLET_UNSEAL_MESSAGE, + SEALED_MESSAGE = GAUNTLET_SEAL_MESSAGE, ), - BOOTS_FLAGS = list( + /obj/item/clothing/shoes/mod = list( UNSEALED_CLOTHING = THICKMATERIAL, SEALED_CLOTHING = STOPSPRESSUREDAMAGE, CAN_OVERSLOT = TRUE, + UNSEALED_MESSAGE = BOOT_UNSEAL_MESSAGE, + SEALED_MESSAGE = BOOT_SEAL_MESSAGE, ), ), ) @@ -893,30 +1084,38 @@ /obj/item/instrument, /obj/item/toy/balloon_animal, ) - skins = list( + variants = list( "cosmohonk" = list( - HELMET_FLAGS = list( + /obj/item/clothing/head/mod = list( UNSEALED_LAYER = NECK_LAYER, UNSEALED_CLOTHING = SNUG_FIT|THICKMATERIAL, SEALED_CLOTHING = STOPSPRESSUREDAMAGE|HEADINTERNALS, UNSEALED_INVISIBILITY = HIDEEARS|HIDEHAIR, SEALED_INVISIBILITY = HIDEFACIALHAIR|HIDEMASK|HIDEEYES|HIDEFACE|HIDESNOUT, SEALED_COVER = HEADCOVERSMOUTH|HEADCOVERSEYES|PEPPERPROOF, + UNSEALED_MESSAGE = HELMET_UNSEAL_MESSAGE, + SEALED_MESSAGE = HELMET_SEAL_MESSAGE, ), - CHESTPLATE_FLAGS = list( + /obj/item/clothing/suit/mod = list( UNSEALED_CLOTHING = THICKMATERIAL, SEALED_CLOTHING = STOPSPRESSUREDAMAGE, SEALED_INVISIBILITY = HIDEJUMPSUIT, + UNSEALED_MESSAGE = CHESTPLATE_UNSEAL_MESSAGE, + SEALED_MESSAGE = CHESTPLATE_SEAL_MESSAGE, ), - GAUNTLETS_FLAGS = list( + /obj/item/clothing/gloves/mod = list( UNSEALED_CLOTHING = THICKMATERIAL, SEALED_CLOTHING = STOPSPRESSUREDAMAGE, CAN_OVERSLOT = TRUE, + UNSEALED_MESSAGE = GAUNTLET_UNSEAL_MESSAGE, + SEALED_MESSAGE = GAUNTLET_SEAL_MESSAGE, ), - BOOTS_FLAGS = list( + /obj/item/clothing/shoes/mod = list( UNSEALED_CLOTHING = THICKMATERIAL, SEALED_CLOTHING = STOPSPRESSUREDAMAGE, CAN_OVERSLOT = TRUE, + UNSEALED_MESSAGE = BOOT_UNSEAL_MESSAGE, + SEALED_MESSAGE = BOOT_SEAL_MESSAGE, ), ), ) @@ -960,55 +1159,71 @@ /obj/item/melee/energy/sword, /obj/item/shield/energy, ) - skins = list( + variants = list( "syndicate" = list( - HELMET_FLAGS = list( + /obj/item/clothing/head/mod = list( UNSEALED_LAYER = NECK_LAYER, UNSEALED_CLOTHING = SNUG_FIT, SEALED_CLOTHING = THICKMATERIAL|STOPSPRESSUREDAMAGE|HEADINTERNALS, UNSEALED_INVISIBILITY = HIDEFACIALHAIR, SEALED_INVISIBILITY = HIDEMASK|HIDEEARS|HIDEEYES|HIDEFACE|HIDEHAIR|HIDESNOUT, SEALED_COVER = HEADCOVERSMOUTH|HEADCOVERSEYES|PEPPERPROOF, + UNSEALED_MESSAGE = HELMET_UNSEAL_MESSAGE, + SEALED_MESSAGE = HELMET_SEAL_MESSAGE, ), - CHESTPLATE_FLAGS = list( + /obj/item/clothing/suit/mod = list( UNSEALED_CLOTHING = THICKMATERIAL, SEALED_CLOTHING = STOPSPRESSUREDAMAGE, SEALED_INVISIBILITY = HIDEJUMPSUIT, + UNSEALED_MESSAGE = CHESTPLATE_UNSEAL_MESSAGE, + SEALED_MESSAGE = CHESTPLATE_SEAL_MESSAGE, ), - GAUNTLETS_FLAGS = list( + /obj/item/clothing/gloves/mod = list( UNSEALED_CLOTHING = THICKMATERIAL, SEALED_CLOTHING = STOPSPRESSUREDAMAGE, CAN_OVERSLOT = TRUE, + UNSEALED_MESSAGE = GAUNTLET_UNSEAL_MESSAGE, + SEALED_MESSAGE = GAUNTLET_SEAL_MESSAGE, ), - BOOTS_FLAGS = list( + /obj/item/clothing/shoes/mod = list( UNSEALED_CLOTHING = THICKMATERIAL, SEALED_CLOTHING = STOPSPRESSUREDAMAGE, CAN_OVERSLOT = TRUE, + UNSEALED_MESSAGE = BOOT_UNSEAL_MESSAGE, + SEALED_MESSAGE = BOOT_SEAL_MESSAGE, ), ), "honkerative" = list( - HELMET_FLAGS = list( + /obj/item/clothing/head/mod = list( UNSEALED_LAYER = NECK_LAYER, UNSEALED_CLOTHING = SNUG_FIT, SEALED_CLOTHING = THICKMATERIAL|STOPSPRESSUREDAMAGE|HEADINTERNALS, UNSEALED_INVISIBILITY = HIDEFACIALHAIR, SEALED_INVISIBILITY = HIDEMASK|HIDEEARS|HIDEEYES|HIDEFACE|HIDEHAIR|HIDESNOUT, SEALED_COVER = HEADCOVERSMOUTH|HEADCOVERSEYES|PEPPERPROOF, + UNSEALED_MESSAGE = HELMET_UNSEAL_MESSAGE, + SEALED_MESSAGE = HELMET_SEAL_MESSAGE, ), - CHESTPLATE_FLAGS = list( + /obj/item/clothing/suit/mod = list( UNSEALED_CLOTHING = THICKMATERIAL, SEALED_CLOTHING = STOPSPRESSUREDAMAGE, SEALED_INVISIBILITY = HIDEJUMPSUIT, + UNSEALED_MESSAGE = CHESTPLATE_UNSEAL_MESSAGE, + SEALED_MESSAGE = CHESTPLATE_SEAL_MESSAGE, ), - GAUNTLETS_FLAGS = list( + /obj/item/clothing/gloves/mod = list( UNSEALED_CLOTHING = THICKMATERIAL, SEALED_CLOTHING = STOPSPRESSUREDAMAGE, CAN_OVERSLOT = TRUE, + UNSEALED_MESSAGE = GAUNTLET_UNSEAL_MESSAGE, + SEALED_MESSAGE = GAUNTLET_SEAL_MESSAGE, ), - BOOTS_FLAGS = list( + /obj/item/clothing/shoes/mod = list( UNSEALED_CLOTHING = THICKMATERIAL, SEALED_CLOTHING = STOPSPRESSUREDAMAGE, CAN_OVERSLOT = TRUE, + UNSEALED_MESSAGE = BOOT_UNSEAL_MESSAGE, + SEALED_MESSAGE = BOOT_SEAL_MESSAGE, ), ), ) @@ -1051,30 +1266,37 @@ /obj/item/melee/energy/sword, /obj/item/shield/energy, ) - skins = list( + variants = list( "elite" = list( - HELMET_FLAGS = list( - UNSEALED_LAYER = null, + /obj/item/clothing/head/mod = list( UNSEALED_CLOTHING = SNUG_FIT, SEALED_CLOTHING = THICKMATERIAL|STOPSPRESSUREDAMAGE|BLOCK_GAS_SMOKE_EFFECT|HEADINTERNALS, UNSEALED_INVISIBILITY = HIDEFACIALHAIR, SEALED_INVISIBILITY = HIDEMASK|HIDEEARS|HIDEEYES|HIDEFACE|HIDEHAIR|HIDESNOUT, SEALED_COVER = HEADCOVERSMOUTH|HEADCOVERSEYES|PEPPERPROOF, + UNSEALED_MESSAGE = HELMET_UNSEAL_MESSAGE, + SEALED_MESSAGE = HELMET_SEAL_MESSAGE, ), - CHESTPLATE_FLAGS = list( + /obj/item/clothing/suit/mod = list( UNSEALED_CLOTHING = THICKMATERIAL, SEALED_CLOTHING = STOPSPRESSUREDAMAGE, SEALED_INVISIBILITY = HIDEJUMPSUIT, + UNSEALED_MESSAGE = CHESTPLATE_UNSEAL_MESSAGE, + SEALED_MESSAGE = CHESTPLATE_SEAL_MESSAGE, ), - GAUNTLETS_FLAGS = list( + /obj/item/clothing/gloves/mod = list( UNSEALED_CLOTHING = THICKMATERIAL, SEALED_CLOTHING = STOPSPRESSUREDAMAGE, CAN_OVERSLOT = TRUE, + UNSEALED_MESSAGE = GAUNTLET_UNSEAL_MESSAGE, + SEALED_MESSAGE = GAUNTLET_SEAL_MESSAGE, ), - BOOTS_FLAGS = list( + /obj/item/clothing/shoes/mod = list( UNSEALED_CLOTHING = THICKMATERIAL, SEALED_CLOTHING = STOPSPRESSUREDAMAGE, CAN_OVERSLOT = TRUE, + UNSEALED_MESSAGE = BOOT_UNSEAL_MESSAGE, + SEALED_MESSAGE = BOOT_SEAL_MESSAGE, ), ), ) @@ -1118,26 +1340,29 @@ /obj/item/melee/energy/sword, /obj/item/shield/energy, ) - skins = list( + variants = list( "infiltrator" = list( - HELMET_FLAGS = list( - UNSEALED_LAYER = null, + /obj/item/clothing/head/mod = list( UNSEALED_CLOTHING = SNUG_FIT|THICKMATERIAL, UNSEALED_INVISIBILITY = HIDEEARS|HIDEHAIR, SEALED_INVISIBILITY = HIDEFACIALHAIR|HIDEMASK|HIDEEYES|HIDEFACE|HIDESNOUT, SEALED_COVER = HEADCOVERSMOUTH|HEADCOVERSEYES|PEPPERPROOF, CAN_OVERSLOT = TRUE, + UNSEALED_MESSAGE = HELMET_UNSEAL_MESSAGE, + SEALED_MESSAGE = HELMET_SEAL_MESSAGE, ), - CHESTPLATE_FLAGS = list( + /obj/item/clothing/suit/mod = list( UNSEALED_CLOTHING = THICKMATERIAL, SEALED_INVISIBILITY = HIDEJUMPSUIT, CAN_OVERSLOT = TRUE, + UNSEALED_MESSAGE = CHESTPLATE_UNSEAL_MESSAGE, + SEALED_MESSAGE = CHESTPLATE_SEAL_MESSAGE, ), - GAUNTLETS_FLAGS = list( + /obj/item/clothing/gloves/mod = list( SEALED_CLOTHING = THICKMATERIAL, CAN_OVERSLOT = TRUE, ), - BOOTS_FLAGS = list( + /obj/item/clothing/shoes/mod = list( SEALED_CLOTHING = THICKMATERIAL, CAN_OVERSLOT = TRUE, ), @@ -1173,7 +1398,7 @@ charge_drain = DEFAULT_CHARGE_DRAIN * 2 slowdown_inactive = 0.0 slowdown_active = -0.5 - inbuilt_modules = list(/obj/item/mod/module/quick_carry/advanced, /obj/item/mod/module/organ_thrower) + inbuilt_modules = list(/obj/item/mod/module/quick_carry/advanced) allowed_suit_storage = list( /obj/item/assembly/flash, /obj/item/healthanalyzer, @@ -1195,30 +1420,38 @@ /obj/item/storage/bag/chemistry, /obj/item/storage/pill_bottle, ) - skins = list( + variants = list( "interdyne" = list( - HELMET_FLAGS = list( + /obj/item/clothing/head/mod = list( UNSEALED_LAYER = NECK_LAYER, UNSEALED_CLOTHING = SNUG_FIT, SEALED_CLOTHING = THICKMATERIAL|STOPSPRESSUREDAMAGE|BLOCK_GAS_SMOKE_EFFECT|HEADINTERNALS, UNSEALED_INVISIBILITY = HIDEFACIALHAIR, SEALED_INVISIBILITY = HIDEMASK|HIDEEARS|HIDEEYES|HIDEFACE|HIDEHAIR|HIDESNOUT, SEALED_COVER = HEADCOVERSMOUTH|HEADCOVERSEYES|PEPPERPROOF, + UNSEALED_MESSAGE = HELMET_UNSEAL_MESSAGE, + SEALED_MESSAGE = HELMET_SEAL_MESSAGE, ), - CHESTPLATE_FLAGS = list( + /obj/item/clothing/suit/mod = list( UNSEALED_CLOTHING = THICKMATERIAL, SEALED_CLOTHING = STOPSPRESSUREDAMAGE, SEALED_INVISIBILITY = HIDEJUMPSUIT, + UNSEALED_MESSAGE = CHESTPLATE_UNSEAL_MESSAGE, + SEALED_MESSAGE = CHESTPLATE_SEAL_MESSAGE, ), - GAUNTLETS_FLAGS = list( + /obj/item/clothing/gloves/mod = list( UNSEALED_CLOTHING = THICKMATERIAL, SEALED_CLOTHING = STOPSPRESSUREDAMAGE, CAN_OVERSLOT = TRUE, + UNSEALED_MESSAGE = GAUNTLET_UNSEAL_MESSAGE, + SEALED_MESSAGE = GAUNTLET_SEAL_MESSAGE, ), - BOOTS_FLAGS = list( + /obj/item/clothing/shoes/mod = list( UNSEALED_CLOTHING = THICKMATERIAL, SEALED_CLOTHING = STOPSPRESSUREDAMAGE, CAN_OVERSLOT = TRUE, + UNSEALED_MESSAGE = BOOT_UNSEAL_MESSAGE, + SEALED_MESSAGE = BOOT_SEAL_MESSAGE, ), ), ) @@ -1259,29 +1492,34 @@ /obj/item/highfrequencyblade/wizard, /obj/item/gun/magic, ) - skins = list( + variants = list( "enchanted" = list( - HELMET_FLAGS = list( - UNSEALED_LAYER = null, + /obj/item/clothing/head/mod = list( UNSEALED_CLOTHING = SNUG_FIT|THICKMATERIAL|CASTING_CLOTHES, SEALED_CLOTHING = STOPSPRESSUREDAMAGE|HEADINTERNALS, UNSEALED_INVISIBILITY = HIDEFACIALHAIR|HIDEMASK|HIDEEARS|HIDEEYES|HIDEFACE|HIDEHAIR|HIDESNOUT, UNSEALED_COVER = HEADCOVERSMOUTH|HEADCOVERSEYES|PEPPERPROOF, + UNSEALED_MESSAGE = HELMET_UNSEAL_MESSAGE, + SEALED_MESSAGE = HELMET_SEAL_MESSAGE, ), - CHESTPLATE_FLAGS = list( + /obj/item/clothing/suit/mod = list( UNSEALED_CLOTHING = THICKMATERIAL|CASTING_CLOTHES, SEALED_CLOTHING = STOPSPRESSUREDAMAGE, SEALED_INVISIBILITY = HIDEJUMPSUIT, ), - GAUNTLETS_FLAGS = list( + /obj/item/clothing/gloves/mod = list( UNSEALED_CLOTHING = THICKMATERIAL, SEALED_CLOTHING = STOPSPRESSUREDAMAGE, CAN_OVERSLOT = TRUE, + UNSEALED_MESSAGE = GAUNTLET_UNSEAL_MESSAGE, + SEALED_MESSAGE = GAUNTLET_SEAL_MESSAGE, ), - BOOTS_FLAGS = list( + /obj/item/clothing/shoes/mod = list( UNSEALED_CLOTHING = THICKMATERIAL, SEALED_CLOTHING = STOPSPRESSUREDAMAGE, CAN_OVERSLOT = TRUE, + UNSEALED_MESSAGE = BOOT_UNSEAL_MESSAGE, + SEALED_MESSAGE = BOOT_SEAL_MESSAGE, ), ), ) @@ -1320,30 +1558,37 @@ /obj/item/melee/baton, /obj/item/restraints/handcuffs, ) - skins = list( + variants = list( "ninja" = list( - HELMET_FLAGS = list( - UNSEALED_LAYER = null, + /obj/item/clothing/head/mod = list( UNSEALED_CLOTHING = SNUG_FIT|THICKMATERIAL, SEALED_CLOTHING = STOPSPRESSUREDAMAGE|HEADINTERNALS, UNSEALED_INVISIBILITY = HIDEEARS|HIDEHAIR, SEALED_INVISIBILITY = HIDEFACIALHAIR|HIDEMASK|HIDEEYES|HIDEFACE|HIDESNOUT, SEALED_COVER = HEADCOVERSMOUTH|HEADCOVERSEYES|PEPPERPROOF, + UNSEALED_MESSAGE = HELMET_UNSEAL_MESSAGE, + SEALED_MESSAGE = HELMET_SEAL_MESSAGE, ), - CHESTPLATE_FLAGS = list( + /obj/item/clothing/suit/mod = list( UNSEALED_CLOTHING = THICKMATERIAL, SEALED_CLOTHING = STOPSPRESSUREDAMAGE, SEALED_INVISIBILITY = HIDEJUMPSUIT, + UNSEALED_MESSAGE = CHESTPLATE_UNSEAL_MESSAGE, + SEALED_MESSAGE = CHESTPLATE_SEAL_MESSAGE, ), - GAUNTLETS_FLAGS = list( + /obj/item/clothing/gloves/mod = list( UNSEALED_CLOTHING = THICKMATERIAL, SEALED_CLOTHING = STOPSPRESSUREDAMAGE, CAN_OVERSLOT = TRUE, + UNSEALED_MESSAGE = GAUNTLET_UNSEAL_MESSAGE, + SEALED_MESSAGE = GAUNTLET_SEAL_MESSAGE, ), - BOOTS_FLAGS = list( + /obj/item/clothing/shoes/mod = list( UNSEALED_CLOTHING = THICKMATERIAL, SEALED_CLOTHING = STOPSPRESSUREDAMAGE, CAN_OVERSLOT = TRUE, + UNSEALED_MESSAGE = BOOT_UNSEAL_MESSAGE, + SEALED_MESSAGE = BOOT_SEAL_MESSAGE, ), ), ) @@ -1385,29 +1630,36 @@ /obj/item/pipe_dispenser, /obj/item/construction/rcd, ) - skins = list( + variants = list( "prototype" = list( - HELMET_FLAGS = list( - UNSEALED_LAYER = null, + /obj/item/clothing/head/mod = list( UNSEALED_CLOTHING = SNUG_FIT|THICKMATERIAL, SEALED_CLOTHING = STOPSPRESSUREDAMAGE|HEADINTERNALS, UNSEALED_INVISIBILITY = HIDEFACIALHAIR|HIDEMASK|HIDEEARS|HIDEEYES|HIDEFACE|HIDEHAIR|HIDESNOUT, UNSEALED_COVER = HEADCOVERSMOUTH|HEADCOVERSEYES|PEPPERPROOF, + UNSEALED_MESSAGE = HELMET_UNSEAL_MESSAGE, + SEALED_MESSAGE = HELMET_SEAL_MESSAGE, ), - CHESTPLATE_FLAGS = list( + /obj/item/clothing/suit/mod = list( UNSEALED_CLOTHING = THICKMATERIAL, SEALED_CLOTHING = STOPSPRESSUREDAMAGE, SEALED_INVISIBILITY = HIDEJUMPSUIT, + UNSEALED_MESSAGE = CHESTPLATE_UNSEAL_MESSAGE, + SEALED_MESSAGE = CHESTPLATE_SEAL_MESSAGE, ), - GAUNTLETS_FLAGS = list( + /obj/item/clothing/gloves/mod = list( UNSEALED_CLOTHING = THICKMATERIAL, SEALED_CLOTHING = STOPSPRESSUREDAMAGE, CAN_OVERSLOT = TRUE, + UNSEALED_MESSAGE = GAUNTLET_UNSEAL_MESSAGE, + SEALED_MESSAGE = GAUNTLET_SEAL_MESSAGE, ), - BOOTS_FLAGS = list( + /obj/item/clothing/shoes/mod = list( UNSEALED_CLOTHING = THICKMATERIAL, SEALED_CLOTHING = STOPSPRESSUREDAMAGE, CAN_OVERSLOT = TRUE, + UNSEALED_MESSAGE = BOOT_UNSEAL_MESSAGE, + SEALED_MESSAGE = BOOT_SEAL_MESSAGE, ), ), ) @@ -1423,6 +1675,73 @@ acid = 75 wound = 5 +/datum/mod_theme/glitch + name = "glitch" + desc = "A modsuit outfitted for elite Cyber Authority units to track, capture, and eliminate organic intruders." + extended_desc = "The Cyber Authority function as a digital police force, patrolling the digital realm and enforcing the law. Cyber Tac units are \ + the elite of the elite, outfitted with lethal weaponry and fast mobility specially designed to quell organic uprisings." + default_skin = "glitch" + armor_type = /datum/armor/mod_theme_glitch + resistance_flags = FIRE_PROOF|ACID_PROOF + atom_flags = PREVENT_CONTENTS_EXPLOSION_1 + max_heat_protection_temperature = FIRE_IMMUNITY_MAX_TEMP_PROTECT + complexity_max = DEFAULT_MAX_COMPLEXITY + 3 + siemens_coefficient = 0 + slowdown_inactive = 1 + slowdown_active = 0.5 + ui_theme = "terminal" + inbuilt_modules = list(/obj/item/mod/module/armor_booster) + allowed_suit_storage = list( + /obj/item/ammo_box, + /obj/item/ammo_casing, + /obj/item/restraints/handcuffs, + /obj/item/assembly/flash, + ) + variants = list( + "glitch" = list( + /obj/item/clothing/head/mod = list( + UNSEALED_CLOTHING = SNUG_FIT, + SEALED_CLOTHING = THICKMATERIAL|STOPSPRESSUREDAMAGE|BLOCK_GAS_SMOKE_EFFECT|HEADINTERNALS, + UNSEALED_INVISIBILITY = HIDEFACIALHAIR, + SEALED_INVISIBILITY = HIDEMASK|HIDEEARS|HIDEEYES|HIDEFACE|HIDEHAIR|HIDESNOUT, + SEALED_COVER = HEADCOVERSMOUTH|HEADCOVERSEYES|PEPPERPROOF, + UNSEALED_MESSAGE = HELMET_UNSEAL_MESSAGE, + SEALED_MESSAGE = HELMET_SEAL_MESSAGE, + ), + /obj/item/clothing/suit/mod = list( + UNSEALED_CLOTHING = THICKMATERIAL, + SEALED_CLOTHING = STOPSPRESSUREDAMAGE, + SEALED_INVISIBILITY = HIDEJUMPSUIT, + UNSEALED_MESSAGE = CHESTPLATE_UNSEAL_MESSAGE, + SEALED_MESSAGE = CHESTPLATE_SEAL_MESSAGE, + ), + /obj/item/clothing/gloves/mod = list( + UNSEALED_CLOTHING = THICKMATERIAL, + SEALED_CLOTHING = STOPSPRESSUREDAMAGE, + CAN_OVERSLOT = TRUE, + UNSEALED_MESSAGE = GAUNTLET_UNSEAL_MESSAGE, + SEALED_MESSAGE = GAUNTLET_SEAL_MESSAGE, + ), + /obj/item/clothing/shoes/mod = list( + UNSEALED_CLOTHING = THICKMATERIAL, + SEALED_CLOTHING = STOPSPRESSUREDAMAGE, + CAN_OVERSLOT = TRUE, + UNSEALED_MESSAGE = BOOT_UNSEAL_MESSAGE, + SEALED_MESSAGE = BOOT_SEAL_MESSAGE, + ), + ), + ) + +/datum/armor/mod_theme_glitch + melee = 15 + bullet = 20 + laser = 35 + bomb = 65 + bio = 100 + fire = 100 + acid = 100 + wound = 100 + /datum/mod_theme/responsory name = "responsory" desc = "A high-speed rescue suit by Nanotrasen, intended for its emergency response teams." @@ -1444,54 +1763,69 @@ /obj/item/assembly/flash, /obj/item/melee/baton, ) - skins = list( + variants = list( "responsory" = list( - HELMET_FLAGS = list( + /obj/item/clothing/head/mod = list( UNSEALED_LAYER = NECK_LAYER, UNSEALED_CLOTHING = SNUG_FIT, SEALED_CLOTHING = THICKMATERIAL|STOPSPRESSUREDAMAGE|BLOCK_GAS_SMOKE_EFFECT|HEADINTERNALS, UNSEALED_INVISIBILITY = HIDEFACIALHAIR, SEALED_INVISIBILITY = HIDEMASK|HIDEEARS|HIDEEYES|HIDEFACE|HIDEHAIR|HIDESNOUT, SEALED_COVER = HEADCOVERSMOUTH|HEADCOVERSEYES|PEPPERPROOF, + UNSEALED_MESSAGE = HELMET_UNSEAL_MESSAGE, + SEALED_MESSAGE = HELMET_SEAL_MESSAGE, ), - CHESTPLATE_FLAGS = list( + /obj/item/clothing/suit/mod = list( UNSEALED_CLOTHING = THICKMATERIAL, SEALED_CLOTHING = STOPSPRESSUREDAMAGE, SEALED_INVISIBILITY = HIDEJUMPSUIT, + UNSEALED_MESSAGE = CHESTPLATE_UNSEAL_MESSAGE, + SEALED_MESSAGE = CHESTPLATE_SEAL_MESSAGE, ), - GAUNTLETS_FLAGS = list( + /obj/item/clothing/gloves/mod = list( UNSEALED_CLOTHING = THICKMATERIAL, SEALED_CLOTHING = STOPSPRESSUREDAMAGE, CAN_OVERSLOT = TRUE, + UNSEALED_MESSAGE = GAUNTLET_UNSEAL_MESSAGE, + SEALED_MESSAGE = GAUNTLET_SEAL_MESSAGE, ), - BOOTS_FLAGS = list( + /obj/item/clothing/shoes/mod = list( UNSEALED_CLOTHING = THICKMATERIAL, SEALED_CLOTHING = STOPSPRESSUREDAMAGE, CAN_OVERSLOT = TRUE, + UNSEALED_MESSAGE = BOOT_UNSEAL_MESSAGE, + SEALED_MESSAGE = BOOT_SEAL_MESSAGE, ), ), "inquisitory" = list( - HELMET_FLAGS = list( - UNSEALED_LAYER = null, + /obj/item/clothing/head/mod = list( UNSEALED_CLOTHING = SNUG_FIT|THICKMATERIAL, SEALED_CLOTHING = STOPSPRESSUREDAMAGE|BLOCK_GAS_SMOKE_EFFECT|HEADINTERNALS, UNSEALED_INVISIBILITY = HIDEFACIALHAIR|HIDEMASK|HIDEEARS|HIDEEYES|HIDEFACE|HIDEHAIR|HIDESNOUT, UNSEALED_COVER = HEADCOVERSMOUTH|HEADCOVERSEYES|PEPPERPROOF, + UNSEALED_MESSAGE = HELMET_UNSEAL_MESSAGE, + SEALED_MESSAGE = HELMET_SEAL_MESSAGE, ), - CHESTPLATE_FLAGS = list( + /obj/item/clothing/suit/mod = list( UNSEALED_CLOTHING = THICKMATERIAL, SEALED_CLOTHING = STOPSPRESSUREDAMAGE, SEALED_INVISIBILITY = HIDEJUMPSUIT, + UNSEALED_MESSAGE = CHESTPLATE_UNSEAL_MESSAGE, + SEALED_MESSAGE = CHESTPLATE_SEAL_MESSAGE, ), - GAUNTLETS_FLAGS = list( + /obj/item/clothing/gloves/mod = list( UNSEALED_CLOTHING = THICKMATERIAL, SEALED_CLOTHING = STOPSPRESSUREDAMAGE, CAN_OVERSLOT = TRUE, + UNSEALED_MESSAGE = GAUNTLET_UNSEAL_MESSAGE, + SEALED_MESSAGE = GAUNTLET_SEAL_MESSAGE, ), - BOOTS_FLAGS = list( + /obj/item/clothing/shoes/mod = list( UNSEALED_CLOTHING = THICKMATERIAL, SEALED_CLOTHING = STOPSPRESSUREDAMAGE, CAN_OVERSLOT = TRUE, + UNSEALED_MESSAGE = BOOT_UNSEAL_MESSAGE, + SEALED_MESSAGE = BOOT_SEAL_MESSAGE, ), ), ) @@ -1543,30 +1877,37 @@ /obj/item/melee/energy/sword, /obj/item/shield/energy, ) - skins = list( + variants = list( "apocryphal" = list( - HELMET_FLAGS = list( - UNSEALED_LAYER = null, + /obj/item/clothing/head/mod = list( UNSEALED_CLOTHING = SNUG_FIT|THICKMATERIAL, SEALED_CLOTHING = STOPSPRESSUREDAMAGE|HEADINTERNALS, UNSEALED_INVISIBILITY = HIDEEARS|HIDEHAIR, SEALED_INVISIBILITY = HIDEFACIALHAIR|HIDEMASK|HIDEEYES|HIDEFACE|HIDESNOUT, SEALED_COVER = HEADCOVERSMOUTH|HEADCOVERSEYES|PEPPERPROOF, + UNSEALED_MESSAGE = HELMET_UNSEAL_MESSAGE, + SEALED_MESSAGE = HELMET_SEAL_MESSAGE, ), - CHESTPLATE_FLAGS = list( + /obj/item/clothing/suit/mod = list( UNSEALED_CLOTHING = THICKMATERIAL, SEALED_CLOTHING = STOPSPRESSUREDAMAGE, SEALED_INVISIBILITY = HIDEJUMPSUIT, + UNSEALED_MESSAGE = CHESTPLATE_UNSEAL_MESSAGE, + SEALED_MESSAGE = CHESTPLATE_SEAL_MESSAGE, ), - GAUNTLETS_FLAGS = list( + /obj/item/clothing/gloves/mod = list( UNSEALED_CLOTHING = THICKMATERIAL, SEALED_CLOTHING = STOPSPRESSUREDAMAGE, CAN_OVERSLOT = TRUE, + UNSEALED_MESSAGE = GAUNTLET_UNSEAL_MESSAGE, + SEALED_MESSAGE = GAUNTLET_SEAL_MESSAGE, ), - BOOTS_FLAGS = list( + /obj/item/clothing/shoes/mod = list( UNSEALED_CLOTHING = THICKMATERIAL, SEALED_CLOTHING = STOPSPRESSUREDAMAGE, CAN_OVERSLOT = TRUE, + UNSEALED_MESSAGE = BOOT_UNSEAL_MESSAGE, + SEALED_MESSAGE = BOOT_SEAL_MESSAGE, ), ), ) @@ -1605,30 +1946,37 @@ /obj/item/assembly/flash, /obj/item/melee/baton, ) - skins = list( + variants = list( "corporate" = list( - HELMET_FLAGS = list( - UNSEALED_LAYER = null, + /obj/item/clothing/head/mod = list( UNSEALED_CLOTHING = SNUG_FIT|THICKMATERIAL, SEALED_CLOTHING = STOPSPRESSUREDAMAGE|HEADINTERNALS, UNSEALED_INVISIBILITY = HIDEFACIALHAIR|HIDEEARS|HIDEHAIR|HIDESNOUT, SEALED_INVISIBILITY = HIDEMASK|HIDEEYES|HIDEFACE, SEALED_COVER = HEADCOVERSMOUTH|HEADCOVERSEYES|PEPPERPROOF, + UNSEALED_MESSAGE = HELMET_UNSEAL_MESSAGE, + SEALED_MESSAGE = HELMET_SEAL_MESSAGE, ), - CHESTPLATE_FLAGS = list( + /obj/item/clothing/suit/mod = list( UNSEALED_CLOTHING = THICKMATERIAL, SEALED_CLOTHING = STOPSPRESSUREDAMAGE, SEALED_INVISIBILITY = HIDEJUMPSUIT, + UNSEALED_MESSAGE = CHESTPLATE_UNSEAL_MESSAGE, + SEALED_MESSAGE = CHESTPLATE_SEAL_MESSAGE, ), - GAUNTLETS_FLAGS = list( + /obj/item/clothing/gloves/mod = list( UNSEALED_CLOTHING = THICKMATERIAL, SEALED_CLOTHING = STOPSPRESSUREDAMAGE, CAN_OVERSLOT = TRUE, + UNSEALED_MESSAGE = GAUNTLET_UNSEAL_MESSAGE, + SEALED_MESSAGE = GAUNTLET_SEAL_MESSAGE, ), - BOOTS_FLAGS = list( + /obj/item/clothing/shoes/mod = list( UNSEALED_CLOTHING = THICKMATERIAL, SEALED_CLOTHING = STOPSPRESSUREDAMAGE, CAN_OVERSLOT = TRUE, + UNSEALED_MESSAGE = BOOT_UNSEAL_MESSAGE, + SEALED_MESSAGE = BOOT_SEAL_MESSAGE, ), ), ) @@ -1661,30 +2009,38 @@ allowed_suit_storage = list( /obj/item/restraints/handcuffs, ) - skins = list( + variants = list( "chrono" = list( - HELMET_FLAGS = list( + /obj/item/clothing/head/mod = list( UNSEALED_LAYER = NECK_LAYER, UNSEALED_CLOTHING = SNUG_FIT, SEALED_CLOTHING = THICKMATERIAL|STOPSPRESSUREDAMAGE|BLOCK_GAS_SMOKE_EFFECT|HEADINTERNALS, UNSEALED_INVISIBILITY = HIDEFACIALHAIR, SEALED_INVISIBILITY = HIDEMASK|HIDEEARS|HIDEEYES|HIDEFACE|HIDEHAIR|HIDESNOUT, SEALED_COVER = HEADCOVERSMOUTH|HEADCOVERSEYES|PEPPERPROOF, + UNSEALED_MESSAGE = HELMET_UNSEAL_MESSAGE, + SEALED_MESSAGE = HELMET_SEAL_MESSAGE, ), - CHESTPLATE_FLAGS = list( + /obj/item/clothing/suit/mod = list( UNSEALED_CLOTHING = THICKMATERIAL, SEALED_CLOTHING = STOPSPRESSUREDAMAGE, SEALED_INVISIBILITY = HIDEJUMPSUIT, + UNSEALED_MESSAGE = CHESTPLATE_UNSEAL_MESSAGE, + SEALED_MESSAGE = CHESTPLATE_SEAL_MESSAGE, ), - GAUNTLETS_FLAGS = list( + /obj/item/clothing/gloves/mod = list( UNSEALED_CLOTHING = THICKMATERIAL, SEALED_CLOTHING = STOPSPRESSUREDAMAGE, CAN_OVERSLOT = TRUE, + UNSEALED_MESSAGE = GAUNTLET_UNSEAL_MESSAGE, + SEALED_MESSAGE = GAUNTLET_SEAL_MESSAGE, ), - BOOTS_FLAGS = list( + /obj/item/clothing/shoes/mod = list( UNSEALED_CLOTHING = THICKMATERIAL, SEALED_CLOTHING = STOPSPRESSUREDAMAGE, CAN_OVERSLOT = TRUE, + UNSEALED_MESSAGE = BOOT_UNSEAL_MESSAGE, + SEALED_MESSAGE = BOOT_SEAL_MESSAGE, ), ), ) @@ -1719,31 +2075,38 @@ allowed_suit_storage = list( /obj/item/gun, ) - skins = list( + variants = list( "debug" = list( - HELMET_FLAGS = list( - UNSEALED_LAYER = null, + /obj/item/clothing/head/mod = list( UNSEALED_CLOTHING = SNUG_FIT|THICKMATERIAL, SEALED_CLOTHING = STOPSPRESSUREDAMAGE|BLOCK_GAS_SMOKE_EFFECT|HEADINTERNALS, UNSEALED_INVISIBILITY = HIDEFACIALHAIR|HIDEEARS|HIDEHAIR|HIDESNOUT, SEALED_INVISIBILITY = HIDEMASK|HIDEEARS|HIDEEYES|HIDEFACE, UNSEALED_COVER = HEADCOVERSMOUTH, SEALED_COVER = HEADCOVERSEYES|PEPPERPROOF, + UNSEALED_MESSAGE = HELMET_UNSEAL_MESSAGE, + SEALED_MESSAGE = HELMET_SEAL_MESSAGE, ), - CHESTPLATE_FLAGS = list( + /obj/item/clothing/suit/mod = list( UNSEALED_CLOTHING = THICKMATERIAL, SEALED_CLOTHING = STOPSPRESSUREDAMAGE, SEALED_INVISIBILITY = HIDEJUMPSUIT, + UNSEALED_MESSAGE = CHESTPLATE_UNSEAL_MESSAGE, + SEALED_MESSAGE = CHESTPLATE_SEAL_MESSAGE, ), - GAUNTLETS_FLAGS = list( + /obj/item/clothing/gloves/mod = list( UNSEALED_CLOTHING = THICKMATERIAL, SEALED_CLOTHING = STOPSPRESSUREDAMAGE, CAN_OVERSLOT = TRUE, + UNSEALED_MESSAGE = GAUNTLET_UNSEAL_MESSAGE, + SEALED_MESSAGE = GAUNTLET_SEAL_MESSAGE, ), - BOOTS_FLAGS = list( + /obj/item/clothing/shoes/mod = list( UNSEALED_CLOTHING = THICKMATERIAL, SEALED_CLOTHING = STOPSPRESSUREDAMAGE, CAN_OVERSLOT = TRUE, + UNSEALED_MESSAGE = BOOT_UNSEAL_MESSAGE, + SEALED_MESSAGE = BOOT_SEAL_MESSAGE, ), ), ) @@ -1779,24 +2142,25 @@ allowed_suit_storage = list( /obj/item/gun, ) - skins = list( + variants = list( "debug" = list( - HELMET_FLAGS = list( - UNSEALED_LAYER = null, + /obj/item/clothing/head/mod = list( UNSEALED_CLOTHING = SNUG_FIT|THICKMATERIAL|STOPSPRESSUREDAMAGE|BLOCK_GAS_SMOKE_EFFECT|HEADINTERNALS, UNSEALED_INVISIBILITY = HIDEFACIALHAIR|HIDEEARS|HIDEHAIR|HIDESNOUT, SEALED_INVISIBILITY = HIDEMASK|HIDEEARS|HIDEEYES|HIDEFACE, UNSEALED_COVER = HEADCOVERSMOUTH|HEADCOVERSEYES|PEPPERPROOF, + UNSEALED_MESSAGE = HELMET_UNSEAL_MESSAGE, + SEALED_MESSAGE = HELMET_SEAL_MESSAGE, ), - CHESTPLATE_FLAGS = list( + /obj/item/clothing/suit/mod = list( UNSEALED_CLOTHING = THICKMATERIAL|STOPSPRESSUREDAMAGE, SEALED_INVISIBILITY = HIDEJUMPSUIT, ), - GAUNTLETS_FLAGS = list( + /obj/item/clothing/gloves/mod = list( UNSEALED_CLOTHING = THICKMATERIAL|STOPSPRESSUREDAMAGE, CAN_OVERSLOT = TRUE, ), - BOOTS_FLAGS = list( + /obj/item/clothing/shoes/mod = list( UNSEALED_CLOTHING = THICKMATERIAL|STOPSPRESSUREDAMAGE, CAN_OVERSLOT = TRUE, ), diff --git a/code/modules/mod/mod_types.dm b/code/modules/mod/mod_types.dm index 2789763e12cd2..8843a811756d7 100644 --- a/code/modules/mod/mod_types.dm +++ b/code/modules/mod/mod_types.dm @@ -212,7 +212,7 @@ /obj/item/mod/module/storage, /obj/item/mod/module/waddle, /obj/item/mod/module/bikehorn, - /obj/item/mod/module/balloon_advanced, + /obj/item/mod/module/balloon/advanced, ) /obj/item/mod/control/pre_equipped/traitor @@ -352,6 +352,7 @@ starting_frequency = MODLINK_FREQ_SYNDICATE applied_cell = /obj/item/stock_parts/cell/super applied_modules = list( + /obj/item/mod/module/organ_thrower, /obj/item/mod/module/defibrillator/combat, /obj/item/mod/module/flashlight, /obj/item/mod/module/health_analyzer, @@ -413,6 +414,23 @@ /obj/item/mod/module/anomaly_locked/kinesis/prototype, ) +/obj/item/mod/control/pre_equipped/glitch + theme = /datum/mod_theme/glitch + starting_frequency = null + applied_cell = /obj/item/stock_parts/cell/bluespace + applied_modules = list( + /obj/item/mod/module/storage, + /obj/item/mod/module/magnetic_harness, + /obj/item/mod/module/jetpack/advanced, + /obj/item/mod/module/jump_jet, + /obj/item/mod/module/flashlight, + ) + default_pins = list( + /obj/item/mod/module/armor_booster, + /obj/item/mod/module/jetpack/advanced, + /obj/item/mod/module/jump_jet, + ) + /obj/item/mod/control/pre_equipped/responsory theme = /datum/mod_theme/responsory starting_frequency = MODLINK_FREQ_CENTCOM diff --git a/code/modules/mod/mod_ui.dm b/code/modules/mod/mod_ui.dm index 2f1e6faa0f429..f994b91060fea 100644 --- a/code/modules/mod/mod_ui.dm +++ b/code/modules/mod/mod_ui.dm @@ -53,7 +53,7 @@ "cooldown" = round(COOLDOWN_TIMELEFT(module, cooldown_timer), 1 SECONDS), "id" = module.tgui_id, "ref" = REF(module), - "configuration_data" = module.get_configuration(user) + "configuration_data" = module.get_configuration(user), )) data["module_custom_status"] = module_custom_status data["module_info"] = module_info @@ -64,10 +64,13 @@ data["ui_theme"] = ui_theme data["control"] = name data["complexity_max"] = complexity_max - data["helmet"] = helmet?.name - data["chestplate"] = chestplate?.name - data["gauntlets"] = gauntlets?.name - data["boots"] = boots?.name + var/part_info = list() + for(var/obj/item/part as anything in get_parts()) + part_info += list(list( + "slot" = english_list(parse_slot_flags(part.slot_flags)), + "name" = part.name, + )) + data["parts"] = part_info return data /obj/item/mod/control/ui_state(mob/user) diff --git a/code/modules/mod/modules/_module.dm b/code/modules/mod/modules/_module.dm index 8b3166f811b4a..4bd4ef0d2ab80 100644 --- a/code/modules/mod/modules/_module.dm +++ b/code/modules/mod/modules/_module.dm @@ -43,6 +43,8 @@ var/list/pinned_to = list() /// flags that let the module ability be used in odd circumstances var/allow_flags = NONE + /// A list of slots required in the suit to work. Formatted like list(x|y, z, ...) where either x or y are required and z is required. + var/list/required_slots = list() /// Timer for the cooldown COOLDOWN_DECLARE(cooldown_timer) @@ -65,23 +67,50 @@ /obj/item/mod/module/examine(mob/user) . = ..() + if(length(required_slots)) + var/list/slot_strings = list() + for(var/slot in required_slots) + var/list/slot_list = parse_slot_flags(slot) + slot_strings += (length(slot_list) == 1 ? "" : "one of ") + english_list(slot_list, and_text = " or ") + . += span_notice("Requires the MOD unit to have the following slots: [english_list(slot_strings)]") if(HAS_TRAIT(user, TRAIT_DIAGNOSTIC_HUD)) . += span_notice("Complexity level: [complexity]") +/// Looks through the MODsuit's parts to see if it has the parts required to support this module +/obj/item/mod/module/proc/has_required_parts(list/parts, need_extended = FALSE) + if(!length(required_slots)) + return TRUE + var/total_slot_flags = NONE + for(var/part_slot in parts) + if(need_extended) + var/datum/mod_part/part_datum = parts[part_slot] + if(part_datum.part_item.loc == mod) + continue + total_slot_flags |= text2num(part_slot) + var/list/needed_slots = required_slots.Copy() + for(var/needed_slot in needed_slots) + if(!(needed_slot & total_slot_flags)) + break + needed_slots -= needed_slot + return !length(needed_slots) /// Called when the module is selected from the TGUI, radial or the action button /obj/item/mod/module/proc/on_select() + if(!mod.wearer) + if(ismob(mod.loc)) + balloon_alert(mod.loc, "not equipped!") + return if(((!mod.active || mod.activating) && !(allow_flags & MODULE_ALLOW_INACTIVE)) || module_type == MODULE_PASSIVE) if(mod.wearer) balloon_alert(mod.wearer, "not active!") return if(module_type != MODULE_USABLE) if(active) - on_deactivation() + deactivate() else - on_activation() + activate() else - on_use() + used() SEND_SIGNAL(mod, COMSIG_MOD_MODULE_SELECTED, src) /// Apply a cooldown until this item can be used again @@ -92,7 +121,7 @@ SEND_SIGNAL(src, COMSIG_MODULE_COOLDOWN_STARTED, applied_cooldown) /// Called when the module is activated -/obj/item/mod/module/proc/on_activation() +/obj/item/mod/module/proc/activate() if(!COOLDOWN_FINISHED(src, cooldown_timer)) balloon_alert(mod.wearer, "on cooldown!") return FALSE @@ -106,7 +135,7 @@ if(SEND_SIGNAL(src, COMSIG_MODULE_TRIGGERED, mod.wearer) & MOD_ABORT_USE) return FALSE if(module_type == MODULE_ACTIVE) - if(mod.selected_module && !mod.selected_module.on_deactivation(display_message = FALSE)) + if(mod.selected_module && !mod.selected_module.deactivate(display_message = FALSE)) return FALSE mod.selected_module = src if(device) @@ -126,10 +155,11 @@ mod.wearer.update_clothing(mod.slot_flags) start_cooldown() SEND_SIGNAL(src, COMSIG_MODULE_ACTIVATED) + on_activation() return TRUE /// Called when the module is deactivated -/obj/item/mod/module/proc/on_deactivation(display_message = TRUE, deleting = FALSE) +/obj/item/mod/module/proc/deactivate(display_message = TRUE, deleting = FALSE) active = FALSE if(module_type == MODULE_ACTIVE) mod.selected_module = null @@ -144,10 +174,11 @@ used_signal = null mod.wearer.update_clothing(mod.slot_flags) SEND_SIGNAL(src, COMSIG_MODULE_DEACTIVATED, mod.wearer) + on_deactivation(display_message = TRUE, deleting = FALSE) return TRUE /// Called when the module is used -/obj/item/mod/module/proc/on_use() +/obj/item/mod/module/proc/used() if(!COOLDOWN_FINISHED(src, cooldown_timer)) balloon_alert(mod.wearer, "on cooldown!") return FALSE @@ -164,6 +195,7 @@ addtimer(CALLBACK(mod.wearer, TYPE_PROC_REF(/mob, update_clothing), mod.slot_flags), cooldown_time+1) //need to run it a bit after the cooldown starts to avoid conflicts mod.wearer.update_clothing(mod.slot_flags) SEND_SIGNAL(src, COMSIG_MODULE_USED) + on_use() return TRUE /// Called when an activated module without a device is used @@ -171,7 +203,7 @@ if(!(allow_flags & MODULE_ALLOW_INCAPACITATED) && mod.wearer.incapacitated(IGNORE_GRAB)) return FALSE mod.wearer.face_atom(target) - if(!on_use()) + if(!used()) return FALSE return TRUE @@ -185,22 +217,34 @@ /obj/item/mod/module/proc/on_process(seconds_per_tick) if(active) if(!drain_power(active_power_cost * seconds_per_tick)) - on_deactivation() + deactivate() return FALSE on_active_process(seconds_per_tick) else drain_power(idle_power_cost * seconds_per_tick) return TRUE +/// Called from the module's activate() +/obj/item/mod/module/proc/on_activation() + return + +/// Called from the module's deactivate() +/obj/item/mod/module/proc/on_deactivation(display_message = TRUE, deleting = FALSE) + return + +/// Called from the module's used() +/obj/item/mod/module/proc/on_use() + return + /// Called on the MODsuit's process if it is an active module /obj/item/mod/module/proc/on_active_process(seconds_per_tick) return -/// Called from MODsuit's install() proc, so when the module is installed. +/// Called from MODsuit's install() proc, so when the module is installed /obj/item/mod/module/proc/on_install() return -/// Called from MODsuit's uninstall() proc, so when the module is uninstalled. +/// Called from MODsuit's uninstall() proc, so when the module is uninstalled /obj/item/mod/module/proc/on_uninstall(deleting = FALSE) return @@ -258,7 +302,7 @@ if(part.loc == mod.wearer) return if(part == device) - on_deactivation(display_message = FALSE) + deactivate(display_message = FALSE) /// Called when the device gets deleted on active modules /obj/item/mod/module/proc/on_device_deletion(datum/source) @@ -321,7 +365,7 @@ if(user.get_active_held_item() != device) return - on_deactivation() + deactivate() return COMSIG_KB_ACTIVATED ///Anomaly Locked - Causes the module to not function without an anomaly. diff --git a/code/modules/mod/modules/module_kinesis.dm b/code/modules/mod/modules/module_kinesis.dm index 4f4fa44ff966c..81a266f8ff41a 100644 --- a/code/modules/mod/modules/module_kinesis.dm +++ b/code/modules/mod/modules/module_kinesis.dm @@ -15,6 +15,7 @@ overlay_state_inactive = "module_kinesis" overlay_state_active = "module_kinesis_on" accepted_anomalies = list(/obj/item/assembly/signaler/anomaly/grav) + required_slots = list(ITEM_SLOT_GLOVES) /// Range of the knesis grab. var/grab_range = 5 /// Time between us hitting objects with kinesis. @@ -63,9 +64,6 @@ grab_atom(target) /obj/item/mod/module/anomaly_locked/kinesis/on_deactivation(display_message = TRUE, deleting = FALSE) - . = ..() - if(!.) - return clear_grab(playsound = !deleting) /obj/item/mod/module/anomaly_locked/kinesis/process(seconds_per_tick) diff --git a/code/modules/mod/modules/module_pathfinder.dm b/code/modules/mod/modules/module_pathfinder.dm index 1681496036887..64790eacb3bec 100644 --- a/code/modules/mod/modules/module_pathfinder.dm +++ b/code/modules/mod/modules/module_pathfinder.dm @@ -13,6 +13,7 @@ complexity = 1 use_energy_cost = DEFAULT_CHARGE_DRAIN * 10 incompatible_modules = list(/obj/item/mod/module/pathfinder) + required_slots = list(ITEM_SLOT_BACK|ITEM_SLOT_BELT) /// The pathfinding implant. var/obj/item/implant/mod/implant diff --git a/code/modules/mod/modules/modules_antag.dm b/code/modules/mod/modules/modules_antag.dm index bd96c5aec5ff4..8d8d777592466 100644 --- a/code/modules/mod/modules/modules_antag.dm +++ b/code/modules/mod/modules/modules_antag.dm @@ -23,11 +23,9 @@ /// Speed that we actually added. var/actual_speed_added = 0 /// Armor values added to the suit parts. - var/list/armor_mod = /datum/armor/mod_module_armor_boost + var/datum/armor/armor_mod = /datum/armor/mod_module_armor_boost /// List of parts of the suit that are spaceproofed, for giving them back the pressure protection. var/list/spaceproofed = list() - /// List of traits added when the mod is activated - var/list/traits_to_add = list(TRAIT_HEAD_INJURY_BLOCKED) /obj/item/mod/module/armor_booster/no_speedbost speed_added = 0 @@ -39,25 +37,27 @@ energy = 15 /obj/item/mod/module/armor_booster/on_suit_activation() - mod.helmet.flash_protect = FLASH_PROTECTION_WELDER + var/obj/item/clothing/head_cover = mod.get_part_from_slot(ITEM_SLOT_HEAD) || mod.get_part_from_slot(ITEM_SLOT_MASK) || mod.get_part_from_slot(ITEM_SLOT_EYES) + if(istype(head_cover)) + head_cover.flash_protect = FLASH_PROTECTION_WELDER /obj/item/mod/module/armor_booster/on_suit_deactivation(deleting = FALSE) if(deleting) return - mod.helmet.flash_protect = initial(mod.helmet.flash_protect) + var/obj/item/clothing/head_cover = mod.get_part_from_slot(ITEM_SLOT_HEAD) || mod.get_part_from_slot(ITEM_SLOT_MASK) || mod.get_part_from_slot(ITEM_SLOT_EYES) + if(istype(head_cover)) + head_cover.flash_protect = initial(head_cover.flash_protect) /obj/item/mod/module/armor_booster/on_activation() - . = ..() - if(!.) - return playsound(src, 'sound/mecha/mechmove03.ogg', 25, TRUE, SHORT_RANGE_SOUND_EXTRARANGE) balloon_alert(mod.wearer, "armor boosted, EVA lost") actual_speed_added = max(0, min(mod.slowdown_active, speed_added)) mod.slowdown -= actual_speed_added mod.wearer.update_equipment_speed_mods() - mod.wearer.add_traits(traits_to_add, MOD_TRAIT) - var/list/parts = mod.mod_parts + mod - for(var/obj/item/part as anything in parts) + var/obj/item/clothing/head_cover = mod.get_part_from_slot(ITEM_SLOT_HEAD) || mod.get_part_from_slot(ITEM_SLOT_MASK) || mod.get_part_from_slot(ITEM_SLOT_EYES) + if(istype(head_cover)) + ADD_TRAIT(mod.wearer, TRAIT_HEAD_INJURY_BLOCKED, MOD_TRAIT) + for(var/obj/item/part as anything in mod.get_parts(all = TRUE)) part.set_armor(part.get_armor().add_other_armor(armor_mod)) if(!remove_pressure_protection || !isclothing(part)) continue @@ -67,17 +67,15 @@ spaceproofed[clothing_part] = TRUE /obj/item/mod/module/armor_booster/on_deactivation(display_message = TRUE, deleting = FALSE) - . = ..() - if(!.) - return if(!deleting) playsound(src, 'sound/mecha/mechmove03.ogg', 25, TRUE, SHORT_RANGE_SOUND_EXTRARANGE) balloon_alert(mod.wearer, "armor retracts, EVA ready") mod.slowdown += actual_speed_added mod.wearer.update_equipment_speed_mods() - mod.wearer.remove_traits(traits_to_add, MOD_TRAIT) - var/list/parts = mod.mod_parts + mod - for(var/obj/item/part as anything in parts) + var/obj/item/clothing/head_cover = mod.get_part_from_slot(ITEM_SLOT_HEAD) || mod.get_part_from_slot(ITEM_SLOT_MASK) || mod.get_part_from_slot(ITEM_SLOT_EYES) + if(istype(head_cover)) + REMOVE_TRAIT(mod.wearer, TRAIT_HEAD_INJURY_BLOCKED, MOD_TRAIT) + for(var/obj/item/part as anything in mod.get_parts(all = TRUE)) part.set_armor(part.get_armor().subtract_other_armor(armor_mod)) if(!remove_pressure_protection || !isclothing(part)) continue @@ -103,6 +101,7 @@ idle_power_cost = DEFAULT_CHARGE_DRAIN * 0.5 use_energy_cost = DEFAULT_CHARGE_DRAIN * 2 incompatible_modules = list(/obj/item/mod/module/energy_shield) + required_slots = list(ITEM_SLOT_BACK) /// Max charges of the shield. var/max_charges = 1 /// The time it takes for the first charge to recover. @@ -167,6 +166,7 @@ shield_icon_file = 'icons/effects/magic.dmi' shield_icon = "mageshield" recharge_path = /obj/item/wizard_armour_charge + required_slots = list() ///Magic Nullifier - Protects you from magic. /obj/item/mod/module/anti_magic @@ -179,6 +179,7 @@ icon_state = "magic_nullifier" removable = FALSE incompatible_modules = list(/obj/item/mod/module/anti_magic) + required_slots = list(ITEM_SLOT_BACK) /obj/item/mod/module/anti_magic/on_suit_activation() mod.wearer.add_traits(list(TRAIT_ANTIMAGIC, TRAIT_HOLY), MOD_TRAIT) @@ -193,6 +194,7 @@ The field will neutralize all magic that comes into contact with the user. \ It will not protect the caster from social ridicule." icon_state = "magic_neutralizer" + required_slots = list() /obj/item/mod/module/anti_magic/wizard/on_suit_activation() mod.wearer.add_traits(list(TRAIT_ANTIMAGIC, TRAIT_ANTIMAGIC_NO_SELFBLOCK), MOD_TRAIT) @@ -254,6 +256,7 @@ complexity = 1 idle_power_cost = DEFAULT_CHARGE_DRAIN * 0.1 incompatible_modules = list(/obj/item/mod/module/noslip) + required_slots = list(ITEM_SLOT_FEET) /obj/item/mod/module/noslip/on_suit_activation() ADD_TRAIT(mod.wearer, TRAIT_NO_SLIP_WATER, MOD_TRAIT) @@ -298,6 +301,7 @@ cooldown_time = 2.5 SECONDS overlay_state_inactive = "module_flamethrower" overlay_state_active = "module_flamethrower_on" + required_slots = list(ITEM_SLOT_OCLOTHING|ITEM_SLOT_ICLOTHING) /obj/item/mod/module/flamethrower/on_select_use(atom/target) . = ..() @@ -320,6 +324,7 @@ use_energy_cost = DEFAULT_CHARGE_DRAIN * 5 incompatible_modules = list(/obj/item/mod/module/power_kick) cooldown_time = 5 SECONDS + required_slots = list(ITEM_SLOT_FEET) /// Damage on kick. var/damage = 20 /// The wound bonus of the kick. @@ -399,13 +404,13 @@ return_look() possible_disguises = null -/obj/item/mod/module/chameleon/on_use() +/obj/item/mod/module/chameleon/used() if(mod.active || mod.activating) balloon_alert(mod.wearer, "suit active!") - return - . = ..() - if(!.) - return + return FALSE + return ..() + +/obj/item/mod/module/chameleon/on_use() if(current_disguise) return_look() return @@ -433,10 +438,9 @@ mod.name = "[mod.theme.name] [initial(mod.name)]" mod.desc = "[initial(mod.desc)] [mod.theme.desc]" mod.icon_state = "[mod.skin]-[initial(mod.icon_state)]" - var/list/mod_skin = mod.theme.skins[mod.skin] + var/list/mod_skin = mod.theme.variants[mod.skin] mod.icon = mod_skin[MOD_ICON_OVERRIDE] || 'icons/obj/clothing/modsuit/mod_clothing.dmi' mod.worn_icon = mod_skin[MOD_WORN_ICON_OVERRIDE] || 'icons/mob/clothing/modsuit/mod_clothing.dmi' - mod.alternate_worn_layer = mod_skin[CONTROL_LAYER] mod.lefthand_file = initial(mod.lefthand_file) mod.righthand_file = initial(mod.righthand_file) mod.worn_icon_state = null @@ -481,6 +485,7 @@ complexity = 0 idle_power_cost = DEFAULT_CHARGE_DRAIN * 0.1 removable = FALSE + required_slots = list(ITEM_SLOT_BACK|ITEM_SLOT_BELT) var/datum/proximity_monitor/advanced/demoraliser/demoralizer /obj/item/mod/module/demoralizer/on_suit_activation() @@ -500,6 +505,7 @@ removable = FALSE idle_power_cost = DEFAULT_CHARGE_DRAIN * 0 incompatible_modules = list(/obj/item/mod/module/infiltrator, /obj/item/mod/module/armor_booster, /obj/item/mod/module/welding, /obj/item/mod/module/headprotector) + required_slots = list(ITEM_SLOT_FEET, ITEM_SLOT_HEAD, ITEM_SLOT_OCLOTHING) /// List of traits added when the suit is activated var/list/traits_to_add = list(TRAIT_SILENT_FOOTSTEPS, TRAIT_UNKNOWN, TRAIT_HEAD_INJURY_BLOCKED) @@ -510,18 +516,22 @@ mod.item_flags &= ~EXAMINE_SKIP /obj/item/mod/module/infiltrator/on_suit_activation() - mod.wearer.add_traits(traits_to_add, MOD_TRAIT) - mod.helmet.flash_protect = FLASH_PROTECTION_WELDER + mod.wearer.add_traits(list(TRAIT_SILENT_FOOTSTEPS, TRAIT_UNKNOWN), MOD_TRAIT) + var/obj/item/clothing/head_cover = mod.get_part_from_slot(ITEM_SLOT_HEAD) + if(istype(head_cover)) + head_cover.flash_protect = FLASH_PROTECTION_WELDER /obj/item/mod/module/infiltrator/on_suit_deactivation(deleting = FALSE) mod.wearer.remove_traits(traits_to_add, MOD_TRAIT) if(deleting) return - mod.helmet.flash_protect = initial(mod.helmet.flash_protect) + var/obj/item/clothing/head_cover = mod.get_part_from_slot(ITEM_SLOT_HEAD) + if(istype(head_cover)) + head_cover.flash_protect = initial(head_cover.flash_protect) ///Medbeam - Medbeam but built into a modsuit /obj/item/mod/module/medbeam - name = "MOD Medbeam Module" + name = "MOD medical beamgun module" desc = "A wrist mounted variant of the medbeam gun, allowing the user to heal their allies without the risk of dropping it." icon_state = "chronogun" module_type = MODULE_ACTIVE @@ -531,6 +541,7 @@ incompatible_modules = list(/obj/item/mod/module/medbeam) removable = TRUE cooldown_time = 0.5 + required_slots = list(ITEM_SLOT_BACK) /obj/item/gun/medbeam/mod name = "MOD medbeam" diff --git a/code/modules/mod/modules/modules_engineering.dm b/code/modules/mod/modules/modules_engineering.dm index 1ddcab0818073..cb830b2128e7e 100644 --- a/code/modules/mod/modules/modules_engineering.dm +++ b/code/modules/mod/modules/modules_engineering.dm @@ -10,14 +10,19 @@ complexity = 1 incompatible_modules = list(/obj/item/mod/module/welding, /obj/item/mod/module/armor_booster) overlay_state_inactive = "module_welding" + required_slots = list(ITEM_SLOT_HEAD|ITEM_SLOT_EYES|ITEM_SLOT_MASK) /obj/item/mod/module/welding/on_suit_activation() - mod.helmet.flash_protect = FLASH_PROTECTION_WELDER + var/obj/item/clothing/head_cover = mod.get_part_from_slot(ITEM_SLOT_HEAD) || mod.get_part_from_slot(ITEM_SLOT_MASK) || mod.get_part_from_slot(ITEM_SLOT_EYES) + if(istype(head_cover)) + head_cover.flash_protect = FLASH_PROTECTION_WELDER /obj/item/mod/module/welding/on_suit_deactivation(deleting = FALSE) if(deleting) return - mod.helmet.flash_protect = initial(mod.helmet.flash_protect) + var/obj/item/clothing/head_cover = mod.get_part_from_slot(ITEM_SLOT_HEAD) || mod.get_part_from_slot(ITEM_SLOT_MASK) || mod.get_part_from_slot(ITEM_SLOT_EYES) + if(istype(head_cover)) + head_cover.flash_protect = initial(head_cover.flash_protect) ///T-Ray Scan - Scans the terrain for undertile objects. /obj/item/mod/module/t_ray @@ -31,6 +36,7 @@ active_power_cost = DEFAULT_CHARGE_DRAIN * 0.5 incompatible_modules = list(/obj/item/mod/module/t_ray) cooldown_time = 0.5 SECONDS + required_slots = list(ITEM_SLOT_HEAD|ITEM_SLOT_EYES|ITEM_SLOT_MASK) /// T-ray scan range. var/range = 4 @@ -50,23 +56,18 @@ active_power_cost = DEFAULT_CHARGE_DRAIN * 0.5 incompatible_modules = list(/obj/item/mod/module/magboot, /obj/item/mod/module/atrocinator) cooldown_time = 0.5 SECONDS + required_slots = list(ITEM_SLOT_FEET) /// Slowdown added onto the suit. var/slowdown_active = 0.5 /// A list of traits to add to the wearer when we're active (see: Magboots) var/list/active_traits = list(TRAIT_NO_SLIP_WATER, TRAIT_NO_SLIP_ICE, TRAIT_NO_SLIP_SLIDE, TRAIT_NEGATES_GRAVITY) /obj/item/mod/module/magboot/on_activation() - . = ..() - if(!.) - return mod.wearer.add_traits(active_traits, MOD_TRAIT) mod.slowdown += slowdown_active mod.wearer.update_equipment_speed_mods() /obj/item/mod/module/magboot/on_deactivation(display_message = TRUE, deleting = FALSE) - . = ..() - if(!.) - return mod.wearer.remove_traits(active_traits, MOD_TRAIT) mod.slowdown -= slowdown_active mod.wearer.update_equipment_speed_mods() @@ -89,8 +90,9 @@ use_energy_cost = DEFAULT_CHARGE_DRAIN incompatible_modules = list(/obj/item/mod/module/tether) cooldown_time = 1.5 SECONDS + required_slots = list(ITEM_SLOT_GLOVES) -/obj/item/mod/module/tether/on_use() +/obj/item/mod/module/tether/used() if(mod.wearer.has_gravity(get_turf(src))) balloon_alert(mod.wearer, "too much gravity!") playsound(src, 'sound/weapons/gun/general/dry_fire.ogg', 25, TRUE) @@ -153,14 +155,14 @@ AddComponent(/datum/component/geiger_sound) ADD_TRAIT(mod.wearer, TRAIT_BYPASS_EARLY_IRRADIATED_CHECK, MOD_TRAIT) RegisterSignal(mod.wearer, COMSIG_IN_RANGE_OF_IRRADIATION, PROC_REF(on_pre_potential_irradiation)) - for(var/obj/item/part in mod.mod_parts) + for(var/obj/item/part in mod.get_parts(all = TRUE)) ADD_TRAIT(part, TRAIT_RADIATION_PROTECTED_CLOTHING, MOD_TRAIT) /obj/item/mod/module/rad_protection/on_suit_deactivation(deleting = FALSE) qdel(GetComponent(/datum/component/geiger_sound)) REMOVE_TRAIT(mod.wearer, TRAIT_BYPASS_EARLY_IRRADIATED_CHECK, MOD_TRAIT) UnregisterSignal(mod.wearer, COMSIG_IN_RANGE_OF_IRRADIATION) - for(var/obj/item/part in mod.mod_parts) + for(var/obj/item/part in mod.get_parts(all = TRUE)) REMOVE_TRAIT(part, TRAIT_RADIATION_PROTECTED_CLOTHING, MOD_TRAIT) /obj/item/mod/module/rad_protection/add_ui_data() @@ -190,6 +192,7 @@ use_energy_cost = DEFAULT_CHARGE_DRAIN * 2 incompatible_modules = list(/obj/item/mod/module/constructor, /obj/item/mod/module/quick_carry) cooldown_time = 11 SECONDS + required_slots = list(ITEM_SLOT_GLOVES) /obj/item/mod/module/constructor/on_suit_activation() ADD_TRAIT(mod.wearer, TRAIT_QUICK_BUILD, MOD_TRAIT) @@ -198,15 +201,12 @@ REMOVE_TRAIT(mod.wearer, TRAIT_QUICK_BUILD, MOD_TRAIT) /obj/item/mod/module/constructor/on_use() - . = ..() - if(!.) - return rcd_scan(src, fade_time = 10 SECONDS) drain_power(use_energy_cost) ///Safety-First Head Protection - Protects your brain matter from sudden impacts. /obj/item/mod/module/headprotector - name = "MOD Safety-First Head Protection module" + name = "MOD safety-first head protection module" desc = "A series of dampening plates are installed along the back and upper areas of \ the helmet. These plates absorb abrupt kinetic shocks delivered to the skull. \ The bulk of this module prevents it from being installed in any suit that is capable \ @@ -215,6 +215,7 @@ icon_state = "welding" complexity = 1 incompatible_modules = list(/obj/item/mod/module/armor_booster, /obj/item/mod/module/infiltrator) + required_slots = list(ITEM_SLOT_HEAD) /obj/item/mod/module/constructor/on_suit_activation() ADD_TRAIT(mod.wearer, TRAIT_HEAD_INJURY_BLOCKED, MOD_TRAIT) @@ -233,6 +234,7 @@ device = /obj/item/reagent_containers/spray/mister incompatible_modules = list(/obj/item/mod/module/mister) cooldown_time = 0.5 SECONDS + required_slots = list(ITEM_SLOT_BACK) /// Volume of our reagent holder. var/volume = 500 diff --git a/code/modules/mod/modules/modules_general.dm b/code/modules/mod/modules/modules_general.dm index 2aec3e361c4b4..87cab74b24f76 100644 --- a/code/modules/mod/modules/modules_general.dm +++ b/code/modules/mod/modules/modules_general.dm @@ -8,6 +8,7 @@ icon_state = "storage" complexity = 3 incompatible_modules = list(/obj/item/mod/module/storage, /obj/item/mod/module/plate_compression) + required_slots = list(ITEM_SLOT_BACK) /// Max weight class of items in the storage. var/max_w_class = WEIGHT_CLASS_NORMAL /// Max combined weight of all items in the storage. @@ -28,16 +29,20 @@ modstorage.set_real_location(src) modstorage.allow_big_nesting = big_nesting atom_storage.locked = STORAGE_NOT_LOCKED - RegisterSignal(mod.chestplate, COMSIG_ITEM_PRE_UNEQUIP, PROC_REF(on_chestplate_unequip)) + var/obj/item/clothing/suit = mod.get_part_from_slot(ITEM_SLOT_OCLOTHING) + if(istype(suit)) + RegisterSignal(suit, COMSIG_ITEM_PRE_UNEQUIP, PROC_REF(on_suit_unequip)) /obj/item/mod/module/storage/on_uninstall(deleting = FALSE) atom_storage.locked = STORAGE_FULLY_LOCKED QDEL_NULL(mod.atom_storage) if(!deleting) atom_storage.remove_all(mod.drop_location()) - UnregisterSignal(mod.chestplate, COMSIG_ITEM_PRE_UNEQUIP) + var/obj/item/clothing/suit = mod.get_part_from_slot(ITEM_SLOT_OCLOTHING) + if(istype(suit)) + UnregisterSignal(suit, COMSIG_ITEM_PRE_UNEQUIP) -/obj/item/mod/module/storage/proc/on_chestplate_unequip(obj/item/source, force, atom/newloc, no_move, invdrop, silent) +/obj/item/mod/module/storage/proc/on_suit_unequip(obj/item/source, force, atom/newloc, no_move, invdrop, silent) if(QDELETED(source) || !mod.wearer || newloc == mod.wearer || !mod.wearer.s_store) return if(!atom_storage?.attempt_insert(mod.wearer.s_store, mod.wearer, override = TRUE)) @@ -68,14 +73,14 @@ /obj/item/mod/module/storage/belt name = "MOD case storage module" desc = "Some concessions had to be made when creating a compressed modular suit core. \ - As a result, Roseus Galactic equipped their suit with a slimline storage case. \ - If you find this equipped to a standard modular suit, then someone has almost certainly shortchanged you on a proper storage module." + As a result, Roseus Galactic equipped their suit with a slimline storage case. \ + If you find this equipped to a standard modular suit, then someone has almost certainly shortchanged you on a proper storage module." icon_state = "storage_case" complexity = 0 max_w_class = WEIGHT_CLASS_SMALL - removable = FALSE max_combined_w_class = 21 max_items = 7 + required_slots = list(ITEM_SLOT_BELT) /obj/item/mod/module/storage/bluespace name = "MOD bluespace storage module" @@ -102,6 +107,7 @@ cooldown_time = 0.5 SECONDS overlay_state_inactive = "module_jetpack" overlay_state_active = "module_jetpack_on" + required_slots = list(ITEM_SLOT_BACK) /// Do we give the wearer a speed buff. var/full_speed = FALSE /// Do we have stabilizers? If yes the user won't move from inertia. @@ -138,14 +144,10 @@ ) /obj/item/mod/module/jetpack/on_activation() - . = ..() - if(!.) - return if(full_speed) mod.wearer.add_movespeed_modifier(/datum/movespeed_modifier/jetpack/fullspeed) /obj/item/mod/module/jetpack/on_deactivation(display_message = TRUE, deleting = FALSE) - . = ..() if(full_speed) mod.wearer.remove_movespeed_modifier(/datum/movespeed_modifier/jetpack/fullspeed) @@ -188,6 +190,7 @@ cooldown_time = 30 SECONDS use_energy_cost = DEFAULT_CHARGE_DRAIN * 5 incompatible_modules = list(/obj/item/mod/module/jump_jet) + required_slots = list(ITEM_SLOT_BACK) /obj/item/mod/module/jump_jet/on_use() . = ..() @@ -228,6 +231,7 @@ use_energy_cost = DEFAULT_CHARGE_DRAIN * 0.1 incompatible_modules = list(/obj/item/mod/module/status_readout) tgui_id = "status_readout" + required_slots = list(ITEM_SLOT_BACK) /// Does this show damage types, body temp, satiety var/display_detailed_vitals = TRUE /// Does this show DNA data @@ -305,22 +309,41 @@ complexity = 1 incompatible_modules = list(/obj/item/mod/module/mouthhole) overlay_state_inactive = "module_apparatus" + required_slots = list(ITEM_SLOT_HEAD|ITEM_SLOT_MASK) /// Former flags of the helmet. - var/former_flags = NONE + var/former_helmet_flags = NONE /// Former visor flags of the helmet. - var/former_visor_flags = NONE + var/former_visor_helmet_flags = NONE + /// Former flags of the mask. + var/former_mask_flags = NONE + /// Former visor flags of the mask. + var/former_visor_mask_flags = NONE /obj/item/mod/module/mouthhole/on_install() - former_flags = mod.helmet.flags_cover - former_visor_flags = mod.helmet.visor_flags_cover - mod.helmet.flags_cover &= ~(HEADCOVERSMOUTH|PEPPERPROOF) - mod.helmet.visor_flags_cover &= ~(HEADCOVERSMOUTH|PEPPERPROOF) + var/obj/item/clothing/helmet = mod.get_part_from_slot(ITEM_SLOT_HEAD) + if(istype(helmet)) + former_helmet_flags = helmet.flags_cover + former_visor_helmet_flags = helmet.visor_flags_cover + helmet.flags_cover &= ~(HEADCOVERSMOUTH|PEPPERPROOF) + helmet.visor_flags_cover &= ~(HEADCOVERSMOUTH|PEPPERPROOF) + var/obj/item/clothing/mask = mod.get_part_from_slot(ITEM_SLOT_MASK) + if(istype(mask)) + former_mask_flags = mask.flags_cover + former_visor_mask_flags = mask.visor_flags_cover + mask.flags_cover &= ~(MASKCOVERSMOUTH |PEPPERPROOF) + mask.visor_flags_cover &= ~(MASKCOVERSMOUTH |PEPPERPROOF) /obj/item/mod/module/mouthhole/on_uninstall(deleting = FALSE) if(deleting) return - mod.helmet.flags_cover |= former_flags - mod.helmet.visor_flags_cover |= former_visor_flags + var/obj/item/clothing/helmet = mod.get_part_from_slot(ITEM_SLOT_HEAD) + if(istype(helmet)) + helmet.flags_cover |= former_helmet_flags + helmet.visor_flags_cover |= former_visor_helmet_flags + var/obj/item/clothing/mask = mod.get_part_from_slot(ITEM_SLOT_MASK) + if(istype(mask)) + mask.flags_cover |= former_mask_flags + mask.visor_flags_cover |= former_visor_mask_flags ///EMP Shield - Protects the suit from EMPs. /obj/item/mod/module/emp_shield @@ -332,6 +355,7 @@ complexity = 1 idle_power_cost = DEFAULT_CHARGE_DRAIN * 0.3 incompatible_modules = list(/obj/item/mod/module/emp_shield) + required_slots = list(ITEM_SLOT_BACK|ITEM_SLOT_BELT) /obj/item/mod/module/emp_shield/on_install() mod.AddElement(/datum/element/empprotection, EMP_PROTECT_ALL) @@ -349,7 +373,7 @@ /obj/item/mod/module/emp_shield/advanced/on_suit_activation() mod.wearer.AddElement(/datum/element/empprotection, EMP_PROTECT_SELF|EMP_PROTECT_CONTENTS) -/obj/item/mod/module/emp_shield/advanced/on_suit_deactivation(deleting) +/obj/item/mod/module/emp_shield/advanced/on_suit_deactivation(deleting = FALSE) mod.wearer.RemoveElement(/datum/element/empprotection, EMP_PROTECT_SELF|EMP_PROTECT_CONTENTS) ///Flashlight - Gives the suit a customizable flashlight. @@ -370,6 +394,7 @@ light_range = 4 light_power = 1 light_on = FALSE + required_slots = list(ITEM_SLOT_HEAD|ITEM_SLOT_MASK) /// Charge drain per range amount. var/base_power = DEFAULT_CHARGE_DRAIN * 0.1 /// Minimum range we can set. @@ -384,17 +409,11 @@ UnregisterSignal(mod.wearer, COMSIG_HIT_BY_SABOTEUR) /obj/item/mod/module/flashlight/on_activation() - . = ..() - if(!.) - return set_light_flags(light_flags | LIGHT_ATTACHED) set_light_on(active) active_power_cost = base_power * light_range /obj/item/mod/module/flashlight/on_deactivation(display_message = TRUE, deleting = FALSE) - . = ..() - if(!.) - return set_light_flags(light_flags & ~LIGHT_ATTACHED) set_light_on(active) @@ -464,15 +483,13 @@ use_energy_cost = DEFAULT_CHARGE_DRAIN * 2 incompatible_modules = list(/obj/item/mod/module/dispenser) cooldown_time = 5 SECONDS + required_slots = list(ITEM_SLOT_GLOVES) /// Path we dispense. var/dispense_type = /obj/item/food/burger/plain /// Time it takes for us to dispense. var/dispense_time = 0 SECONDS /obj/item/mod/module/dispenser/on_use() - . = ..() - if(!.) - return if(dispense_time && !do_after(mod.wearer, dispense_time, target = mod)) balloon_alert(mod.wearer, "interrupted!") return FALSE @@ -494,6 +511,7 @@ complexity = 1 use_energy_cost = DEFAULT_CHARGE_DRAIN * 5 incompatible_modules = list(/obj/item/mod/module/longfall) + required_slots = list(ITEM_SLOT_FEET) /obj/item/mod/module/longfall/on_suit_activation() RegisterSignal(mod.wearer, COMSIG_LIVING_Z_IMPACT, PROC_REF(z_impact_react)) @@ -532,6 +550,7 @@ active_power_cost = DEFAULT_CHARGE_DRAIN * 0.3 incompatible_modules = list(/obj/item/mod/module/thermal_regulator) cooldown_time = 0.5 SECONDS + required_slots = list(ITEM_SLOT_BACK|ITEM_SLOT_BELT) /// The temperature we are regulating to. var/temperature_setting = BODYTEMP_NORMAL /// Minimum temperature we can set. @@ -579,9 +598,6 @@ UnregisterSignal(mod, COMSIG_ATOM_EMAG_ACT) /obj/item/mod/module/dna_lock/on_use() - . = ..() - if(!.) - return dna = mod.wearer.dna.unique_enzymes balloon_alert(mod.wearer, "dna updated") drain_power(use_energy_cost) @@ -640,6 +656,7 @@ idle_power_cost = DEFAULT_CHARGE_DRAIN * 0.3 incompatible_modules = list(/obj/item/mod/module/plasma_stabilizer) overlay_state_inactive = "module_plasma" + required_slots = list(ITEM_SLOT_HEAD) /obj/item/mod/module/plasma_stabilizer/generate_worn_overlay() if(locate(/obj/item/mod/module/infiltrator) in mod.modules) @@ -663,6 +680,7 @@ This is a must-have for Nanotrasen Captains, enabling them to show off their authoritative hat even while in their MODsuit." icon_state = "hat_holder" incompatible_modules = list(/obj/item/mod/module/hat_stabilizer) + required_slots = list(ITEM_SLOT_HEAD) /*Intentionally left inheriting 0 complexity and removable = TRUE; even though it comes inbuilt into the Magnate/Corporate MODS and spawns in maints, I like the idea of stealing them*/ /// Currently "stored" hat. No armor or function will be inherited, only the icon and cover flags. @@ -672,18 +690,24 @@ var/former_visor_flags /obj/item/mod/module/hat_stabilizer/on_suit_activation() - RegisterSignal(mod.helmet, COMSIG_ATOM_EXAMINE, PROC_REF(add_examine)) - RegisterSignal(mod.helmet, COMSIG_ATOM_ATTACKBY, PROC_REF(place_hat)) - RegisterSignal(mod.helmet, COMSIG_ATOM_ATTACK_HAND_SECONDARY, PROC_REF(remove_hat)) + var/obj/item/clothing/helmet = mod.get_part_from_slot(ITEM_SLOT_HEAD) + if(!istype(helmet)) + return + RegisterSignal(helmet, COMSIG_ATOM_EXAMINE, PROC_REF(add_examine)) + RegisterSignal(helmet, COMSIG_ATOM_ATTACKBY, PROC_REF(place_hat)) + RegisterSignal(helmet, COMSIG_ATOM_ATTACK_HAND_SECONDARY, PROC_REF(remove_hat)) /obj/item/mod/module/hat_stabilizer/on_suit_deactivation(deleting = FALSE) if(deleting) return if(attached_hat) //knock off the helmet if its on their head. Or, technically, auto-rightclick it for them; that way it saves us code, AND gives them the bubble remove_hat(src, mod.wearer) - UnregisterSignal(mod.helmet, COMSIG_ATOM_EXAMINE) - UnregisterSignal(mod.helmet, COMSIG_ATOM_ATTACKBY) - UnregisterSignal(mod.helmet, COMSIG_ATOM_ATTACK_HAND_SECONDARY) + var/obj/item/clothing/helmet = mod.get_part_from_slot(ITEM_SLOT_HEAD) + if(!istype(helmet)) + return + UnregisterSignal(helmet, COMSIG_ATOM_EXAMINE) + UnregisterSignal(helmet, COMSIG_ATOM_ATTACKBY) + UnregisterSignal(helmet, COMSIG_ATOM_ATTACK_HAND_SECONDARY) /obj/item/mod/module/hat_stabilizer/proc/add_examine(datum/source, mob/user, list/base_examine) SIGNAL_HANDLER @@ -708,10 +732,12 @@ return if(mod.wearer.transferItemToLoc(hitting_item, src, force = FALSE, silent = TRUE)) attached_hat = hat - former_flags = mod.helmet.flags_cover - former_visor_flags = mod.helmet.visor_flags_cover - mod.helmet.flags_cover |= attached_hat.flags_cover - mod.helmet.visor_flags_cover |= attached_hat.visor_flags_cover + var/obj/item/clothing/helmet = mod.get_part_from_slot(ITEM_SLOT_HEAD) + if(istype(helmet)) + former_flags = helmet.flags_cover + former_visor_flags = helmet.visor_flags_cover + helmet.flags_cover |= attached_hat.flags_cover + helmet.visor_flags_cover |= attached_hat.visor_flags_cover balloon_alert(user, "hat attached, right-click to remove") mod.wearer.update_clothing(mod.slot_flags) @@ -731,10 +757,21 @@ else balloon_alert_to_viewers("the hat falls to the floor!") attached_hat = null - mod.helmet.flags_cover = former_flags - mod.helmet.visor_flags_cover = former_visor_flags + var/obj/item/clothing/helmet = mod.get_part_from_slot(ITEM_SLOT_HEAD) + if(istype(helmet)) + helmet.flags_cover = former_flags + helmet.visor_flags_cover = former_visor_flags mod.wearer.update_clothing(mod.slot_flags) +/obj/item/mod/module/hat_stabilizer/syndicate + name = "MOD elite hat stabilizer module" + desc = "A simple set of deployable stands, directly atop one's head; \ + these will deploy under a hat to keep it from falling off, allowing them to be worn atop the sealed helmet. \ + You still need to take the hat off your head while the helmet deploys, though. This is a must-have for \ + Syndicate Operatives and Agents alike, enabling them to continue to style on the opposition even while in their MODsuit." + complexity = 0 + removable = FALSE + ///Sign Language Translator - allows people to sign over comms using the modsuit's gloves. /obj/item/mod/module/signlang_radio name = "MOD glove translator module" @@ -745,6 +782,7 @@ complexity = 1 idle_power_cost = DEFAULT_CHARGE_DRAIN * 0.3 incompatible_modules = list(/obj/item/mod/module/signlang_radio) + required_slots = list(ITEM_SLOT_GLOVES) /obj/item/mod/module/signlang_radio/on_suit_activation() ADD_TRAIT(mod.wearer, TRAIT_CAN_SIGN_ON_COMMS, MOD_TRAIT) @@ -759,6 +797,7 @@ icon_state = "joint_torsion" complexity = 1 incompatible_modules = list(/obj/item/mod/module/joint_torsion) + required_slots = list(ITEM_SLOT_FEET) var/power_per_step = DEFAULT_CHARGE_DRAIN * 0.3 /obj/item/mod/module/joint_torsion/on_suit_activation() @@ -788,15 +827,6 @@ return mod.core.add_charge(power_per_step) -/obj/item/mod/module/hat_stabilizer/syndicate - name = "MOD elite hat stabilizer module" - desc = "A simple set of deployable stands, directly atop one's head; \ - these will deploy under a hat to keep it from falling off, allowing them to be worn atop the sealed helmet. \ - You still need to take the hat off your head while the helmet deploys, though. This is a must-have for \ - Syndicate Operatives and Agents alike, enabling them to continue to style on the opposition even while in their MODsuit." - complexity = 0 - removable = FALSE - /// Module that shoves garbage inside its material container when the user crosses it, and eject the recycled material with MMB. /obj/item/mod/module/recycler name = "MOD recycler module" @@ -810,6 +840,7 @@ incompatible_modules = list(/obj/item/mod/module/recycler) overlay_state_inactive = "module_recycler" overlay_state_active = "module_recycler" + required_slots = list(ITEM_SLOT_BACK|ITEM_SLOT_BELT) /// A multiplier of the amount of material extracted from the item var/efficiency = 1 /// Items that will be collected diff --git a/code/modules/mod/modules/modules_maint.dm b/code/modules/mod/modules/modules_maint.dm index 1f7c322e031f7..0d45bc4a44db8 100644 --- a/code/modules/mod/modules/modules_maint.dm +++ b/code/modules/mod/modules/modules_maint.dm @@ -10,6 +10,7 @@ icon_state = "springlock" complexity = 3 // it is inside every part of your suit, so incompatible_modules = list(/obj/item/mod/module/springlock) + var/set_off = FALSE /obj/item/mod/module/springlock/on_install() mod.activation_step_time *= 0.5 @@ -27,12 +28,13 @@ /obj/item/mod/module/springlock/proc/on_wearer_exposed(atom/source, list/reagents, datum/reagents/source_reagents, methods, volume_modifier, show_message) SIGNAL_HANDLER - if(!(methods & (VAPOR|PATCH|TOUCH))) + if(!(methods & (VAPOR|PATCH|TOUCH)) || set_off || mod.wearer.stat == DEAD) return //remove non-touch reagent exposure to_chat(mod.wearer, span_danger("[src] makes an ominous click sound...")) playsound(src, 'sound/items/modsuit/springlock.ogg', 75, TRUE) addtimer(CALLBACK(src, PROC_REF(snap_shut)), rand(3 SECONDS, 5 SECONDS)) RegisterSignal(mod, COMSIG_MOD_ACTIVATE, PROC_REF(on_activate_spring_block)) + set_off = TRUE ///Signal fired when wearer attempts to activate/deactivate suits /obj/item/mod/module/springlock/proc/on_activate_spring_block(datum/source, user) @@ -55,6 +57,7 @@ mod.wearer.investigate_log("has been killed by [src].", INVESTIGATE_DEATHS) mod.wearer.death() //just in case, for some reason, they're still alive flash_color(mod.wearer, flash_color = "#FF0000", flash_time = 10 SECONDS) + set_off = FALSE ///Rave Visor - Gives you a rainbow visor and plays jukebox music to you. /obj/item/mod/module/visor/rave @@ -63,6 +66,7 @@ icon_state = "rave_visor" complexity = 1 overlay_state_inactive = "module_rave" + required_slots = list(ITEM_SLOT_HEAD|ITEM_SLOT_MASK) /// The client colors applied to the wearer. var/datum/client_colour/rave_screen /// The current element in the rainbow_order list we are on. @@ -90,17 +94,11 @@ return ..() /obj/item/mod/module/visor/rave/on_activation() - . = ..() - if(!.) - return rave_screen = mod.wearer.add_client_colour(/datum/client_colour/rave) rave_screen.update_colour(rainbow_order[rave_number]) music_player.start_music(mod.wearer) /obj/item/mod/module/visor/rave/on_deactivation(display_message = TRUE, deleting = FALSE) - . = ..() - if(!.) - return QDEL_NULL(rave_screen) if(isnull(music_player.active_song_sound)) return @@ -151,11 +149,9 @@ use_energy_cost = DEFAULT_CHARGE_DRAIN * 5 incompatible_modules = list(/obj/item/mod/module/tanner) cooldown_time = 30 SECONDS + required_slots = list(ITEM_SLOT_OCLOTHING|ITEM_SLOT_ICLOTHING) /obj/item/mod/module/tanner/on_use() - . = ..() - if(!.) - return playsound(src, 'sound/machines/microwave/microwave-end.ogg', 50, TRUE) var/datum/reagents/holder = new() holder.add_reagent(/datum/reagent/spraytan, 10) @@ -174,16 +170,17 @@ use_energy_cost = DEFAULT_CHARGE_DRAIN * 0.5 incompatible_modules = list(/obj/item/mod/module/balloon) cooldown_time = 15 SECONDS + required_slots = list(ITEM_SLOT_HEAD|ITEM_SLOT_MASK) + var/balloon_path = /obj/item/toy/balloon + var/blowing_time = 10 SECONDS + var/oxygen_damage = 20 /obj/item/mod/module/balloon/on_use() - . = ..() - if(!.) - return - if(!do_after(mod.wearer, 10 SECONDS, target = mod)) + if(!do_after(mod.wearer, blowing_time, target = mod)) return FALSE - mod.wearer.adjustOxyLoss(20) + mod.wearer.adjustOxyLoss(oxygen_damage) playsound(src, 'sound/items/modsuit/inflate_bloon.ogg', 50, TRUE) - var/obj/item/toy/balloon/balloon = new(get_turf(src)) + var/obj/item/balloon = new balloon_path(get_turf(src)) mod.wearer.put_in_hands(balloon) drain_power(use_energy_cost) @@ -198,13 +195,11 @@ use_energy_cost = DEFAULT_CHARGE_DRAIN * 0.5 incompatible_modules = list(/obj/item/mod/module/paper_dispenser) cooldown_time = 5 SECONDS + required_slots = list(ITEM_SLOT_GLOVES) /// The total number of sheets created by this MOD. The more sheets, them more likely they set on fire. var/num_sheets_dispensed = 0 /obj/item/mod/module/paper_dispenser/on_use() - . = ..() - if(!.) - return if(!do_after(mod.wearer, 1 SECONDS, target = mod)) return FALSE @@ -243,6 +238,7 @@ device = /obj/item/stamp/mod incompatible_modules = list(/obj/item/mod/module/stamp) cooldown_time = 0.5 SECONDS + required_slots = list(ITEM_SLOT_GLOVES) /obj/item/stamp/mod name = "MOD electronic stamp" @@ -267,15 +263,13 @@ incompatible_modules = list(/obj/item/mod/module/atrocinator, /obj/item/mod/module/magboot, /obj/item/mod/module/anomaly_locked/antigrav) cooldown_time = 0.5 SECONDS overlay_state_inactive = "module_atrocinator" + required_slots = list(ITEM_SLOT_BACK|ITEM_SLOT_BELT) /// How many steps the user has taken since turning the suit on, used for footsteps. var/step_count = 0 /// If you use the module on a planetary turf, you fly up. To the sky. var/you_fucked_up = FALSE /obj/item/mod/module/atrocinator/on_activation() - . = ..() - if(!.) - return playsound(src, 'sound/effects/curseattack.ogg', 50) mod.wearer.AddElement(/datum/element/forced_gravity, NEGATIVE_GRAVITY) RegisterSignal(mod.wearer, COMSIG_MOVABLE_MOVED, PROC_REF(check_upstairs)) @@ -284,14 +278,14 @@ passtable_on(mod.wearer, MOD_TRAIT) check_upstairs() //todo at some point flip your screen around -/obj/item/mod/module/atrocinator/on_deactivation(display_message = TRUE, deleting = FALSE) +/obj/item/mod/module/atrocinator/deactivate(display_message = TRUE, deleting = FALSE) if(you_fucked_up && !deleting) to_chat(mod.wearer, span_danger("It's too late.")) return FALSE - . = ..() - if(!.) - return - if(deleting) + return ..() + +/obj/item/mod/module/atrocinator/on_deactivation(display_message = TRUE, deleting = FALSE) + if(!deleting) playsound(src, 'sound/effects/curseattack.ogg', 50) qdel(mod.wearer.RemoveElement(/datum/element/forced_gravity, NEGATIVE_GRAVITY)) UnregisterSignal(mod.wearer, COMSIG_MOVABLE_MOVED) diff --git a/code/modules/mod/modules/modules_medical.dm b/code/modules/mod/modules/modules_medical.dm index 0e04de51c86cf..3cf1d34a63a83 100644 --- a/code/modules/mod/modules/modules_medical.dm +++ b/code/modules/mod/modules/modules_medical.dm @@ -9,8 +9,7 @@ name = "MOD health analyzer module" desc = "A module installed into the glove of the suit. This is a high-tech biological scanning suite, \ allowing the user indepth information on the vitals and injuries of others even at a distance, \ - all with the flick of the wrist. Data is displayed in a convenient package on HUD in the helmet, \ - but it's up to you to do something with it." + all with the flick of the wrist. Data is displayed in a convenient package, but it's up to you to do something with it." icon_state = "health" module_type = MODULE_ACTIVE complexity = 1 @@ -18,6 +17,7 @@ incompatible_modules = list(/obj/item/mod/module/health_analyzer) cooldown_time = 0.5 SECONDS tgui_id = "health_analyzer" + required_slots = list(ITEM_SLOT_GLOVES) /// Scanning mode, changes how we scan something. var/mode = HEALTH_SCAN @@ -74,6 +74,7 @@ complexity = 1 idle_power_cost = DEFAULT_CHARGE_DRAIN * 0.3 incompatible_modules = list(/obj/item/mod/module/quick_carry, /obj/item/mod/module/constructor) + required_slots = list(ITEM_SLOT_GLOVES) var/quick_carry_trait = TRAIT_QUICK_CARRY /obj/item/mod/module/quick_carry/on_suit_activation() @@ -105,6 +106,7 @@ device = /obj/item/reagent_containers/syringe/mod incompatible_modules = list(/obj/item/mod/module/injector) cooldown_time = 0.5 SECONDS + required_slots = list(ITEM_SLOT_GLOVES) /obj/item/reagent_containers/syringe/mod name = "MOD injector syringe" @@ -131,6 +133,7 @@ use_energy_cost = DEFAULT_CHARGE_DRAIN incompatible_modules = list(/obj/item/mod/module/organ_thrower, /obj/item/mod/module/microwave_beam) cooldown_time = 0.5 SECONDS + required_slots = list(ITEM_SLOT_GLOVES) /// How many organs the module can hold. var/max_organs = 5 /// A list of all our organs. @@ -247,6 +250,7 @@ overlay_state_active = "module_defibrillator_active" incompatible_modules = list(/obj/item/mod/module/defibrillator) cooldown_time = 0.5 SECONDS + required_slots = list(ITEM_SLOT_GLOVES) var/defib_cooldown = 5 SECONDS /obj/item/mod/module/defibrillator/Initialize(mapload) @@ -308,6 +312,7 @@ incompatible_modules = list(/obj/item/mod/module/thread_ripper) cooldown_time = 1.5 SECONDS overlay_state_inactive = "module_threadripper" + required_slots = list(ITEM_SLOT_GLOVES) /// An associated list of ripped clothing and the body part covering slots they covered before var/list/ripped_clothing = list() @@ -357,7 +362,7 @@ playsound(src, 'sound/items/zip.ogg', 25, TRUE) balloon_alert(mod.wearer, "clothing mended") -/obj/item/mod/module/thread_ripper/on_suit_deactivation(deleting) +/obj/item/mod/module/thread_ripper/on_suit_deactivation(deleting = FALSE) if(!length(ripped_clothing)) return for(var/obj/item/clothing as anything in ripped_clothing) diff --git a/code/modules/mod/modules/modules_ninja.dm b/code/modules/mod/modules/modules_ninja.dm index d52a5e1fb4c43..a868eb6205659 100644 --- a/code/modules/mod/modules/modules_ninja.dm +++ b/code/modules/mod/modules/modules_ninja.dm @@ -13,15 +13,13 @@ use_energy_cost = DEFAULT_CHARGE_DRAIN * 10 incompatible_modules = list(/obj/item/mod/module/stealth) cooldown_time = 5 SECONDS + required_slots = list(ITEM_SLOT_BACK|ITEM_SLOT_BELT) /// Whether or not the cloak turns off on bumping. var/bumpoff = TRUE /// The alpha applied when the cloak is on. var/stealth_alpha = 50 /obj/item/mod/module/stealth/on_activation() - . = ..() - if(!.) - return if(bumpoff) RegisterSignal(mod.wearer, COMSIG_LIVING_MOB_BUMP, PROC_REF(unstealth)) RegisterSignal(mod.wearer, COMSIG_LIVING_UNARMED_ATTACK, PROC_REF(on_unarmed_attack)) @@ -31,9 +29,6 @@ drain_power(use_energy_cost) /obj/item/mod/module/stealth/on_deactivation(display_message = TRUE, deleting = FALSE) - . = ..() - if(!.) - return if(bumpoff) UnregisterSignal(mod.wearer, COMSIG_LIVING_MOB_BUMP) UnregisterSignal(mod.wearer, list(COMSIG_LIVING_UNARMED_ATTACK, COMSIG_MOB_ITEM_ATTACK, COMSIG_ATOM_ATTACKBY, COMSIG_ATOM_ATTACK_HAND, COMSIG_ATOM_BULLET_ACT, COMSIG_ATOM_HITBY, COMSIG_ATOM_HULK_ATTACK, COMSIG_ATOM_ATTACK_PAW, COMSIG_CARBON_CUFF_ATTEMPTED)) @@ -45,7 +40,7 @@ to_chat(mod.wearer, span_warning("[src] gets discharged from contact!")) do_sparks(2, TRUE, src) drain_power(use_energy_cost) - on_deactivation(display_message = TRUE, deleting = FALSE) + deactivate() /obj/item/mod/module/stealth/proc/on_unarmed_attack(datum/source, atom/target) SIGNAL_HANDLER @@ -99,6 +94,7 @@ removable = FALSE complexity = 0 overlay_state_inactive = null + required_slots = list(ITEM_SLOT_HEAD|ITEM_SLOT_EYES|ITEM_SLOT_MASK) /obj/item/mod/module/welding/camera_vision/on_suit_activation() . = ..() @@ -133,6 +129,7 @@ icon_state = "hacker" removable = FALSE incompatible_modules = list(/obj/item/mod/module/hacker) + required_slots = list(ITEM_SLOT_GLOVES) /// Whether or not the communication console hack was used to summon another antagonist. var/communication_console_hack_success = FALSE /// How many times the module has been used to force open doors. @@ -173,6 +170,7 @@ use_energy_cost = DEFAULT_CHARGE_DRAIN * 2 incompatible_modules = list(/obj/item/mod/module/weapon_recall) cooldown_time = 0.5 SECONDS + required_slots = list(ITEM_SLOT_GLOVES, ITEM_SLOT_BACK|ITEM_SLOT_BELT) /// The item linked to the module that will get recalled. var/obj/item/linked_weapon /// The accepted typepath we can link to. @@ -185,9 +183,6 @@ REMOVE_TRAIT(mod.wearer, TRAIT_NOGUNS, MOD_TRAIT) /obj/item/mod/module/weapon_recall/on_use() - . = ..() - if(!.) - return if(!linked_weapon) var/obj/item/weapon_to_link = mod.wearer.is_holding_item_of_type(accepted_type) if(!weapon_to_link) @@ -288,9 +283,6 @@ cooldown_time = 8 SECONDS /obj/item/mod/module/emp_shield/pulse/on_use() - . = ..() - if(!.) - return playsound(src, 'sound/effects/empulse.ogg', 60, TRUE) empulse(src, heavy_range = 4, light_range = 6) drain_power(use_energy_cost) @@ -320,6 +312,7 @@ use_energy_cost = DEFAULT_CHARGE_DRAIN * 6 incompatible_modules = list(/obj/item/mod/module/energy_net) cooldown_time = 5 SECONDS + required_slots = list(ITEM_SLOT_GLOVES) /// List of all energy nets this module made. var/list/energy_nets = list() @@ -404,6 +397,7 @@ allow_flags = MODULE_ALLOW_INCAPACITATED incompatible_modules = list(/obj/item/mod/module/adrenaline_boost) cooldown_time = 12 SECONDS + required_slots = list(ITEM_SLOT_BACK|ITEM_SLOT_BELT) /// What reagent we need to refill? var/reagent_required = /datum/reagent/uranium/radium /// How much of a reagent we need to refill the boost. @@ -414,13 +408,13 @@ create_reagents(reagent_required_amount) reagents.add_reagent(reagent_required, reagent_required_amount) -/obj/item/mod/module/adrenaline_boost/on_use() +/obj/item/mod/module/adrenaline_boost/used() if(!reagents.has_reagent(reagent_required, reagent_required_amount)) balloon_alert(mod.wearer, "no charge!") - return - . = ..() - if(!.) - return + return FALSE + return ..() + +/obj/item/mod/module/adrenaline_boost/on_use() if(IS_SPACE_NINJA(mod.wearer)) mod.wearer.say(pick_list_replacements(NINJA_FILE, "lines"), forced = type) to_chat(mod.wearer, span_notice("You have used the adrenaline boost.")) @@ -438,7 +432,7 @@ /obj/item/mod/module/adrenaline_boost/on_install() RegisterSignal(mod, COMSIG_ATOM_ATTACKBY, PROC_REF(on_attackby)) -/obj/item/mod/module/adrenaline_boost/on_uninstall(deleting) +/obj/item/mod/module/adrenaline_boost/on_uninstall(deleting = FALSE) UnregisterSignal(mod, COMSIG_ATOM_ATTACKBY) /obj/item/mod/module/adrenaline_boost/attackby(obj/item/attacking_item, mob/user, params) diff --git a/code/modules/mod/modules/modules_science.dm b/code/modules/mod/modules/modules_science.dm index a5a56975f6c53..9f2c54b8effc3 100644 --- a/code/modules/mod/modules/modules_science.dm +++ b/code/modules/mod/modules/modules_science.dm @@ -12,17 +12,12 @@ active_power_cost = DEFAULT_CHARGE_DRAIN * 0.2 incompatible_modules = list(/obj/item/mod/module/reagent_scanner) cooldown_time = 0.5 SECONDS + required_slots = list(ITEM_SLOT_HEAD|ITEM_SLOT_EYES|ITEM_SLOT_MASK) /obj/item/mod/module/reagent_scanner/on_activation() - . = ..() - if(!.) - return ADD_TRAIT(mod.wearer, TRAIT_REAGENT_SCANNER, MOD_TRAIT) /obj/item/mod/module/reagent_scanner/on_deactivation(display_message = TRUE, deleting = FALSE) - . = ..() - if(!.) - return REMOVE_TRAIT(mod.wearer, TRAIT_REAGENT_SCANNER, MOD_TRAIT) /obj/item/mod/module/reagent_scanner/advanced @@ -32,16 +27,10 @@ var/explosion_detection_dist = 21 /obj/item/mod/module/reagent_scanner/advanced/on_activation() - . = ..() - if(!.) - return ADD_TRAIT(mod.wearer, TRAIT_RESEARCH_SCANNER, MOD_TRAIT) RegisterSignal(SSdcs, COMSIG_GLOB_EXPLOSION, PROC_REF(sense_explosion)) /obj/item/mod/module/reagent_scanner/advanced/on_deactivation(display_message = TRUE, deleting = FALSE) - . = ..() - if(!.) - return REMOVE_TRAIT(mod.wearer, TRAIT_RESEARCH_SCANNER, MOD_TRAIT) UnregisterSignal(SSdcs, COMSIG_GLOB_EXPLOSION) @@ -66,20 +55,15 @@ incompatible_modules = list(/obj/item/mod/module/anomaly_locked, /obj/item/mod/module/atrocinator) cooldown_time = 0.5 SECONDS accepted_anomalies = list(/obj/item/assembly/signaler/anomaly/grav) + required_slots = list(ITEM_SLOT_BACK|ITEM_SLOT_BELT) /obj/item/mod/module/anomaly_locked/antigrav/on_activation() - . = ..() - if(!.) - return if(mod.wearer.has_gravity()) new /obj/effect/temp_visual/mook_dust(get_turf(src)) mod.wearer.AddElement(/datum/element/forced_gravity, 0) playsound(src, 'sound/effects/gravhit.ogg', 50) /obj/item/mod/module/anomaly_locked/antigrav/on_deactivation(display_message = TRUE, deleting = FALSE) - . = ..() - if(!.) - return mod.wearer.RemoveElement(/datum/element/forced_gravity, 0) if(deleting) return @@ -103,6 +87,7 @@ use_energy_cost = DEFAULT_CHARGE_DRAIN * 5 cooldown_time = 5 SECONDS accepted_anomalies = list(/obj/item/assembly/signaler/anomaly/bluespace) + required_slots = list(ITEM_SLOT_BACK|ITEM_SLOT_BELT) /// Time it takes to teleport var/teleport_time = 3 SECONDS diff --git a/code/modules/mod/modules/modules_security.dm b/code/modules/mod/modules/modules_security.dm index 6d91b24469ba0..2a317becf18e6 100644 --- a/code/modules/mod/modules/modules_security.dm +++ b/code/modules/mod/modules/modules_security.dm @@ -8,6 +8,7 @@ complexity = 2 use_energy_cost = DEFAULT_CHARGE_DRAIN incompatible_modules = list(/obj/item/mod/module/magnetic_harness) + required_slots = list(ITEM_SLOT_OCLOTHING) /// Time before we activate the magnet. var/magnet_delay = 0.8 SECONDS /// The typecache of all guns we allow. @@ -21,13 +22,19 @@ guns_typecache = typecacheof(list(/obj/item/gun/ballistic, /obj/item/gun/energy, /obj/item/gun/grenadelauncher, /obj/item/gun/chem, /obj/item/gun/syringe)) /obj/item/mod/module/magnetic_harness/on_install() - already_allowed_guns = guns_typecache & mod.chestplate.allowed - mod.chestplate.allowed |= guns_typecache + var/obj/item/clothing/suit = mod.get_part_from_slot(ITEM_SLOT_OCLOTHING) + if(!istype(suit)) + return + already_allowed_guns = guns_typecache & suit.allowed + suit.allowed |= guns_typecache /obj/item/mod/module/magnetic_harness/on_uninstall(deleting = FALSE) if(deleting) return - mod.chestplate.allowed -= (guns_typecache - already_allowed_guns) + var/obj/item/clothing/suit = mod.get_part_from_slot(ITEM_SLOT_OCLOTHING) + if(!istype(suit)) + return + suit.allowed -= (guns_typecache - already_allowed_guns) /obj/item/mod/module/magnetic_harness/on_suit_activation() RegisterSignal(mod.wearer, COMSIG_MOB_UNEQUIPPED_ITEM, PROC_REF(check_dropped_item)) @@ -65,6 +72,7 @@ cooldown_time = 5 SECONDS overlay_state_inactive = "module_pepper" overlay_state_use = "module_pepper_used" + required_slots = list(ITEM_SLOT_OCLOTHING) /obj/item/mod/module/pepper_shoulders/on_suit_activation() RegisterSignal(mod.wearer, COMSIG_LIVING_CHECK_BLOCK, PROC_REF(on_check_block)) @@ -73,9 +81,6 @@ UnregisterSignal(mod.wearer, COMSIG_LIVING_CHECK_BLOCK) /obj/item/mod/module/pepper_shoulders/on_use() - . = ..() - if(!.) - return playsound(src, 'sound/effects/spray.ogg', 30, TRUE, -6) var/datum/reagents/capsaicin_holder = new(10) capsaicin_holder.add_reagent(/datum/reagent/consumable/condensedcapsaicin, 10) @@ -92,7 +97,7 @@ if(!check_power(use_energy_cost)) return mod.wearer.visible_message(span_warning("[src] reacts to the attack with a smoke of pepper spray!"), span_notice("Your [src] releases a cloud of pepper spray!")) - on_use() + used() ///Holster - Instantly holsters any not huge gun. /obj/item/mod/module/holster @@ -107,13 +112,11 @@ incompatible_modules = list(/obj/item/mod/module/holster) cooldown_time = 0.5 SECONDS allow_flags = MODULE_ALLOW_INACTIVE + required_slots = list(ITEM_SLOT_OCLOTHING|ITEM_SLOT_GLOVES|ITEM_SLOT_FEET) /// Gun we have holstered. var/obj/item/gun/holstered /obj/item/mod/module/holster/on_use() - . = ..() - if(!.) - return if(!holstered) var/obj/item/gun/holding = mod.wearer.get_active_held_item() if(!holding) @@ -155,19 +158,14 @@ use_energy_cost = DEFAULT_CHARGE_DRAIN * 0.5 incompatible_modules = list(/obj/item/mod/module/megaphone) cooldown_time = 0.5 SECONDS + required_slots = list(ITEM_SLOT_HEAD|ITEM_SLOT_EYES|ITEM_SLOT_MASK) /// List of spans we add to the speaker. var/list/voicespan = list(SPAN_COMMAND) /obj/item/mod/module/megaphone/on_activation() - . = ..() - if(!.) - return RegisterSignal(mod.wearer, COMSIG_MOB_SAY, PROC_REF(handle_speech)) /obj/item/mod/module/megaphone/on_deactivation(display_message = TRUE, deleting = FALSE) - . = ..() - if(!.) - return UnregisterSignal(mod.wearer, COMSIG_MOB_SAY) /obj/item/mod/module/megaphone/proc/handle_speech(datum/source, list/speech_args) @@ -190,6 +188,7 @@ use_energy_cost = DEFAULT_CHARGE_DRAIN * 0.5 incompatible_modules = list(/obj/item/mod/module/criminalcapture) cooldown_time = 0.5 SECONDS + required_slots = list(ITEM_SLOT_BACK|ITEM_SLOT_BELT) /// Time to capture a prisoner. var/capture_time = 2.5 SECONDS /// Time to dematerialize a bodybag. @@ -203,10 +202,7 @@ idle_power_cost = linked_bodybag ? (DEFAULT_CHARGE_DRAIN * 3) : 0 return ..() -/obj/item/mod/module/criminalcapture/on_deactivation(display_message, deleting) - . = ..() - if(!.) - return +/obj/item/mod/module/criminalcapture/on_deactivation(display_message = TRUE, deleting = FALSE) if(!linked_bodybag) return packup() @@ -273,9 +269,6 @@ dispense_type = /obj/item/grenade/mirage /obj/item/mod/module/dispenser/mirage/on_use() - . = ..() - if(!.) - return var/obj/item/grenade/mirage/grenade = . grenade.arm_grenade(mod.wearer) @@ -310,6 +303,7 @@ active_power_cost = DEFAULT_CHARGE_DRAIN incompatible_modules = list(/obj/item/mod/module/projectile_dampener) cooldown_time = 1.5 SECONDS + required_slots = list(ITEM_SLOT_BACK|ITEM_SLOT_BELT) /// Radius of the dampening field. var/field_radius = 2 /// Damage multiplier on projectiles. @@ -328,9 +322,6 @@ projectile_effect = image('icons/effects/fields.dmi', "projectile_dampen_effect") /obj/item/mod/module/projectile_dampener/on_activation() - . = ..() - if(!.) - return if(istype(dampening_field)) QDEL_NULL(dampening_field) dampening_field = new(mod.wearer, field_radius, TRUE, src) @@ -370,6 +361,7 @@ complexity = 2 incompatible_modules = list(/obj/item/mod/module/active_sonar) cooldown_time = 15 SECONDS + required_slots = list(ITEM_SLOT_HEAD|ITEM_SLOT_EYES|ITEM_SLOT_MASK) /// Time between us displaying radial scans var/scan_cooldown_time = 0.5 SECONDS /// The current slice we're going to scan @@ -454,9 +446,6 @@ COOLDOWN_START(src, scan_cooldown, scan_cooldown_time) /obj/item/mod/module/active_sonar/on_use() - . = ..() - if(!.) - return balloon_alert(mod.wearer, "readying sonar...") playsound(mod.wearer, 'sound/mecha/skyfall_power_up.ogg', vol = 20, vary = TRUE, extrarange = SHORT_RANGE_SOUND_EXTRARANGE) if(!do_after(mod.wearer, 1.1 SECONDS, target = mod)) @@ -486,6 +475,7 @@ module_type = MODULE_PASSIVE complexity = 3 incompatible_modules = list(/obj/item/mod/module/shooting_assistant) + required_slots = list(ITEM_SLOT_GLOVES) var/selected_mode = SHOOTING_ASSISTANT_OFF ///Association list, the assoc values are the balloon alerts shown to the user when the mode is set. var/static/list/available_modes = list( @@ -585,6 +575,7 @@ icon_state = "bulwark" complexity = 3 incompatible_modules = list(/obj/item/mod/module/shove_blocker) + required_slots = list(ITEM_SLOT_OCLOTHING) /obj/item/mod/module/shove_blocker/on_suit_activation() mod.wearer.add_traits(list(TRAIT_BRAWLING_KNOCKDOWN_BLOCKED, TRAIT_NO_STAGGER, TRAIT_NO_THROW_HITPUSH), MOD_TRAIT) @@ -603,6 +594,7 @@ desc = "Enhanced gauntlent grip pads that help with placing individuals in restraints more quickly. Doesn't look like they'll come off." removable = FALSE complexity = 0 + required_slots = list(ITEM_SLOT_GLOVES) /obj/item/mod/module/quick_cuff/on_suit_activation() . = ..() diff --git a/code/modules/mod/modules/modules_service.dm b/code/modules/mod/modules/modules_service.dm index be71c62180298..044137f0f2d07 100644 --- a/code/modules/mod/modules/modules_service.dm +++ b/code/modules/mod/modules/modules_service.dm @@ -13,36 +13,17 @@ cooldown_time = 1 SECONDS /obj/item/mod/module/bikehorn/on_use() - . = ..() - if(!.) - return playsound(src, 'sound/items/bikehorn.ogg', 100, FALSE) drain_power(use_energy_cost) ///Advanced Balloon Blower - Blows a long balloon. -/obj/item/mod/module/balloon_advanced +/obj/item/mod/module/balloon/advanced name = "MOD advanced balloon blower module" desc = "A relatively new piece of technology developed by finest clown engineers to make long balloons and balloon animals \ - at party-appropriate rate." - icon_state = "bloon" - module_type = MODULE_USABLE - complexity = 1 - use_energy_cost = DEFAULT_CHARGE_DRAIN * 0.5 - incompatible_modules = list(/obj/item/mod/module/balloon_advanced) - cooldown_time = 15 SECONDS - -/obj/item/mod/module/balloon_advanced/on_use() - . = ..() - if(!.) - return - if(!do_after(mod.wearer, 15 SECONDS, target = mod)) - return FALSE - mod.wearer.adjustOxyLoss(20) - playsound(src, 'sound/items/modsuit/inflate_bloon.ogg', 50, TRUE) - var/obj/item/toy/balloon/long/l_balloon = new(get_turf(src)) - mod.wearer.put_in_hands(l_balloon) - drain_power(use_energy_cost) - + at party-appropriate rate." + cooldown_time = 20 SECONDS + balloon_path = /obj/item/toy/balloon/long + blowing_time = 15 SECONDS ///Microwave Beam - Microwaves items instantly. /obj/item/mod/module/microwave_beam @@ -56,6 +37,7 @@ use_energy_cost = DEFAULT_CHARGE_DRAIN * 5 incompatible_modules = list(/obj/item/mod/module/microwave_beam, /obj/item/mod/module/organ_thrower) cooldown_time = 10 SECONDS + required_slots = list(ITEM_SLOT_GLOVES) /obj/item/mod/module/microwave_beam/on_select_use(atom/target) . = ..() @@ -84,7 +66,7 @@ /obj/item/mod/module/waddle name = "MOD waddle module" desc = "Some of the most primitive technology in use by Honk Co. This module works off an automatic intention system, \ - utilizing its' sensitivity to the pilot's often-limited brainwaves to directly read their next step, \ + utilizing its sensitivity to the pilot's often-limited brainwaves to directly read their next step, \ affecting the boots they're installed in. Employing a twin-linked gravitonic drive to create \ miniaturized etheric blasts of space-time beneath the user's feet, this enables them to... \ to waddle around, bouncing to and fro with a pep in their step." @@ -92,16 +74,20 @@ complexity = 1 idle_power_cost = DEFAULT_CHARGE_DRAIN * 0.2 incompatible_modules = list(/obj/item/mod/module/waddle) + required_slots = list(ITEM_SLOT_FEET) /obj/item/mod/module/waddle/on_suit_activation() - mod.boots.AddComponent(/datum/component/squeak, list('sound/effects/footstep/clownstep1.ogg'=1,'sound/effects/footstep/clownstep2.ogg'=1), 50, falloff_exponent = 20) //die off quick please + var/obj/item/shoes = mod.get_part_from_slot(ITEM_SLOT_FEET) + if(shoes) + shoes.AddComponent(/datum/component/squeak, list('sound/effects/footstep/clownstep1.ogg'=1,'sound/effects/footstep/clownstep2.ogg'=1), 50, falloff_exponent = 20) //die off quick please mod.wearer.AddElementTrait(TRAIT_WADDLING, MOD_TRAIT, /datum/element/waddling) if(is_clown_job(mod.wearer.mind?.assigned_role)) mod.wearer.add_mood_event("clownshoes", /datum/mood_event/clownshoes) /obj/item/mod/module/waddle/on_suit_deactivation(deleting = FALSE) - if(!deleting) - qdel(mod.boots.GetComponent(/datum/component/squeak)) + var/obj/item/shoes = mod.get_part_from_slot(ITEM_SLOT_FEET) + if(shoes && !deleting) + qdel(shoes.GetComponent(/datum/component/squeak)) REMOVE_TRAIT(mod.wearer, TRAIT_WADDLING, MOD_TRAIT) if(is_clown_job(mod.wearer.mind?.assigned_role)) mod.wearer.clear_mood_event("clownshoes") diff --git a/code/modules/mod/modules/modules_supply.dm b/code/modules/mod/modules/modules_supply.dm index de1efdcc4e2fd..c86cb182c6b84 100644 --- a/code/modules/mod/modules/modules_supply.dm +++ b/code/modules/mod/modules/modules_supply.dm @@ -19,9 +19,6 @@ AddComponent(/datum/component/gps/item, "MOD0", state = GLOB.deep_inventory_state, overlay_state = FALSE) /obj/item/mod/module/gps/on_use() - . = ..() - if(!.) - return attack_self(mod.wearer) ///Hydraulic Clamp - Lets you pick up and drop crates. @@ -38,6 +35,7 @@ cooldown_time = 0.5 SECONDS overlay_state_inactive = "module_clamp" overlay_state_active = "module_clamp_on" + required_slots = list(ITEM_SLOT_GLOVES, ITEM_SLOT_BACK) /// Time it takes to load a crate. var/load_time = 3 SECONDS /// The max amount of crates you can carry. @@ -110,6 +108,7 @@ load_time = 1 SECONDS max_crates = 5 use_mod_colors = TRUE + required_slots = list(ITEM_SLOT_BACK) ///Drill - Lets you dig through rock and basalt. /obj/item/mod/module/drill @@ -123,17 +122,12 @@ incompatible_modules = list(/obj/item/mod/module/drill) cooldown_time = 0.5 SECONDS overlay_state_active = "module_drill" + required_slots = list(ITEM_SLOT_GLOVES) /obj/item/mod/module/drill/on_activation() - . = ..() - if(!.) - return RegisterSignal(mod.wearer, COMSIG_MOVABLE_BUMP, PROC_REF(bump_mine)) /obj/item/mod/module/drill/on_deactivation(display_message = TRUE, deleting = FALSE) - . = ..() - if(!.) - return UnregisterSignal(mod.wearer, COMSIG_MOVABLE_BUMP) /obj/item/mod/module/drill/on_select_use(atom/target) @@ -180,6 +174,7 @@ incompatible_modules = list(/obj/item/mod/module/orebag) cooldown_time = 0.5 SECONDS allow_flags = MODULE_ALLOW_INACTIVE + required_slots = list(ITEM_SLOT_BACK) /// The ores stored in the bag. var/list/ores = list() @@ -208,9 +203,6 @@ ores += ore /obj/item/mod/module/orebag/on_use() - . = ..() - if(!.) - return for(var/obj/item/ore as anything in ores) ore.forceMove(drop_location()) ores -= ore @@ -228,6 +220,7 @@ overlay_state_inactive = "module_hydraulic" overlay_state_active = "module_hydraulic_active" use_mod_colors = TRUE + required_slots = list(ITEM_SLOT_BACK) /// Time it takes to launch var/launch_time = 2 SECONDS /// User overlay @@ -316,6 +309,7 @@ cooldown_time = 1.5 SECONDS overlay_state_active = "module_magnet" use_mod_colors = TRUE + required_slots = list(ITEM_SLOT_BACK) /obj/item/mod/module/magnet/on_select_use(atom/target) . = ..() @@ -340,9 +334,6 @@ callback = CALLBACK(src, PROC_REF(check_locker), locker)) /obj/item/mod/module/magnet/on_deactivation(display_message = TRUE, deleting = FALSE) - . = ..() - if(!.) - return if(istype(mod.wearer.pulling, /obj/structure/closet)) mod.wearer.stop_pulling() @@ -370,6 +361,7 @@ incompatible_modules = list(/obj/item/mod/module/ash_accretion) overlay_state_inactive = "module_ash" use_mod_colors = TRUE + required_slots = list(ITEM_SLOT_OCLOTHING|ITEM_SLOT_ICLOTHING) /// How many tiles we can travel to max out the armor. var/max_traveled_tiles = 10 /// How many tiles we traveled through. @@ -423,9 +415,8 @@ UnregisterSignal(mod.wearer, COMSIG_MOVABLE_MOVED) if(!traveled_tiles) return - var/list/parts = mod.mod_parts + mod var/datum/armor/to_remove = get_armor_by_type(armor_mod) - for(var/obj/item/part as anything in parts) + for(var/obj/item/part as anything in mod.get_parts(all = TRUE)) part.set_armor(part.get_armor().subtract_other_armor(to_remove.generate_new_with_multipliers(list(ARMOR_ALL = traveled_tiles)))) if(traveled_tiles == max_traveled_tiles) mod.slowdown += speed_added @@ -445,8 +436,7 @@ if(traveled_tiles >= max_traveled_tiles) return traveled_tiles++ - var/list/parts = mod.mod_parts + mod - for(var/obj/item/part as anything in parts) + for(var/obj/item/part as anything in mod.get_parts(all = TRUE)) part.set_armor(part.get_armor().add_other_armor(armor_mod)) if(traveled_tiles >= max_traveled_tiles) balloon_alert(mod.wearer, "fully ash covered") @@ -465,8 +455,7 @@ mod.slowdown += actual_speed_added mod.wearer.update_equipment_speed_mods() traveled_tiles-- - var/list/parts = mod.mod_parts + mod - for(var/obj/item/part as anything in parts) + for(var/obj/item/part as anything in mod.get_parts(all = TRUE)) part.set_armor(part.get_armor().subtract_other_armor(armor_mod)) if(traveled_tiles <= 0) balloon_alert(mod.wearer, "ran out of ash!") @@ -482,6 +471,7 @@ use_energy_cost = DEFAULT_CHARGE_DRAIN * 3 incompatible_modules = list(/obj/item/mod/module/sphere_transform) cooldown_time = 1.25 SECONDS + required_slots = list(ITEM_SLOT_OCLOTHING|ITEM_SLOT_ICLOTHING, ITEM_SLOT_HEAD|ITEM_SLOT_MASK) /// Time it takes us to complete the animation. var/animate_time = 0.25 SECONDS /// List of traits to add/remove from our subject as needed. @@ -492,13 +482,13 @@ TRAIT_NO_SLIP_ALL, ) -/obj/item/mod/module/sphere_transform/on_activation() +/obj/item/mod/module/sphere_transform/activate() if(!mod.wearer.has_gravity()) balloon_alert(mod.wearer, "no gravity!") return FALSE - . = ..() - if(!.) - return + return ..() + +/obj/item/mod/module/sphere_transform/on_activation() playsound(src, 'sound/items/modsuit/ballin.ogg', 100, TRUE) mod.wearer.add_filter("mod_ball", 1, alpha_mask_filter(icon = icon('icons/mob/clothing/modsuit/mod_modules.dmi', "ball_mask"), flags = MASK_INVERSE)) mod.wearer.add_filter("mod_blur", 2, angular_blur_filter(size = 15)) @@ -513,9 +503,6 @@ RegisterSignal(mod.wearer, COMSIG_MOB_STATCHANGE, PROC_REF(on_statchange)) /obj/item/mod/module/sphere_transform/on_deactivation(display_message = TRUE, deleting = FALSE) - . = ..() - if(!.) - return if(!deleting) playsound(src, 'sound/items/modsuit/ballin.ogg', 100, TRUE, frequency = -1) mod.wearer.base_pixel_y += 4 @@ -528,7 +515,7 @@ mod.wearer.remove_movespeed_modifier(/datum/movespeed_modifier/sphere) UnregisterSignal(mod.wearer, COMSIG_MOB_STATCHANGE) -/obj/item/mod/module/sphere_transform/on_use() +/obj/item/mod/module/sphere_transform/used() if(!lavaland_equipment_pressure_check(get_turf(src))) balloon_alert(mod.wearer, "too much pressure!") playsound(src, 'sound/weapons/gun/general/dry_fire.ogg', 25, TRUE) @@ -550,14 +537,14 @@ animate(mod.wearer) //stop the animation mod.wearer.SpinAnimation(1.5) //start it back again if(!mod.wearer.has_gravity()) - on_deactivation() //deactivate in no grav + deactivate() //deactivate in no grav /obj/item/mod/module/sphere_transform/proc/on_statchange(datum/source) SIGNAL_HANDLER if(!mod.wearer.stat) return - on_deactivation() + deactivate() /obj/projectile/bullet/mining_bomb name = "mining bomb" diff --git a/code/modules/mod/modules/modules_timeline.dm b/code/modules/mod/modules/modules_timeline.dm index 4e4d751065c71..522ddf57501d1 100644 --- a/code/modules/mod/modules/modules_timeline.dm +++ b/code/modules/mod/modules/modules_timeline.dm @@ -28,9 +28,6 @@ UnregisterSignal(mod, COMSIG_MOD_MODULE_REMOVAL) /obj/item/mod/module/eradication_lock/on_use() - . = ..() - if(!.) - return true_owner_ckey = mod.wearer.ckey balloon_alert(mod.wearer, "user remembered") drain_power(use_energy_cost) @@ -65,11 +62,9 @@ use_energy_cost = DEFAULT_CHARGE_DRAIN * 5 incompatible_modules = list(/obj/item/mod/module/rewinder) cooldown_time = 20 SECONDS + required_slots = list(ITEM_SLOT_BACK) /obj/item/mod/module/rewinder/on_use() - . = ..() - if(!.) - return balloon_alert(mod.wearer, "anchor point set") playsound(src, 'sound/items/modsuit/time_anchor_set.ogg', 50, TRUE) //stops all mods from triggering during rewinding @@ -109,16 +104,17 @@ use_energy_cost = DEFAULT_CHARGE_DRAIN * 5 incompatible_modules = list(/obj/item/mod/module/timestopper) cooldown_time = 60 SECONDS + required_slots = list(ITEM_SLOT_BACK) ///The current timestop in progress. var/obj/effect/timestop/channelled/timestop -/obj/item/mod/module/timestopper/on_use() - . = ..() - if(!.) - return +/obj/item/mod/module/timestopper/used() if(timestop) mod.balloon_alert(mod.wearer, "already freezing time!") - return + return FALSE + return ..() + +/obj/item/mod/module/timestopper/on_use() //stops all mods from triggering during timestop- including timestop itself for(var/obj/item/mod/module/module as anything in mod.modules) RegisterSignal(module, COMSIG_MODULE_TRIGGERED, PROC_REF(on_module_triggered)) @@ -157,18 +153,18 @@ incompatible_modules = list(/obj/item/mod/module/timeline_jumper) cooldown_time = 5 SECONDS allow_flags = MODULE_ALLOW_PHASEOUT + required_slots = list(ITEM_SLOT_BACK) ///The dummy for phasing from this module, the wearer is phased out while this exists. var/obj/effect/dummy/phased_mob/chrono/phased_mob -/obj/item/mod/module/timeline_jumper/on_use() - . = ..() - if(!.) - return +/obj/item/mod/module/timeline_jumper/used() var/area/noteleport_check = get_area(mod.wearer) if(noteleport_check && noteleport_check.area_flags & NOTELEPORT) to_chat(mod.wearer, span_danger("Some dull, universal force is between you and the [phased_mob ? "current timeline" : "stream between timelines"].")) return FALSE + return ..() +/obj/item/mod/module/timeline_jumper/on_use() if(!phased_mob) //phasing out mod.visible_message(span_warning("[mod.wearer] leaps out of the timeline!")) @@ -210,6 +206,7 @@ use_energy_cost = DEFAULT_CHARGE_DRAIN * 5 incompatible_modules = list(/obj/item/mod/module/tem) cooldown_time = 0.5 SECONDS + required_slots = list(ITEM_SLOT_BACK) ///Reference to the chrono field being controlled by this module var/obj/structure/chrono_field/field = null ///Where the chronofield maker was when the field went up diff --git a/code/modules/mod/modules/modules_visor.dm b/code/modules/mod/modules/modules_visor.dm index e8656fe92331a..4527fa631a65c 100644 --- a/code/modules/mod/modules/modules_visor.dm +++ b/code/modules/mod/modules/modules_visor.dm @@ -9,15 +9,13 @@ active_power_cost = DEFAULT_CHARGE_DRAIN * 0.3 incompatible_modules = list(/obj/item/mod/module/visor) cooldown_time = 0.5 SECONDS + required_slots = list(ITEM_SLOT_HEAD|ITEM_SLOT_EYES|ITEM_SLOT_MASK) /// The HUD type given by the visor. var/hud_type /// The traits given by the visor. var/list/visor_traits = list() /obj/item/mod/module/visor/on_activation() - . = ..() - if(!.) - return if(hud_type) var/datum/atom_hud/hud = GLOB.huds[hud_type] hud.show_to(mod.wearer) @@ -26,9 +24,6 @@ mod.wearer.update_sight() /obj/item/mod/module/visor/on_deactivation(display_message = TRUE, deleting = FALSE) - . = ..() - if(!.) - return if(hud_type) var/datum/atom_hud/hud = GLOB.huds[hud_type] hud.hide_from(mod.wearer) diff --git a/code/modules/unit_tests/modsuit.dm b/code/modules/unit_tests/modsuit.dm index 0dfc9815117d4..33aedb9ce49be 100644 --- a/code/modules/unit_tests/modsuit.dm +++ b/code/modules/unit_tests/modsuit.dm @@ -7,10 +7,6 @@ for(var/modpath in paths) var/obj/item/mod/control/pre_equipped/mod = new modpath() TEST_ASSERT(mod.theme, "[modpath] spawned without a theme.") - TEST_ASSERT(mod.helmet, "[modpath] spawned without a helmet.") - TEST_ASSERT(mod.chestplate, "[modpath] spawned without a chestplate.") - TEST_ASSERT(mod.gauntlets, "[modpath] spawned without gauntlets.") - TEST_ASSERT(mod.boots, "[modpath] spawned without boots.") var/list/modules = list() var/complexity_max = mod.complexity_max var/complexity = 0 @@ -18,6 +14,7 @@ module = new module() complexity += module.complexity TEST_ASSERT(complexity <= complexity_max, "[modpath] starting modules reach above max complexity.") + TEST_ASSERT(module.has_required_parts(mod.mod_parts), "[modpath] initial module [module.type] is not supported by its parts.") for(var/obj/item/mod/module/module_to_check as anything in modules) TEST_ASSERT(!is_type_in_list(module, module_to_check.incompatible_modules), "[modpath] initial module [module.type] is incompatible with initial module [module_to_check.type]") TEST_ASSERT(!is_type_in_list(module_to_check, module.incompatible_modules), "[modpath] initial module [module.type] is incompatible with initial module [module_to_check.type]") diff --git a/code/modules/unit_tests/suit_storage_icons.dm b/code/modules/unit_tests/suit_storage_icons.dm index 12305e7abfc0b..7cc987bb46801 100644 --- a/code/modules/unit_tests/suit_storage_icons.dm +++ b/code/modules/unit_tests/suit_storage_icons.dm @@ -14,9 +14,9 @@ for(var/path in clothing_path::allowed) //find all usable suit storage stuff. wearable_item_paths |= path - for(var/obj/item/mod/control/mod_path in subtypesof(/obj/item/mod/control)) - for(var/path in mod_path::chestplate::allowed) - wearable_item_paths |= path + for(var/datum/mod_theme/mod_theme as anything in GLOB.mod_themes) + mod_theme = GLOB.mod_themes[mod_theme] + wearable_item_paths |= mod_theme.allowed_suit_storage var/list/already_warned_icons = list() var/count = 1 //to be removed once the test goes live / into CI failure mode. diff --git a/tgstation.dme b/tgstation.dme index 4cdb2cb189616..efc21a337a1e4 100644 --- a/tgstation.dme +++ b/tgstation.dme @@ -5142,6 +5142,7 @@ #include "code\modules\mod\mod_core.dm" #include "code\modules\mod\mod_link.dm" #include "code\modules\mod\mod_paint.dm" +#include "code\modules\mod\mod_part.dm" #include "code\modules\mod\mod_theme.dm" #include "code\modules\mod\mod_types.dm" #include "code\modules\mod\mod_ui.dm" diff --git a/tgui/packages/tgui/interfaces/MODsuit.tsx b/tgui/packages/tgui/interfaces/MODsuit.tsx index 8752fc3c8741a..2b7070e3ba50b 100644 --- a/tgui/packages/tgui/interfaces/MODsuit.tsx +++ b/tgui/packages/tgui/interfaces/MODsuit.tsx @@ -27,10 +27,7 @@ type MODsuitData = { ui_theme: string; control: string; complexity_max: number; - helmet: string; - chestplate: string; - gauntlets: string; - boots: string; + parts: PartData[]; // Dynamic suit_status: SuitStatus; user_status: UserStatus; @@ -38,6 +35,11 @@ type MODsuitData = { module_info: Module[]; }; +type PartData = { + slot: string; + name: string; +}; + type SuitStatus = { core_name: string; cell_charge_current: number; @@ -477,7 +479,7 @@ const SuitStatusSection = (props) => { const HardwareSection = (props) => { const { act, data } = useBackend(); - const { control, helmet, chestplate, gauntlets, boots } = data; + const { control } = data; const { ai_name, core_name } = data.suit_status; return (
@@ -489,19 +491,28 @@ const HardwareSection = (props) => { {core_name || 'No Core Detected'} {control} - {helmet || 'None'} - - {chestplate || 'None'} - - - {gauntlets || 'None'} - - {boots || 'None'} +
); }; +const ModParts = (props) => { + const { act, data } = useBackend(); + const { parts } = data; + return ( + <> + {parts.map((part) => { + return ( + + {part.name} + + ); + })} + + ); +}; + const UserStatusSection = (props) => { const { act, data } = useBackend(); const { active } = data.suit_status; From 78d05937c416ae9b01149467e2e46a5c9e53609b Mon Sep 17 00:00:00 2001 From: orange man <61334995+comfyorange@users.noreply.github.com> Date: Mon, 20 May 2024 17:04:18 +1200 Subject: [PATCH 025/103] Automatic changelog for PR #82905 [ci skip] --- html/changelogs/AutoChangeLog-pr-82905.yml | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-82905.yml diff --git a/html/changelogs/AutoChangeLog-pr-82905.yml b/html/changelogs/AutoChangeLog-pr-82905.yml new file mode 100644 index 0000000000000..ff7fe2bda96f0 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-82905.yml @@ -0,0 +1,5 @@ +author: "Fikou" +delete-after: True +changes: + - refactor: "modsuits have been refactored if you see bugs report them" + - bugfix: "admin cargo tech modsuit outfit now works correctly" \ No newline at end of file From f1ce07b2e0202f562b80dd6954a7a7d27b2c2d87 Mon Sep 17 00:00:00 2001 From: Striders13 <53361823+Striders13@users.noreply.github.com> Date: Mon, 20 May 2024 10:06:23 +0500 Subject: [PATCH 026/103] Sentience balloon can now assign antag to affected mobs (#83322) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## About The Pull Request ![Đ¸Đ·Đ¾Đ±Ñ€Đ°Đ¶ĐµĐ½Đ¸Đµ](https://github.com/tgstation/tgstation/assets/53361823/732725fe-7c87-48dd-a0d0-bab990e54cef) ![Đ¸Đ·Đ¾Đ±Ñ€Đ°Đ¶ĐµĐ½Đ¸Đµ](https://github.com/tgstation/tgstation/assets/53361823/4b78a0ae-05e2-40ea-9f48-574fb9ba1140) there's probably a better way to show the list of antags ## Why It's Good For The Game I wanna give out antag datum to things I spawn, doing it one by one is annoying ## Changelog :cl: admin: sentience balloon can now assign antag to affected mobs /:cl: --- code/modules/admin/fun_balloon.dm | 11 +++++++++++ .../packages/tgui/interfaces/SentienceFunBalloon.jsx | 12 ++++++++++-- 2 files changed, 21 insertions(+), 2 deletions(-) diff --git a/code/modules/admin/fun_balloon.dm b/code/modules/admin/fun_balloon.dm index b65f72f8f4d79..c95fce43dc943 100644 --- a/code/modules/admin/fun_balloon.dm +++ b/code/modules/admin/fun_balloon.dm @@ -38,6 +38,8 @@ desc = "When this pops, things are gonna get more aware around here." var/group_name = "a bunch of giant spiders" var/effect_range = 3 + var/antag_type = null + var/make_antag = FALSE /obj/effect/fun_balloon/sentience/ui_interact(mob/user, datum/tgui/ui) ui = SStgui.try_update_ui(user, src, ui) @@ -49,6 +51,7 @@ var/list/data = list() data["group_name"] = group_name data["range"] = effect_range + data["antag"] = make_antag return data /obj/effect/fun_balloon/sentience/ui_state(mob/user) @@ -73,6 +76,11 @@ if("effect_range") effect_range = params["updated_range"] + if("select_antag") + var/list/paths = subtypesof(/datum/antagonist) + antag_type = input(usr,"Select antag", "Antagonist selection") as null|anything in sort_list(paths) + make_antag = TRUE + if("pop") if(!popped) popped = TRUE @@ -105,6 +113,9 @@ message_admins("[key_name_admin(C)] has taken control of ([key_name_admin(body)])") body.ghostize(FALSE) body.key = C.key + if (make_antag) + body.mind.add_antag_datum(antag_type) + continue new /obj/effect/temp_visual/gravpush(get_turf(body)) // ----------- Emergency Shuttle Balloon diff --git a/tgui/packages/tgui/interfaces/SentienceFunBalloon.jsx b/tgui/packages/tgui/interfaces/SentienceFunBalloon.jsx index 62330cc6a05c4..ab4353aab2846 100644 --- a/tgui/packages/tgui/interfaces/SentienceFunBalloon.jsx +++ b/tgui/packages/tgui/interfaces/SentienceFunBalloon.jsx @@ -11,9 +11,9 @@ import { Window } from '../layouts'; export const SentienceFunBalloon = (props) => { const { act, data } = useBackend(); - const { group_name, range } = data; + const { group_name, range, antag } = data; return ( - +
@@ -44,6 +44,14 @@ export const SentienceFunBalloon = (props) => { } /> + + act('select_antag')} + /> +
From d4410a25420ace6cfadc339e7ff522db3b8a3bfb Mon Sep 17 00:00:00 2001 From: orange man <61334995+comfyorange@users.noreply.github.com> Date: Mon, 20 May 2024 17:06:43 +1200 Subject: [PATCH 027/103] Automatic changelog for PR #83322 [ci skip] --- html/changelogs/AutoChangeLog-pr-83322.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-83322.yml diff --git a/html/changelogs/AutoChangeLog-pr-83322.yml b/html/changelogs/AutoChangeLog-pr-83322.yml new file mode 100644 index 0000000000000..47e72c4c16382 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-83322.yml @@ -0,0 +1,4 @@ +author: "Striders13" +delete-after: True +changes: + - admin: "sentience balloon can now assign antag to affected mobs" \ No newline at end of file From 56f881008d96456c8efe1b90f63e75d3b084d4c3 Mon Sep 17 00:00:00 2001 From: necromanceranne <40847847+necromanceranne@users.noreply.github.com> Date: Mon, 20 May 2024 16:33:49 +1000 Subject: [PATCH 028/103] Unreverts the fixes from #82713; the mining station once again no longer rapidly loses power (#83319) ## About The Pull Request #82537 unfortunately reverted my fixes in #82713 because of how old that PR was when it was merged. So this restores those fixes. ## Why It's Good For The Game The bane of map prs that stay up for a really long time is that this happens a lot more than you would think. ## Changelog :cl: fix: Miners can actually access and fix their engineering issues on the lavaland base via the engineering section of the base. AGAIN. fix: The gulag SMES unit is no longer needlessly draining the entire power grid of the main mining base. AGAIN. /:cl: --- _maps/map_files/Mining/Lavaland.dmm | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/_maps/map_files/Mining/Lavaland.dmm b/_maps/map_files/Mining/Lavaland.dmm index 72fe092d5caa1..f2d6eb671e38f 100644 --- a/_maps/map_files/Mining/Lavaland.dmm +++ b/_maps/map_files/Mining/Lavaland.dmm @@ -645,6 +645,15 @@ }, /turf/open/misc/asteroid/basalt/lava_land_surface, /area/lavaland/surface/outdoors) +"ey" = ( +/obj/structure/lattice/catwalk/mining, +/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, +/obj/item/toy/plush/shark{ + desc = "A plushie depicting a somewhat cartoonish shark. The tag calls it a 'hĂ¡karl', noting that it was made by an obscure furniture manufacturer in old Scandinavia. This one seems to have some cable wiring sticking out of its mouth." + }, +/turf/open/lava/smooth/lava_land_surface, +/area/lavaland/surface/outdoors) "ez" = ( /obj/structure/chair/comfy/teal{ dir = 4 @@ -2869,7 +2878,7 @@ /area/mine/laborcamp/production) "ps" = ( /obj/structure/cable, -/obj/machinery/power/smes/full, +/obj/machinery/power/smes/super/full, /obj/effect/decal/cleanable/dirt, /turf/open/floor/plating, /area/mine/maintenance/service) @@ -5038,7 +5047,7 @@ /turf/open/floor/plating/lavaland_atmos, /area/lavaland/surface/outdoors) "Ee" = ( -/obj/machinery/power/smes/full, +/obj/machinery/power/smes/super/full, /obj/structure/cable, /turf/open/floor/plating, /area/mine/maintenance/labor) @@ -29901,7 +29910,7 @@ Xw aj aj aj -cU +ey aj aj aj From 0699adf1a9bc173d9056997b45725a5a19d8dbb0 Mon Sep 17 00:00:00 2001 From: orange man <61334995+comfyorange@users.noreply.github.com> Date: Mon, 20 May 2024 18:34:09 +1200 Subject: [PATCH 029/103] Automatic changelog for PR #83319 [ci skip] --- html/changelogs/AutoChangeLog-pr-83319.yml | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-83319.yml diff --git a/html/changelogs/AutoChangeLog-pr-83319.yml b/html/changelogs/AutoChangeLog-pr-83319.yml new file mode 100644 index 0000000000000..bbc049c558803 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-83319.yml @@ -0,0 +1,5 @@ +author: "necromanceranne" +delete-after: True +changes: + - bugfix: "Miners can actually access and fix their engineering issues on the lavaland base via the engineering section of the base. AGAIN." + - bugfix: "The gulag SMES unit is no longer needlessly draining the entire power grid of the main mining base. AGAIN." \ No newline at end of file From ff882b7429da696e425070df66f53dedaf5214ae Mon Sep 17 00:00:00 2001 From: Watermelon914 <37270891+Watermelon914@users.noreply.github.com> Date: Mon, 20 May 2024 06:36:24 +0000 Subject: [PATCH 030/103] Fixed lights doing processing when they shouldn't need to. (#83313) ## About The Pull Request Lights would do processing if they spawned with a mock cell, since it would never pass the conditional to see if the cell was full and stop processing since the cell didn't exist. This fixes that by making it so that having no cell equates to having a full one. This is expected since whenever any charge is supposed to be used by the cell, it will generate the cell which will have full charge. ## Why It's Good For The Game Fixes a potential performance hog. Metastation dropped from 2800 processing machinery to 1900 after implementing this change. ## Changelog No player facing changes --------- Co-authored-by: Watermelon914 <3052169-Watermelon914@users.noreply.gitlab.com> --- code/modules/power/lighting/light.dm | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/code/modules/power/lighting/light.dm b/code/modules/power/lighting/light.dm index 2d552dbbe9edb..43713cc49ae0c 100644 --- a/code/modules/power/lighting/light.dm +++ b/code/modules/power/lighting/light.dm @@ -286,11 +286,17 @@ var/delay = rand(BROKEN_SPARKS_MIN, BROKEN_SPARKS_MAX) addtimer(CALLBACK(src, PROC_REF(broken_sparks)), delay, TIMER_UNIQUE | TIMER_NO_HASH_WAIT) +/obj/machinery/light/proc/is_full_charge() + if(cell) + return cell.charge == cell.maxcharge + return TRUE + /obj/machinery/light/process(seconds_per_tick) - if(has_power()) //If the light is being powered by the station. + if(has_power()) + // If the cell is done mooching station power, and reagents don't need processing, stop processing + if(is_full_charge() && !reagents) + return PROCESS_KILL if(cell) - if(cell.charge == cell.maxcharge && !reagents) //If the cell is done mooching station power, and reagents don't need processing, stop processing - return PROCESS_KILL charge_cell(LIGHT_EMERGENCY_POWER_USE * seconds_per_tick, cell = cell) //Recharge emergency power automatically while not using it if(reagents) //with most reagents coming out at 300, and with most meaningful reactions coming at 370+, this rate gives a few seconds of time to place it in and get out of dodge regardless of input. reagents.adjust_thermal_energy(8 * reagents.total_volume * SPECIFIC_HEAT_DEFAULT * seconds_per_tick) From f2fcbbb5b46a1e7a7d73215ce87fb8da08f7e377 Mon Sep 17 00:00:00 2001 From: dopamiin0 <112458553+dopamiin0@users.noreply.github.com> Date: Mon, 20 May 2024 01:38:16 -0500 Subject: [PATCH 031/103] Adds more ingredients to the chef's grocery console. (#83308) ## About The Pull Request As title. The chef's grocery console now has twenty four!!! new orderable options that are commonly used in cooking. ## Why It's Good For The Game Chefs can spend more of their time playing as a chef and less of their time not playing as a chef ## Changelog :cl: add: Nanotrasen has made strides in their frontier sector food networks, increasing the selection of produce available to chefs. /:cl: --- .../order_items/cook/order_milk_eggs.dm | 10 +++ .../orders/order_items/cook/order_reagents.dm | 10 +++ .../orders/order_items/cook/order_veggies.dm | 88 +++++++++++++++++++ 3 files changed, 108 insertions(+) diff --git a/code/game/machinery/computer/orders/order_items/cook/order_milk_eggs.dm b/code/game/machinery/computer/orders/order_items/cook/order_milk_eggs.dm index fcd0737675bec..9e5413f854863 100644 --- a/code/game/machinery/computer/orders/order_items/cook/order_milk_eggs.dm +++ b/code/game/machinery/computer/orders/order_items/cook/order_milk_eggs.dm @@ -134,3 +134,13 @@ name = "Mothic Pantry Pack" item_path = /obj/item/storage/box/mothic_cans_sauces cost_per_order = 120 + +/datum/orderable_item/milk_eggs/armorfish + name = "Cleaned Armorfish" + item_path = /obj/item/food/fishmeat/armorfish + cost_per_order = 30 + +/datum/orderable_item/milk_eggs/moonfish + name = "Moonfish" + item_path = /obj/item/food/fishmeat/moonfish + cost_per_order = 30 diff --git a/code/game/machinery/computer/orders/order_items/cook/order_reagents.dm b/code/game/machinery/computer/orders/order_items/cook/order_reagents.dm index d6b4728d10496..39fb38df550ef 100644 --- a/code/game/machinery/computer/orders/order_items/cook/order_reagents.dm +++ b/code/game/machinery/computer/orders/order_items/cook/order_reagents.dm @@ -95,3 +95,13 @@ name = "Grounding Solution" item_path = /obj/item/reagent_containers/condiment/grounding_solution cost_per_order = 30 + +/datum/orderable_item/reagents/honey + name = "Honey" + item_path = /obj/item/reagent_containers/condiment/honey + cost_per_order = 125 //its high quality honey :) + +/datum/orderable_item/reagents/mayonnaise + name = "Mayonnaise" + item_path = /obj/item/reagent_containers/condiment/mayonnaise + cost_per_order = 30 diff --git a/code/game/machinery/computer/orders/order_items/cook/order_veggies.dm b/code/game/machinery/computer/orders/order_items/cook/order_veggies.dm index 506920986dd2c..f96562724d27d 100644 --- a/code/game/machinery/computer/orders/order_items/cook/order_veggies.dm +++ b/code/game/machinery/computer/orders/order_items/cook/order_veggies.dm @@ -89,3 +89,91 @@ name = "Pickled Voltvine" item_path = /obj/item/food/pickled_voltvine cost_per_order = 5 + +/datum/orderable_item/veggies/chili + name = "Chili" + item_path = /obj/item/food/grown/chili + +/datum/orderable_item/veggies/berries + name = "Berries" + item_path = /obj/item/food/grown/berries + +/datum/orderable_item/veggies/pineapple + name = "Pineapple" + item_path = /obj/item/food/grown/pineapple + +/datum/orderable_item/veggies/peas + name = "Peas" + item_path = /obj/item/food/grown/peas + +/datum/orderable_item/veggies/korta_nut //nanotrasen does not devote as much of their resources to pathetic lizard crops + name = "Korta Nut" + item_path = /obj/item/food/grown/korta_nut + cost_per_order = 15 + +/datum/orderable_item/veggies/parsnip + name = "Parsnip" + item_path = /obj/item/food/grown/parsnip + +/datum/orderable_item/veggies/redbeet + name = "Red Beet" + item_path = /obj/item/food/grown/redbeet + +/datum/orderable_item/veggies/orange + name = "Orange" + item_path = /obj/item/food/grown/citrus/orange + +/datum/orderable_item/veggies/vanillapod + name = "Vanilla" + item_path = /obj/item/food/grown/vanillapod + cost_per_order = 25 //food items that are treated as mutations in game should be more expensive. groceries shouldnt include ACTUAL mutations but i think real foods are ok + +/datum/orderable_item/veggies/sweetkorta + name = "Sweet Korta Nut" + item_path = /obj/item/food/grown/korta_nut/sweet + cost_per_order = 30 + +/datum/orderable_item/veggies/redonion + name = "Red Onion" + item_path = /obj/item/food/grown/onion/red + cost_per_order = 25 + +/datum/orderable_item/veggies/peanut + name = "Peanut" + item_path = /obj/item/food/grown/peanut + +/datum/orderable_item/veggies/sweetpotato + name = "Sweet Potato" + item_path = /obj/item/food/grown/potato/sweet + cost_per_order = 25 + +/datum/orderable_item/veggies/oat + name = "Oat" + item_path = /obj/item/food/grown/oat + +/datum/orderable_item/veggies/trumpet + name = "Spaceman's Trumpet" + item_path = /obj/item/food/grown/trumpet + cost_per_order = 25 + +/datum/orderable_item/veggies/banana + name = "Banana" + item_path = /obj/item/food/grown/banana + +/datum/orderable_item/veggies/ghostchili + name = "Ghost Chili" + item_path = /obj/item/food/grown/ghost_chili + cost_per_order = 25 + +/datum/orderable_item/veggies/lemon + name = "Lemon" + item_path = /obj/item/food/grown/citrus/lemon + +/datum/orderable_item/veggies/lime + name = "Lime" + item_path = /obj/item/food/grown/citrus/lime + +/datum/orderable_item/veggies/toechtauese + name = "TöchtaĂ¼se berries" + item_path = /obj/item/food/grown/toechtauese + cost_per_order = 15 From 5d0672e51ad1854805bcc14de601c3c3551cb4b4 Mon Sep 17 00:00:00 2001 From: orange man <61334995+comfyorange@users.noreply.github.com> Date: Mon, 20 May 2024 18:38:35 +1200 Subject: [PATCH 032/103] Automatic changelog for PR #83308 [ci skip] --- html/changelogs/AutoChangeLog-pr-83308.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-83308.yml diff --git a/html/changelogs/AutoChangeLog-pr-83308.yml b/html/changelogs/AutoChangeLog-pr-83308.yml new file mode 100644 index 0000000000000..d6aa3402cceba --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-83308.yml @@ -0,0 +1,4 @@ +author: "dopamiin0" +delete-after: True +changes: + - rscadd: "Nanotrasen has made strides in their frontier sector food networks, increasing the selection of produce available to chefs." \ No newline at end of file From 35d8acfe7b81e1d329204a83c312e48731ace9e5 Mon Sep 17 00:00:00 2001 From: Jacquerel Date: Mon, 20 May 2024 07:45:22 +0100 Subject: [PATCH 033/103] Changelings can't transform people into species they cannot absorb (#83286) ## About The Pull Request This PR makes a change to the Transform Sting ability to prevent you from turning people into species that have unabsorbable DNA. Now you may ask "Jacquerel, how do you even have a DNA profile of a species with unabsorbable DNA in the first place?" The answer is that we do not do any species checks when assigning roundstart antagonists, or when admins try to make someone into a Changeling. The upshot of this is that while you can't copy the DNA of a plasmaman and then wander around turning random people into plasmamen (instantly setting them on fire and suffocating them), you can **start** the round as a Plasmaman, apply _your own_ DNA to people, and have them experience those consequences. We _could_ change this so that people queueing as Plasmaman who also are assigned to be Changelings use their forced human profile... but I think that's more boring than this solution (and might lead to very slightly more metagaming). This way _also_ adds a little bit of protection for the cases of admins giving the changeling antag datum to Golems, Monkeys, Skeletons, Androids, or the like. Just in case admins _want_ to turn people into burning skeletons with transform sting, I have added a variable on the ability which you can toggle to disable the check. ## Changelog :cl: balance: If you can't absorb a species' DNA as a changeling, you also can't use transform sting to turn someone into that species. /:cl: --- code/modules/antagonists/changeling/powers/tiny_prick.dm | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/code/modules/antagonists/changeling/powers/tiny_prick.dm b/code/modules/antagonists/changeling/powers/tiny_prick.dm index ea172fee0134b..c8bbee26481a6 100644 --- a/code/modules/antagonists/changeling/powers/tiny_prick.dm +++ b/code/modules/antagonists/changeling/powers/tiny_prick.dm @@ -77,6 +77,8 @@ VAR_FINAL/datum/changeling_profile/selected_dna /// Duration of the sting var/sting_duration = 8 MINUTES + /// Set this to false via VV to allow golem, plasmaman, or monkey changelings to turn other people into golems, plasmamen, or monkeys + var/verify_valid_species = TRUE /datum/action/changeling/sting/transformation/Grant(mob/grant_to) . = ..() @@ -99,6 +101,9 @@ return if(!new_selected_dna || changeling.chosen_sting || selected_dna) // selected other sting or other DNA while sleeping return + if(verify_valid_species && (TRAIT_NO_DNA_COPY in new_selected_dna.dna.species.inherent_traits)) + user.balloon_alert(user, "dna incompatible!") + return selected_dna = new_selected_dna return ..() From 251a7c9e9847907ebd3c56e9c5783cc248333421 Mon Sep 17 00:00:00 2001 From: orange man <61334995+comfyorange@users.noreply.github.com> Date: Mon, 20 May 2024 18:45:41 +1200 Subject: [PATCH 034/103] Automatic changelog for PR #83286 [ci skip] --- html/changelogs/AutoChangeLog-pr-83286.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-83286.yml diff --git a/html/changelogs/AutoChangeLog-pr-83286.yml b/html/changelogs/AutoChangeLog-pr-83286.yml new file mode 100644 index 0000000000000..4f83dad85f947 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-83286.yml @@ -0,0 +1,4 @@ +author: "Jacquerel" +delete-after: True +changes: + - balance: "If you can't absorb a species' DNA as a changeling, you also can't use transform sting to turn someone into that species." \ No newline at end of file From a97fe316dbe961591a73c82a3a119ba22fa49cff Mon Sep 17 00:00:00 2001 From: Sadboysuss <96586172+Sadboysuss@users.noreply.github.com> Date: Mon, 20 May 2024 09:49:41 +0300 Subject: [PATCH 035/103] Gateway sounds (#83274) ## About The Pull Request Adds sounds for the gateway ### Sound files: https://drive.google.com/drive/folders/1POAc79zV95aX8sRKJVcxu31HjxhzLrzS?usp=sharing ### Demo: https://github.com/tgstation/tgstation/assets/96586172/a4318ac5-8184-4364-8b12-4d67a225825d ## Why It's Good For The Game Having sounds for an alien piece of tech adds to the immersion ## Changelog :cl: grungussuss and Virgilcore sound: added sounds for the gateway /:cl: --- code/modules/awaymissions/gateway.dm | 5 +++++ sound/effects/gateway_calibrated.ogg | Bin 0 -> 24013 bytes sound/effects/gateway_calibrating.ogg | Bin 0 -> 70938 bytes sound/effects/gateway_close.ogg | Bin 0 -> 22074 bytes sound/effects/gateway_open.ogg | Bin 0 -> 34902 bytes sound/effects/gateway_travel.ogg | Bin 0 -> 28203 bytes 6 files changed, 5 insertions(+) create mode 100644 sound/effects/gateway_calibrated.ogg create mode 100644 sound/effects/gateway_calibrating.ogg create mode 100644 sound/effects/gateway_close.ogg create mode 100644 sound/effects/gateway_open.ogg create mode 100644 sound/effects/gateway_travel.ogg diff --git a/code/modules/awaymissions/gateway.dm b/code/modules/awaymissions/gateway.dm index 72cb8982d3436..665834d4085a9 100644 --- a/code/modules/awaymissions/gateway.dm +++ b/code/modules/awaymissions/gateway.dm @@ -22,6 +22,7 @@ GLOBAL_LIST_EMPTY(gateway_destinations) /datum/gateway_destination/proc/get_available_reason() . = "Unreachable" if(world.time - SSticker.round_start_time < wait) + playsound(src, 'sound/effects/gateway_calibrating.ogg', 80, TRUE, SHORT_RANGE_SOUND_EXTRARANGE) . = "Connection desynchronized. Recalibration in progress." /* Check if the movable is allowed to arrive at this destination (exile implants mostly) */ @@ -134,6 +135,7 @@ GLOBAL_LIST_EMPTY(gateway_destinations) /obj/effect/gateway_portal_bumper/Bumped(atom/movable/AM) if(get_dir(src,AM) == SOUTH) + playsound(src, 'sound/effects/gateway_travel.ogg', 70, TRUE, SHORT_RANGE_SOUND_EXTRARANGE) gateway.Transfer(AM) /obj/effect/gateway_portal_bumper/Destroy(force) @@ -198,6 +200,7 @@ GLOBAL_LIST_EMPTY(gateway_destinations) /obj/machinery/gateway/proc/deactivate() var/datum/gateway_destination/dest = target target = null + playsound(src, 'sound/effects/gateway_close.ogg', 140, TRUE, TRUE, SOUND_RANGE) dest.deactivate(src) QDEL_NULL(portal) update_use_power(IDLE_POWER_USE) @@ -260,6 +263,7 @@ GLOBAL_LIST_EMPTY(gateway_destinations) target.activate(destination) portal_visuals.setup_visuals(target) transport_active = TRUE + playsound(src, 'sound/effects/gateway_open.ogg', 140, TRUE, TRUE, SOUND_RANGE) generate_bumper() update_use_power(ACTIVE_POWER_USE) update_appearance() @@ -302,6 +306,7 @@ GLOBAL_LIST_EMPTY(gateway_destinations) if(calibrated) to_chat(user, span_alert("The gate is already calibrated, there is no work for you to do here.")) else + playsound(src, 'sound/effects/gateway_calibrated.ogg', 80, TRUE, SHORT_RANGE_SOUND_EXTRARANGE) to_chat(user, "[span_boldnotice("Recalibration successful!")]: \black This gate's systems have been fine tuned. Travel to this gate will now be on target.") calibrated = TRUE return TRUE diff --git a/sound/effects/gateway_calibrated.ogg b/sound/effects/gateway_calibrated.ogg new file mode 100644 index 0000000000000000000000000000000000000000..c88d0862c988d67138656d6c14c3dad74a8e3f99 GIT binary patch literal 24013 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 literal 0 HcmV?d00001 diff --git a/sound/effects/gateway_calibrating.ogg b/sound/effects/gateway_calibrating.ogg new file mode 100644 index 0000000000000000000000000000000000000000..09ca63fbc10ff1e6b308ce035a1bed5568d648e3 GIT binary patch literal 70938 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%0D$5LYp!^lE3(%MDF(Vp!;5xae7GgefV-c8Qp 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 yo3d+@si~=V^0I&>f0ss!>CGAZB literal 0 HcmV?d00001 diff --git a/sound/effects/gateway_open.ogg b/sound/effects/gateway_open.ogg new file mode 100644 index 0000000000000000000000000000000000000000..f6d11f7eedee29dd559780ccb1a7459446457dcd GIT binary patch literal 34902 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 literal 0 HcmV?d00001 diff --git a/sound/effects/gateway_travel.ogg b/sound/effects/gateway_travel.ogg new file mode 100644 index 0000000000000000000000000000000000000000..bbaed502790f0c763c19efa70fcbec232d65148d GIT binary patch literal 28203 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 Rwr?Z7%a@Z7QwSOd{129E4Ilsj literal 0 HcmV?d00001 From 00219744f514a1c425e118e8540a5a557a7c1157 Mon Sep 17 00:00:00 2001 From: orange man <61334995+comfyorange@users.noreply.github.com> Date: Mon, 20 May 2024 18:50:00 +1200 Subject: [PATCH 036/103] Automatic changelog for PR #83274 [ci skip] --- html/changelogs/AutoChangeLog-pr-83274.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-83274.yml diff --git a/html/changelogs/AutoChangeLog-pr-83274.yml b/html/changelogs/AutoChangeLog-pr-83274.yml new file mode 100644 index 0000000000000..5b9a468685fbf --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-83274.yml @@ -0,0 +1,4 @@ +author: "grungussuss and Virgilcore" +delete-after: True +changes: + - sound: "added sounds for the gateway" \ No newline at end of file From 2c7fe7b8cd456b61fa31da1000518947c44f9794 Mon Sep 17 00:00:00 2001 From: iwishforducks <65363339+iwishforducks@users.noreply.github.com> Date: Mon, 20 May 2024 02:57:24 -0400 Subject: [PATCH 037/103] Returns medical jumpsuits for medical doctors and CMO (#83191) ## About The Pull Request Gives medical doctors and CMOs back their jumpsuits. Additionally removes their surgery cap from their starting gear. Surgical scrubs and surgery caps are still available in vending machines and in other places. Coroner still has their scrubs. ## Why It's Good For The Game The scrubs have never made sense to be as part of a medical doctor's starting gear. Scrubs are meant to be put on for one surgery and replaced afterwards, not to be worn 24/7. Also, in my opinion, they look goofy as hell. Especially when doctors are wearing lab coats over them. [_Being a medical doctor does not inherently mean you're doing surgeries either._](https://www.youtube.com/watch?v=8byiwOY5XM0) ## Changelog :cl: image: Medical doctors and CMOs now start with their jumpsuits rather than surgery scrubs and caps. /:cl: --- .../jobs/job_types/chief_medical_officer.dm | 3 +-- code/modules/jobs/job_types/medical_doctor.dm | 3 +-- .../mob_spawn/ghost_roles/mining_roles.dm | 2 +- ...reenshot_humanoids__datum_species_moth.png | Bin 1667 -> 1648 bytes 4 files changed, 3 insertions(+), 5 deletions(-) diff --git a/code/modules/jobs/job_types/chief_medical_officer.dm b/code/modules/jobs/job_types/chief_medical_officer.dm index e20ef7c19edd9..3f580b8e932a5 100644 --- a/code/modules/jobs/job_types/chief_medical_officer.dm +++ b/code/modules/jobs/job_types/chief_medical_officer.dm @@ -56,7 +56,7 @@ id = /obj/item/card/id/advanced/silver id_trim = /datum/id_trim/job/chief_medical_officer - uniform = /obj/item/clothing/under/rank/medical/chief_medical_officer/scrubs + uniform = /obj/item/clothing/under/rank/medical/chief_medical_officer suit = /obj/item/clothing/suit/toggle/labcoat/cmo suit_store = /obj/item/flashlight/pen/paramedic backpack_contents = list( @@ -64,7 +64,6 @@ ) belt = /obj/item/modular_computer/pda/heads/cmo ears = /obj/item/radio/headset/heads/cmo - head = /obj/item/clothing/head/utility/surgerycap/cmo shoes = /obj/item/clothing/shoes/sneakers/blue l_pocket = /obj/item/laser_pointer/blue r_pocket = /obj/item/pinpointer/crew diff --git a/code/modules/jobs/job_types/medical_doctor.dm b/code/modules/jobs/job_types/medical_doctor.dm index a0f2971df2306..ccfcbae1623e6 100644 --- a/code/modules/jobs/job_types/medical_doctor.dm +++ b/code/modules/jobs/job_types/medical_doctor.dm @@ -44,12 +44,11 @@ jobtype = /datum/job/doctor id_trim = /datum/id_trim/job/medical_doctor - uniform = /obj/item/clothing/under/rank/medical/scrubs/blue + uniform = /obj/item/clothing/under/rank/medical/doctor suit = /obj/item/clothing/suit/toggle/labcoat suit_store = /obj/item/flashlight/pen belt = /obj/item/modular_computer/pda/medical ears = /obj/item/radio/headset/headset_med - head = /obj/item/clothing/head/utility/surgerycap shoes = /obj/item/clothing/shoes/sneakers/white l_hand = /obj/item/storage/medkit/surgery diff --git a/code/modules/mob_spawn/ghost_roles/mining_roles.dm b/code/modules/mob_spawn/ghost_roles/mining_roles.dm index 53fa001097039..5fb3337b911e7 100644 --- a/code/modules/mob_spawn/ghost_roles/mining_roles.dm +++ b/code/modules/mob_spawn/ghost_roles/mining_roles.dm @@ -34,7 +34,7 @@ if(3) flavour_text += "you were a doctor on one of Nanotrasen's space stations, but you left behind that damn corporation's tyranny and everything it stood for. From a metaphorical hell \ to a literal one, you find yourself nonetheless missing the recycled air and warm floors of what you left behind... but you'd still rather be here than there." - outfit.uniform = /obj/item/clothing/under/rank/medical/scrubs/blue + outfit.uniform = /obj/item/clothing/under/rank/medical/doctor outfit.suit = /obj/item/clothing/suit/toggle/labcoat outfit.back = /obj/item/storage/backpack/medic if(4) diff --git a/code/modules/unit_tests/screenshots/screenshot_humanoids__datum_species_moth.png b/code/modules/unit_tests/screenshots/screenshot_humanoids__datum_species_moth.png index ed782c8ec9f6e1a2ad9e042a639cda20952bd908..284205a73ec132117c951f148a2dc7f207e5e6da 100644 GIT binary patch delta 1382 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 Hu0mjf9Wjgj From 663e710a09393912cbf938d8e37f96e3544a8a14 Mon Sep 17 00:00:00 2001 From: orange man <61334995+comfyorange@users.noreply.github.com> Date: Mon, 20 May 2024 18:57:44 +1200 Subject: [PATCH 038/103] Automatic changelog for PR #83191 [ci skip] --- html/changelogs/AutoChangeLog-pr-83191.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-83191.yml diff --git a/html/changelogs/AutoChangeLog-pr-83191.yml b/html/changelogs/AutoChangeLog-pr-83191.yml new file mode 100644 index 0000000000000..79d5188b590b9 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-83191.yml @@ -0,0 +1,4 @@ +author: "iwishforducks" +delete-after: True +changes: + - image: "Medical doctors and CMOs now start with their jumpsuits rather than surgery scrubs and caps." \ No newline at end of file From cd4cc0f9e3c7d6506d03444613bb37ca7b4c87f2 Mon Sep 17 00:00:00 2001 From: carlarctg <53100513+carlarctg@users.noreply.github.com> Date: Mon, 20 May 2024 04:01:13 -0300 Subject: [PATCH 039/103] Halved Psyker echolocation cooldown (#83125) ## About The Pull Request Default psyker refresh rate has gone from '2 seconds' to '1 second' ## Why It's Good For The Game I tried playing Psyker a few rounds ago. Oh my god. It was so bad. Genuinely, I spent more time looking at the fadeout screen than actually seeing things. It was horrible and most importantly extremely nauseating. I wasn't even able to make my way to the station nor find where my guns even were. I had just eaten lunch and literally had to stop and suicide just so I didn't throw up. In real life. I injected the 2 gore injectors and noticed there was another meat cube with nearby expended gore injectors next to me. Someone else joined as Psyker and did the same thing after noticing how unplayable it was. While testing in local I was shocked by how much better it felt. Trying to compare the two experiences made me realize that there is a HUGE diference between the 'real' cooldown in local and on live. Due to that, I'm just going ahead and shortening the cooldown, which will hopefully bring Echocolocation into its INTENDED design, rather than the UNINTENDED slower, laggier version. I think the main reason it was nauseating on live, unlike local, is that in local, I spend more time being able to see things. In live, I spent more time looking at the black fading screen. While I labeled it as balance, this is probably closer to a qol or fix than anything else imo. It brings Psyker into its intended design and tries to stop it causing real life nausea. ## Changelog :cl: balance: Halved Psyker echolocation cooldown. This will hopefully make it actually usable. /:cl: --- code/datums/components/echolocation.dm | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/code/datums/components/echolocation.dm b/code/datums/components/echolocation.dm index 13ef8f4ed2431..60a6d0fa8aa3c 100644 --- a/code/datums/components/echolocation.dm +++ b/code/datums/components/echolocation.dm @@ -1,8 +1,8 @@ /datum/component/echolocation /// Radius of our view. var/echo_range = 4 - /// Time between echolocations. - var/cooldown_time = 1.8 SECONDS + /// Time between echolocations. IMPORTANT!! The effective time in local and the effective time in live are very different. The second is noticeably slower, + var/cooldown_time = 1 SECONDS /// Time for the image to start fading out. var/image_expiry_time = 1.4 SECONDS /// Time for the image to fade in. From f46691de5462f20230e3fc7f98c0e4490defa073 Mon Sep 17 00:00:00 2001 From: orange man <61334995+comfyorange@users.noreply.github.com> Date: Mon, 20 May 2024 19:01:30 +1200 Subject: [PATCH 040/103] Automatic changelog for PR #83125 [ci skip] --- html/changelogs/AutoChangeLog-pr-83125.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-83125.yml diff --git a/html/changelogs/AutoChangeLog-pr-83125.yml b/html/changelogs/AutoChangeLog-pr-83125.yml new file mode 100644 index 0000000000000..fcf31111b345f --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-83125.yml @@ -0,0 +1,4 @@ +author: "carlarctg" +delete-after: True +changes: + - balance: "Halved Psyker echolocation cooldown. This will hopefully make it actually usable." \ No newline at end of file From 74f6a755ef25b389af64a0bb5420d97b1bfa3bd9 Mon Sep 17 00:00:00 2001 From: Jacquerel Date: Mon, 20 May 2024 08:16:42 +0100 Subject: [PATCH 041/103] Advanced Health Analysers can detect certain organs (#83305) ## About The Pull Request This PR makes certain organs appear in the output of the Advanced Health Analyzer, even if they are at 100% health. ![image](https://github.com/tgstation/tgstation/assets/7483112/0a0f143e-e29b-4107-9f96-612278709548) The organs this applies to are: - Legion Tumours - Heretic Organs which you get when you are sacrificed - Abductor Organs (but it doesn't specify what they do) It doesn't apply to xenomorph or changeling eggs, or romerol tumours, as those are supposed to be "stealthy". ## Why It's Good For The Game Basically I just saw someone ask for this to be possible and thought it sounded like a reasonable idea; none of these three things are intended to be particularly stealthy and it seemed like reasonably nice medical quality of life not to have to do exploratory surgery to detect their presence. It should be reasonably obvious to a medical practitioner with the correct tools that something is wrong here. ## Changelog :cl: balance: Certain unhealthy organs can be detected via the advanced health scanner /:cl: --- code/__DEFINES/surgery.dm | 2 ++ .../items/devices/scanners/health_analyzer.dm | 2 +- .../antagonists/abductor/equipment/gland.dm | 2 +- .../heretic/items/corrupted_organs.dm | 7 +++++ .../basic/lavaland/legion/legion_tumour.dm | 1 + code/modules/surgery/organs/_organ.dm | 27 +++++++++++-------- .../organs/internal/appendix/_appendix.dm | 2 +- 7 files changed, 29 insertions(+), 14 deletions(-) diff --git a/code/__DEFINES/surgery.dm b/code/__DEFINES/surgery.dm index cada3f9eb21aa..42e00045761e5 100644 --- a/code/__DEFINES/surgery.dm +++ b/code/__DEFINES/surgery.dm @@ -26,6 +26,8 @@ #define ORGAN_HIDDEN (1<<9) /// Has the organ already been inserted inside someone #define ORGAN_VIRGIN (1<<10) +/// ALWAYS show this when scanned by advanced scanners, even if it is totally healthy +#define ORGAN_PROMINENT (1<<11) /// Helper to figure out if a limb is organic #define IS_ORGANIC_LIMB(limb) (limb.bodytype & BODYTYPE_ORGANIC) diff --git a/code/game/objects/items/devices/scanners/health_analyzer.dm b/code/game/objects/items/devices/scanners/health_analyzer.dm index 10c301af1c63d..c8c76c583e103 100644 --- a/code/game/objects/items/devices/scanners/health_analyzer.dm +++ b/code/game/objects/items/devices/scanners/health_analyzer.dm @@ -279,7 +279,7 @@ Status" for(var/obj/item/organ/organ as anything in humantarget.organs) - var/status = organ.get_status_text() + var/status = organ.get_status_text(advanced) if (status != "") render = TRUE toReport += "[organ.name]:\ diff --git a/code/modules/antagonists/abductor/equipment/gland.dm b/code/modules/antagonists/abductor/equipment/gland.dm index 960851280e313..29ea5f1e78502 100644 --- a/code/modules/antagonists/abductor/equipment/gland.dm +++ b/code/modules/antagonists/abductor/equipment/gland.dm @@ -3,7 +3,7 @@ desc = "A nausea-inducing hunk of twisting flesh and metal." icon = 'icons/obj/antags/abductor.dmi' icon_state = "gland" - organ_flags = ORGAN_ROBOTIC // weird? + organ_flags = ORGAN_ROBOTIC | ORGAN_PROMINENT // weird? /// Shows name of the gland as well as a description of what it does upon examination by abductor scientists and observers. var/abductor_hint = "baseline placebo referencer" diff --git a/code/modules/antagonists/heretic/items/corrupted_organs.dm b/code/modules/antagonists/heretic/items/corrupted_organs.dm index 311e84c805599..3bd3ead7f6094 100644 --- a/code/modules/antagonists/heretic/items/corrupted_organs.dm +++ b/code/modules/antagonists/heretic/items/corrupted_organs.dm @@ -2,6 +2,7 @@ /obj/item/organ/internal/eyes/corrupt name = "corrupt orbs" desc = "These eyes have seen something they shouldn't have." + organ_flags = ORGAN_ORGANIC | ORGAN_EDIBLE | ORGAN_VIRGIN | ORGAN_PROMINENT /// The override images we are applying var/list/hallucinations @@ -39,6 +40,7 @@ /obj/item/organ/internal/tongue/corrupt name = "corrupt tongue" desc = "This one tells only lies." + organ_flags = ORGAN_ORGANIC | ORGAN_EDIBLE | ORGAN_VIRGIN | ORGAN_PROMINENT /obj/item/organ/internal/tongue/corrupt/Initialize(mapload) . = ..() @@ -65,6 +67,7 @@ /obj/item/organ/internal/liver/corrupt name = "corrupt liver" desc = "After what you've seen you could really go for a drink." + organ_flags = ORGAN_ORGANIC | ORGAN_EDIBLE | ORGAN_VIRGIN | ORGAN_PROMINENT /// How much extra ingredients to add? var/amount_added = 5 /// What extra ingredients can we add? @@ -108,6 +111,7 @@ /obj/item/organ/internal/stomach/corrupt name = "corrupt stomach" desc = "This parasite demands an unwholesome diet in order to be satisfied." + organ_flags = ORGAN_ORGANIC | ORGAN_EDIBLE | ORGAN_VIRGIN | ORGAN_PROMINENT /// Do we have an unholy thirst? var/thirst_satiated = FALSE /// Timer for when we get thirsty again @@ -173,6 +177,7 @@ /obj/item/organ/internal/heart/corrupt name = "corrupt heart" desc = "What corruption is this spreading along with the blood?" + organ_flags = ORGAN_ORGANIC | ORGAN_EDIBLE | ORGAN_VIRGIN | ORGAN_PROMINENT /// How long until the next heart? COOLDOWN_DECLARE(hand_cooldown) @@ -192,6 +197,7 @@ /obj/item/organ/internal/lungs/corrupt name = "corrupt lungs" desc = "Some things SHOULD be drowned in tar." + organ_flags = ORGAN_ORGANIC | ORGAN_EDIBLE | ORGAN_VIRGIN | ORGAN_PROMINENT /// How likely are we not to cough every time we take a breath? var/cough_chance = 15 /// How much gas to emit? @@ -226,6 +232,7 @@ /obj/item/organ/internal/appendix/corrupt name = "corrupt appendix" desc = "What kind of dark, cosmic force is even going to bother to corrupt an appendix?" + organ_flags = ORGAN_ORGANIC | ORGAN_EDIBLE | ORGAN_VIRGIN | ORGAN_PROMINENT /// How likely are we to spawn worms? var/worm_chance = 2 diff --git a/code/modules/mob/living/basic/lavaland/legion/legion_tumour.dm b/code/modules/mob/living/basic/lavaland/legion/legion_tumour.dm index 3e6931917ed29..3f678da6910bc 100644 --- a/code/modules/mob/living/basic/lavaland/legion/legion_tumour.dm +++ b/code/modules/mob/living/basic/lavaland/legion/legion_tumour.dm @@ -7,6 +7,7 @@ icon_state = "legion_remains" zone = BODY_ZONE_CHEST slot = ORGAN_SLOT_PARASITE_EGG + organ_flags = ORGAN_ORGANIC | ORGAN_EDIBLE | ORGAN_VIRGIN | ORGAN_PROMINENT decay_factor = STANDARD_ORGAN_DECAY * 3 // About 5 minutes outside of a host /// What stage of growth the corruption has reached. var/stage = 0 diff --git a/code/modules/surgery/organs/_organ.dm b/code/modules/surgery/organs/_organ.dm index a3cda722a358d..e4bb7dfe769fe 100644 --- a/code/modules/surgery/organs/_organ.dm +++ b/code/modules/surgery/organs/_organ.dm @@ -318,18 +318,23 @@ INITIALIZE_IMMEDIATE(/obj/item/organ) replacement.set_organ_damage(damage) /// Called by medical scanners to get a simple summary of how healthy the organ is. Returns an empty string if things are fine. -/obj/item/organ/proc/get_status_text() - var/status = "" +/obj/item/organ/proc/get_status_text(advanced) + if(advanced && (organ_flags & ORGAN_PROMINENT)) + return "Harmful Foreign Body" + if(owner.has_reagent(/datum/reagent/inverse/technetium)) - status = "[round((damage/maxHealth)*100, 1)]% damaged." - else if(organ_flags & ORGAN_FAILING) - status = "Non-Functional" - else if(damage > high_threshold) - status = "Severely Damaged" - else if (damage > low_threshold) - status = "Mildly Damaged" - - return status + return "[round((damage/maxHealth)*100, 1)]% damaged." + + if(organ_flags & ORGAN_FAILING) + return "Non-Functional" + + if(damage > high_threshold) + return "Severely Damaged" + + if (damage > low_threshold) + return "Mildly Damaged" + + return "" /// Tries to replace the existing organ on the passed mob with this one, with special handling for replacing a brain without ghosting target /obj/item/organ/proc/replace_into(mob/living/carbon/new_owner) diff --git a/code/modules/surgery/organs/internal/appendix/_appendix.dm b/code/modules/surgery/organs/internal/appendix/_appendix.dm index e5190f1282ec7..83ed8da84aca0 100644 --- a/code/modules/surgery/organs/internal/appendix/_appendix.dm +++ b/code/modules/surgery/organs/internal/appendix/_appendix.dm @@ -87,7 +87,7 @@ ADD_TRAIT(organ_owner, TRAIT_DISEASELIKE_SEVERITY_MEDIUM, type) organ_owner.med_hud_set_status() -/obj/item/organ/internal/appendix/get_status_text() +/obj/item/organ/internal/appendix/get_status_text(advanced) if((!(organ_flags & ORGAN_FAILING)) && inflamation_stage) return "Inflamed" else From b5d0246b8a02cce948fc4625077b899042ef6cf2 Mon Sep 17 00:00:00 2001 From: orange man <61334995+comfyorange@users.noreply.github.com> Date: Mon, 20 May 2024 19:17:00 +1200 Subject: [PATCH 042/103] Automatic changelog for PR #83305 [ci skip] --- html/changelogs/AutoChangeLog-pr-83305.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-83305.yml diff --git a/html/changelogs/AutoChangeLog-pr-83305.yml b/html/changelogs/AutoChangeLog-pr-83305.yml new file mode 100644 index 0000000000000..a9d2bfa8a0123 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-83305.yml @@ -0,0 +1,4 @@ +author: "Jacquerel" +delete-after: True +changes: + - balance: "Certain unhealthy organs can be detected via the advanced health scanner" \ No newline at end of file From 1c15cfc0a109bc6f3b3498500b2edcd1981e518d Mon Sep 17 00:00:00 2001 From: starrm4nn <139372157+starrm4nn@users.noreply.github.com> Date: Mon, 20 May 2024 07:18:00 +0000 Subject: [PATCH 043/103] Anacea can't be bruteforced by Multiver (#83300) ## About The Pull Request Multiver will stop purging all chems when Anacea is present in the blood ## Why It's Good For The Game Anacea is supposed to be countered by 2 specific chems (Pentetic Acid or Calomel), Bruteforcing it with the most common purging chem on station is pretty lame. ## Changelog :cl: balance: Multiver stops purging when Anacea is present in the bloodstream. /:cl: --- .../reagents/chemistry/reagents/cat2_medicine_reagents.dm | 2 ++ 1 file changed, 2 insertions(+) diff --git a/code/modules/reagents/chemistry/reagents/cat2_medicine_reagents.dm b/code/modules/reagents/chemistry/reagents/cat2_medicine_reagents.dm index 369efd99dcb35..7e47586e20c3b 100644 --- a/code/modules/reagents/chemistry/reagents/cat2_medicine_reagents.dm +++ b/code/modules/reagents/chemistry/reagents/cat2_medicine_reagents.dm @@ -386,6 +386,8 @@ if(the_reagent2 == src) continue var/amount2purge = 3 + if(holder.has_reagent(/datum/reagent/toxin/anacea)) + amount2purge = 0 if(medibonus >= 3 && istype(the_reagent2, /datum/reagent/medicine)) //3 unique meds (2+multiver) | (1 + pure multiver) will make it not purge medicines continue affected_mob.reagents.remove_reagent(the_reagent2.type, amount2purge * REM * seconds_per_tick) From 33e9b241dd5971b5625870e7e410ba33a7044813 Mon Sep 17 00:00:00 2001 From: orange man <61334995+comfyorange@users.noreply.github.com> Date: Mon, 20 May 2024 19:18:17 +1200 Subject: [PATCH 044/103] Automatic changelog for PR #83300 [ci skip] --- html/changelogs/AutoChangeLog-pr-83300.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-83300.yml diff --git a/html/changelogs/AutoChangeLog-pr-83300.yml b/html/changelogs/AutoChangeLog-pr-83300.yml new file mode 100644 index 0000000000000..773724f24d5c4 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-83300.yml @@ -0,0 +1,4 @@ +author: "starrm4nn" +delete-after: True +changes: + - balance: "Multiver stops purging when Anacea is present in the bloodstream." \ No newline at end of file From 7e8ba6fb9cb390c0086b89a4c0cbb3e0658d6163 Mon Sep 17 00:00:00 2001 From: starrm4nn <139372157+starrm4nn@users.noreply.github.com> Date: Mon, 20 May 2024 07:19:03 +0000 Subject: [PATCH 045/103] Buff Antihol's purge rate up (#83281) ## About The Pull Request Buff Antihol's purge rate to 8u when pure (6u minimum) ## Why It's Good For The Game Antihol in its current state is pretty worthless when its better than multiver and calomel by 1u WHEN PURE and equal to them otherwise. It does a pretty shit job when its supposed to purge a single category of reagents (Alcoholic drinks) and the biggest offenders for poisoning from massive volumes in the blood, This should make it actually worth something even if its still inferior to potassium water purging. ## Changelog :cl: balance: Buffs Antihol's purge rate to 8u/tick when pure (6u/tick minimum). /:cl: --- code/modules/reagents/chemistry/reagents/medicine_reagents.dm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/modules/reagents/chemistry/reagents/medicine_reagents.dm b/code/modules/reagents/chemistry/reagents/medicine_reagents.dm index d4f26367a5a54..cf5f41ef82c66 100644 --- a/code/modules/reagents/chemistry/reagents/medicine_reagents.dm +++ b/code/modules/reagents/chemistry/reagents/medicine_reagents.dm @@ -1108,7 +1108,7 @@ . = ..() for(var/effect in status_effects_to_clear) affected_mob.remove_status_effect(effect) - affected_mob.reagents.remove_reagent(/datum/reagent/consumable/ethanol, 3 * REM * seconds_per_tick * normalise_creation_purity(), include_subtypes = TRUE) + affected_mob.reagents.remove_reagent(/datum/reagent/consumable/ethanol, 8 * REM * seconds_per_tick * normalise_creation_purity(), include_subtypes = TRUE) if(affected_mob.adjustToxLoss(-0.2 * REM * seconds_per_tick, updating_health = FALSE, required_biotype = affected_biotype)) . = UPDATE_MOB_HEALTH affected_mob.adjust_drunk_effect(-10 * REM * seconds_per_tick * normalise_creation_purity()) From e984e6a7fe420b65a00cf637e948ea423c2c60ef Mon Sep 17 00:00:00 2001 From: orange man <61334995+comfyorange@users.noreply.github.com> Date: Mon, 20 May 2024 19:19:21 +1200 Subject: [PATCH 046/103] Automatic changelog for PR #83281 [ci skip] --- html/changelogs/AutoChangeLog-pr-83281.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-83281.yml diff --git a/html/changelogs/AutoChangeLog-pr-83281.yml b/html/changelogs/AutoChangeLog-pr-83281.yml new file mode 100644 index 0000000000000..804f8c2121b9a --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-83281.yml @@ -0,0 +1,4 @@ +author: "starrm4nn" +delete-after: True +changes: + - balance: "Buffs Antihol's purge rate to 8u/tick when pure (6u/tick minimum)." \ No newline at end of file From 8566c9d0c07e6fe1ebc332f794c30a1c15bef96c Mon Sep 17 00:00:00 2001 From: tmyqlfpir <80724828+tmyqlfpir@users.noreply.github.com> Date: Mon, 20 May 2024 17:20:33 +1000 Subject: [PATCH 047/103] Fix MetaStation service hallway door bypass (#83297) ## About The Pull Request This PR fixes a one-click all access oversight for MetaStation's service hallway. An additional reinforced window has been added between the plastic flaps and the door, thus preventing the character from opening it while lying down. https://github.com/tgstation/tgstation/assets/80724828/47102cdc-a7f1-42e2-888c-940f47bc51c9 https://github.com/tgstation/tgstation/assets/80724828/e4fa1b2e-5602-40f4-820c-20fa8d704ef2 ## Why It's Good For The Game The service hallway should not be accessible just by lying down and clicking once. ## Changelog :cl: fix: [Metastation] Service hallway door being bypassed by lying down /:cl: --- _maps/map_files/MetaStation/MetaStation.dmm | 1 + 1 file changed, 1 insertion(+) diff --git a/_maps/map_files/MetaStation/MetaStation.dmm b/_maps/map_files/MetaStation/MetaStation.dmm index f1218d4d70732..d592135038d8c 100644 --- a/_maps/map_files/MetaStation/MetaStation.dmm +++ b/_maps/map_files/MetaStation/MetaStation.dmm @@ -19251,6 +19251,7 @@ /obj/effect/turf_decal/tile/bar{ dir = 1 }, +/obj/structure/window/spawner/directional/south, /turf/open/floor/iron, /area/station/hallway/secondary/service) "hcv" = ( From 3cffd16711eebdaae412a02777b054791e4a6c60 Mon Sep 17 00:00:00 2001 From: orange man <61334995+comfyorange@users.noreply.github.com> Date: Mon, 20 May 2024 19:20:53 +1200 Subject: [PATCH 048/103] Automatic changelog for PR #83297 [ci skip] --- html/changelogs/AutoChangeLog-pr-83297.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-83297.yml diff --git a/html/changelogs/AutoChangeLog-pr-83297.yml b/html/changelogs/AutoChangeLog-pr-83297.yml new file mode 100644 index 0000000000000..63f421b317d04 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-83297.yml @@ -0,0 +1,4 @@ +author: "tmyqlfpir" +delete-after: True +changes: + - bugfix: "[Metastation] Service hallway door being bypassed by lying down" \ No newline at end of file From 659c9254958c1da6b29fb02375d3bd342e94ab63 Mon Sep 17 00:00:00 2001 From: ArcaneMusic <41715314+ArcaneMusic@users.noreply.github.com> Date: Mon, 20 May 2024 03:23:09 -0400 Subject: [PATCH 049/103] Ore vents now have countermeasures against walling them off from all sides. (#83295) ## About The Pull Request This PR fixes some balance and practicality issues with the spawner component that has affected vent mining and the associated wave defense. * The turf_peel() proc now checks to see if it's pulling no turf from the inside or outside of it's peel, in which case it now has a default case where it returns it's center turf instead. * As a consequence of this, the center turf is where mobs will spawn if an ore vent is unable to find any space where it can spawn any new hostile mobs. Upon testing this, it worked fairly well, but ultimately node drones were capable of tanking enough hits for long enough that typically they could still survive a small vent's onslaught. As a precaution, I've made two additional changes. * Node drones have had their maximum health dropped slightly, from 500 health to 300 health. * As a secondary precaution, if a spawner using the turf peel method cannot spawn correctly, it will send a signal, which ore vents are now registered to. When called on an ore vent, it has new behavior to clear the offending nearby turfs and create a pathway to allow nearby mobs to get access to the vent. * (**This is an explosion**.) ## Why It's Good For The Game Fixes an unreported on the repo but repeatedly pinged issue regarding ore vent waves where players could often wall off or blockoff an ore vent in such a way that it allows vents to be functionally immortal by quickly walling off the vent using sandstone doors. This should help to prevent players cheesing the intended gameplay mechanic, as well as keep up the challenge to arcmining wave defense without some additional nuance. I may have gone a little overboard with the health tweaks as well, but considering that even with the explosions, I was able to survive the repeated explosions on the vent, I think this should work quite well all things considered. Still, open to feedback there. ## Changelog :cl: balance: Ore vents, if blocked off from all four sides while being defended, now cause a mild gas explosion, resulting in a mild dissuasive explosion. fix: NODE drones spawned from ore vent defense have lower maximum health. /:cl: --- .../dcs/signals/signals_mob/signals_mob_spawner.dm | 3 +++ code/__HELPERS/spatial_info.dm | 3 +++ code/datums/components/spawner.dm | 2 ++ code/game/objects/structures/lavaland/ore_vent.dm | 9 +++++++++ .../mob/living/basic/lavaland/node_drone/node_drone.dm | 6 ++++-- 5 files changed, 21 insertions(+), 2 deletions(-) diff --git a/code/__DEFINES/dcs/signals/signals_mob/signals_mob_spawner.dm b/code/__DEFINES/dcs/signals/signals_mob/signals_mob_spawner.dm index 6ff8b1e8d61d4..2e1b157ec11f8 100644 --- a/code/__DEFINES/dcs/signals/signals_mob/signals_mob_spawner.dm +++ b/code/__DEFINES/dcs/signals/signals_mob/signals_mob_spawner.dm @@ -2,5 +2,8 @@ /// called when a spawner spawns a mob #define COMSIG_SPAWNER_SPAWNED "spawner_spawned" +/// Called when a spawner spawns a mob in a turf peel, but we need to use the default case. +#define COMSIG_SPAWNER_SPAWNED_DEFAULT "spawner_spawned_default" + /// called when a ghost clicks a spawner role: (mob/living) #define COMSIG_GHOSTROLE_SPAWNED "ghostrole_spawned" diff --git a/code/__HELPERS/spatial_info.dm b/code/__HELPERS/spatial_info.dm index 98e11b483bab7..c23e3a408a53c 100644 --- a/code/__HELPERS/spatial_info.dm +++ b/code/__HELPERS/spatial_info.dm @@ -468,5 +468,8 @@ if(possible_spawn in inner) continue peel += possible_spawn + + if(!length(peel)) + return center //Offer the center only as a default case when we don't have a valid circle. return peel diff --git a/code/datums/components/spawner.dm b/code/datums/components/spawner.dm index 7c85c1a5b2b70..29767d11ce6d1 100644 --- a/code/datums/components/spawner.dm +++ b/code/datums/components/spawner.dm @@ -72,6 +72,8 @@ picked_spot = pick(turf_peel(spawn_distance, spawn_distance_exclude, spawner.loc, view_based = TRUE)) if(!picked_spot) picked_spot = pick(circle_range_turfs(spawner.loc, spawn_distance)) + if(picked_spot == spawner.loc) + SEND_SIGNAL(spawner, COMSIG_SPAWNER_SPAWNED_DEFAULT) created = new chosen_mob_type(picked_spot) else if (spawn_distance >= 1) picked_spot = pick(circle_range_turfs(spawner.loc, spawn_distance)) diff --git a/code/game/objects/structures/lavaland/ore_vent.dm b/code/game/objects/structures/lavaland/ore_vent.dm index c8961a5769ccf..55b160e0109c5 100644 --- a/code/game/objects/structures/lavaland/ore_vent.dm +++ b/code/game/objects/structures/lavaland/ore_vent.dm @@ -82,6 +82,8 @@ icon_state = icon_state_tapped update_appearance(UPDATE_ICON_STATE) add_overlay(mutable_appearance('icons/obj/mining_zones/terrain.dmi', "well", ABOVE_MOB_LAYER)) + + RegisterSignal(src, COMSIG_SPAWNER_SPAWNED_DEFAULT, PROC_REF(anti_cheese)) return ..() /obj/structure/ore_vent/Destroy() @@ -407,6 +409,13 @@ COOLDOWN_START(src, manual_vent_cooldown, 10 SECONDS) return new_rock +/** + * When the ore vent cannot spawn a mob due to being blocked from all sides, we cause some MILD, MILD explosions. + * Explosion matches a gibtonite light explosion, as a way to clear neartby solid structures, with a high likelyhood of breaking the NODE drone. + */ +/obj/structure/ore_vent/proc/anti_cheese() + explosion(src, heavy_impact_range = 1, light_impact_range = 3, flame_range = 0, flash_range = 0, adminlog = FALSE) + //comes with the station, and is already tapped. /obj/structure/ore_vent/starter_resources name = "active ore vent" diff --git a/code/modules/mob/living/basic/lavaland/node_drone/node_drone.dm b/code/modules/mob/living/basic/lavaland/node_drone/node_drone.dm index d85ad69682c7d..8559fc82b6802 100644 --- a/code/modules/mob/living/basic/lavaland/node_drone/node_drone.dm +++ b/code/modules/mob/living/basic/lavaland/node_drone/node_drone.dm @@ -17,8 +17,8 @@ icon_living = "mining_node_active" icon_dead = "mining_node_active" - maxHealth = 500 - health = 500 + maxHealth = 300 // We adjust the max health based on the vent size in the arrive() proc. + health = 300 density = TRUE pass_flags = PASSTABLE|PASSGRILLE|PASSMOB mob_size = MOB_SIZE_LARGE @@ -74,6 +74,8 @@ /mob/living/basic/node_drone/proc/arrive(obj/structure/ore_vent/parent_vent) attached_vent = parent_vent + maxHealth = 300 + ((attached_vent.boulder_size/BOULDER_SIZE_SMALL) * 100) + health = maxHealth flying_state = FLY_IN_STATE update_appearance(UPDATE_ICON_STATE) pixel_z = 400 From 01582a0a1d7c12401bada7a4fb4bab4c6d741839 Mon Sep 17 00:00:00 2001 From: orange man <61334995+comfyorange@users.noreply.github.com> Date: Mon, 20 May 2024 19:23:30 +1200 Subject: [PATCH 050/103] Automatic changelog for PR #83295 [ci skip] --- html/changelogs/AutoChangeLog-pr-83295.yml | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-83295.yml diff --git a/html/changelogs/AutoChangeLog-pr-83295.yml b/html/changelogs/AutoChangeLog-pr-83295.yml new file mode 100644 index 0000000000000..890f18ebfd204 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-83295.yml @@ -0,0 +1,5 @@ +author: "ArcaneMusic" +delete-after: True +changes: + - balance: "Ore vents, if blocked off from all four sides while being defended, now cause a mild gas explosion, resulting in a mild dissuasive explosion." + - bugfix: "NODE drones spawned from ore vent defense have lower maximum health." \ No newline at end of file From 24eb71f0f13770ab7fa2181c72fe9c800a528a07 Mon Sep 17 00:00:00 2001 From: Xander3359 <66163761+Xander3359@users.noreply.github.com> Date: Mon, 20 May 2024 12:04:03 -0400 Subject: [PATCH 051/103] fix RD remote not having AI_UPLOAD access (#83328) ## About The Pull Request RD should have access to doors leading to the AI/AI-related things, so I'm adding this access to the remote as well ## Why It's Good For The Game Fix remote lacking access to things the AI can open ## Changelog :cl: fix: The RD remote works on the AI upload door now /:cl: --- code/__DEFINES/access.dm | 1 + 1 file changed, 1 insertion(+) diff --git a/code/__DEFINES/access.dm b/code/__DEFINES/access.dm index ef254589129c4..325116eb5b869 100644 --- a/code/__DEFINES/access.dm +++ b/code/__DEFINES/access.dm @@ -467,6 +467,7 @@ #define REGION_RESEARCH "Research" /// Used to seed the accesses_by_region list in SSid_access. A list of all research regional accesses that are overseen by the RD. #define REGION_ACCESS_RESEARCH list( \ + ACCESS_AI_UPLOAD, \ ACCESS_GENETICS, \ ACCESS_MECH_SCIENCE, \ ACCESS_MINISAT, \ From c1eb3a23063d0a6a0919bd9f6aa89916681aaa70 Mon Sep 17 00:00:00 2001 From: Watermelon914 <37270891+Watermelon914@users.noreply.github.com> Date: Mon, 20 May 2024 16:04:37 +0000 Subject: [PATCH 052/103] Fixed spies having a duplicate elite syndicate modsuit (#83336) ## About The Pull Request As the title says. These are the uplink items exclusive to traitor uplinks. Spies already get a variant of the hardsuit based on the nukie variant of this uplink item. ## Why It's Good For The Game An uplink should have access to one or the other, not both. ## Changelog :cl: fix: Fixed spies having a slightly increased chance of getting a different cost model for the elite syndicate hardsuit /:cl: --------- Co-authored-by: Watermelon914 <3052169-Watermelon914@users.noreply.gitlab.com> --- code/modules/uplink/uplink_items/suits.dm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/modules/uplink/uplink_items/suits.dm b/code/modules/uplink/uplink_items/suits.dm index 57982a8cf980a..8e7212744822a 100644 --- a/code/modules/uplink/uplink_items/suits.dm +++ b/code/modules/uplink/uplink_items/suits.dm @@ -70,6 +70,6 @@ provides the user with superior armor and mobility compared to the standard Syndicate MODsuit." item = /obj/item/mod/control/pre_equipped/traitor_elite // This one costs more than the nuke op counterpart - purchasable_from = ~(UPLINK_NUKE_OPS | UPLINK_CLOWN_OPS) + purchasable_from = ~(UPLINK_NUKE_OPS | UPLINK_CLOWN_OPS | UPLINK_SPY) progression_minimum = 90 MINUTES cost = 16 From e26f1393ded1728ded8d27152b2d291c6929b785 Mon Sep 17 00:00:00 2001 From: orange man <61334995+comfyorange@users.noreply.github.com> Date: Tue, 21 May 2024 04:04:59 +1200 Subject: [PATCH 053/103] Automatic changelog for PR #83336 [ci skip] --- html/changelogs/AutoChangeLog-pr-83336.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-83336.yml diff --git a/html/changelogs/AutoChangeLog-pr-83336.yml b/html/changelogs/AutoChangeLog-pr-83336.yml new file mode 100644 index 0000000000000..66a8e7a988387 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-83336.yml @@ -0,0 +1,4 @@ +author: "Watermelon914" +delete-after: True +changes: + - bugfix: "Fixed spies having a slightly increased chance of getting a different cost model for the elite syndicate hardsuit" \ No newline at end of file From 2058f0dda3cec516f1ab72e0f5bd8b029d847cb1 Mon Sep 17 00:00:00 2001 From: orange man <61334995+comfyorange@users.noreply.github.com> Date: Tue, 21 May 2024 04:05:01 +1200 Subject: [PATCH 054/103] Automatic changelog for PR #83328 [ci skip] --- html/changelogs/AutoChangeLog-pr-83328.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-83328.yml diff --git a/html/changelogs/AutoChangeLog-pr-83328.yml b/html/changelogs/AutoChangeLog-pr-83328.yml new file mode 100644 index 0000000000000..790fa10bd8556 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-83328.yml @@ -0,0 +1,4 @@ +author: "Xander3359" +delete-after: True +changes: + - bugfix: "The RD remote works on the AI upload door now" \ No newline at end of file From 7ad681c567a43fd054ec5c38a96744ff64cd6a08 Mon Sep 17 00:00:00 2001 From: nikothedude <59709059+nikothedude@users.noreply.github.com> Date: Mon, 20 May 2024 12:05:25 -0400 Subject: [PATCH 055/103] Minor raptor spellchecking (#83339) ## About The Pull Request Spellchecks a few things in raptor code. ## Why It's Good For The Game typos and bad grammar are bad surprisingly ## Changelog :cl: spellcheck: Improved the grammar/spelling of a few raptor descriptions /:cl: --- code/modules/mob/living/basic/lavaland/raptor/_raptor.dm | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/code/modules/mob/living/basic/lavaland/raptor/_raptor.dm b/code/modules/mob/living/basic/lavaland/raptor/_raptor.dm index 78c4e9c61ea9c..d79ae5582f696 100644 --- a/code/modules/mob/living/basic/lavaland/raptor/_raptor.dm +++ b/code/modules/mob/living/basic/lavaland/raptor/_raptor.dm @@ -21,7 +21,7 @@ GLOBAL_LIST_EMPTY(raptor_population) /mob/living/basic/mining/raptor name = "raptor" - desc = "A trusty powerful stead. Taming it might prove difficult..." + desc = "A trusty, powerful steed. Taming it might prove difficult..." icon = 'icons/mob/simple/lavaland/raptor_big.dmi' speed = 2 mob_biotypes = MOB_ORGANIC|MOB_BEAST @@ -202,7 +202,7 @@ GLOBAL_LIST_EMPTY(raptor_population) melee_damage_upper = 20 raptor_color = RAPTOR_RED dex_description = "A resilient breed of raptors, battle-tested and bred for the purpose of humbling its foes in combat, \ - This breed demonstrates higher combat capabilities than its peers and oozes rutheless aggression." + This breed demonstrates higher combat capabilities than its peers and oozes ruthless aggression." child_path = /mob/living/basic/mining/raptor/baby_raptor/red /mob/living/basic/mining/raptor/purple @@ -231,7 +231,7 @@ GLOBAL_LIST_EMPTY(raptor_population) health = 460 raptor_color = RAPTOR_GREEN dex_description = "A tough breed of raptor, made to withstand the harshest of punishment and to laugh in the face of pain, \ - This breed is able to withstand more beating than its peers." + this breed is able to withstand more punishment than its peers." child_path = /mob/living/basic/mining/raptor/baby_raptor/green /mob/living/basic/mining/raptor/green/Initialize(mapload) From ade3a00d016d3a18188da8116e0fd5008e1c8981 Mon Sep 17 00:00:00 2001 From: orange man <61334995+comfyorange@users.noreply.github.com> Date: Tue, 21 May 2024 04:05:45 +1200 Subject: [PATCH 056/103] Automatic changelog for PR #83339 [ci skip] --- html/changelogs/AutoChangeLog-pr-83339.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-83339.yml diff --git a/html/changelogs/AutoChangeLog-pr-83339.yml b/html/changelogs/AutoChangeLog-pr-83339.yml new file mode 100644 index 0000000000000..1364a990bad00 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-83339.yml @@ -0,0 +1,4 @@ +author: "nikothedude" +delete-after: True +changes: + - spellcheck: "Improved the grammar/spelling of a few raptor descriptions" \ No newline at end of file From 53814a4be3b975ee398b4a7b9d0d3373aa250047 Mon Sep 17 00:00:00 2001 From: kawoppi <94711066+kawoppi@users.noreply.github.com> Date: Mon, 20 May 2024 18:08:15 +0200 Subject: [PATCH 057/103] fixes Booze-O-Mat and ShadyCigs Deluxe selling to minors (#83332) ## About The Pull Request now they block the purchase and alert security like they used to ![image](https://github.com/tgstation/tgstation/assets/94711066/f1370e73-9acc-44eb-94dc-87273fe42b4f) ## Why It's Good For The Game fixes #82653 ## Changelog :cl: fix: underage drinkers beware: the Booze-O-Mat and ShadyCigs Deluxe check your age again /:cl: --- code/modules/vending/_vending.dm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/modules/vending/_vending.dm b/code/modules/vending/_vending.dm index 096cd735bd483..8e69eb10ce03f 100644 --- a/code/modules/vending/_vending.dm +++ b/code/modules/vending/_vending.dm @@ -1417,7 +1417,7 @@ GLOBAL_LIST_EMPTY(vending_machines_to_restock) if(isliving(usr)) living_user = usr card_used = living_user.get_idcard(TRUE) - else if(age_restrictions && item_record.age_restricted && (!card_used.registered_age || card_used.registered_age < AGE_MINOR)) + if(age_restrictions && item_record.age_restricted && (!card_used.registered_age || card_used.registered_age < AGE_MINOR)) speak("You are not of legal age to purchase [item_record.name].") if(!(usr in GLOB.narcd_underages)) if (isnull(sec_radio)) From 4d4ebc4e2543bd6c6723f8102c78cf4581f1d885 Mon Sep 17 00:00:00 2001 From: orange man <61334995+comfyorange@users.noreply.github.com> Date: Tue, 21 May 2024 04:08:37 +1200 Subject: [PATCH 058/103] Automatic changelog for PR #83332 [ci skip] --- html/changelogs/AutoChangeLog-pr-83332.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-83332.yml diff --git a/html/changelogs/AutoChangeLog-pr-83332.yml b/html/changelogs/AutoChangeLog-pr-83332.yml new file mode 100644 index 0000000000000..f3a43ca09f9e9 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-83332.yml @@ -0,0 +1,4 @@ +author: "kawoppi" +delete-after: True +changes: + - bugfix: "underage drinkers beware: the Booze-O-Mat and ShadyCigs Deluxe check your age again" \ No newline at end of file From 194eab2b9773c746b078875d0b072f247d3ac64b Mon Sep 17 00:00:00 2001 From: Profakos Date: Mon, 20 May 2024 18:09:55 +0200 Subject: [PATCH 059/103] [No GBP] Slime people will not be eaten be slimes (#83340) ## About The Pull Request This PR readds a missing faction check that got lost during basic mob conversion. Partially at least, previous, it ensured that FACTION_NEUTRAL was a one way faction, protecting slimes from other things, while keeping all the other factions via a check that fully reimplemented `faction_check` in a less efficient way. Rather then reimplementing this behaviour, I have just made them check for the FACTION_SLIME, similarly how regal rats skip converting already converted frogs and cockroaches. So in short, slimes once again will not attack slime people, but everything else is fair game once they get hungry (except for people who are in their friend list). I am not fully happy with this solution, but I would rather not make a new list by subtracting FACTION_NEUTRAL every time they check someone. ## Why It's Good For The Game One of the unique features of slime people was that slimes consider them friends and family. This PR brings this back this feature I forgot to reimplement. Fixes #83324 ## Changelog :cl: fix: Slimes will no longer consider feeding upon slime people /:cl: --- code/modules/mob/living/basic/slime/ai/behaviours.dm | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/code/modules/mob/living/basic/slime/ai/behaviours.dm b/code/modules/mob/living/basic/slime/ai/behaviours.dm index e573bd57354f7..1cd4677994531 100644 --- a/code/modules/mob/living/basic/slime/ai/behaviours.dm +++ b/code/modules/mob/living/basic/slime/ai/behaviours.dm @@ -32,6 +32,10 @@ if(REF(dinner) in hunter.faction) //Don't eat our friends... return + var/static/list/slime_faction = list(FACTION_SLIME) + if(faction_check(slime_faction, dinner.faction)) //Don't try to eat slimy things, no matter how hungry we are. Anyone else can be betrayed. + return + if(!hunter.can_feed_on(dinner, check_adjacent = FALSE)) //Are they tasty to slimes? return From 0e9dc3501e457c254a4bba32092958d77b2b5abe Mon Sep 17 00:00:00 2001 From: orange man <61334995+comfyorange@users.noreply.github.com> Date: Tue, 21 May 2024 04:10:15 +1200 Subject: [PATCH 060/103] Automatic changelog for PR #83340 [ci skip] --- html/changelogs/AutoChangeLog-pr-83340.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-83340.yml diff --git a/html/changelogs/AutoChangeLog-pr-83340.yml b/html/changelogs/AutoChangeLog-pr-83340.yml new file mode 100644 index 0000000000000..daebd8cd66be2 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-83340.yml @@ -0,0 +1,4 @@ +author: "Profakos" +delete-after: True +changes: + - bugfix: "Slimes will no longer consider feeding upon slime people" \ No newline at end of file From 64b5f4d0fffc2bb750e0a0a8da7dc041d8c807e0 Mon Sep 17 00:00:00 2001 From: Watermelon914 <37270891+Watermelon914@users.noreply.github.com> Date: Mon, 20 May 2024 16:14:34 +0000 Subject: [PATCH 061/103] Sets cache lifespan to 0 (#83316) ## About The Pull Request As title says. Should clear out dynamic rsc every round. https://www.byond.com/docs/ref/#/world/var/cache_lifespan ## Why It's Good For The Game Dynamic rsc balloons to huge sizes, we really don't need the dynamic rsc Co-authored-by: Watermelon914 <3052169-Watermelon914@users.noreply.gitlab.com> --- code/world.dm | 1 + 1 file changed, 1 insertion(+) diff --git a/code/world.dm b/code/world.dm index 8b1cdbf1fe496..7cc35e5529ad8 100644 --- a/code/world.dm +++ b/code/world.dm @@ -17,6 +17,7 @@ hub_password = "kMZy3U5jJHSiBQjr" name = "/tg/ Station 13" fps = 20 + cache_lifespan = 0 map_format = SIDE_MAP #ifdef FIND_REF_NO_CHECK_TICK loop_checks = FALSE From 9076dc9205f97be718d0c8d5b47ab8783c4762f7 Mon Sep 17 00:00:00 2001 From: Ben10Omintrix <138636438+Ben10Omintrix@users.noreply.github.com> Date: Mon, 20 May 2024 21:00:47 +0300 Subject: [PATCH 062/103] fixes riding mobs through space (#83345) ## About The Pull Request this fixes being able to ride all mobs through space, apart from things which actually can like carps ## Why It's Good For The Game fixes being able to ride all mobs through space ## Changelog :cl: fix: fixes being able to ride all mobs through space /:cl: --- code/datums/components/riding/riding_mob.dm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/datums/components/riding/riding_mob.dm b/code/datums/components/riding/riding_mob.dm index d6c07d434237a..a808784b815ec 100644 --- a/code/datums/components/riding/riding_mob.dm +++ b/code/datums/components/riding/riding_mob.dm @@ -97,7 +97,7 @@ return ..() /datum/component/riding/creature/driver_move(atom/movable/movable_parent, mob/living/user, direction) - if(!COOLDOWN_FINISHED(src, vehicle_move_cooldown)) + if(!COOLDOWN_FINISHED(src, vehicle_move_cooldown) || !Process_Spacemove()) return COMPONENT_DRIVER_BLOCK_MOVE if(!keycheck(user)) if(ispath(keytype, /obj/item)) From 5394ba20edd5bbf71ed1c212260a596fd8cb2517 Mon Sep 17 00:00:00 2001 From: orange man <61334995+comfyorange@users.noreply.github.com> Date: Tue, 21 May 2024 06:01:07 +1200 Subject: [PATCH 063/103] Automatic changelog for PR #83345 [ci skip] --- html/changelogs/AutoChangeLog-pr-83345.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-83345.yml diff --git a/html/changelogs/AutoChangeLog-pr-83345.yml b/html/changelogs/AutoChangeLog-pr-83345.yml new file mode 100644 index 0000000000000..8f627d989ca80 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-83345.yml @@ -0,0 +1,4 @@ +author: "Ben10Omintrix" +delete-after: True +changes: + - bugfix: " fixes being able to ride all mobs through space" \ No newline at end of file From 5dbe59d6c29268528090acad2b81fd497a94b0db Mon Sep 17 00:00:00 2001 From: Changelogs Date: Tue, 21 May 2024 00:21:18 +0000 Subject: [PATCH 064/103] Automatic changelog compile [ci skip] --- html/changelogs/AutoChangeLog-pr-82905.yml | 5 -- html/changelogs/AutoChangeLog-pr-83125.yml | 4 -- html/changelogs/AutoChangeLog-pr-83191.yml | 4 -- html/changelogs/AutoChangeLog-pr-83268.yml | 5 -- html/changelogs/AutoChangeLog-pr-83274.yml | 4 -- html/changelogs/AutoChangeLog-pr-83279.yml | 4 -- html/changelogs/AutoChangeLog-pr-83281.yml | 4 -- html/changelogs/AutoChangeLog-pr-83283.yml | 5 -- html/changelogs/AutoChangeLog-pr-83286.yml | 4 -- html/changelogs/AutoChangeLog-pr-83287.yml | 4 -- html/changelogs/AutoChangeLog-pr-83288.yml | 4 -- html/changelogs/AutoChangeLog-pr-83293.yml | 4 -- html/changelogs/AutoChangeLog-pr-83294.yml | 4 -- html/changelogs/AutoChangeLog-pr-83295.yml | 5 -- html/changelogs/AutoChangeLog-pr-83297.yml | 4 -- html/changelogs/AutoChangeLog-pr-83298.yml | 4 -- html/changelogs/AutoChangeLog-pr-83299.yml | 4 -- html/changelogs/AutoChangeLog-pr-83300.yml | 4 -- html/changelogs/AutoChangeLog-pr-83302.yml | 4 -- html/changelogs/AutoChangeLog-pr-83305.yml | 4 -- html/changelogs/AutoChangeLog-pr-83308.yml | 4 -- html/changelogs/AutoChangeLog-pr-83319.yml | 5 -- html/changelogs/AutoChangeLog-pr-83321.yml | 4 -- html/changelogs/AutoChangeLog-pr-83322.yml | 4 -- html/changelogs/AutoChangeLog-pr-83328.yml | 4 -- html/changelogs/AutoChangeLog-pr-83332.yml | 4 -- html/changelogs/AutoChangeLog-pr-83336.yml | 4 -- html/changelogs/AutoChangeLog-pr-83339.yml | 4 -- html/changelogs/AutoChangeLog-pr-83340.yml | 4 -- html/changelogs/AutoChangeLog-pr-83345.yml | 4 -- html/changelogs/archive/2024-05.yml | 71 ++++++++++++++++++++++ 31 files changed, 71 insertions(+), 125 deletions(-) delete mode 100644 html/changelogs/AutoChangeLog-pr-82905.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-83125.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-83191.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-83268.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-83274.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-83279.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-83281.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-83283.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-83286.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-83287.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-83288.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-83293.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-83294.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-83295.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-83297.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-83298.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-83299.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-83300.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-83302.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-83305.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-83308.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-83319.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-83321.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-83322.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-83328.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-83332.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-83336.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-83339.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-83340.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-83345.yml diff --git a/html/changelogs/AutoChangeLog-pr-82905.yml b/html/changelogs/AutoChangeLog-pr-82905.yml deleted file mode 100644 index ff7fe2bda96f0..0000000000000 --- a/html/changelogs/AutoChangeLog-pr-82905.yml +++ /dev/null @@ -1,5 +0,0 @@ -author: "Fikou" -delete-after: True -changes: - - refactor: "modsuits have been refactored if you see bugs report them" - - bugfix: "admin cargo tech modsuit outfit now works correctly" \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-83125.yml b/html/changelogs/AutoChangeLog-pr-83125.yml deleted file mode 100644 index fcf31111b345f..0000000000000 --- a/html/changelogs/AutoChangeLog-pr-83125.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "carlarctg" -delete-after: True -changes: - - balance: "Halved Psyker echolocation cooldown. This will hopefully make it actually usable." \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-83191.yml b/html/changelogs/AutoChangeLog-pr-83191.yml deleted file mode 100644 index 79d5188b590b9..0000000000000 --- a/html/changelogs/AutoChangeLog-pr-83191.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "iwishforducks" -delete-after: True -changes: - - image: "Medical doctors and CMOs now start with their jumpsuits rather than surgery scrubs and caps." \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-83268.yml b/html/changelogs/AutoChangeLog-pr-83268.yml deleted file mode 100644 index ddd5581fc79d2..0000000000000 --- a/html/changelogs/AutoChangeLog-pr-83268.yml +++ /dev/null @@ -1,5 +0,0 @@ -author: "ShizCalev" -delete-after: True -changes: - - bugfix: "Malf AI can now properly interact with APCs under their control" - - bugfix: "Malf AI & their slaved cyborgs won't be told that access is denied when trying to right-click lock/unlock APCs." \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-83274.yml b/html/changelogs/AutoChangeLog-pr-83274.yml deleted file mode 100644 index 5b9a468685fbf..0000000000000 --- a/html/changelogs/AutoChangeLog-pr-83274.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "grungussuss and Virgilcore" -delete-after: True -changes: - - sound: "added sounds for the gateway" \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-83279.yml b/html/changelogs/AutoChangeLog-pr-83279.yml deleted file mode 100644 index d1f3631f57b3d..0000000000000 --- a/html/changelogs/AutoChangeLog-pr-83279.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "ShizCalev" -delete-after: True -changes: - - bugfix: "Icecream vats will no longer eat cyborg beakers." \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-83281.yml b/html/changelogs/AutoChangeLog-pr-83281.yml deleted file mode 100644 index 804f8c2121b9a..0000000000000 --- a/html/changelogs/AutoChangeLog-pr-83281.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "starrm4nn" -delete-after: True -changes: - - balance: "Buffs Antihol's purge rate to 8u/tick when pure (6u/tick minimum)." \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-83283.yml b/html/changelogs/AutoChangeLog-pr-83283.yml deleted file mode 100644 index 855531a30258d..0000000000000 --- a/html/changelogs/AutoChangeLog-pr-83283.yml +++ /dev/null @@ -1,5 +0,0 @@ -author: "Melbert" -delete-after: True -changes: - - qol: "Custom emotes now default to both visible and audible rather than just audible" - - qol: "Invoking the custom emote verb now explains how to set your custom emote to visible or audible" \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-83286.yml b/html/changelogs/AutoChangeLog-pr-83286.yml deleted file mode 100644 index 4f83dad85f947..0000000000000 --- a/html/changelogs/AutoChangeLog-pr-83286.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "Jacquerel" -delete-after: True -changes: - - balance: "If you can't absorb a species' DNA as a changeling, you also can't use transform sting to turn someone into that species." \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-83287.yml b/html/changelogs/AutoChangeLog-pr-83287.yml deleted file mode 100644 index b22a2e037283b..0000000000000 --- a/html/changelogs/AutoChangeLog-pr-83287.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "Pickle-Coding" -delete-after: True -changes: - - balance: "Cargo ripley's cell starts fully charged." \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-83288.yml b/html/changelogs/AutoChangeLog-pr-83288.yml deleted file mode 100644 index ddc929033878a..0000000000000 --- a/html/changelogs/AutoChangeLog-pr-83288.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "EnterTheJake" -delete-after: True -changes: - - spellcheck: "Pulse of entropy description now displays the correct reagents for the ritual" \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-83293.yml b/html/changelogs/AutoChangeLog-pr-83293.yml deleted file mode 100644 index 77a688e3d9d28..0000000000000 --- a/html/changelogs/AutoChangeLog-pr-83293.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "Fikou" -delete-after: True -changes: - - bugfix: "carps now properly stop floating when you kill them" \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-83294.yml b/html/changelogs/AutoChangeLog-pr-83294.yml deleted file mode 100644 index 908e790bee223..0000000000000 --- a/html/changelogs/AutoChangeLog-pr-83294.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "Ben10Omintrix" -delete-after: True -changes: - - bugfix: "playful raptors now correctly play with owners" \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-83295.yml b/html/changelogs/AutoChangeLog-pr-83295.yml deleted file mode 100644 index 890f18ebfd204..0000000000000 --- a/html/changelogs/AutoChangeLog-pr-83295.yml +++ /dev/null @@ -1,5 +0,0 @@ -author: "ArcaneMusic" -delete-after: True -changes: - - balance: "Ore vents, if blocked off from all four sides while being defended, now cause a mild gas explosion, resulting in a mild dissuasive explosion." - - bugfix: "NODE drones spawned from ore vent defense have lower maximum health." \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-83297.yml b/html/changelogs/AutoChangeLog-pr-83297.yml deleted file mode 100644 index 63f421b317d04..0000000000000 --- a/html/changelogs/AutoChangeLog-pr-83297.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "tmyqlfpir" -delete-after: True -changes: - - bugfix: "[Metastation] Service hallway door being bypassed by lying down" \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-83298.yml b/html/changelogs/AutoChangeLog-pr-83298.yml deleted file mode 100644 index ed255d8f9095f..0000000000000 --- a/html/changelogs/AutoChangeLog-pr-83298.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "Sadboysuss" -delete-after: True -changes: - - bugfix: "HoS on birdshot now has a pet like on all other maps" \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-83299.yml b/html/changelogs/AutoChangeLog-pr-83299.yml deleted file mode 100644 index 5616c75e5e75c..0000000000000 --- a/html/changelogs/AutoChangeLog-pr-83299.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "Sadboysuss" -delete-after: True -changes: - - bugfix: "jumpsuit sensors quick maxing now works" \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-83300.yml b/html/changelogs/AutoChangeLog-pr-83300.yml deleted file mode 100644 index 773724f24d5c4..0000000000000 --- a/html/changelogs/AutoChangeLog-pr-83300.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "starrm4nn" -delete-after: True -changes: - - balance: "Multiver stops purging when Anacea is present in the bloodstream." \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-83302.yml b/html/changelogs/AutoChangeLog-pr-83302.yml deleted file mode 100644 index 0cd0e16936891..0000000000000 --- a/html/changelogs/AutoChangeLog-pr-83302.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "Jacquerel" -delete-after: True -changes: - - admin: "Various bad things that can happen as a result of Legion organs are now logged" \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-83305.yml b/html/changelogs/AutoChangeLog-pr-83305.yml deleted file mode 100644 index a9d2bfa8a0123..0000000000000 --- a/html/changelogs/AutoChangeLog-pr-83305.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "Jacquerel" -delete-after: True -changes: - - balance: "Certain unhealthy organs can be detected via the advanced health scanner" \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-83308.yml b/html/changelogs/AutoChangeLog-pr-83308.yml deleted file mode 100644 index d6aa3402cceba..0000000000000 --- a/html/changelogs/AutoChangeLog-pr-83308.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "dopamiin0" -delete-after: True -changes: - - rscadd: "Nanotrasen has made strides in their frontier sector food networks, increasing the selection of produce available to chefs." \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-83319.yml b/html/changelogs/AutoChangeLog-pr-83319.yml deleted file mode 100644 index bbc049c558803..0000000000000 --- a/html/changelogs/AutoChangeLog-pr-83319.yml +++ /dev/null @@ -1,5 +0,0 @@ -author: "necromanceranne" -delete-after: True -changes: - - bugfix: "Miners can actually access and fix their engineering issues on the lavaland base via the engineering section of the base. AGAIN." - - bugfix: "The gulag SMES unit is no longer needlessly draining the entire power grid of the main mining base. AGAIN." \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-83321.yml b/html/changelogs/AutoChangeLog-pr-83321.yml deleted file mode 100644 index 2e6ee1aaf6f61..0000000000000 --- a/html/changelogs/AutoChangeLog-pr-83321.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "ShizCalev" -delete-after: True -changes: - - bugfix: "Balloons are no longer invisible when held." \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-83322.yml b/html/changelogs/AutoChangeLog-pr-83322.yml deleted file mode 100644 index 47e72c4c16382..0000000000000 --- a/html/changelogs/AutoChangeLog-pr-83322.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "Striders13" -delete-after: True -changes: - - admin: "sentience balloon can now assign antag to affected mobs" \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-83328.yml b/html/changelogs/AutoChangeLog-pr-83328.yml deleted file mode 100644 index 790fa10bd8556..0000000000000 --- a/html/changelogs/AutoChangeLog-pr-83328.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "Xander3359" -delete-after: True -changes: - - bugfix: "The RD remote works on the AI upload door now" \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-83332.yml b/html/changelogs/AutoChangeLog-pr-83332.yml deleted file mode 100644 index f3a43ca09f9e9..0000000000000 --- a/html/changelogs/AutoChangeLog-pr-83332.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "kawoppi" -delete-after: True -changes: - - bugfix: "underage drinkers beware: the Booze-O-Mat and ShadyCigs Deluxe check your age again" \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-83336.yml b/html/changelogs/AutoChangeLog-pr-83336.yml deleted file mode 100644 index 66a8e7a988387..0000000000000 --- a/html/changelogs/AutoChangeLog-pr-83336.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "Watermelon914" -delete-after: True -changes: - - bugfix: "Fixed spies having a slightly increased chance of getting a different cost model for the elite syndicate hardsuit" \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-83339.yml b/html/changelogs/AutoChangeLog-pr-83339.yml deleted file mode 100644 index 1364a990bad00..0000000000000 --- a/html/changelogs/AutoChangeLog-pr-83339.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "nikothedude" -delete-after: True -changes: - - spellcheck: "Improved the grammar/spelling of a few raptor descriptions" \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-83340.yml b/html/changelogs/AutoChangeLog-pr-83340.yml deleted file mode 100644 index daebd8cd66be2..0000000000000 --- a/html/changelogs/AutoChangeLog-pr-83340.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "Profakos" -delete-after: True -changes: - - bugfix: "Slimes will no longer consider feeding upon slime people" \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-83345.yml b/html/changelogs/AutoChangeLog-pr-83345.yml deleted file mode 100644 index 8f627d989ca80..0000000000000 --- a/html/changelogs/AutoChangeLog-pr-83345.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "Ben10Omintrix" -delete-after: True -changes: - - bugfix: " fixes being able to ride all mobs through space" \ No newline at end of file diff --git a/html/changelogs/archive/2024-05.yml b/html/changelogs/archive/2024-05.yml index 05dafdfef0c7f..25688eb731a0d 100644 --- a/html/changelogs/archive/2024-05.yml +++ b/html/changelogs/archive/2024-05.yml @@ -505,3 +505,74 @@ - balance: Nukies ordnance now include more gasses and stock parts sheets, spacemenart, ben10omintrix, goofball, infrared baron, aofie: - rscadd: adds lavaland raptors and the raptor ranch +2024-05-21: + ArcaneMusic: + - balance: Ore vents, if blocked off from all four sides while being defended, now + cause a mild gas explosion, resulting in a mild dissuasive explosion. + - bugfix: NODE drones spawned from ore vent defense have lower maximum health. + Ben10Omintrix: + - bugfix: ' fixes being able to ride all mobs through space' + - bugfix: playful raptors now correctly play with owners + EnterTheJake: + - spellcheck: Pulse of entropy description now displays the correct reagents for + the ritual + Fikou: + - bugfix: carps now properly stop floating when you kill them + - refactor: modsuits have been refactored if you see bugs report them + - bugfix: admin cargo tech modsuit outfit now works correctly + Jacquerel: + - balance: Certain unhealthy organs can be detected via the advanced health scanner + - balance: If you can't absorb a species' DNA as a changeling, you also can't use + transform sting to turn someone into that species. + - admin: Various bad things that can happen as a result of Legion organs are now + logged + Melbert: + - qol: Custom emotes now default to both visible and audible rather than just audible + - qol: Invoking the custom emote verb now explains how to set your custom emote + to visible or audible + Pickle-Coding: + - balance: Cargo ripley's cell starts fully charged. + Profakos: + - bugfix: Slimes will no longer consider feeding upon slime people + Sadboysuss: + - bugfix: HoS on birdshot now has a pet like on all other maps + - bugfix: jumpsuit sensors quick maxing now works + ShizCalev: + - bugfix: Icecream vats will no longer eat cyborg beakers. + - bugfix: Balloons are no longer invisible when held. + - bugfix: Malf AI can now properly interact with APCs under their control + - bugfix: Malf AI & their slaved cyborgs won't be told that access is denied when + trying to right-click lock/unlock APCs. + Striders13: + - admin: sentience balloon can now assign antag to affected mobs + Watermelon914: + - bugfix: Fixed spies having a slightly increased chance of getting a different + cost model for the elite syndicate hardsuit + Xander3359: + - bugfix: The RD remote works on the AI upload door now + carlarctg: + - balance: Halved Psyker echolocation cooldown. This will hopefully make it actually + usable. + dopamiin0: + - rscadd: Nanotrasen has made strides in their frontier sector food networks, increasing + the selection of produce available to chefs. + grungussuss and Virgilcore: + - sound: added sounds for the gateway + iwishforducks: + - image: Medical doctors and CMOs now start with their jumpsuits rather than surgery + scrubs and caps. + kawoppi: + - bugfix: 'underage drinkers beware: the Booze-O-Mat and ShadyCigs Deluxe check + your age again' + necromanceranne: + - bugfix: Miners can actually access and fix their engineering issues on the lavaland + base via the engineering section of the base. AGAIN. + - bugfix: The gulag SMES unit is no longer needlessly draining the entire power + grid of the main mining base. AGAIN. + nikothedude: + - spellcheck: Improved the grammar/spelling of a few raptor descriptions + starrm4nn: + - balance: Buffs Antihol's purge rate to 8u/tick when pure (6u/tick minimum). + - balance: Multiver stops purging when Anacea is present in the bloodstream. + tmyqlfpir: + - bugfix: '[Metastation] Service hallway door being bypassed by lying down' From e8aea936eb7803f6ae05b3e08799895e4a4e865f Mon Sep 17 00:00:00 2001 From: Horatio22 <69338705+Horatio22@users.noreply.github.com> Date: Mon, 20 May 2024 21:09:20 -0700 Subject: [PATCH 065/103] Corrects player-facing instances of "recieve" (#83350) ## About The Pull Request Changes all player-facing instances of "recieve" to the correct spelling "receive". There are still a handful of instances in the code, but this PR doesn't mess with those. ## Why It's Good For The Game It's important to speel things correctly. ## Changelog :cl: spellcheck: Correctly spells "received." /:cl: --- code/game/objects/items/choice_beacon.dm | 2 +- code/game/objects/structures/deployable_turret.dm | 2 +- code/game/objects/structures/syndicate_uplink_beacon.dm | 2 +- code/modules/antagonists/_common/antag_spawner.dm | 2 +- code/modules/mob/living/carbon/human/_species.dm | 4 ++-- code/modules/mob/living/carbon/human/species_types/felinid.dm | 2 +- 6 files changed, 7 insertions(+), 7 deletions(-) diff --git a/code/game/objects/items/choice_beacon.dm b/code/game/objects/items/choice_beacon.dm index 06385b765cfab..75a3f35c80b97 100644 --- a/code/game/objects/items/choice_beacon.dm +++ b/code/game/objects/items/choice_beacon.dm @@ -139,7 +139,7 @@ icon_state = "self_delivery" inhand_icon_state = "self_delivery" company_source = "S.E.L.F." - company_message = span_bold("Request status: Recieved. Package status: Delivered. Notes: To assure optimal value, use supplied Interdyne-brand autosurgeons to change implantment status.") + company_message = span_bold("Request status: Received. Package status: Delivered. Notes: To assure optimal value, use supplied Interdyne-brand autosurgeons to change implantment status.") /obj/item/choice_beacon/augments/generate_display_names() var/static/list/augment_list diff --git a/code/game/objects/structures/deployable_turret.dm b/code/game/objects/structures/deployable_turret.dm index 7b03348288abb..b2bb5fe51c595 100644 --- a/code/game/objects/structures/deployable_turret.dm +++ b/code/game/objects/structures/deployable_turret.dm @@ -213,7 +213,7 @@ /obj/machinery/deployable_turret/hmg name = "heavy machine gun turret" - desc = "A heavy calibre machine gun commonly used by Nanotrasen forces, famed for it's ability to give people on the recieving end more holes than normal." + desc = "A heavy caliber machine gun commonly used by Nanotrasen forces, famed for it's ability to give people on the receiving end more holes than normal." icon_state = "hmg" max_integrity = 250 projectile_type = /obj/projectile/bullet/manned_turret/hmg diff --git a/code/game/objects/structures/syndicate_uplink_beacon.dm b/code/game/objects/structures/syndicate_uplink_beacon.dm index 2106fade55a5c..33e260e8d209a 100644 --- a/code/game/objects/structures/syndicate_uplink_beacon.dm +++ b/code/game/objects/structures/syndicate_uplink_beacon.dm @@ -3,7 +3,7 @@ name = "suspicious beacon" icon = 'icons/obj/machines/telecomms.dmi' icon_state = "relay_traitor" - desc = "This ramshackle device seems capable of recieving and sending signals for some nefarious purpose." + desc = "This ramshackle device seems capable of receiving and sending signals for some nefarious purpose." density = TRUE anchored = TRUE /// Traitor's code that they speak into the radio diff --git a/code/modules/antagonists/_common/antag_spawner.dm b/code/modules/antagonists/_common/antag_spawner.dm index 18dce0501ff65..ae4b8e8db6edf 100644 --- a/code/modules/antagonists/_common/antag_spawner.dm +++ b/code/modules/antagonists/_common/antag_spawner.dm @@ -170,7 +170,7 @@ /obj/item/antag_spawner/nuke_ops/overwatch name = "overwatch support beacon" desc = "Assigns an Overwatch Intelligence Agent to your operation. Stationed at their own remote outpost, they can view station cameras, alarms, and even move the Infiltrator shuttle! \ - Also, all members of your operation will recieve body cameras that they can view your progress from." + Also, all members of your operation will receive body cameras that they can view your progress from." special_role_name = ROLE_OPERATIVE_OVERWATCH outfit = /datum/outfit/syndicate/support use_subtypes = FALSE diff --git a/code/modules/mob/living/carbon/human/_species.dm b/code/modules/mob/living/carbon/human/_species.dm index 24a35e683e36d..82d51c173cb05 100644 --- a/code/modules/mob/living/carbon/human/_species.dm +++ b/code/modules/mob/living/carbon/human/_species.dm @@ -1839,7 +1839,7 @@ GLOBAL_LIST_EMPTY(features_by_species) SPECIES_PERK_TYPE = SPECIES_NEUTRAL_PERK, SPECIES_PERK_ICON = "tint", SPECIES_PERK_NAME = initial(exotic_blood.name), - SPECIES_PERK_DESC = "[name] blood is [initial(exotic_blood.name)], which can make recieving medical treatment harder.", + SPECIES_PERK_DESC = "[name] blood is [initial(exotic_blood.name)], which can make receiving medical treatment harder.", )) // Otherwise otherwise, see if they have an exotic bloodtype set @@ -1848,7 +1848,7 @@ GLOBAL_LIST_EMPTY(features_by_species) SPECIES_PERK_TYPE = SPECIES_NEUTRAL_PERK, SPECIES_PERK_ICON = "tint", SPECIES_PERK_NAME = "Exotic Blood", - SPECIES_PERK_DESC = "[plural_form] have \"[exotic_bloodtype]\" type blood, which can make recieving medical treatment harder.", + SPECIES_PERK_DESC = "[plural_form] have \"[exotic_bloodtype]\" type blood, which can make receiving medical treatment harder.", )) return to_add 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 1e8cf9def9463..4866501584a96 100644 --- a/code/modules/mob/living/carbon/human/species_types/felinid.dm +++ b/code/modules/mob/living/carbon/human/species_types/felinid.dm @@ -228,7 +228,7 @@ SPECIES_PERK_ICON = FA_ICON_PERSON_FALLING, SPECIES_PERK_NAME = "Catlike Grace", SPECIES_PERK_DESC = "Felinids have catlike instincts allowing them to land upright on their feet. \ - Instead of being knocked down from falling, you only recieve a short slowdown. \ + Instead of being knocked down from falling, you only receive a short slowdown. \ However, they do not have catlike legs, and the fall will deal additional damage.", ), list( From 2eccea74e9ef3fe38ec03edfe1dcf5e41bd7403b Mon Sep 17 00:00:00 2001 From: Horatio22 <69338705+Horatio22@users.noreply.github.com> Date: Mon, 20 May 2024 21:10:04 -0700 Subject: [PATCH 066/103] Correct spelling for moonlight amulet (#83351) ## About The Pull Request Changes all instances of "amulette" to "amulet" (except for icon_state instances of the misspelling). ## Why It's Good For The Game Spelling ## Changelog :cl: spellcheck: Corrects spelling of "amulette" to "amulet" /:cl: --- .../mood_events/generic_negative_events.dm | 2 +- .../antagonists/heretic/items/heretic_necks.dm | 12 ++++++------ .../antagonists/heretic/knowledge/moon_lore.dm | 16 ++++++++-------- .../heretic/knowledge/side_ash_moon.dm | 2 +- .../heretic/knowledge/side_lock_moon.dm | 4 ++-- 5 files changed, 18 insertions(+), 18 deletions(-) diff --git a/code/datums/mood_events/generic_negative_events.dm b/code/datums/mood_events/generic_negative_events.dm index 0e54c21e70234..e6cf8f2d3d80e 100644 --- a/code/datums/mood_events/generic_negative_events.dm +++ b/code/datums/mood_events/generic_negative_events.dm @@ -469,7 +469,7 @@ mood_change = -3 timeout = 5 MINUTES -/datum/mood_event/amulette_insanity +/datum/mood_event/amulet_insanity description = "I sEe THe LiGHt, It mUsT BE stOPPed" mood_change = -6 timeout = 5 MINUTES diff --git a/code/modules/antagonists/heretic/items/heretic_necks.dm b/code/modules/antagonists/heretic/items/heretic_necks.dm index c1f244dfd0e8f..e24c17abdeeba 100644 --- a/code/modules/antagonists/heretic/items/heretic_necks.dm +++ b/code/modules/antagonists/heretic/items/heretic_necks.dm @@ -52,9 +52,9 @@ w_class = WEIGHT_CLASS_SMALL -// The amulette conversion tool used by moon heretics -/obj/item/clothing/neck/heretic_focus/moon_amulette - name = "Moonlight Amulette" +// The amulet conversion tool used by moon heretics +/obj/item/clothing/neck/heretic_focus/moon_amulet + name = "Moonlight Amulet" desc = "A piece of the mind, the soul and the moon. Gazing into it makes your head spin and hear whispers of laughter and joy." icon = 'icons/obj/antags/eldritch.dmi' icon_state = "moon_amulette" @@ -62,11 +62,11 @@ // How much damage does this item do to the targets sanity? var/sanity_damage = 20 -/obj/item/clothing/neck/heretic_focus/moon_amulette/attack(mob/living/target, mob/living/user, params) +/obj/item/clothing/neck/heretic_focus/moon_amulet/attack(mob/living/target, mob/living/user, params) var/mob/living/carbon/human/hit = target if(!IS_HERETIC_OR_MONSTER(user)) user.balloon_alert(user, "you feel a presence watching you") - user.add_mood_event("Moon Amulette Insanity", /datum/mood_event/amulette_insanity) + user.add_mood_event("Moon Amulet Insanity", /datum/mood_event/amulet_insanity) user.mob_mood.set_sanity(user.mob_mood.sanity - 50) return if(hit.can_block_magic()) @@ -75,7 +75,7 @@ return if(hit.mob_mood.sanity_level < SANITY_LEVEL_UNSTABLE) user.balloon_alert(user, "their mind is too strong!") - hit.add_mood_event("Moon Amulette Insanity", /datum/mood_event/amulette_insanity) + hit.add_mood_event("Moon Amulet Insanity", /datum/mood_event/amulet_insanity) hit.mob_mood.set_sanity(hit.mob_mood.sanity - sanity_damage) else user.balloon_alert(user, "their mind bends to see the truth!") diff --git a/code/modules/antagonists/heretic/knowledge/moon_lore.dm b/code/modules/antagonists/heretic/knowledge/moon_lore.dm index b708bf6584e9c..e2af5390ba810 100644 --- a/code/modules/antagonists/heretic/knowledge/moon_lore.dm +++ b/code/modules/antagonists/heretic/knowledge/moon_lore.dm @@ -13,7 +13,7 @@ * Mark of Moon * Ritual of Knowledge * Lunar Parade - * Moonlight Amulette + * Moonlight Amulet * > Sidepaths: * Curse of Paralasys * Unfathomable Curio @@ -103,15 +103,15 @@ desc = "Grants you Lunar Parade, a spell that - after a short charge - sends a carnival forward \ when hitting someone they are forced to join the parade and suffer hallucinations." gain_text = "The music like a reflection of the soul compelled them, like moths to a flame they followed" - next_knowledge = list(/datum/heretic_knowledge/moon_amulette) + next_knowledge = list(/datum/heretic_knowledge/moon_amulet) spell_to_add = /datum/action/cooldown/spell/pointed/projectile/moon_parade cost = 1 route = PATH_MOON -/datum/heretic_knowledge/moon_amulette - name = "Moonlight Amulette" - desc = "Allows you to transmute 2 sheets of glass, a heart and a tie to create a Moonlight Amulette. \ +/datum/heretic_knowledge/moon_amulet + name = "Moonlight Amulet" + desc = "Allows you to transmute 2 sheets of glass, a heart and a tie to create a Moonlight Amulet. \ If the item is used on someone with low sanity they go berserk attacking everyone, \ if their sanity isn't low enough it decreases their mood." gain_text = "At the head of the parade he stood, the moon condensed into one mass, a reflection of the soul." @@ -127,7 +127,7 @@ /obj/item/stack/sheet/glass = 2, /obj/item/clothing/neck/tie = 1, ) - result_atoms = list(/obj/item/clothing/neck/heretic_focus/moon_amulette) + result_atoms = list(/obj/item/clothing/neck/heretic_focus/moon_amulet) cost = 1 route = PATH_MOON @@ -171,7 +171,7 @@ Bring 3 corpses with more than 50 brain damage to a transmutation rune to complete the ritual. \ When completed, you become a harbinger of madness gaining and aura of passive sanity decrease, \ confusion increase and, if their sanity is low enough, brain damage and blindness. \ - 1/5th of the crew will turn into acolytes and follow your command, they will all recieve moonlight amulettes." + 1/5th of the crew will turn into acolytes and follow your command, they will all receive moonlight amulets." gain_text = "We dived down towards the crowd, his soul splitting off in search of greater venture \ for where the Ringleader had started the parade, I shall continue it unto the suns demise \ WITNESS MY ASCENSION, THE MOON SMILES ONCE MORE AND FOREVER MORE IT SHALL!" @@ -229,7 +229,7 @@ continue var/datum/antagonist/lunatic/lunatic = crewmate.mind.add_antag_datum(/datum/antagonist/lunatic) lunatic.set_master(user.mind, user) - var/obj/item/clothing/neck/heretic_focus/moon_amulette/amulet = new(crewmate_turf) + var/obj/item/clothing/neck/heretic_focus/moon_amulet/amulet = new(crewmate_turf) var/static/list/slots = list( "neck" = ITEM_SLOT_NECK, "hands" = ITEM_SLOT_HANDS, diff --git a/code/modules/antagonists/heretic/knowledge/side_ash_moon.dm b/code/modules/antagonists/heretic/knowledge/side_ash_moon.dm index a4810c706c118..f933bbfda1d26 100644 --- a/code/modules/antagonists/heretic/knowledge/side_ash_moon.dm +++ b/code/modules/antagonists/heretic/knowledge/side_ash_moon.dm @@ -25,7 +25,7 @@ gain_text = "The flesh of humanity is weak. Make them bleed. Show them their fragility." next_knowledge = list( /datum/heretic_knowledge/mad_mask, - /datum/heretic_knowledge/moon_amulette, + /datum/heretic_knowledge/moon_amulet, ) required_atoms = list( /obj/item/bodypart/leg/left = 1, diff --git a/code/modules/antagonists/heretic/knowledge/side_lock_moon.dm b/code/modules/antagonists/heretic/knowledge/side_lock_moon.dm index f1dd564310be5..5ab50a8b84f3c 100644 --- a/code/modules/antagonists/heretic/knowledge/side_lock_moon.dm +++ b/code/modules/antagonists/heretic/knowledge/side_lock_moon.dm @@ -23,7 +23,7 @@ gain_text = "The mansus holds many a curio, some are not meant for the mortal eye." next_knowledge = list( /datum/heretic_knowledge/spell/burglar_finesse, - /datum/heretic_knowledge/moon_amulette, + /datum/heretic_knowledge/moon_amulet, ) required_atoms = list( /obj/item/organ/internal/lungs = 1, @@ -48,7 +48,7 @@ They yearn for mortal eyes again, and I shall grant that wish." next_knowledge = list( /datum/heretic_knowledge/spell/burglar_finesse, - /datum/heretic_knowledge/moon_amulette, + /datum/heretic_knowledge/moon_amulet, ) required_atoms = list(/obj/item/canvas = 1) result_atoms = list(/obj/item/canvas) From 2a4bfd6328d8ac56acdae0439fe7342453ef3faf Mon Sep 17 00:00:00 2001 From: Xander3359 <66163761+Xander3359@users.noreply.github.com> Date: Tue, 21 May 2024 00:11:25 -0400 Subject: [PATCH 067/103] fix a door on icebox in the bridge (#83326) ## About The Pull Request Fix this: ![image](https://github.com/tgstation/tgstation/assets/66163761/9437c0a0-b79a-4427-9033-782f34fae9f2) ## Why It's Good For The Game Fix a mapping mistake ## Changelog :cl: fix: fixed a weird door in icebox bridge /:cl: --- _maps/map_files/IceBoxStation/IceBoxStation.dmm | 1 - 1 file changed, 1 deletion(-) diff --git a/_maps/map_files/IceBoxStation/IceBoxStation.dmm b/_maps/map_files/IceBoxStation/IceBoxStation.dmm index cc0e0ed7842f1..18925cfd927a0 100644 --- a/_maps/map_files/IceBoxStation/IceBoxStation.dmm +++ b/_maps/map_files/IceBoxStation/IceBoxStation.dmm @@ -32093,7 +32093,6 @@ }, /obj/item/pen, /obj/effect/turf_decal/tile/blue/anticorner/contrasted, -/obj/machinery/door/airlock, /turf/open/floor/iron, /area/station/command/bridge) "jJV" = ( From 726bdf5891bbe455497d9a536df76a8b18e3b964 Mon Sep 17 00:00:00 2001 From: Antonio Tosti <5588048+atosti@users.noreply.github.com> Date: Mon, 20 May 2024 21:11:47 -0700 Subject: [PATCH 068/103] Viewing Reticence Stats no longer causes NtOS error (#83343) ## About The Pull Request These changes correctly place Reticence's default power module into a `list()` object, preventing an NtOS error when using the "View Stats" button inside the mech. This resolves a bug in the UI, which had prevented players from viewing their Reticence mech's stats, and modifying its loaded modules therein. Closes #82374 Before: ![reticence-before](https://github.com/tgstation/tgstation/assets/5588048/9c90e7f2-13b6-49bb-af9b-6ad68834bfd4) After: ![reticence-after](https://github.com/tgstation/tgstation/assets/5588048/96862f04-cc00-4d6f-bdeb-c34193794ab5) ## Why It's Good For The Game Syndicate Mimes can now scream (inaudibly) for joy, as they'll be able to inspect and modify their mech as was intended. ## Changelog :cl: fix: Viewing Reticence's stats no longer causes an NtOS UI error /:cl: --- code/modules/vehicles/mecha/combat/reticence.dm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/modules/vehicles/mecha/combat/reticence.dm b/code/modules/vehicles/mecha/combat/reticence.dm index 5e400b12d9788..5dcc5f34e912b 100644 --- a/code/modules/vehicles/mecha/combat/reticence.dm +++ b/code/modules/vehicles/mecha/combat/reticence.dm @@ -37,7 +37,7 @@ MECHA_L_ARM = /obj/item/mecha_parts/mecha_equipment/weapon/ballistic/silenced, MECHA_R_ARM = /obj/item/mecha_parts/mecha_equipment/rcd, MECHA_UTILITY = list(/obj/item/mecha_parts/mecha_equipment/radio, /obj/item/mecha_parts/mecha_equipment/air_tank/full, /obj/item/mecha_parts/mecha_equipment/thrusters/ion), - MECHA_POWER = /obj/item/mecha_parts/mecha_equipment/generator, + MECHA_POWER = list(/obj/item/mecha_parts/mecha_equipment/generator), MECHA_ARMOR = list(), ) From 79031b3b53a584fddb5855c4dc7dd2ee555c2e9a Mon Sep 17 00:00:00 2001 From: hack-wrench <60922927+hack-wrench@users.noreply.github.com> Date: Tue, 21 May 2024 07:12:43 +0300 Subject: [PATCH 069/103] add smoke kit to uplink (#83330) ## About The Pull Request Add smoke kit (5 grenades) by 2 TC ## Why It's Good For The Game Smokes can be a good addition for stealth implant, vanishing and slicing with a katana ## Proof of Testing
Screenshots/Videos OLD ![image](https://github.com/tgstation/tgstation/assets/60922927/89b56042-2b25-4f5e-bfd4-b5d088c56abd) ![image](https://github.com/tgstation/tgstation/assets/60922927/56d0c084-6c46-4e58-8931-c30d623858ee)
## Changelog :cl: add: Added smoke kit (5 grenades) with four grenades to uplink by 2 TC /:cl: --------- Co-authored-by: Helg2 <93882977+Helg2@users.noreply.github.com> --- code/game/objects/items/storage/uplink_kits.dm | 7 +++++++ code/modules/uplink/uplink_items/explosive.dm | 6 ++++++ 2 files changed, 13 insertions(+) diff --git a/code/game/objects/items/storage/uplink_kits.dm b/code/game/objects/items/storage/uplink_kits.dm index 5b42bf3e432d9..7bd009016148e 100644 --- a/code/game/objects/items/storage/uplink_kits.dm +++ b/code/game/objects/items/storage/uplink_kits.dm @@ -440,6 +440,13 @@ new /obj/item/grenade/empgrenade(src) new /obj/item/implanter/emp(src) +/obj/item/storage/box/syndie_kit/smoke + name = "smoke kit" + +/obj/item/storage/box/syndie_kit/smoke/PopulateContents() + for(var/i in 1 to 5) + new /obj/item/grenade/smokebomb(src) + /obj/item/storage/box/syndie_kit/mail_counterfeit name = "mail counterfeit kit" desc = "A box full of mail counterfeit devices. Nothing stops the mail." diff --git a/code/modules/uplink/uplink_items/explosive.dm b/code/modules/uplink/uplink_items/explosive.dm index 72f40b00dfca3..ef9f3b4f074c5 100644 --- a/code/modules/uplink/uplink_items/explosive.dm +++ b/code/modules/uplink/uplink_items/explosive.dm @@ -57,6 +57,12 @@ if(HAS_TRAIT(SSstation, STATION_TRAIT_CYBERNETIC_REVOLUTION)) cost *= 3 +/datum/uplink_item/explosives/smoke + name = "Smoke Grenades" + desc = "A box that contains five smoke grenades. Useful for vanishing and ninja fans with katana." + item = /obj/item/storage/box/syndie_kit/smoke + cost = 2 + /datum/uplink_item/explosives/pizza_bomb name = "Pizza Bomb" desc = "A pizza box with a bomb cunningly attached to the lid. The timer needs to be set by opening the box; afterwards, \ From 93ec270f37d797d4df95278cac30aa296d8dfab4 Mon Sep 17 00:00:00 2001 From: Wayland-Smithy <64715958+Wayland-Smithy@users.noreply.github.com> Date: Mon, 20 May 2024 21:13:25 -0700 Subject: [PATCH 070/103] Fix Crew Monitor scrolling breaking once focused (#83348) ## About The Pull Request Due to the nested scrollable section that grows to fill once focused you can no longer scroll the outer window using the wheel. Very annoying especially for us sillycones. This PR removes the inner scrollbar that never scrolls anyway, but is happy to eat your inputs. ![LqSBlgPuxe](https://github.com/tgstation/tgstation/assets/64715958/b1ff6534-1175-4c12-a893-d5925c1a0deb) ## Why It's Good For The Game Functional UI good. QOL good. ## Changelog :cl: qol: Crew Monitor UI now scrolls properly even after clicking the inner list. /:cl: --- tgui/packages/tgui/interfaces/CrewConsole.tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/tgui/packages/tgui/interfaces/CrewConsole.tsx b/tgui/packages/tgui/interfaces/CrewConsole.tsx index aa4f272f24869..52af3eaff4320 100644 --- a/tgui/packages/tgui/interfaces/CrewConsole.tsx +++ b/tgui/packages/tgui/interfaces/CrewConsole.tsx @@ -175,7 +175,6 @@ const CrewTable = () => { return (
From 9ef76503d3425b98215824a15d538cb5403d7334 Mon Sep 17 00:00:00 2001 From: orange man <61334995+comfyorange@users.noreply.github.com> Date: Tue, 21 May 2024 16:14:24 +1200 Subject: [PATCH 071/103] Automatic changelog for PR #83350 [ci skip] --- html/changelogs/AutoChangeLog-pr-83350.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-83350.yml diff --git a/html/changelogs/AutoChangeLog-pr-83350.yml b/html/changelogs/AutoChangeLog-pr-83350.yml new file mode 100644 index 0000000000000..1e1c389a904b7 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-83350.yml @@ -0,0 +1,4 @@ +author: "Horatio22" +delete-after: True +changes: + - spellcheck: "Correctly spells \"received.\"" \ No newline at end of file From c718eae58c35d1bb54ea9cabfdea4f1f95b8b6cf Mon Sep 17 00:00:00 2001 From: orange man <61334995+comfyorange@users.noreply.github.com> Date: Tue, 21 May 2024 16:15:29 +1200 Subject: [PATCH 072/103] Automatic changelog for PR #83351 [ci skip] --- html/changelogs/AutoChangeLog-pr-83351.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-83351.yml diff --git a/html/changelogs/AutoChangeLog-pr-83351.yml b/html/changelogs/AutoChangeLog-pr-83351.yml new file mode 100644 index 0000000000000..2da58856e0401 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-83351.yml @@ -0,0 +1,4 @@ +author: "Horatio22" +delete-after: True +changes: + - spellcheck: "Corrects spelling of \"amulette\" to \"amulet\"" \ No newline at end of file From c65f558b1d19cee679da63234522da09322bd236 Mon Sep 17 00:00:00 2001 From: orange man <61334995+comfyorange@users.noreply.github.com> Date: Tue, 21 May 2024 16:15:32 +1200 Subject: [PATCH 073/103] Automatic changelog for PR #83326 [ci skip] --- html/changelogs/AutoChangeLog-pr-83326.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-83326.yml diff --git a/html/changelogs/AutoChangeLog-pr-83326.yml b/html/changelogs/AutoChangeLog-pr-83326.yml new file mode 100644 index 0000000000000..8fcf500a894ba --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-83326.yml @@ -0,0 +1,4 @@ +author: "Xander3359" +delete-after: True +changes: + - bugfix: "fixed a weird door in icebox bridge" \ No newline at end of file From c629bfb01c61aba4e01846041fd317afb386d463 Mon Sep 17 00:00:00 2001 From: orange man <61334995+comfyorange@users.noreply.github.com> Date: Tue, 21 May 2024 16:16:03 +1200 Subject: [PATCH 074/103] Automatic changelog for PR #83330 [ci skip] --- html/changelogs/AutoChangeLog-pr-83330.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-83330.yml diff --git a/html/changelogs/AutoChangeLog-pr-83330.yml b/html/changelogs/AutoChangeLog-pr-83330.yml new file mode 100644 index 0000000000000..a008e2750d47a --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-83330.yml @@ -0,0 +1,4 @@ +author: "hack-wrench" +delete-after: True +changes: + - rscadd: "Added smoke kit (5 grenades) with four grenades to uplink by 2 TC" \ No newline at end of file From 1ebb5e32398f5c5b81934804eceef6b2c1037ec3 Mon Sep 17 00:00:00 2001 From: orange man <61334995+comfyorange@users.noreply.github.com> Date: Tue, 21 May 2024 16:16:38 +1200 Subject: [PATCH 075/103] Automatic changelog for PR #83348 [ci skip] --- html/changelogs/AutoChangeLog-pr-83348.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-83348.yml diff --git a/html/changelogs/AutoChangeLog-pr-83348.yml b/html/changelogs/AutoChangeLog-pr-83348.yml new file mode 100644 index 0000000000000..7b39be8264a6b --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-83348.yml @@ -0,0 +1,4 @@ +author: "Wayland-Smithy" +delete-after: True +changes: + - qol: "Crew Monitor UI now scrolls properly even after clicking the inner list." \ No newline at end of file From b664b1f4844c7c8a1a91adc916c2aefc8e227aef Mon Sep 17 00:00:00 2001 From: Fikou <23585223+Fikou@users.noreply.github.com> Date: Tue, 21 May 2024 12:11:53 +0200 Subject: [PATCH 076/103] reverts the description of the nuke op reinforcement beacon (#83341) ## About The Pull Request Changes the description of the reinforcement beacon from "MI13 designed one-use radio for calling immediate backup. Have no regards for safety of whom it summons - they are all inferior clones from Interdyne's genebanks anyway." back to what it used to be- "A single-use beacon designed to quickly launch reinforcement operatives into the field." ## Why It's Good For The Game This change was brought in a sprite PR that had no justification for its code changes. I don't like this lore change, it seems needlessly "edgy", and I designed the reinforcements to be flavorful workers from different companies that are part of the Syndicate as you can see by all their different random outfits, them being "inferior clones from genebanks" is a weird contrast to that and doesn't sit well with me. And the random MI13 drop is eh. ## Changelog :cl: spellcheck: the nuke op reinforcement beacon no longer talks about clones /:cl: --- code/modules/antagonists/_common/antag_spawner.dm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/modules/antagonists/_common/antag_spawner.dm b/code/modules/antagonists/_common/antag_spawner.dm index ae4b8e8db6edf..bc22eedbfa189 100644 --- a/code/modules/antagonists/_common/antag_spawner.dm +++ b/code/modules/antagonists/_common/antag_spawner.dm @@ -95,7 +95,7 @@ */ /obj/item/antag_spawner/nuke_ops name = "syndicate operative beacon" - desc = "MI13 designed one-use radio for calling immediate backup. Have no regards for safety of whom it summons - they are all inferior clones from Interdyne's genebanks anyway." + desc = "A single-use beacon designed to quickly launch reinforcement operatives into the field." icon = 'icons/obj/devices/voice.dmi' icon_state = "nukietalkie" /// The name of the special role given to the recruit From 2ad2dbb6086535c27e002f26bf7387c22b6e069d Mon Sep 17 00:00:00 2001 From: orange man <61334995+comfyorange@users.noreply.github.com> Date: Tue, 21 May 2024 22:12:13 +1200 Subject: [PATCH 077/103] Automatic changelog for PR #83341 [ci skip] --- html/changelogs/AutoChangeLog-pr-83341.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-83341.yml diff --git a/html/changelogs/AutoChangeLog-pr-83341.yml b/html/changelogs/AutoChangeLog-pr-83341.yml new file mode 100644 index 0000000000000..17b2eb7982526 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-83341.yml @@ -0,0 +1,4 @@ +author: "Fikou" +delete-after: True +changes: + - spellcheck: "the nuke op reinforcement beacon no longer talks about clones" \ No newline at end of file From cb67d2cf3f963137c8a2eea8774dbc869b95f77a Mon Sep 17 00:00:00 2001 From: Watermelon914 <37270891+Watermelon914@users.noreply.github.com> Date: Tue, 21 May 2024 10:47:46 +0000 Subject: [PATCH 078/103] Changes default chat preferences for new players (#83311) ## About The Pull Request New players will no longer have ghost ears, ghost sight and ghost whispers on by default. ## Why It's Good For The Game This information is usually overwhelming and the first thing a new player will do upon dying will be to try and turn these settings off. We should just have them off by default and let players toggle them on if they really want to know what everyone is saying at all times. ## Changelog :cl: qol: New players will no longer start with ghost ears, ghost sight and ghost whispers on by default. /:cl: Co-authored-by: Watermelon914 <3052169-Watermelon914@users.noreply.gitlab.com> --- code/__DEFINES/preferences.dm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/__DEFINES/preferences.dm b/code/__DEFINES/preferences.dm index c7daddd2970ae..2989310fb9b73 100644 --- a/code/__DEFINES/preferences.dm +++ b/code/__DEFINES/preferences.dm @@ -35,7 +35,7 @@ #define CHAT_GHOSTLAWS (1<<11) #define CHAT_LOGIN_LOGOUT (1<<12) -#define TOGGLES_DEFAULT_CHAT (CHAT_OOC|CHAT_DEAD|CHAT_GHOSTEARS|CHAT_GHOSTSIGHT|CHAT_PRAYER|CHAT_PULLR|CHAT_GHOSTWHISPER|CHAT_GHOSTPDA|CHAT_GHOSTRADIO|CHAT_BANKCARD|CHAT_GHOSTLAWS|CHAT_LOGIN_LOGOUT) +#define TOGGLES_DEFAULT_CHAT (CHAT_OOC|CHAT_DEAD|CHAT_PRAYER|CHAT_PULLR|CHAT_GHOSTPDA|CHAT_GHOSTRADIO|CHAT_BANKCARD|CHAT_GHOSTLAWS|CHAT_LOGIN_LOGOUT) #define PARALLAX_INSANE "Insane" #define PARALLAX_HIGH "High" From 998d0282bd894f64659c1e5092e4a5f4272960fd Mon Sep 17 00:00:00 2001 From: orange man <61334995+comfyorange@users.noreply.github.com> Date: Tue, 21 May 2024 22:48:11 +1200 Subject: [PATCH 079/103] Automatic changelog for PR #83311 [ci skip] --- html/changelogs/AutoChangeLog-pr-83311.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-83311.yml diff --git a/html/changelogs/AutoChangeLog-pr-83311.yml b/html/changelogs/AutoChangeLog-pr-83311.yml new file mode 100644 index 0000000000000..dccd8a3f144dd --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-83311.yml @@ -0,0 +1,4 @@ +author: "Watermelon914" +delete-after: True +changes: + - qol: "New players will no longer start with ghost ears, ghost sight and ghost whispers on by default." \ No newline at end of file From 929b56265065e7715e161eb66ecb3ced5357e734 Mon Sep 17 00:00:00 2001 From: Joshua Kidder <49173900+Metekillot@users.noreply.github.com> Date: Tue, 21 May 2024 07:15:40 -0400 Subject: [PATCH 080/103] Makes wound noises drop off more quickly, requires higher severity for conspicuous messaging (#83323) ## About The Pull Request Wounds are louder than the attacks that cause them. As well, if you are using a weapon that is meant to be silent or stealthy, the sound of your victim spraying blood ends up being louder than the silenced pistol you're using. This pull request changes wound sounds to drop off more quickly and not penetrate walls (attack sounds already penetrate walls in almost all cases already), and also increases the severity needed for a wound to be broadcast to anyone in view, instead of only to combat message range. ## Why It's Good For The Game It doesn't make sense for the sound of the wound you inflict to be louder than the weapon you're using. This mostly applies to silenced or stealthy weapons. ## Changelog :cl: Bisar balance: A wound being inflicted doesn't get broadcasted to everyone in view until a higher severity now. sound: Wound sounds drop off more quickly, and no longer travel through walls. This has no effect on attack sounds. /:cl: --- code/datums/wounds/_wounds.dm | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/code/datums/wounds/_wounds.dm b/code/datums/wounds/_wounds.dm index c081ee4845fa5..a48c0ccf59431 100644 --- a/code/datums/wounds/_wounds.dm +++ b/code/datums/wounds/_wounds.dm @@ -215,13 +215,13 @@ var/msg = span_danger("[victim]'s [limb.plaintext_zone] [occur_text]!") var/vis_dist = COMBAT_MESSAGE_RANGE - if(severity > WOUND_SEVERITY_MODERATE) + if(severity > WOUND_SEVERITY_SEVERE) msg = "[msg]" vis_dist = DEFAULT_MESSAGE_RANGE victim.visible_message(msg, span_userdanger("Your [limb.plaintext_zone] [occur_text]!"), vision_distance = vis_dist) if(sound_effect) - playsound(L.owner, sound_effect, sound_volume + (20 * severity), TRUE) + playsound(L.owner, sound_effect, sound_volume + (20 * severity), TRUE, falloff_exponent = SOUND_FALLOFF_EXPONENT + 2, ignore_walls = FALSE, falloff_distance = 0) wound_injury(old_wound, attack_direction = attack_direction) if(!demoted) From 1edd8f703cd42967b6acdab779cd3b3983293be9 Mon Sep 17 00:00:00 2001 From: orange man <61334995+comfyorange@users.noreply.github.com> Date: Tue, 21 May 2024 23:16:01 +1200 Subject: [PATCH 081/103] Automatic changelog for PR #83323 [ci skip] --- html/changelogs/AutoChangeLog-pr-83323.yml | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-83323.yml diff --git a/html/changelogs/AutoChangeLog-pr-83323.yml b/html/changelogs/AutoChangeLog-pr-83323.yml new file mode 100644 index 0000000000000..a95374bbeaa87 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-83323.yml @@ -0,0 +1,5 @@ +author: "Bisar" +delete-after: True +changes: + - balance: "A wound being inflicted doesn't get broadcasted to everyone in view until a higher severity now." + - sound: "Wound sounds drop off more quickly, and no longer travel through walls. This has no effect on attack sounds." \ No newline at end of file From 33013fc14277cbdb0c0f545298e3d9e5902793da Mon Sep 17 00:00:00 2001 From: SyncIt21 <110812394+SyncIt21@users.noreply.github.com> Date: Tue, 21 May 2024 16:48:45 +0530 Subject: [PATCH 082/103] Makes monkey powder reaction instant (#83354) ## About The Pull Request - Fixes #83347 This issue title is misleading because the actual problem is with the monkey reaction Because this reaction is currently not instant it will only require `CHEMICAL_QUANTIZATION_LEVEL`(0.0001)u of reagents to be present for the reaction to occur. This means even though the actual requirements are 50u power & 1u water in reality you only need 0.005u(50 * 0.0001) powder & 0.0001u(1 * 0.0001) water for the reaction to occur. This is expected behaviour for non instant reactions because we still want reactions to occur but yield less products when less required reagent amounts are present but it's not ideal for monkey reactions ## Changelog :cl: fix: Monkey power reactions are instant and won't occur when exact reagent requirements (50u power & 1u water) or above aren't met. Stops players from cheesing monkeys from plumbing factories /:cl: --- code/modules/reagents/chemistry/recipes/others.dm | 1 + 1 file changed, 1 insertion(+) diff --git a/code/modules/reagents/chemistry/recipes/others.dm b/code/modules/reagents/chemistry/recipes/others.dm index dee575cf06363..cf9c7ae38c64e 100644 --- a/code/modules/reagents/chemistry/recipes/others.dm +++ b/code/modules/reagents/chemistry/recipes/others.dm @@ -577,6 +577,7 @@ /datum/chemical_reaction/monkey required_reagents = list(/datum/reagent/monkey_powder = 50, /datum/reagent/water = 1) + reaction_flags = REACTION_INSTANT mix_message = "Expands into a brown mass before shaping itself into a monkey!." /datum/chemical_reaction/monkey/on_reaction(datum/reagents/holder, datum/equilibrium/reaction, created_volume) From 5a4c57cd6216d470efe219e92f5e19e38b0a9133 Mon Sep 17 00:00:00 2001 From: orange man <61334995+comfyorange@users.noreply.github.com> Date: Tue, 21 May 2024 23:19:05 +1200 Subject: [PATCH 083/103] Automatic changelog for PR #83354 [ci skip] --- html/changelogs/AutoChangeLog-pr-83354.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-83354.yml diff --git a/html/changelogs/AutoChangeLog-pr-83354.yml b/html/changelogs/AutoChangeLog-pr-83354.yml new file mode 100644 index 0000000000000..03c84bb43fe98 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-83354.yml @@ -0,0 +1,4 @@ +author: "SyncIt21" +delete-after: True +changes: + - bugfix: "Monkey power reactions are instant and won't occur when exact reagent requirements (50u power & 1u water) or above aren't met. Stops players from cheesing monkeys from plumbing factories" \ No newline at end of file From cf643bf25d6f39faa1a841c78cde49a2e9d62e7a Mon Sep 17 00:00:00 2001 From: Nick Date: Tue, 21 May 2024 15:27:23 +0200 Subject: [PATCH 084/103] Removes night vision quirk (#83356) ## About The Pull Request This pr removes the quirk night vision from being selectable ## Why It's Good For The Game Since the night vision rework this gives instead of the 3 tiles around you full soft vision in the darkness Heres 2 screenshots to compare the difference. This is what people without night vision see. ![image](https://github.com/tgstation/tgstation/assets/24854897/0dc0d56d-a96c-40b6-aec1-b63f917cdd66) This is what people with night vision see. ![image](https://github.com/tgstation/tgstation/assets/24854897/72352b72-a929-499e-8f5c-07404db23f0a) Night vision does not define a character and is 100% client side. this also turns antags like nightmares that hide in the shadows less scary and just make the envoirement boring when it comes to combat darkness vs light has 0 adventages because majority of the people run night vision antags who break lights to rely on this adventage just end up wasting time because everyone has inbuilt night vision ## Changelog :cl: del: Removes night vision quirk /:cl: --- .../quirks/positive_quirks/night_vision.dm | 28 ------------------- tgstation.dme | 1 - 2 files changed, 29 deletions(-) delete mode 100644 code/datums/quirks/positive_quirks/night_vision.dm diff --git a/code/datums/quirks/positive_quirks/night_vision.dm b/code/datums/quirks/positive_quirks/night_vision.dm deleted file mode 100644 index 808a213db514b..0000000000000 --- a/code/datums/quirks/positive_quirks/night_vision.dm +++ /dev/null @@ -1,28 +0,0 @@ -/datum/quirk/night_vision - name = "Night Vision" - desc = "You can see slightly more clearly in full darkness than most people." - icon = FA_ICON_MOON - value = 4 - mob_trait = TRAIT_NIGHT_VISION - gain_text = span_notice("The shadows seem a little less dark.") - lose_text = span_danger("Everything seems a little darker.") - medical_record_text = "Patient's eyes show above-average acclimation to darkness." - mail_goodies = list( - /obj/item/flashlight/flashdark, - /obj/item/food/grown/mushroom/glowshroom/shadowshroom, - /obj/item/skillchip/light_remover, - ) - -/datum/quirk/night_vision/add(client/client_source) - refresh_quirk_holder_eyes() - -/datum/quirk/night_vision/remove() - refresh_quirk_holder_eyes() - -/datum/quirk/night_vision/proc/refresh_quirk_holder_eyes() - var/mob/living/carbon/human/human_quirk_holder = quirk_holder - var/obj/item/organ/internal/eyes/eyes = human_quirk_holder.get_organ_by_type(/obj/item/organ/internal/eyes) - if(!eyes || eyes.lighting_cutoff) - return - // We've either added or removed TRAIT_NIGHT_VISION before calling this proc. Just refresh the eyes. - eyes.refresh() diff --git a/tgstation.dme b/tgstation.dme index efc21a337a1e4..dad78a6420a68 100644 --- a/tgstation.dme +++ b/tgstation.dme @@ -1738,7 +1738,6 @@ #include "code\datums\quirks\positive_quirks\light_step.dm" #include "code\datums\quirks\positive_quirks\mime_fan.dm" #include "code\datums\quirks\positive_quirks\musician.dm" -#include "code\datums\quirks\positive_quirks\night_vision.dm" #include "code\datums\quirks\positive_quirks\poster_boy.dm" #include "code\datums\quirks\positive_quirks\self_aware.dm" #include "code\datums\quirks\positive_quirks\settler.dm" From aacb7a5f0dc1346d88d364b50eb3967185752cd0 Mon Sep 17 00:00:00 2001 From: orange man <61334995+comfyorange@users.noreply.github.com> Date: Wed, 22 May 2024 01:33:01 +1200 Subject: [PATCH 085/103] Automatic changelog for PR #83356 [ci skip] --- html/changelogs/AutoChangeLog-pr-83356.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-83356.yml diff --git a/html/changelogs/AutoChangeLog-pr-83356.yml b/html/changelogs/AutoChangeLog-pr-83356.yml new file mode 100644 index 0000000000000..430ec868e294d --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-83356.yml @@ -0,0 +1,4 @@ +author: "improvedname" +delete-after: True +changes: + - rscdel: "Removes night vision quirk" \ No newline at end of file From e6a6f8df955c66b658305ad97b5a13d46489a057 Mon Sep 17 00:00:00 2001 From: nikothedude <59709059+nikothedude@users.noreply.github.com> Date: Tue, 21 May 2024 12:28:18 -0400 Subject: [PATCH 086/103] Fixes deathmatch modifier menu (#83335) ## About The Pull Request Title. I dont understand this code very well, but I feel like passing in a static FALSE into mod_menu_open isnt intentional? Also, I have a feeling this ternary was flipped, since non-hosts would get getting the lsit of modifiers while the host gets nothing. ## Why It's Good For The Game BUGS BAD ## Changelog :cl: fix: The deathmatch modifier menu works now /:cl: --- code/modules/deathmatch/deathmatch_lobby.dm | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/code/modules/deathmatch/deathmatch_lobby.dm b/code/modules/deathmatch/deathmatch_lobby.dm index 1f4678ba1685d..918808126c69c 100644 --- a/code/modules/deathmatch/deathmatch_lobby.dm +++ b/code/modules/deathmatch/deathmatch_lobby.dm @@ -363,8 +363,8 @@ data["map"]["min_players"] = map.min_players data["map"]["max_players"] = map.max_players - data["mod_menu_open"] = FALSE - data["modifiers"] = has_auth ? list() : get_modifier_list(is_host, mod_menu_open) + data["mod_menu_open"] = mod_menu_open + data["modifiers"] = has_auth ? get_modifier_list(is_host, mod_menu_open) : list() data["observers"] = get_observer_list() data["players"] = get_player_list() data["playing"] = playing From a647080840700269b8ec873f729f9f379c50f0bc Mon Sep 17 00:00:00 2001 From: orange man <61334995+comfyorange@users.noreply.github.com> Date: Wed, 22 May 2024 04:28:41 +1200 Subject: [PATCH 087/103] Automatic changelog for PR #83335 [ci skip] --- html/changelogs/AutoChangeLog-pr-83335.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-83335.yml diff --git a/html/changelogs/AutoChangeLog-pr-83335.yml b/html/changelogs/AutoChangeLog-pr-83335.yml new file mode 100644 index 0000000000000..d8dad6e970d4a --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-83335.yml @@ -0,0 +1,4 @@ +author: "nikothedude" +delete-after: True +changes: + - bugfix: "The deathmatch modifier menu works now" \ No newline at end of file From a0b20e0e3387a3f57586991e32999eedcb98c40b Mon Sep 17 00:00:00 2001 From: SyncIt21 <110812394+SyncIt21@users.noreply.github.com> Date: Tue, 21 May 2024 21:59:57 +0530 Subject: [PATCH 088/103] Crafting menu loads long lists faster (#83355) ## About The Pull Request - Fixes #83304 Can't say how much faster it is now but you can definitely see a difference when using Virtual Lists. ## Changelog :cl: fix: Crafting menu loads long lists faster /:cl: --- .../tgui/interfaces/PersonalCrafting.tsx | 57 ++++++++++--------- 1 file changed, 31 insertions(+), 26 deletions(-) diff --git a/tgui/packages/tgui/interfaces/PersonalCrafting.tsx b/tgui/packages/tgui/interfaces/PersonalCrafting.tsx index 166ab59b44ece..9acb77f1c4d7a 100644 --- a/tgui/packages/tgui/interfaces/PersonalCrafting.tsx +++ b/tgui/packages/tgui/interfaces/PersonalCrafting.tsx @@ -15,6 +15,7 @@ import { Stack, Tabs, Tooltip, + VirtualList, } from '../components'; import { Window } from '../layouts'; import { Food } from './PreferencesMenu/data'; @@ -496,32 +497,36 @@ export const PersonalCrafting = (props) => { style={{ overflowY: 'auto' }} > {recipes.length > 0 ? ( - recipes - .slice(0, displayLimit) - .map((item) => - display_compact ? ( - - ) : ( - - ), - ) + + {recipes + .slice(0, displayLimit) + .map((item) => + display_compact ? ( + + ) : ( + + ), + )} + ) : ( No recipes found. From 44c0b5b1dc0c4e56c0c959f7fb865c9d2a22d13d Mon Sep 17 00:00:00 2001 From: nikothedude <59709059+nikothedude@users.noreply.github.com> Date: Tue, 21 May 2024 12:30:19 -0400 Subject: [PATCH 089/103] Adds a new deathmatch modifier that enables quirks (#83338) ## About The Pull Request Title. ## Why It's Good For The Game Quirks can be pretty silly, especially the negative ones, and its kinda a shame we dont apply them in deathmatch. This fixes that! You can now finally play DM in a wheelchair to show off how robust you are to your friends. ## Changelog :cl: add: Adds a new deathmatch modifier that enables quirks /:cl: --- code/modules/deathmatch/deathmatch_modifier.dm | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/code/modules/deathmatch/deathmatch_modifier.dm b/code/modules/deathmatch/deathmatch_modifier.dm index 127700b734f1e..ec5c20cf919b1 100644 --- a/code/modules/deathmatch/deathmatch_modifier.dm +++ b/code/modules/deathmatch/deathmatch_modifier.dm @@ -544,3 +544,13 @@ /datum/deathmatch_modifier/hear_global_chat/apply(mob/living/carbon/player, datum/deathmatch_lobby/lobby) player.add_traits(list(TRAIT_SIXTHSENSE, TRAIT_XRAY_HEARING), DEATHMATCH_TRAIT) + +/datum/deathmatch_modifier/apply_quirks + name = "Quirks enabled" + description = "Applies selected quirks to all players" + +/datum/deathmatch_modifier/apply_quirks/apply(mob/living/carbon/player, datum/deathmatch_lobby/lobby) + if (!player.client) + return + + SSquirks.AssignQuirks(player, player.client) From 39a12d7a13b2a392e9f2b8ae3c0f61e9e907b79b Mon Sep 17 00:00:00 2001 From: orange man <61334995+comfyorange@users.noreply.github.com> Date: Wed, 22 May 2024 04:30:32 +1200 Subject: [PATCH 090/103] Automatic changelog for PR #83355 [ci skip] --- html/changelogs/AutoChangeLog-pr-83355.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-83355.yml diff --git a/html/changelogs/AutoChangeLog-pr-83355.yml b/html/changelogs/AutoChangeLog-pr-83355.yml new file mode 100644 index 0000000000000..af3c34c3df588 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-83355.yml @@ -0,0 +1,4 @@ +author: "SyncIt21" +delete-after: True +changes: + - bugfix: "Crafting menu loads long lists faster" \ No newline at end of file From 7a79993a1617a7bd06785a1de1a43559c4a590ae Mon Sep 17 00:00:00 2001 From: orange man <61334995+comfyorange@users.noreply.github.com> Date: Wed, 22 May 2024 04:30:41 +1200 Subject: [PATCH 091/103] Automatic changelog for PR #83338 [ci skip] --- html/changelogs/AutoChangeLog-pr-83338.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-83338.yml diff --git a/html/changelogs/AutoChangeLog-pr-83338.yml b/html/changelogs/AutoChangeLog-pr-83338.yml new file mode 100644 index 0000000000000..da74e145fed49 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-83338.yml @@ -0,0 +1,4 @@ +author: "nikothedude" +delete-after: True +changes: + - rscadd: "Adds a new deathmatch modifier that enables quirks" \ No newline at end of file From b830ba11b76754308b10ff83b2ecd1d1683fb4d9 Mon Sep 17 00:00:00 2001 From: necromanceranne <40847847+necromanceranne@users.noreply.github.com> Date: Wed, 22 May 2024 07:50:58 +1000 Subject: [PATCH 092/103] Research Directors are now strong (the Athletics trait, that is). Suplexing a rod is an incredible workout. (#83269) ## About The Pull Request Grants the Research Director TRAIT_STRENGTH via their skill chip. This trait is only relevant to athletics-related activities. They still need to actually do the workout before they see any results. Fitness bros will overestimate the RD's power level due to their ability to suplex an immovable rod. Suplexing a rod grants an incredible amount of athletics skill, increased by how many people the rod has taken out. The frequency of this happening is bound to be pretty small, but it's a nice in-round reward for accomplishing the task (and maybe blowing up a department as a result), and also potentially a large number of casualties on top of that. ## Why It's Good For The Game The athletics changes didn't acknowledge that there is already someone on the station that is, for some reason, unnaturally stronger than everyone else. The Research Director. So now, fitness bros think they're naturally swole. Mind over matter, I guess? I just think it'd be funny if by suplexing the rod once, you gain incredible physical power and then need to take a nap because boy that sure was an explosive amount of strength you had to apply. Since this only happens with looping rods, I don't imagine it will disrupt fitness as a skill too much. ## Changelog :cl: add: The Research Director is now actually strong. add: Fitness bros will determine the Research Director to be stronger than they actually are, without even working out. How does he do it? balance: Suplexing a rod grants a large burst of athletics experience. add: The more sentient casualties of the rod, the more experience suplexing that rod grants. Absorb the souls of the weak and feeble. /:cl: --- code/modules/events/immovable_rod/immovable_rod.dm | 8 +++++++- .../skill_learning/generic_skillchips/rod_suplex.dm | 6 +++--- code/modules/mob/living/carbon/human/human_helpers.dm | 2 ++ 3 files changed, 12 insertions(+), 4 deletions(-) diff --git a/code/modules/events/immovable_rod/immovable_rod.dm b/code/modules/events/immovable_rod/immovable_rod.dm index e9d2995218d56..e1f0ada0e600c 100644 --- a/code/modules/events/immovable_rod/immovable_rod.dm +++ b/code/modules/events/immovable_rod/immovable_rod.dm @@ -247,10 +247,16 @@ strongman.client?.give_award(/datum/award/achievement/jobs/feat_of_strength, strongman) strongman.visible_message( span_boldwarning("[strongman] suplexes [src] into the ground!"), - span_warning("You suplex [src] into the ground!") + span_warning("As you suplex [src] into the ground, your body ripples with power!") ) new /obj/structure/festivus/anchored(drop_location()) new /obj/effect/anomaly/flux(drop_location()) + + var/is_heavy_gravity = strongman.has_gravity() > STANDARD_GRAVITY //If for some reason you have to suplex the rod in heavy gravity, you get the double experience here as well, why not + var/experience_gained = 100 * num_sentient_mobs_hit * (is_heavy_gravity ? 2 : 1) // We gain more expeirence the more sentient mobs the rod has taken out. The deadlier the rod, the stronger we become. At 25 sentient mobs, we instantly become a legendary athlete. + strongman.mind?.adjust_experience(/datum/skill/athletics, experience_gained) + strongman.apply_status_effect(/datum/status_effect/exercised) //time for a nap, you earned it + qdel(src) return TRUE diff --git a/code/modules/library/skill_learning/generic_skillchips/rod_suplex.dm b/code/modules/library/skill_learning/generic_skillchips/rod_suplex.dm index b889073909d61..bff83423be73e 100644 --- a/code/modules/library/skill_learning/generic_skillchips/rod_suplex.dm +++ b/code/modules/library/skill_learning/generic_skillchips/rod_suplex.dm @@ -1,12 +1,12 @@ /obj/item/skillchip/research_director name = "R.D.S.P.L.X. skillchip" desc = "Knowledge of how to solve the ancient conumdrum; what happens when an unstoppable force meets an immovable object." - auto_traits = list(TRAIT_ROD_SUPLEX) + auto_traits = list(TRAIT_ROD_SUPLEX, TRAIT_STRENGTH) skill_name = "True Strength" skill_description = "The knowledge and strength to resolve the most ancient conumdrum; what happens when an unstoppable force meets an immovable object." skill_icon = "dumbbell" - activate_message = "You realise if you apply the correct force, at the correct angle, it is possible to make the immovable permanently movable." - deactivate_message = "You forget how to permanently anchor a paradoxical object." + activate_message = "You realise if you apply the correct force, at the correct angle, it is possible to make the immovable permanently movable. And... damn, you look huge." + deactivate_message = "You forget how to permanently anchor a paradoxical object. Also, you should really hit the gym..." chip_category = SKILLCHIP_CATEGORY_GENERAL skillchip_flags = NONE slot_use = 1 diff --git a/code/modules/mob/living/carbon/human/human_helpers.dm b/code/modules/mob/living/carbon/human/human_helpers.dm index e2ed47300cc14..9ba754569c108 100644 --- a/code/modules/mob/living/carbon/human/human_helpers.dm +++ b/code/modules/mob/living/carbon/human/human_helpers.dm @@ -335,6 +335,8 @@ fitness_modifier *= 2 if (HAS_TRAIT(src, TRAIT_STRENGTH)) fitness_modifier *= 1.5 + if (HAS_TRAIT(src, TRAIT_ROD_SUPLEX)) + fitness_modifier *= 2 // To be able to suplex a rod, you must possess an incredible amount of power if (HAS_TRAIT(src, TRAIT_EASILY_WOUNDED)) fitness_modifier /= 2 if (HAS_TRAIT(src, TRAIT_GAMER)) From 67533e3898afdd34959af6a49d3efc47daea90e3 Mon Sep 17 00:00:00 2001 From: orange man <61334995+comfyorange@users.noreply.github.com> Date: Wed, 22 May 2024 09:51:20 +1200 Subject: [PATCH 093/103] Automatic changelog for PR #83269 [ci skip] --- html/changelogs/AutoChangeLog-pr-83269.yml | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-83269.yml diff --git a/html/changelogs/AutoChangeLog-pr-83269.yml b/html/changelogs/AutoChangeLog-pr-83269.yml new file mode 100644 index 0000000000000..52f37e3827405 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-83269.yml @@ -0,0 +1,7 @@ +author: "necromanceranne" +delete-after: True +changes: + - rscadd: "The Research Director is now actually strong." + - rscadd: "Fitness bros will determine the Research Director to be stronger than they actually are, without even working out. How does he do it?" + - balance: "Suplexing a rod grants a large burst of athletics experience." + - rscadd: "The more sentient casualties of the rod, the more experience suplexing that rod grants. Absorb the souls of the weak and feeble." \ No newline at end of file From 2d3bd114a923dd6e3c640d21109cb47466a13885 Mon Sep 17 00:00:00 2001 From: Iamgoofball Date: Tue, 21 May 2024 15:29:34 -0700 Subject: [PATCH 094/103] Removes a shit clown name and adds a better clown name instead (#83362) ## About The Pull Request Removes a shit clown name and adds a better clown name instead ## Why It's Good For The Game Disgraced nazi artist has been replaced with a professional clown who's an expert in cocaine. Someone brought up we didn't have this in the clown name pool. ## Changelog :cl: spellcheck: Removes a shit clown name and adds a better clown name instead /:cl: --------- Co-authored-by: MrMelbert <51863163+MrMelbert@users.noreply.github.com> --- strings/names/clown.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/strings/names/clown.txt b/strings/names/clown.txt index 028494580babe..1a5f8740ae7fe 100644 --- a/strings/names/clown.txt +++ b/strings/names/clown.txt @@ -28,6 +28,7 @@ Delicious Dan Dinkster Dinky Doodle Doctor Greenthumb +Doctor Rockso Doink Early Worm Eggy @@ -118,7 +119,6 @@ Unimaginable Nut Valid Vincent Weather Report Widderwise -Yanye Kest Yesterdays Beef Yobbo Ziggy Yoyo From c0cee335798159d3c2c0fd6f0aa7d93c1895686c Mon Sep 17 00:00:00 2001 From: norsvenska <73006946+norsvenska@users.noreply.github.com> Date: Wed, 22 May 2024 00:29:46 +0200 Subject: [PATCH 095/103] Changes the adjust_visor interaction text to be more neutral (#83366) ## About The Pull Request Following #79784, things such as welding helmets and breath masks used the same code for adjusting them. When adjusting it, it would either print "You adjust [the object] up" if you are adjusting it to its non-normal state, or "You adjust [the object] down". So, when you adjust the welding helmet's visor up, it prints the former and makes sense. Masks, however, were a different story. When you adjust the mask down, it would print "You adjust the mask up" to chat, which doesn't make sense. This just changes the text to be more neutral in terms of direction. ## Why It's Good For The Game I don't adjust the breath mask up when I drop it down to my chest ## Changelog :cl: spellcheck: The message displayed when adjusting a mask no longer incorrectly states the way in which the mask has moved. /:cl: --- code/modules/clothing/clothing.dm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/modules/clothing/clothing.dm b/code/modules/clothing/clothing.dm index d13f025e0b138..e9ec547755d5e 100644 --- a/code/modules/clothing/clothing.dm +++ b/code/modules/clothing/clothing.dm @@ -480,7 +480,7 @@ BLIND // can't see anything visor_toggling() - to_chat(user, span_notice("You adjust [src] [up ? "up" : "down"].")) + to_chat(user, span_notice("You push [src] [up ? "out of the way" : "back into place"].")) update_item_action_buttons() From 6af64fe0e2d152aa94e0585aa78b443766fc8aba Mon Sep 17 00:00:00 2001 From: orange man <61334995+comfyorange@users.noreply.github.com> Date: Wed, 22 May 2024 10:36:32 +1200 Subject: [PATCH 096/103] Automatic changelog for PR #83362 [ci skip] --- html/changelogs/AutoChangeLog-pr-83362.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-83362.yml diff --git a/html/changelogs/AutoChangeLog-pr-83362.yml b/html/changelogs/AutoChangeLog-pr-83362.yml new file mode 100644 index 0000000000000..a546a922c0793 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-83362.yml @@ -0,0 +1,4 @@ +author: "Iamgoofball" +delete-after: True +changes: + - spellcheck: "Removes a shit clown name and adds a better clown name instead" \ No newline at end of file From 8a34c7c42bbba1a9297e52a426bcbfa1546144b0 Mon Sep 17 00:00:00 2001 From: orange man <61334995+comfyorange@users.noreply.github.com> Date: Wed, 22 May 2024 10:36:42 +1200 Subject: [PATCH 097/103] Automatic changelog for PR #83366 [ci skip] --- html/changelogs/AutoChangeLog-pr-83366.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-83366.yml diff --git a/html/changelogs/AutoChangeLog-pr-83366.yml b/html/changelogs/AutoChangeLog-pr-83366.yml new file mode 100644 index 0000000000000..aa3c5cc62cd5b --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-83366.yml @@ -0,0 +1,4 @@ +author: "norsvenska" +delete-after: True +changes: + - spellcheck: "The message displayed when adjusting a mask no longer incorrectly states the way in which the mask has moved." \ No newline at end of file From 29e84bca180e805e7ccbbd8480c77ec3a2d6fef7 Mon Sep 17 00:00:00 2001 From: Changelogs Date: Wed, 22 May 2024 00:26:43 +0000 Subject: [PATCH 098/103] Automatic changelog compile [ci skip] --- html/changelogs/AutoChangeLog-pr-83269.yml | 7 ---- html/changelogs/AutoChangeLog-pr-83311.yml | 4 --- html/changelogs/AutoChangeLog-pr-83323.yml | 5 --- html/changelogs/AutoChangeLog-pr-83326.yml | 4 --- html/changelogs/AutoChangeLog-pr-83330.yml | 4 --- html/changelogs/AutoChangeLog-pr-83335.yml | 4 --- html/changelogs/AutoChangeLog-pr-83338.yml | 4 --- html/changelogs/AutoChangeLog-pr-83341.yml | 4 --- html/changelogs/AutoChangeLog-pr-83348.yml | 4 --- html/changelogs/AutoChangeLog-pr-83350.yml | 4 --- html/changelogs/AutoChangeLog-pr-83351.yml | 4 --- html/changelogs/AutoChangeLog-pr-83354.yml | 4 --- html/changelogs/AutoChangeLog-pr-83355.yml | 4 --- html/changelogs/AutoChangeLog-pr-83356.yml | 4 --- html/changelogs/AutoChangeLog-pr-83362.yml | 4 --- html/changelogs/AutoChangeLog-pr-83366.yml | 4 --- html/changelogs/archive/2024-05.yml | 42 ++++++++++++++++++++++ 17 files changed, 42 insertions(+), 68 deletions(-) delete mode 100644 html/changelogs/AutoChangeLog-pr-83269.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-83311.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-83323.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-83326.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-83330.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-83335.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-83338.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-83341.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-83348.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-83350.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-83351.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-83354.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-83355.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-83356.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-83362.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-83366.yml diff --git a/html/changelogs/AutoChangeLog-pr-83269.yml b/html/changelogs/AutoChangeLog-pr-83269.yml deleted file mode 100644 index 52f37e3827405..0000000000000 --- a/html/changelogs/AutoChangeLog-pr-83269.yml +++ /dev/null @@ -1,7 +0,0 @@ -author: "necromanceranne" -delete-after: True -changes: - - rscadd: "The Research Director is now actually strong." - - rscadd: "Fitness bros will determine the Research Director to be stronger than they actually are, without even working out. How does he do it?" - - balance: "Suplexing a rod grants a large burst of athletics experience." - - rscadd: "The more sentient casualties of the rod, the more experience suplexing that rod grants. Absorb the souls of the weak and feeble." \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-83311.yml b/html/changelogs/AutoChangeLog-pr-83311.yml deleted file mode 100644 index dccd8a3f144dd..0000000000000 --- a/html/changelogs/AutoChangeLog-pr-83311.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "Watermelon914" -delete-after: True -changes: - - qol: "New players will no longer start with ghost ears, ghost sight and ghost whispers on by default." \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-83323.yml b/html/changelogs/AutoChangeLog-pr-83323.yml deleted file mode 100644 index a95374bbeaa87..0000000000000 --- a/html/changelogs/AutoChangeLog-pr-83323.yml +++ /dev/null @@ -1,5 +0,0 @@ -author: "Bisar" -delete-after: True -changes: - - balance: "A wound being inflicted doesn't get broadcasted to everyone in view until a higher severity now." - - sound: "Wound sounds drop off more quickly, and no longer travel through walls. This has no effect on attack sounds." \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-83326.yml b/html/changelogs/AutoChangeLog-pr-83326.yml deleted file mode 100644 index 8fcf500a894ba..0000000000000 --- a/html/changelogs/AutoChangeLog-pr-83326.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "Xander3359" -delete-after: True -changes: - - bugfix: "fixed a weird door in icebox bridge" \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-83330.yml b/html/changelogs/AutoChangeLog-pr-83330.yml deleted file mode 100644 index a008e2750d47a..0000000000000 --- a/html/changelogs/AutoChangeLog-pr-83330.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "hack-wrench" -delete-after: True -changes: - - rscadd: "Added smoke kit (5 grenades) with four grenades to uplink by 2 TC" \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-83335.yml b/html/changelogs/AutoChangeLog-pr-83335.yml deleted file mode 100644 index d8dad6e970d4a..0000000000000 --- a/html/changelogs/AutoChangeLog-pr-83335.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "nikothedude" -delete-after: True -changes: - - bugfix: "The deathmatch modifier menu works now" \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-83338.yml b/html/changelogs/AutoChangeLog-pr-83338.yml deleted file mode 100644 index da74e145fed49..0000000000000 --- a/html/changelogs/AutoChangeLog-pr-83338.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "nikothedude" -delete-after: True -changes: - - rscadd: "Adds a new deathmatch modifier that enables quirks" \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-83341.yml b/html/changelogs/AutoChangeLog-pr-83341.yml deleted file mode 100644 index 17b2eb7982526..0000000000000 --- a/html/changelogs/AutoChangeLog-pr-83341.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "Fikou" -delete-after: True -changes: - - spellcheck: "the nuke op reinforcement beacon no longer talks about clones" \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-83348.yml b/html/changelogs/AutoChangeLog-pr-83348.yml deleted file mode 100644 index 7b39be8264a6b..0000000000000 --- a/html/changelogs/AutoChangeLog-pr-83348.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "Wayland-Smithy" -delete-after: True -changes: - - qol: "Crew Monitor UI now scrolls properly even after clicking the inner list." \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-83350.yml b/html/changelogs/AutoChangeLog-pr-83350.yml deleted file mode 100644 index 1e1c389a904b7..0000000000000 --- a/html/changelogs/AutoChangeLog-pr-83350.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "Horatio22" -delete-after: True -changes: - - spellcheck: "Correctly spells \"received.\"" \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-83351.yml b/html/changelogs/AutoChangeLog-pr-83351.yml deleted file mode 100644 index 2da58856e0401..0000000000000 --- a/html/changelogs/AutoChangeLog-pr-83351.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "Horatio22" -delete-after: True -changes: - - spellcheck: "Corrects spelling of \"amulette\" to \"amulet\"" \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-83354.yml b/html/changelogs/AutoChangeLog-pr-83354.yml deleted file mode 100644 index 03c84bb43fe98..0000000000000 --- a/html/changelogs/AutoChangeLog-pr-83354.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "SyncIt21" -delete-after: True -changes: - - bugfix: "Monkey power reactions are instant and won't occur when exact reagent requirements (50u power & 1u water) or above aren't met. Stops players from cheesing monkeys from plumbing factories" \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-83355.yml b/html/changelogs/AutoChangeLog-pr-83355.yml deleted file mode 100644 index af3c34c3df588..0000000000000 --- a/html/changelogs/AutoChangeLog-pr-83355.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "SyncIt21" -delete-after: True -changes: - - bugfix: "Crafting menu loads long lists faster" \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-83356.yml b/html/changelogs/AutoChangeLog-pr-83356.yml deleted file mode 100644 index 430ec868e294d..0000000000000 --- a/html/changelogs/AutoChangeLog-pr-83356.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "improvedname" -delete-after: True -changes: - - rscdel: "Removes night vision quirk" \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-83362.yml b/html/changelogs/AutoChangeLog-pr-83362.yml deleted file mode 100644 index a546a922c0793..0000000000000 --- a/html/changelogs/AutoChangeLog-pr-83362.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "Iamgoofball" -delete-after: True -changes: - - spellcheck: "Removes a shit clown name and adds a better clown name instead" \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-83366.yml b/html/changelogs/AutoChangeLog-pr-83366.yml deleted file mode 100644 index aa3c5cc62cd5b..0000000000000 --- a/html/changelogs/AutoChangeLog-pr-83366.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "norsvenska" -delete-after: True -changes: - - spellcheck: "The message displayed when adjusting a mask no longer incorrectly states the way in which the mask has moved." \ No newline at end of file diff --git a/html/changelogs/archive/2024-05.yml b/html/changelogs/archive/2024-05.yml index 25688eb731a0d..08f3a52b9ce33 100644 --- a/html/changelogs/archive/2024-05.yml +++ b/html/changelogs/archive/2024-05.yml @@ -576,3 +576,45 @@ - balance: Multiver stops purging when Anacea is present in the bloodstream. tmyqlfpir: - bugfix: '[Metastation] Service hallway door being bypassed by lying down' +2024-05-22: + Bisar: + - balance: A wound being inflicted doesn't get broadcasted to everyone in view until + a higher severity now. + - sound: Wound sounds drop off more quickly, and no longer travel through walls. + This has no effect on attack sounds. + Fikou: + - spellcheck: the nuke op reinforcement beacon no longer talks about clones + Horatio22: + - spellcheck: Corrects spelling of "amulette" to "amulet" + - spellcheck: Correctly spells "received." + Iamgoofball: + - spellcheck: Removes a shit clown name and adds a better clown name instead + SyncIt21: + - bugfix: Crafting menu loads long lists faster + - bugfix: Monkey power reactions are instant and won't occur when exact reagent + requirements (50u power & 1u water) or above aren't met. Stops players from + cheesing monkeys from plumbing factories + Watermelon914: + - qol: New players will no longer start with ghost ears, ghost sight and ghost whispers + on by default. + Wayland-Smithy: + - qol: Crew Monitor UI now scrolls properly even after clicking the inner list. + Xander3359: + - bugfix: fixed a weird door in icebox bridge + hack-wrench: + - rscadd: Added smoke kit (5 grenades) with four grenades to uplink by 2 TC + improvedname: + - rscdel: Removes night vision quirk + necromanceranne: + - rscadd: The Research Director is now actually strong. + - rscadd: Fitness bros will determine the Research Director to be stronger than + they actually are, without even working out. How does he do it? + - balance: Suplexing a rod grants a large burst of athletics experience. + - rscadd: The more sentient casualties of the rod, the more experience suplexing + that rod grants. Absorb the souls of the weak and feeble. + nikothedude: + - rscadd: Adds a new deathmatch modifier that enables quirks + - bugfix: The deathmatch modifier menu works now + norsvenska: + - spellcheck: The message displayed when adjusting a mask no longer incorrectly + states the way in which the mask has moved. From c3ff3e06c341d59848deb424db3499e7cc9cb30e Mon Sep 17 00:00:00 2001 From: paganiy <126676387+paganiy@users.noreply.github.com> Date: Wed, 22 May 2024 15:31:42 +0300 Subject: [PATCH 099/103] Auto-aim in combat mode at mobs on the floor is disabled after 10 tiles. (#83270) ## About The Pull Request As stated in the title, auto-aiming at prone targets is disabled after the projectile passed more than 10 tiles (the limit of vision of an ordinary spaceman is 9 tiles). Within 10 tiles, shooting in combat mode remains unchanged. This also does not apply to sniper rifles. Here's a preview of how it works: https://github.com/tgstation/tgstation/assets/126676387/d62fbb03-9f63-4a73-a32a-62b4d11e4515 ## Why It's Good For The Game The main problem of shooting in combat mode is shooting in busy corridors. Often, you are unwilling to become a participant in the security's pursuit of the antagonist, and receive unintended projectiles. You will be lucky if the projectile turns out to be non-lethal, but if it is a laser, you can get a second-degree burn or even a catastrophic one from just one shot. (depending on which laser was fired and where you were hit), which is not very pleasant. To stay unharmed and simplify the work of security, it is logical to lie down on the floor. This will not revive the lie-down meta to dodge projectiles, because within sight of the spaceman and even a little further, lying targets will still be hit by projectiles. And if you decide to lie down during the chase to dodge the projectiles, then the pursuers will quickly catch up with you and shoot you in combat mode. ## Changelog :cl: balance: Auto-aim in combat mode at mobs on the floor is disabled after the projectile passes 10 tiles. /:cl: --------- Co-authored-by: paganiy --- code/game/objects/items/shrapnel.dm | 2 ++ code/modules/projectiles/projectile.dm | 18 ++++++++++++------ .../projectiles/projectile/bullets/sniper.dm | 1 + 3 files changed, 15 insertions(+), 6 deletions(-) diff --git a/code/game/objects/items/shrapnel.dm b/code/game/objects/items/shrapnel.dm index c07bc780c9128..9b024cfbb97a2 100644 --- a/code/game/objects/items/shrapnel.dm +++ b/code/game/objects/items/shrapnel.dm @@ -31,6 +31,7 @@ shrapnel_type = /obj/item/shrapnel ricochet_incidence_leeway = 60 hit_prone_targets = TRUE + ignore_range_hit_prone_targets = TRUE sharpness = SHARP_EDGED wound_bonus = 30 embedding = list(embed_chance=70, ignore_throwspeed_threshold=TRUE, fall_chance=1) @@ -73,6 +74,7 @@ /obj/projectile/bullet/pellet/stingball/on_ricochet(atom/A) hit_prone_targets = TRUE // ducking will save you from the first wave, but not the rebounds + ignore_range_hit_prone_targets = TRUE /obj/projectile/bullet/pellet/stingball/mega name = "megastingball pellet" diff --git a/code/modules/projectiles/projectile.dm b/code/modules/projectiles/projectile.dm index 8bc358b43874c..877326fd98546 100644 --- a/code/modules/projectiles/projectile.dm +++ b/code/modules/projectiles/projectile.dm @@ -1,6 +1,7 @@ #define MOVES_HITSCAN -1 //Not actually hitscan but close as we get without actual hitscan. #define MUZZLE_EFFECT_PIXEL_INCREMENT 17 //How many pixels to move the muzzle flash up so your character doesn't look like they're shitting out lasers. +#define MAX_RANGE_HIT_PRONE_TARGETS 10 //How far do the projectile hits the prone mob /obj/projectile name = "projectile" @@ -191,8 +192,10 @@ var/shrapnel_type ///If we have a shrapnel_type defined, these embedding stats will be passed to the spawned shrapnel type, which will roll for embedding on the target var/list/embedding - ///If TRUE, hit mobs even if they're on the floor and not our target + ///If TRUE, hit mobs, even if they are lying on the floor and are not our target within MAX_RANGE_HIT_PRONE_TARGETS tiles var/hit_prone_targets = FALSE + ///if TRUE, ignores the range of MAX_RANGE_HIT_PRONE_TARGETS tiles of hit_prone_targets + var/ignore_range_hit_prone_targets = FALSE ///For what kind of brute wounds we're rolling for, if we're doing such a thing. Lasers obviously don't care since they do burn instead. var/sharpness = NONE ///How much we want to drop damage per tile as it travels through the air @@ -621,13 +624,15 @@ return FALSE if(HAS_TRAIT(living_target, TRAIT_IMMOBILIZED) && HAS_TRAIT(living_target, TRAIT_FLOORED) && HAS_TRAIT(living_target, TRAIT_HANDS_BLOCKED)) return FALSE - if(!hit_prone_targets) + if(hit_prone_targets) var/mob/living/buckled_to = living_target.lowest_buckled_mob() - if(!buckled_to.density) // Will just be us if we're not buckled to another mob - return FALSE - if(living_target.body_position != LYING_DOWN) + if((decayedRange - range) <= MAX_RANGE_HIT_PRONE_TARGETS) // after MAX_RANGE_HIT_PRONE_TARGETS tiles, auto-aim hit for mobs on the floor turns off return TRUE - return TRUE + if(ignore_range_hit_prone_targets) // doesn't apply to projectiles that must hit the target in combat mode or something else, no matter what + return TRUE + if(buckled_to.density) // Will just be us if we're not buckled to another mob + return TRUE + return FALSE /** * Scan if we should hit something and hit it if we need to @@ -1177,6 +1182,7 @@ #undef MOVES_HITSCAN #undef MUZZLE_EFFECT_PIXEL_INCREMENT +#undef MAX_RANGE_HIT_PRONE_TARGETS /// Fire a projectile from this atom at another atom /atom/proc/fire_projectile(projectile_type, atom/target, sound, firer, list/ignore_targets = list()) diff --git a/code/modules/projectiles/projectile/bullets/sniper.dm b/code/modules/projectiles/projectile/bullets/sniper.dm index 4425b20eeedc4..6118d90644d9e 100644 --- a/code/modules/projectiles/projectile/bullets/sniper.dm +++ b/code/modules/projectiles/projectile/bullets/sniper.dm @@ -9,6 +9,7 @@ dismemberment = 50 catastropic_dismemberment = TRUE armour_penetration = 50 + ignore_range_hit_prone_targets = TRUE ///Determines object damage. var/object_damage = 80 ///Determines how much additional damage the round does to mechs. From fc9656170026fbd841c3786786cb1b3a406b2ba0 Mon Sep 17 00:00:00 2001 From: orange man <61334995+comfyorange@users.noreply.github.com> Date: Thu, 23 May 2024 00:32:03 +1200 Subject: [PATCH 100/103] Automatic changelog for PR #83270 [ci skip] --- html/changelogs/AutoChangeLog-pr-83270.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-83270.yml diff --git a/html/changelogs/AutoChangeLog-pr-83270.yml b/html/changelogs/AutoChangeLog-pr-83270.yml new file mode 100644 index 0000000000000..5a6873dd01cff --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-83270.yml @@ -0,0 +1,4 @@ +author: "paganiy" +delete-after: True +changes: + - balance: "Auto-aim in combat mode at mobs on the floor is disabled after the projectile passes 10 tiles." \ No newline at end of file From a551790b6a6fd3493701da54fe0b68a8a26fce67 Mon Sep 17 00:00:00 2001 From: Muffindrake Date: Thu, 23 May 2024 00:07:15 +0200 Subject: [PATCH 101/103] Reduces free medieval holodeck claymore from 4(!) to 6 hit weapon (#83334) ## About The Pull Request Did you know the medieval holodeck has two free claymores with 30 force? Me neither. And I will not have to. ## Why It's Good For The Game Hey AI, I need my free 4-hit weapon. I'm totally not a changeling or anything. Oh and it's not like there are non-human antags on Terry, or antag players that actually play station roles when they didn't get their antag. ## Changelog :cl: balance: reduced claymore/weak force from 30 to 24 and armor penetration from 15 to 10 /:cl: --- code/game/objects/items/religion.dm | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/code/game/objects/items/religion.dm b/code/game/objects/items/religion.dm index b40a81f3642c3..c85bd5fe9615d 100644 --- a/code/game/objects/items/religion.dm +++ b/code/game/objects/items/religion.dm @@ -418,8 +418,8 @@ /obj/item/claymore/weak desc = "This one is rusted." - force = 30 - armour_penetration = 15 + force = 24 + armour_penetration = 10 /obj/item/claymore/weak/ceremonial desc = "A rusted claymore, once at the heart of a powerful scottish clan struck down and oppressed by tyrants, it has been passed down the ages as a symbol of defiance." From 2f6d8541c31439024be513287aa81417a705577a Mon Sep 17 00:00:00 2001 From: orange man <61334995+comfyorange@users.noreply.github.com> Date: Thu, 23 May 2024 10:11:04 +1200 Subject: [PATCH 102/103] Automatic changelog for PR #83334 [ci skip] --- html/changelogs/AutoChangeLog-pr-83334.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-83334.yml diff --git a/html/changelogs/AutoChangeLog-pr-83334.yml b/html/changelogs/AutoChangeLog-pr-83334.yml new file mode 100644 index 0000000000000..626cafcdff571 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-83334.yml @@ -0,0 +1,4 @@ +author: "Muffindrake" +delete-after: True +changes: + - balance: "reduced claymore/weak force from 30 to 24 and armor penetration from 15 to 10" \ No newline at end of file From cf7cdc2004041b321f00d28ebff7a0422e8d14ee Mon Sep 17 00:00:00 2001 From: hack-wrench <60922927+hack-wrench@users.noreply.github.com> Date: Thu, 23 May 2024 01:13:15 +0300 Subject: [PATCH 103/103] Create RUN_SERVER.cmd (#83329) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## About The Pull Request A RUN_SERVER.cmd file is a type of batch file on Windows operating systems that can be used to start a server application. Batch files contain a series of commands that are executed by the command line interpreter. They are useful for automating repetitive tasks and can be particularly handy for starting a server with specific configurations or parameters. ## Why It's Good For The Game By double-clicking the RUN_SERVER.cmd file, all these commands are executed in sequence, starting the server with the defined settings. This makes it much easier to start the server than typing out all the commands each time. It’s a convenient way to manage server settings and ensure consistency across server restarts. Batch files like this are widely used in various applications where a server needs to be started with specific parameters on a Windows environment. ## Proof of Testing
Screenshots/Videos ![image](https://github.com/tgstation/tgstation/assets/60922927/5451cf16-8310-43d2-9ea9-ee57a5d05b8e)
## Changelog :cl: add: Added RUN_SERVER.bat for maintainer issues /:cl: --- RUN_SERVER.cmd | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 RUN_SERVER.cmd diff --git a/RUN_SERVER.cmd b/RUN_SERVER.cmd new file mode 100644 index 0000000000000..70e60a5276da3 --- /dev/null +++ b/RUN_SERVER.cmd @@ -0,0 +1,2 @@ +@echo off +call "%~dp0\tools\build\build.bat" --wait-on-error server %*