From 1cba47ef06b041bf58eb19f5fb612b6e73d2fd8b Mon Sep 17 00:00:00 2001
From: jimmyl <70376633+mc-oofert@users.noreply.github.com>
Date: Fri, 16 Feb 2024 21:19:26 +0100
Subject: [PATCH 01/30] unstashable assembly bombs (#81197)
## About The Pull Request
assembly bombs are bulky
(the like ones you make with a tank and an igniter and some other thing)
## Why It's Good For The Game
these things can (and usually do) gib people, are REALLY easy to
massproduce and you can also fit several in a bag
while still easier to use to gib people than TTVs
at best i think making them bulky should prevent some dude from carrying
like 8 bombs in his backpack and whipping them out and throwing without
any warning because they would have to carry it (or invest in BoH but
thats sci anyway so)
## Changelog
:cl:
balance: assemblybombs are bulky
/:cl:
---------
Co-authored-by: tattle <66640614+dragomagol@users.noreply.github.com>
---
code/game/objects/items/tanks/tanks.dm | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/code/game/objects/items/tanks/tanks.dm b/code/game/objects/items/tanks/tanks.dm
index 6c11c43550718..a670a966805e7 100644
--- a/code/game/objects/items/tanks/tanks.dm
+++ b/code/game/objects/items/tanks/tanks.dm
@@ -440,6 +440,10 @@
if(LAZYLEN(assembly.assemblies) == igniter_count)
return
+
+ if(isitem(loc)) // we are in a storage item
+ balloon_alert(user, "can't reach!")
+ return
if((src in user.get_equipped_items(include_pockets = TRUE, include_accessories = TRUE)) && !user.canUnEquip(src))
balloon_alert(user, "it's stuck!")
@@ -456,6 +460,7 @@
tank_assembly = assembly //Tell the tank about its assembly part
assembly.master = src //Tell the assembly about its new owner
assembly.on_attach()
+ w_class = WEIGHT_CLASS_BULKY
balloon_alert(user, "bomb assembled")
update_appearance(UPDATE_OVERLAYS)
@@ -469,6 +474,7 @@
user.put_in_hands(tank_assembly)
tank_assembly.master = null
tank_assembly = null
+ w_class = initial(w_class)
update_appearance(UPDATE_OVERLAYS)
/// Ignites the contents of the tank. Called when receiving a signal if the tank is welded and has an igniter attached.
From 4fd34879da90f80ae0d00d33ab8900c2fb0e7024 Mon Sep 17 00:00:00 2001
From: orange man <61334995+comfyorange@users.noreply.github.com>
Date: Sat, 17 Feb 2024 09:19:45 +1300
Subject: [PATCH 02/30] Automatic changelog for PR #81197 [ci skip]
---
html/changelogs/AutoChangeLog-pr-81197.yml | 4 ++++
1 file changed, 4 insertions(+)
create mode 100644 html/changelogs/AutoChangeLog-pr-81197.yml
diff --git a/html/changelogs/AutoChangeLog-pr-81197.yml b/html/changelogs/AutoChangeLog-pr-81197.yml
new file mode 100644
index 0000000000000..f579c3ce3c1b6
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-81197.yml
@@ -0,0 +1,4 @@
+author: "mc-oofert"
+delete-after: True
+changes:
+ - balance: "assemblybombs are bulky"
\ No newline at end of file
From 32802c029f24918b21bcbbe055676df78cf03f78 Mon Sep 17 00:00:00 2001
From: MLGTASTICa <61350382+MLGTASTICa@users.noreply.github.com>
Date: Fri, 16 Feb 2024 22:35:10 +0200
Subject: [PATCH 03/30] Salicylic acid & Oxandrolone now care about purity.
(#81191)
## About The Pull Request
Just makes salicylic acid and oxandrolone scale with purity (so they're
consistent with libital & aiuri scaling)
## Why It's Good For The Game
Now mass producing good salicylic acid / oxandrolone with a chem factory
takes some effort.
## Changelog
:cl:
balance: Oxandrolone now scales with purity. Its default purity is 100%
balance: Salicylic acid now scales with purity. Its default purity is
100%
/:cl:
---
.../reagents/chemistry/reagents/medicine_reagents.dm | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/code/modules/reagents/chemistry/reagents/medicine_reagents.dm b/code/modules/reagents/chemistry/reagents/medicine_reagents.dm
index aface2dce34b5..a7e37e26183b1 100644
--- a/code/modules/reagents/chemistry/reagents/medicine_reagents.dm
+++ b/code/modules/reagents/chemistry/reagents/medicine_reagents.dm
@@ -273,9 +273,9 @@
. = ..()
var/need_mob_update
if(affected_mob.getFireLoss() > 25)
- need_mob_update = affected_mob.adjustFireLoss(-4 * REM * seconds_per_tick, updating_health = FALSE, required_bodytype = affected_bodytype) //Twice as effective as AIURI for severe burns
+ need_mob_update = affected_mob.adjustFireLoss(-4 * REM * seconds_per_tick * normalise_creation_purity(), updating_health = FALSE, required_bodytype = affected_bodytype) //Twice as effective as AIURI for severe burns
else
- need_mob_update = affected_mob.adjustFireLoss(-0.5 * REM * seconds_per_tick, updating_health = FALSE, required_bodytype = affected_bodytype) //But only a quarter as effective for more minor ones
+ need_mob_update = affected_mob.adjustFireLoss(-0.5 * REM * seconds_per_tick * normalise_creation_purity(), updating_health = FALSE, required_bodytype = affected_bodytype) //But only a quarter as effective for more minor ones
if(need_mob_update)
return UPDATE_MOB_HEALTH
@@ -535,9 +535,9 @@
. = ..()
var/need_mob_update
if(affected_mob.getBruteLoss() > 25)
- need_mob_update = affected_mob.adjustBruteLoss(-4 * REM * seconds_per_tick, updating_health = FALSE, required_bodytype = affected_bodytype)
+ need_mob_update = affected_mob.adjustBruteLoss(-4 * REM * seconds_per_tick * normalise_creation_purity(), updating_health = FALSE, required_bodytype = affected_bodytype)
else
- need_mob_update = affected_mob.adjustBruteLoss(-0.5 * REM * seconds_per_tick, updating_health = FALSE, required_bodytype = affected_bodytype)
+ need_mob_update = affected_mob.adjustBruteLoss(-0.5 * REM * seconds_per_tick * normalise_creation_purity(), updating_health = FALSE, required_bodytype = affected_bodytype)
if(need_mob_update)
return UPDATE_MOB_HEALTH
From 782fa93a8d817dc22d4ec151c5e830026fe51430 Mon Sep 17 00:00:00 2001
From: orange man <61334995+comfyorange@users.noreply.github.com>
Date: Sat, 17 Feb 2024 09:40:58 +1300
Subject: [PATCH 04/30] Automatic changelog for PR #81191 [ci skip]
---
html/changelogs/AutoChangeLog-pr-81191.yml | 5 +++++
1 file changed, 5 insertions(+)
create mode 100644 html/changelogs/AutoChangeLog-pr-81191.yml
diff --git a/html/changelogs/AutoChangeLog-pr-81191.yml b/html/changelogs/AutoChangeLog-pr-81191.yml
new file mode 100644
index 0000000000000..35f82588c58bb
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-81191.yml
@@ -0,0 +1,5 @@
+author: "MLGTASTICa"
+delete-after: True
+changes:
+ - balance: "Oxandrolone now scales with purity. Its default purity is 100%"
+ - balance: "Salicylic acid now scales with purity. Its default purity is 100%"
\ No newline at end of file
From 63550f5f022b1d06045b7bc80cde95ae9faf6664 Mon Sep 17 00:00:00 2001
From: destrucktoid <39823128+destrucktoid@users.noreply.github.com>
Date: Fri, 16 Feb 2024 20:48:38 +0000
Subject: [PATCH 05/30] Nukie Mediborgs no longer kill slimes with their
nanites (#81458)
## About The Pull Request
Makes it so that regenerative nanites no longer harm slimepeople and in
fact heal them. This was originally PRed downstream by myself in
[Bubberstation](https://github.com/Bubberstation/Bubberstation/pull/1143)
and i've thought to PR it upstream as well to avoid conflicts in the
future, i do think it's a ok change for upstream as well, whilst Nukies
cannot be slimepeople on TG similar to Bubber, they can (in theory)
induct a traitor slimeperson into the team who wouldn't be able to get
healed from the nukie borg. The traitor could also emag the nukie borg
to flip them from working for the nukies. Odds of either of those
happening? Very implausible. However, i still i don't see how it would
negatively affect nukies either.
## Why It's Good For The Game
It's kind of dumb that these magical syndicate nanites that are meant to
be able to heal virtually any wound flounder in the face of slimepeople.
## Changelog
:cl:
fix: Restorative Nanites now heal Slimepeople just as well as they do
other people.
/: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 a7e37e26183b1..d20f2b786277d 100644
--- a/code/modules/reagents/chemistry/reagents/medicine_reagents.dm
+++ b/code/modules/reagents/chemistry/reagents/medicine_reagents.dm
@@ -1235,7 +1235,7 @@
need_mob_update = affected_mob.adjustBruteLoss(-5 * REM * seconds_per_tick, updating_health = FALSE) //A ton of healing - this is a 50 telecrystal investment.
need_mob_update += affected_mob.adjustFireLoss(-5 * REM * seconds_per_tick, updating_health = FALSE)
need_mob_update += affected_mob.adjustOxyLoss(-15 * REM * seconds_per_tick, updating_health = FALSE)
- need_mob_update += affected_mob.adjustToxLoss(-5 * REM * seconds_per_tick, updating_health = FALSE)
+ need_mob_update += affected_mob.adjustToxLoss(-5 * REM * seconds_per_tick, updating_health = FALSE, forced = TRUE, required_biotype = affected_biotype)
need_mob_update += affected_mob.adjustOrganLoss(ORGAN_SLOT_BRAIN, -15 * REM * seconds_per_tick)
if(need_mob_update)
return UPDATE_MOB_HEALTH
From 17a470d8ad74d714a8a19a2467bd2ae8206900e5 Mon Sep 17 00:00:00 2001
From: orange man <61334995+comfyorange@users.noreply.github.com>
Date: Sat, 17 Feb 2024 09:48:58 +1300
Subject: [PATCH 06/30] Automatic changelog for PR #81458 [ci skip]
---
html/changelogs/AutoChangeLog-pr-81458.yml | 4 ++++
1 file changed, 4 insertions(+)
create mode 100644 html/changelogs/AutoChangeLog-pr-81458.yml
diff --git a/html/changelogs/AutoChangeLog-pr-81458.yml b/html/changelogs/AutoChangeLog-pr-81458.yml
new file mode 100644
index 0000000000000..b5143220774fd
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-81458.yml
@@ -0,0 +1,4 @@
+author: "destrucktoid"
+delete-after: True
+changes:
+ - bugfix: "Restorative Nanites now heal Slimepeople just as well as they do other people."
\ No newline at end of file
From 683e2ecfbf5071d0306069c6388cba0674fe30a8 Mon Sep 17 00:00:00 2001
From: jimmyl <70376633+mc-oofert@users.noreply.github.com>
Date: Fri, 16 Feb 2024 23:10:15 +0100
Subject: [PATCH 07/30] bindable action buttons (#81371)
## About The Pull Request
### work started 12/12/2023
you may alt-click action buttons to bind them to a key
these are subject to click cooldown and if an action successfully
triggers click cooldown is triggered so you cant instantly do multiple
alt-click again to unbind
## Why It's Good For The Game
moving your mouse to the top left corner to do combat is not good
gameplay
## Changelog
:cl:
qol: you may altclick action buttons to bind them to a key
/:cl:
---------
Co-authored-by: MrMelbert <51863163+MrMelbert@users.noreply.github.com>
---
.../signals/signals_mob/signals_mob_main.dm | 3 +
code/_onclick/hud/action_button.dm | 24 ++-
code/datums/actions/action.dm | 18 +++
code/modules/keybindings/bindings_client.dm | 5 +-
code/modules/keybindings/setup.dm | 3 +-
code/modules/mob/mob.dm | 4 +
code/modules/mob/mob_defines.dm | 1 -
code/modules/tgui_input/keycombo.dm | 126 +++++++++++++++
tgstation.dme | 1 +
.../tgui/interfaces/KeyComboModal.tsx | 147 ++++++++++++++++++
10 files changed, 326 insertions(+), 6 deletions(-)
create mode 100644 code/modules/tgui_input/keycombo.dm
create mode 100644 tgui/packages/tgui/interfaces/KeyComboModal.tsx
diff --git a/code/__DEFINES/dcs/signals/signals_mob/signals_mob_main.dm b/code/__DEFINES/dcs/signals/signals_mob/signals_mob_main.dm
index 1813198b77415..cd1c636c283ca 100644
--- a/code/__DEFINES/dcs/signals/signals_mob/signals_mob_main.dm
+++ b/code/__DEFINES/dcs/signals/signals_mob/signals_mob_main.dm
@@ -243,3 +243,6 @@
/// from /mob/proc/slip(): (knockdown_amonut, obj/slipped_on, lube_flags [mobs.dm], paralyze, force_drop)
#define COMSIG_MOB_SLIPPED "mob_slipped"
+
+/// from /mob/proc/key_down(): (key, client/client, full_key)
+#define COMSIG_MOB_KEYDOWN "mob_key_down"
diff --git a/code/_onclick/hud/action_button.dm b/code/_onclick/hud/action_button.dm
index 533e8f1e8dd48..92defc661016c 100644
--- a/code/_onclick/hud/action_button.dm
+++ b/code/_onclick/hud/action_button.dm
@@ -18,6 +18,8 @@
/// A weakref of the last thing we hovered over
/// God I hate how dragging works
var/datum/weakref/last_hovored_ref
+ /// overlay for keybind maptext
+ var/mutable_appearance/keybind_maptext
/atom/movable/screen/movable/action_button/Destroy()
if(our_hud)
@@ -48,6 +50,9 @@
return FALSE
var/list/modifiers = params2list(params)
+ if(LAZYACCESS(modifiers, ALT_CLICK))
+ begin_creating_bind(usr)
+ return TRUE
if(LAZYACCESS(modifiers, SHIFT_CLICK))
var/datum/hud/our_hud = usr.hud_used
our_hud.position_action(src, SCRN_OBJ_DEFAULT)
@@ -61,6 +66,14 @@
linked_action.Trigger(trigger_flags = trigger_flags)
return TRUE
+/atom/movable/screen/movable/action_button/proc/begin_creating_bind(mob/user)
+ if(!isnull(linked_action.full_key))
+ linked_action.full_key = null
+ linked_action.update_button_status(src)
+ return
+ linked_action.full_key = tgui_input_keycombo(user, "Please bind a key for this action.")
+ linked_action.update_button_status(src)
+
// Entered and Exited won't fire while you're dragging something, because you're still "holding" it
// Very much byond logic, but I want nice behavior, so we fake it with drag
/atom/movable/screen/movable/action_button/MouseDrag(atom/over_object, src_location, over_location, src_control, over_control, params)
@@ -149,6 +162,15 @@
return
user.client.prefs.action_buttons_screen_locs -= "[name]_[id]"
+/atom/movable/screen/movable/action_button/proc/update_keybind_maptext(key)
+ cut_overlay(keybind_maptext)
+ if(!key)
+ return
+ keybind_maptext = new
+ keybind_maptext.maptext = MAPTEXT("[key]")
+ keybind_maptext.transform = keybind_maptext.transform.Translate(-4, length(key) > 1 ? -6 : 2) //with modifiers, its placed lower so cooldown is visible
+ add_overlay(keybind_maptext)
+
/**
* This is a silly proc used in hud code code to determine what icon and icon state we should be using
* for hud elements (such as action buttons) that don't have their own icon and icon state set.
@@ -241,7 +263,7 @@
action.HideFrom(src)
/atom/movable/screen/button_palette
- desc = "Drag buttons to move them Shift-click any button to reset it Alt-click this to reset all buttons"
+ desc = "Drag buttons to move them Shift-click any button to reset it Alt-click any button to begin binding it to a key Alt-click this to reset all buttons"
icon = 'icons/hud/64x16_actions.dmi'
icon_state = "screen_gen_palette"
screen_loc = ui_action_palette
diff --git a/code/datums/actions/action.dm b/code/datums/actions/action.dm
index 75c9cf59aebf2..39e69ba9fa8fd 100644
--- a/code/datums/actions/action.dm
+++ b/code/datums/actions/action.dm
@@ -46,6 +46,10 @@
var/overlay_icon = 'icons/mob/actions/backgrounds.dmi'
/// This is the icon state for any FOREGROUND overlay icons on the button (such as borders)
var/overlay_icon_state
+
+ /// full key we are bound to
+ var/full_key
+
/// Toggles whether this action is usable or not
var/action_disabled = FALSE
@@ -110,6 +114,7 @@
RegisterSignals(owner, list(SIGNAL_ADDTRAIT(TRAIT_MAGICALLY_PHASED), SIGNAL_REMOVETRAIT(TRAIT_MAGICALLY_PHASED)), PROC_REF(update_status_on_signal))
if(owner_has_control)
+ RegisterSignal(grant_to, COMSIG_MOB_KEYDOWN, PROC_REF(keydown), override = TRUE)
GiveAction(grant_to)
/// Remove the passed mob from being owner of our action
@@ -122,6 +127,7 @@
HideFrom(hud.mymob)
LAZYREMOVE(remove_from?.actions, src) // We aren't always properly inserted into the viewers list, gotta make sure that action's cleared
viewers = list()
+ UnregisterSignal(remove_from, COMSIG_MOB_KEYDOWN)
if(isnull(owner))
return
@@ -312,6 +318,7 @@
* force - whether an update is forced regardless of existing status
*/
/datum/action/proc/update_button_status(atom/movable/screen/movable/action_button/current_button, force = FALSE)
+ current_button.update_keybind_maptext(full_key)
if(IsAvailable())
current_button.color = rgb(255,255,255,255)
else
@@ -411,3 +418,14 @@
/// Checks if our action is actively selected. Used for selecting icons primarily.
/datum/action/proc/is_action_active(atom/movable/screen/movable/action_button/current_button)
return FALSE
+
+/datum/action/proc/keydown(mob/source, key, client/client, full_key)
+ SIGNAL_HANDLER
+ if(isnull(full_key) || full_key != src.full_key)
+ return
+ if(istype(source))
+ if(source.next_click > world.time)
+ return
+ else
+ source.next_click = world.time + CLICK_CD_RANGE
+ INVOKE_ASYNC(src, PROC_REF(Trigger))
diff --git a/code/modules/keybindings/bindings_client.dm b/code/modules/keybindings/bindings_client.dm
index 0a8cc20b38fe5..4a72fb9123da8 100644
--- a/code/modules/keybindings/bindings_client.dm
+++ b/code/modules/keybindings/bindings_client.dm
@@ -75,11 +75,10 @@
if(kb.can_use(src) && kb.down(src) && keycount >= MAX_COMMANDS_PER_KEY)
break
- holder?.key_down(_key, src)
- mob.focus?.key_down(_key, src)
+ holder?.key_down(_key, src, full_key)
+ mob.focus?.key_down(_key, src, full_key)
mob.update_mouse_pointer()
-
/client/verb/keyUp(_key as text)
set instant = TRUE
set hidden = TRUE
diff --git a/code/modules/keybindings/setup.dm b/code/modules/keybindings/setup.dm
index ef87e12d90103..d239c48d9ceee 100644
--- a/code/modules/keybindings/setup.dm
+++ b/code/modules/keybindings/setup.dm
@@ -1,6 +1,7 @@
// Set a client's focus to an object and override these procs on that object to let it handle keypresses
-/datum/proc/key_down(key, client/user) // Called when a key is pressed down initially
+/datum/proc/key_down(key, client/user, full_key) // Called when a key is pressed down initially
+ SHOULD_CALL_PARENT(TRUE)
return
/datum/proc/key_up(key, client/user) // Called when a key is released
return
diff --git a/code/modules/mob/mob.dm b/code/modules/mob/mob.dm
index 0301b59e8a0a7..0085d0b2fb693 100644
--- a/code/modules/mob/mob.dm
+++ b/code/modules/mob/mob.dm
@@ -1647,3 +1647,7 @@
set name = "View Skills"
mind?.print_levels(src)
+
+/mob/key_down(key, client/client, full_key)
+ ..()
+ SEND_SIGNAL(src, COMSIG_MOB_KEYDOWN, key, client, full_key)
diff --git a/code/modules/mob/mob_defines.dm b/code/modules/mob/mob_defines.dm
index 245afb869323f..aaf654e6dba2b 100644
--- a/code/modules/mob/mob_defines.dm
+++ b/code/modules/mob/mob_defines.dm
@@ -200,4 +200,3 @@
var/active_typing_indicator
///the icon currently used for the thinking indicator's bubble
var/active_thinking_indicator
-
diff --git a/code/modules/tgui_input/keycombo.dm b/code/modules/tgui_input/keycombo.dm
new file mode 100644
index 0000000000000..948dbaea234a8
--- /dev/null
+++ b/code/modules/tgui_input/keycombo.dm
@@ -0,0 +1,126 @@
+/**
+ * Creates a TGUI window with a key input. Returns the user's response as a full key with modifiers, eg ShiftK.
+ *
+ * This proc should be used to create windows for key entry that the caller will wait for a response from.
+ * If tgui fancy chat is turned off: Will return a normal input.
+ *
+ * Arguments:
+ * * user - The user to show the number input to.
+ * * message - The content of the number input, shown in the body of the TGUI window.
+ * * title - The title of the number input modal, shown on the top of the TGUI window.
+ * * default - The default (or current) key, shown as a placeholder.
+ */
+/proc/tgui_input_keycombo(mob/user = usr, message, title = "Key Input", default = 0, timeout = 0, ui_state = GLOB.always_state)
+ if (!istype(user))
+ if (istype(user, /client))
+ var/client/client = user
+ user = client.mob
+ else
+ return null
+
+ if (isnull(user.client))
+ return null
+
+ // Client does NOT have tgui_input on: Returns regular input
+ if(!user.client.prefs.read_preference(/datum/preference/toggle/tgui_input))
+ var/input_key = input(user, message, title + "(Modifiers are TGUI only, sorry!)", default) as null|text
+ return input_key[1]
+ var/datum/tgui_input_keycombo/key_input = new(user, message, title, default, timeout, ui_state)
+ key_input.ui_interact(user)
+ key_input.wait()
+ if (key_input)
+ . = key_input.entry
+ qdel(key_input)
+
+/**
+ * # tgui_input_keycombo
+ *
+ * Datum used for instantiating and using a TGUI-controlled key input that prompts the user with
+ * a message and listens for key presses.
+ */
+/datum/tgui_input_keycombo
+ /// Boolean field describing if the tgui_input_number was closed by the user.
+ var/closed
+ /// The default (or current) value, shown as a default. Users can press reset with this.
+ var/default
+ /// The entry that the user has return_typed in.
+ var/entry
+ /// The prompt's body, if any, of the TGUI window.
+ var/message
+ /// The time at which the number input was created, for displaying timeout progress.
+ var/start_time
+ /// The lifespan of the number input, after which the window will close and delete itself.
+ var/timeout
+ /// The title of the TGUI window
+ var/title
+ /// The TGUI UI state that will be returned in ui_state(). Default: always_state
+ var/datum/ui_state/state
+
+/datum/tgui_input_keycombo/New(mob/user, message, title, default, timeout, ui_state)
+ src.default = default
+ src.message = message
+ src.title = title
+ src.state = ui_state
+ if (timeout)
+ src.timeout = timeout
+ start_time = world.time
+ QDEL_IN(src, timeout)
+
+/datum/tgui_input_keycombo/Destroy(force)
+ SStgui.close_uis(src)
+ state = null
+ return ..()
+
+/**
+ * Waits for a user's response to the tgui_input_keycombo's prompt before returning. Returns early if
+ * the window was closed by the user.
+ */
+/datum/tgui_input_keycombo/proc/wait()
+ while (!entry && !closed && !QDELETED(src))
+ stoplag(1)
+
+/datum/tgui_input_keycombo/ui_interact(mob/user, datum/tgui/ui)
+ ui = SStgui.try_update_ui(user, src, ui)
+ if(!ui)
+ ui = new(user, src, "KeyComboModal")
+ ui.open()
+
+/datum/tgui_input_keycombo/ui_close(mob/user)
+ . = ..()
+ closed = TRUE
+
+/datum/tgui_input_keycombo/ui_state(mob/user)
+ return state
+
+/datum/tgui_input_keycombo/ui_static_data(mob/user)
+ var/list/data = list()
+ data["init_value"] = default // Default is a reserved keyword
+ data["large_buttons"] = user.client.prefs.read_preference(/datum/preference/toggle/tgui_input_large)
+ data["message"] = message
+ data["swapped_buttons"] = user.client.prefs.read_preference(/datum/preference/toggle/tgui_input_swapped)
+ data["title"] = title
+ return data
+
+/datum/tgui_input_keycombo/ui_data(mob/user)
+ var/list/data = list()
+ if(timeout)
+ data["timeout"] = CLAMP01((timeout - (world.time - start_time) - 1 SECONDS) / (timeout - 1 SECONDS))
+ return data
+
+/datum/tgui_input_keycombo/ui_act(action, list/params)
+ . = ..()
+ if (.)
+ return
+ switch(action)
+ if("submit")
+ set_entry(params["entry"])
+ closed = TRUE
+ SStgui.close_uis(src)
+ return TRUE
+ if("cancel")
+ closed = TRUE
+ SStgui.close_uis(src)
+ return TRUE
+
+/datum/tgui_input_keycombo/proc/set_entry(entry)
+ src.entry = entry
diff --git a/tgstation.dme b/tgstation.dme
index 0a32dc4496121..45c11123587cd 100644
--- a/tgstation.dme
+++ b/tgstation.dme
@@ -5799,6 +5799,7 @@
#include "code\modules\tgui\states\zlevel.dm"
#include "code\modules\tgui_input\alert.dm"
#include "code\modules\tgui_input\checkboxes.dm"
+#include "code\modules\tgui_input\keycombo.dm"
#include "code\modules\tgui_input\list.dm"
#include "code\modules\tgui_input\number.dm"
#include "code\modules\tgui_input\text.dm"
diff --git a/tgui/packages/tgui/interfaces/KeyComboModal.tsx b/tgui/packages/tgui/interfaces/KeyComboModal.tsx
new file mode 100644
index 0000000000000..e0b598764f156
--- /dev/null
+++ b/tgui/packages/tgui/interfaces/KeyComboModal.tsx
@@ -0,0 +1,147 @@
+import { KEY } from 'common/keys';
+import { useState } from 'react';
+
+import { useBackend, useLocalState } from '../backend';
+import { Autofocus, Box, Button, Section, Stack } from '../components';
+import { Window } from '../layouts';
+import { InputButtons } from './common/InputButtons';
+import { Loader } from './common/Loader';
+
+type KeyInputData = {
+ init_value: string;
+ large_buttons: boolean;
+ message: string;
+ timeout: number;
+ title: string;
+};
+
+const isStandardKey = (event: React.KeyboardEvent): boolean => {
+ return (
+ event.key !== KEY.Alt &&
+ event.key !== KEY.Control &&
+ event.key !== KEY.Shift &&
+ event.key !== KEY.Escape
+ );
+};
+
+const KEY_CODE_TO_BYOND: Record = {
+ DEL: 'Delete',
+ DOWN: 'South',
+ END: 'Southwest',
+ HOME: 'Northwest',
+ INSERT: 'Insert',
+ LEFT: 'West',
+ PAGEDOWN: 'Southeast',
+ PAGEUP: 'Northeast',
+ RIGHT: 'East',
+ SPACEBAR: 'Space',
+ UP: 'North',
+};
+
+const DOM_KEY_LOCATION_NUMPAD = 3;
+
+const formatKeyboardEvent = (
+ event: React.KeyboardEvent,
+): string => {
+ let text = '';
+
+ if (event.altKey) {
+ text += 'Alt';
+ }
+
+ if (event.ctrlKey) {
+ text += 'Ctrl';
+ }
+
+ if (event.shiftKey) {
+ text += 'Shift';
+ }
+
+ if (event.location === DOM_KEY_LOCATION_NUMPAD) {
+ text += 'Numpad';
+ }
+
+ if (isStandardKey(event)) {
+ const key = event.key.toUpperCase();
+ text += KEY_CODE_TO_BYOND[key] || key;
+ }
+
+ return text;
+};
+
+export const KeyComboModal = (props) => {
+ const { act, data } = useBackend();
+ const { init_value, large_buttons, message = '', title, timeout } = data;
+ const [input, setInput] = useState(init_value);
+ const [binding, setBinding] = useLocalState('binding', true);
+
+ const setValue = (value: string) => {
+ if (value === input) {
+ return;
+ }
+ setInput(value);
+ };
+
+ // Dynamically changes the window height based on the message.
+ const windowHeight =
+ 130 +
+ (message.length > 30 ? Math.ceil(message.length / 3) : 0) +
+ (message.length && large_buttons ? 5 : 0);
+
+ return (
+
+ {timeout && }
+ {
+ if (!binding) {
+ if (event.key === KEY.Enter) {
+ act('submit', { entry: input });
+ }
+ if (event.key === KEY.Escape) {
+ act('cancel');
+ }
+ return;
+ }
+
+ event.preventDefault();
+
+ if (isStandardKey(event)) {
+ setValue(formatKeyboardEvent(event));
+ setBinding(false);
+ return;
+ } else if (event.key === KEY.Escape) {
+ setValue(init_value);
+ setBinding(false);
+ return;
+ }
+ }}
+ >
+
+
+
+
+ {message}
+
+
+
+
+
+
+
+
+
+
+ );
+};
From d60ea69656995aa3a948a61fb9f927805f5fdaa5 Mon Sep 17 00:00:00 2001
From: orange man <61334995+comfyorange@users.noreply.github.com>
Date: Sat, 17 Feb 2024 11:10:40 +1300
Subject: [PATCH 08/30] Automatic changelog for PR #81371 [ci skip]
---
html/changelogs/AutoChangeLog-pr-81371.yml | 4 ++++
1 file changed, 4 insertions(+)
create mode 100644 html/changelogs/AutoChangeLog-pr-81371.yml
diff --git a/html/changelogs/AutoChangeLog-pr-81371.yml b/html/changelogs/AutoChangeLog-pr-81371.yml
new file mode 100644
index 0000000000000..9739f6f5fe035
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-81371.yml
@@ -0,0 +1,4 @@
+author: "mc-oofert"
+delete-after: True
+changes:
+ - qol: "you may altclick action buttons to bind them to a key"
\ No newline at end of file
From 56ddac02cac7cfdbbae72fa16eee9b0e4b8c18eb Mon Sep 17 00:00:00 2001
From: Changelogs
Date: Sat, 17 Feb 2024 00:19:23 +0000
Subject: [PATCH 09/30] Automatic changelog compile [ci skip]
---
html/changelogs/AutoChangeLog-pr-81191.yml | 5 ---
html/changelogs/AutoChangeLog-pr-81197.yml | 4 --
html/changelogs/AutoChangeLog-pr-81371.yml | 4 --
html/changelogs/AutoChangeLog-pr-81409.yml | 4 --
html/changelogs/AutoChangeLog-pr-81413.yml | 4 --
html/changelogs/AutoChangeLog-pr-81435.yml | 4 --
html/changelogs/AutoChangeLog-pr-81452.yml | 5 ---
html/changelogs/AutoChangeLog-pr-81458.yml | 4 --
html/changelogs/AutoChangeLog-pr-81459.yml | 6 ---
html/changelogs/AutoChangeLog-pr-81472.yml | 4 --
html/changelogs/AutoChangeLog-pr-81481.yml | 4 --
html/changelogs/AutoChangeLog-pr-81482.yml | 4 --
html/changelogs/AutoChangeLog-pr-81483.yml | 4 --
html/changelogs/AutoChangeLog-pr-81485.yml | 4 --
html/changelogs/AutoChangeLog-pr-81487.yml | 4 --
html/changelogs/AutoChangeLog-pr-81492.yml | 4 --
html/changelogs/AutoChangeLog-pr-81493.yml | 4 --
html/changelogs/archive/2024-02.yml | 43 ++++++++++++++++++++++
18 files changed, 43 insertions(+), 72 deletions(-)
delete mode 100644 html/changelogs/AutoChangeLog-pr-81191.yml
delete mode 100644 html/changelogs/AutoChangeLog-pr-81197.yml
delete mode 100644 html/changelogs/AutoChangeLog-pr-81371.yml
delete mode 100644 html/changelogs/AutoChangeLog-pr-81409.yml
delete mode 100644 html/changelogs/AutoChangeLog-pr-81413.yml
delete mode 100644 html/changelogs/AutoChangeLog-pr-81435.yml
delete mode 100644 html/changelogs/AutoChangeLog-pr-81452.yml
delete mode 100644 html/changelogs/AutoChangeLog-pr-81458.yml
delete mode 100644 html/changelogs/AutoChangeLog-pr-81459.yml
delete mode 100644 html/changelogs/AutoChangeLog-pr-81472.yml
delete mode 100644 html/changelogs/AutoChangeLog-pr-81481.yml
delete mode 100644 html/changelogs/AutoChangeLog-pr-81482.yml
delete mode 100644 html/changelogs/AutoChangeLog-pr-81483.yml
delete mode 100644 html/changelogs/AutoChangeLog-pr-81485.yml
delete mode 100644 html/changelogs/AutoChangeLog-pr-81487.yml
delete mode 100644 html/changelogs/AutoChangeLog-pr-81492.yml
delete mode 100644 html/changelogs/AutoChangeLog-pr-81493.yml
diff --git a/html/changelogs/AutoChangeLog-pr-81191.yml b/html/changelogs/AutoChangeLog-pr-81191.yml
deleted file mode 100644
index 35f82588c58bb..0000000000000
--- a/html/changelogs/AutoChangeLog-pr-81191.yml
+++ /dev/null
@@ -1,5 +0,0 @@
-author: "MLGTASTICa"
-delete-after: True
-changes:
- - balance: "Oxandrolone now scales with purity. Its default purity is 100%"
- - balance: "Salicylic acid now scales with purity. Its default purity is 100%"
\ No newline at end of file
diff --git a/html/changelogs/AutoChangeLog-pr-81197.yml b/html/changelogs/AutoChangeLog-pr-81197.yml
deleted file mode 100644
index f579c3ce3c1b6..0000000000000
--- a/html/changelogs/AutoChangeLog-pr-81197.yml
+++ /dev/null
@@ -1,4 +0,0 @@
-author: "mc-oofert"
-delete-after: True
-changes:
- - balance: "assemblybombs are bulky"
\ No newline at end of file
diff --git a/html/changelogs/AutoChangeLog-pr-81371.yml b/html/changelogs/AutoChangeLog-pr-81371.yml
deleted file mode 100644
index 9739f6f5fe035..0000000000000
--- a/html/changelogs/AutoChangeLog-pr-81371.yml
+++ /dev/null
@@ -1,4 +0,0 @@
-author: "mc-oofert"
-delete-after: True
-changes:
- - qol: "you may altclick action buttons to bind them to a key"
\ No newline at end of file
diff --git a/html/changelogs/AutoChangeLog-pr-81409.yml b/html/changelogs/AutoChangeLog-pr-81409.yml
deleted file mode 100644
index f3f1949b1ad00..0000000000000
--- a/html/changelogs/AutoChangeLog-pr-81409.yml
+++ /dev/null
@@ -1,4 +0,0 @@
-author: "Thunder12345"
-delete-after: True
-changes:
- - qol: "The bitrunning quantum console UI now lists domains in tabs by difficulty."
\ No newline at end of file
diff --git a/html/changelogs/AutoChangeLog-pr-81413.yml b/html/changelogs/AutoChangeLog-pr-81413.yml
deleted file mode 100644
index b64eee4e917c7..0000000000000
--- a/html/changelogs/AutoChangeLog-pr-81413.yml
+++ /dev/null
@@ -1,4 +0,0 @@
-author: "Melbert"
-delete-after: True
-changes:
- - rscadd: "Wizards have a new mobility option available, the Telegram Scepter. The ability to travel anywhere you can see at the point of a wand... but at a price?"
\ No newline at end of file
diff --git a/html/changelogs/AutoChangeLog-pr-81435.yml b/html/changelogs/AutoChangeLog-pr-81435.yml
deleted file mode 100644
index 0ef4705974e09..0000000000000
--- a/html/changelogs/AutoChangeLog-pr-81435.yml
+++ /dev/null
@@ -1,4 +0,0 @@
-author: "Ghommie"
-delete-after: True
-changes:
- - rscadd: "Added three new 'special' bedsheets. One of them is quite rare and made from gondola hide."
\ No newline at end of file
diff --git a/html/changelogs/AutoChangeLog-pr-81452.yml b/html/changelogs/AutoChangeLog-pr-81452.yml
deleted file mode 100644
index d501307c8ba40..0000000000000
--- a/html/changelogs/AutoChangeLog-pr-81452.yml
+++ /dev/null
@@ -1,5 +0,0 @@
-author: "mogeoko"
-delete-after: True
-changes:
- - bugfix: "Thermomachines now reconnect to pipes on multitool's act."
- - bugfix: "Multi-deck connectors won't connect pipes not located in front/top/bottom of it."
\ No newline at end of file
diff --git a/html/changelogs/AutoChangeLog-pr-81458.yml b/html/changelogs/AutoChangeLog-pr-81458.yml
deleted file mode 100644
index b5143220774fd..0000000000000
--- a/html/changelogs/AutoChangeLog-pr-81458.yml
+++ /dev/null
@@ -1,4 +0,0 @@
-author: "destrucktoid"
-delete-after: True
-changes:
- - bugfix: "Restorative Nanites now heal Slimepeople just as well as they do other people."
\ No newline at end of file
diff --git a/html/changelogs/AutoChangeLog-pr-81459.yml b/html/changelogs/AutoChangeLog-pr-81459.yml
deleted file mode 100644
index 39addd9cbe676..0000000000000
--- a/html/changelogs/AutoChangeLog-pr-81459.yml
+++ /dev/null
@@ -1,6 +0,0 @@
-author: "SyncIt21"
-delete-after: True
-changes:
- - qol: "adds examines & screentips for ore box"
- - code_imp: "cleans up some procs for ore box"
- - spellcheck: "corrected description & ui notice of ore box to specify it can hold boulders too"
\ No newline at end of file
diff --git a/html/changelogs/AutoChangeLog-pr-81472.yml b/html/changelogs/AutoChangeLog-pr-81472.yml
deleted file mode 100644
index 0ca1b4ccb0f35..0000000000000
--- a/html/changelogs/AutoChangeLog-pr-81472.yml
+++ /dev/null
@@ -1,4 +0,0 @@
-author: "kawaiinick"
-delete-after: True
-changes:
- - rscadd: "Your mouth now fits combat or survival knives(it's totally safe)"
\ No newline at end of file
diff --git a/html/changelogs/AutoChangeLog-pr-81481.yml b/html/changelogs/AutoChangeLog-pr-81481.yml
deleted file mode 100644
index d076280f163ec..0000000000000
--- a/html/changelogs/AutoChangeLog-pr-81481.yml
+++ /dev/null
@@ -1,4 +0,0 @@
-author: "Sylphet"
-delete-after: True
-changes:
- - bugfix: "cargo lockboxes update iconstates correctly now"
\ No newline at end of file
diff --git a/html/changelogs/AutoChangeLog-pr-81482.yml b/html/changelogs/AutoChangeLog-pr-81482.yml
deleted file mode 100644
index 7306b7c28b4de..0000000000000
--- a/html/changelogs/AutoChangeLog-pr-81482.yml
+++ /dev/null
@@ -1,4 +0,0 @@
-author: "00-Steven"
-delete-after: True
-changes:
- - bugfix: "Space cats CAN into space. (They're back to surviving being in unsuitable atmos.)"
\ No newline at end of file
diff --git a/html/changelogs/AutoChangeLog-pr-81483.yml b/html/changelogs/AutoChangeLog-pr-81483.yml
deleted file mode 100644
index 8c82b8396d588..0000000000000
--- a/html/changelogs/AutoChangeLog-pr-81483.yml
+++ /dev/null
@@ -1,4 +0,0 @@
-author: "IndieanaJones"
-delete-after: True
-changes:
- - bugfix: "Tank spider corpses should no longer be conditionally invisible"
\ No newline at end of file
diff --git a/html/changelogs/AutoChangeLog-pr-81485.yml b/html/changelogs/AutoChangeLog-pr-81485.yml
deleted file mode 100644
index bac62bcf734ae..0000000000000
--- a/html/changelogs/AutoChangeLog-pr-81485.yml
+++ /dev/null
@@ -1,4 +0,0 @@
-author: "IndieanaJones"
-delete-after: True
-changes:
- - bugfix: "Blob Zombies now render their blob heads correctly again."
\ No newline at end of file
diff --git a/html/changelogs/AutoChangeLog-pr-81487.yml b/html/changelogs/AutoChangeLog-pr-81487.yml
deleted file mode 100644
index db13b1e0f97da..0000000000000
--- a/html/changelogs/AutoChangeLog-pr-81487.yml
+++ /dev/null
@@ -1,4 +0,0 @@
-author: "SyncIt21"
-delete-after: True
-changes:
- - bugfix: "Indestructible items like the pai card don't teleport to the ore silo when you insert them into silo linked machine & also displays a message saying it was rejected."
\ No newline at end of file
diff --git a/html/changelogs/AutoChangeLog-pr-81492.yml b/html/changelogs/AutoChangeLog-pr-81492.yml
deleted file mode 100644
index d2aeff28762c2..0000000000000
--- a/html/changelogs/AutoChangeLog-pr-81492.yml
+++ /dev/null
@@ -1,4 +0,0 @@
-author: "13spacemen"
-delete-after: True
-changes:
- - code_imp: "Removed unused global lists and sprite accessories related to tail spines"
\ No newline at end of file
diff --git a/html/changelogs/AutoChangeLog-pr-81493.yml b/html/changelogs/AutoChangeLog-pr-81493.yml
deleted file mode 100644
index 4f7d4b4b89c23..0000000000000
--- a/html/changelogs/AutoChangeLog-pr-81493.yml
+++ /dev/null
@@ -1,4 +0,0 @@
-author: "13spacemen"
-delete-after: True
-changes:
- - code_imp: "removed redundant check for plasmamen in survival box code"
\ No newline at end of file
diff --git a/html/changelogs/archive/2024-02.yml b/html/changelogs/archive/2024-02.yml
index 6afd8b08c3696..d08f7747fd275 100644
--- a/html/changelogs/archive/2024-02.yml
+++ b/html/changelogs/archive/2024-02.yml
@@ -446,3 +446,46 @@
- rscadd: In an attempt to stop the greytide, NanoTrasen has increased security's
baton energy output. This has, through testing, done nothing but make the device
spark more than it used to.
+2024-02-17:
+ 00-Steven:
+ - bugfix: Space cats CAN into space. (They're back to surviving being in unsuitable
+ atmos.)
+ 13spacemen:
+ - code_imp: Removed unused global lists and sprite accessories related to tail spines
+ - code_imp: removed redundant check for plasmamen in survival box code
+ Ghommie:
+ - rscadd: Added three new 'special' bedsheets. One of them is quite rare and made
+ from gondola hide.
+ IndieanaJones:
+ - bugfix: Tank spider corpses should no longer be conditionally invisible
+ - bugfix: Blob Zombies now render their blob heads correctly again.
+ MLGTASTICa:
+ - balance: Oxandrolone now scales with purity. Its default purity is 100%
+ - balance: Salicylic acid now scales with purity. Its default purity is 100%
+ Melbert:
+ - rscadd: Wizards have a new mobility option available, the Telegram Scepter. The
+ ability to travel anywhere you can see at the point of a wand... but at a price?
+ Sylphet:
+ - bugfix: cargo lockboxes update iconstates correctly now
+ SyncIt21:
+ - bugfix: Indestructible items like the pai card don't teleport to the ore silo
+ when you insert them into silo linked machine & also displays a message saying
+ it was rejected.
+ - qol: adds examines & screentips for ore box
+ - code_imp: cleans up some procs for ore box
+ - spellcheck: corrected description & ui notice of ore box to specify it can hold
+ boulders too
+ Thunder12345:
+ - qol: The bitrunning quantum console UI now lists domains in tabs by difficulty.
+ destrucktoid:
+ - bugfix: Restorative Nanites now heal Slimepeople just as well as they do other
+ people.
+ kawaiinick:
+ - rscadd: Your mouth now fits combat or survival knives(it's totally safe)
+ mc-oofert:
+ - balance: assemblybombs are bulky
+ - qol: you may altclick action buttons to bind them to a key
+ mogeoko:
+ - bugfix: Thermomachines now reconnect to pipes on multitool's act.
+ - bugfix: Multi-deck connectors won't connect pipes not located in front/top/bottom
+ of it.
From 27d61bdf22d6ba3c695c60acc35f56a5e2302552 Mon Sep 17 00:00:00 2001
From: LemonInTheDark <58055496+LemonInTheDark@users.noreply.github.com>
Date: Fri, 16 Feb 2024 22:13:47 -0800
Subject: [PATCH 10/30] Fixes blocking movement being weird (#81505)
## About The Pull Request
I was failing to clear the input removal if we had no movement So you'd
step, stop moving, and retain it
Then whenever we rotate, we continue to hold onto that removal forever.
Weird.
Handles... part of? #81501
## Changelog
:cl:
fix:Blocking movement works properly again
/:cl:
---
code/modules/keybindings/bindings_atom.dm | 3 +++
code/modules/mob/mob_movement.dm | 4 ++--
2 files changed, 5 insertions(+), 2 deletions(-)
diff --git a/code/modules/keybindings/bindings_atom.dm b/code/modules/keybindings/bindings_atom.dm
index e9e38489a4df3..e99e3714c6b60 100644
--- a/code/modules/keybindings/bindings_atom.dm
+++ b/code/modules/keybindings/bindings_atom.dm
@@ -11,6 +11,9 @@
// If we're not movin anywhere, we aren't movin anywhere
// Safe because nothing adds to movement_dir after this moment
if(!movement_dir)
+ // No input == our removal would have done nothing
+ // So we can safely forget about it
+ user.next_move_dir_sub = NONE
return FALSE
if(user.next_move_dir_sub)
diff --git a/code/modules/mob/mob_movement.dm b/code/modules/mob/mob_movement.dm
index c54d0fd7c33d0..2403ca2da53c3 100644
--- a/code/modules/mob/mob_movement.dm
+++ b/code/modules/mob/mob_movement.dm
@@ -47,8 +47,8 @@
/client/Move(new_loc, direct)
if(world.time < move_delay) //do not move anything ahead of this check please
return FALSE
- next_move_dir_add = 0
- next_move_dir_sub = 0
+ next_move_dir_add = NONE
+ next_move_dir_sub = NONE
var/old_move_delay = move_delay
move_delay = world.time + world.tick_lag //this is here because Move() can now be called mutiple times per tick
if(!direct || !new_loc)
From 015629df708a17b9667c26d56226270ee927ac1d Mon Sep 17 00:00:00 2001
From: GoldenAlpharex <58045821+GoldenAlpharex@users.noreply.github.com>
Date: Sat, 17 Feb 2024 01:14:57 -0500
Subject: [PATCH 11/30] Spawners menu now displays the amount of uses left
appropriately (#81496)
## About The Pull Request
Prior to this PR, if an individual spawner allowed more than one uses,
it would still display as one use in the menu. Not only that, but
infinite spawners would also show as having just one use. Both of these
behaviors have been fixed, resulting in a much more accurate depiction
of how many uses are left on each spawner.

(The first spawner isn't normally infinite, I just used VV to edit its
`infinite_uses` to `1` for the sake of proving that the display worked).
## Why It's Good For The Game
Being able to know that a spawner is infinite is a good thing for
players, just like being able to know how many uses are left if an
individual spawner can be used by more than one player.
## Changelog
:cl: GoldenAlpharex
fix: The Spawners menu now accurately displays the amount of uses left
in each spawner option, taking into account individual spawners that
either allow more than one use, or an infinite amount of uses.
/:cl:
---
code/datums/spawners_menu.dm | 7 ++++---
tgui/packages/tgui/interfaces/SpawnersMenu.tsx | 13 ++++++++++---
2 files changed, 14 insertions(+), 6 deletions(-)
diff --git a/code/datums/spawners_menu.dm b/code/datums/spawners_menu.dm
index 06b6dbc76a857..c6b64cc3a7ad3 100644
--- a/code/datums/spawners_menu.dm
+++ b/code/datums/spawners_menu.dm
@@ -30,9 +30,9 @@
this["important_warning"] = ""
this["amount_left"] = 0
for(var/spawner_obj in GLOB.mob_spawners[spawner])
+ var/obj/effect/mob_spawn/ghost_role/mob_spawner = spawner_obj
if(!this["desc"])
if(istype(spawner_obj, /obj/effect/mob_spawn))
- var/obj/effect/mob_spawn/ghost_role/mob_spawner = spawner_obj
if(!mob_spawner.allow_spawn(user, silent = TRUE))
continue
this["you_are_text"] = mob_spawner.you_are_text
@@ -41,8 +41,9 @@
else
var/obj/object = spawner_obj
this["desc"] = object.desc
- this["amount_left"] += 1
- if(this["amount_left"] > 0)
+ this["amount_left"] += mob_spawner.uses
+ this["infinite"] += mob_spawner.infinite_use
+ if(this["amount_left"] > 0 || this["infinite"])
data["spawners"] += list(this)
for(var/mob_type in GLOB.joinable_mobs)
var/list/this = list()
diff --git a/tgui/packages/tgui/interfaces/SpawnersMenu.tsx b/tgui/packages/tgui/interfaces/SpawnersMenu.tsx
index 50366a22b2ff9..12f06cfdb62b4 100644
--- a/tgui/packages/tgui/interfaces/SpawnersMenu.tsx
+++ b/tgui/packages/tgui/interfaces/SpawnersMenu.tsx
@@ -10,6 +10,7 @@ type SpawnersMenuContext = {
type spawner = {
name: string;
amount_left: number;
+ infinite: boolean;
desc?: string;
you_are_text?: string;
flavor_text?: string;
@@ -31,9 +32,15 @@ export const SpawnersMenu = (props) => {
title={capitalizeAll(spawner.name)}
buttons={
-
- {spawner.amount_left} left
-
+ {spawner.infinite ? (
+
+ Infinite
+
+ ) : (
+
+ {spawner.amount_left} left
+
+ )}