diff --git a/code/__defines/tgui.dm b/code/__defines/tgui.dm index 96664cf2b3..127f7859ec 100644 --- a/code/__defines/tgui.dm +++ b/code/__defines/tgui.dm @@ -28,6 +28,16 @@ "%7b%22type%22%3a%22[type]%22%2c%22payload%22%3a[url_encode(json_encode(payload))]%7d" \ ) +/// Though not the maximum renderable ByondUis within tgui, this is the maximum that the server will manage per-UI +#define TGUI_MANAGED_BYONDUI_LIMIT 10 + +// These are defines instead of being inline, as they're being sent over +// from tgui-core, so can't be easily played with +#define TGUI_MANAGED_BYONDUI_TYPE_RENDER "renderByondUi" +#define TGUI_MANAGED_BYONDUI_TYPE_UNMOUNT "unmountByondUi" + +#define TGUI_MANAGED_BYONDUI_PAYLOAD_ID "renderByondUi" + /// Max length for Modal Input #define TGUI_MODAL_INPUT_MAX_LENGTH 1024 /// Max length for Modal Input for names diff --git a/code/game/dna/dna2_helpers.dm b/code/game/dna/dna2_helpers.dm index 53a52cd020..96d4162c85 100644 --- a/code/game/dna/dna2_helpers.dm +++ b/code/game/dna/dna2_helpers.dm @@ -66,7 +66,7 @@ if(prob(prob)) M.dna.SetSEValue(i,rand(1,4095),1) M.dna.UpdateSE() - domutcheck(M, null) + domutcheck(M, null, MUTCHK_FORCED|MUTCHK_HIDEMSG) M.UpdateAppearance() return diff --git a/code/modules/client/preference_setup/general/01_basic.dm b/code/modules/client/preference_setup/general/01_basic.dm index a4e03242a3..899946f2d3 100644 --- a/code/modules/client/preference_setup/general/01_basic.dm +++ b/code/modules/client/preference_setup/general/01_basic.dm @@ -41,7 +41,7 @@ pref.real_name = random_name(pref.identifying_gender, pref.species) pref.nickname = sanitize_name(pref.nickname) pref.vore_egg_type = sanitize_inlist(pref.vore_egg_type, GLOB.global_vore_egg_types, initial(pref.vore_egg_type)) - pref.autohiss = sanitize_inlist(pref.autohiss, list("None", "Basic", "Full"), initial(pref.autohiss)) + pref.autohiss = sanitize_inlist(pref.autohiss, list("Off", "Basic", "Full"), initial(pref.autohiss)) // Moved from /datum/preferences/proc/copy_to() /datum/category_item/player_setup_item/general/basic/copy_to_mob(var/mob/living/carbon/human/character) diff --git a/code/modules/tgui/tgui.dm b/code/modules/tgui/tgui.dm index 172274aae9..84b44a9daa 100644 --- a/code/modules/tgui/tgui.dm +++ b/code/modules/tgui/tgui.dm @@ -37,8 +37,8 @@ var/datum/tgui_state/state = null /// Rate limit client refreshes to prevent DoS. COOLDOWN_DECLARE(refresh_cooldown) - /// Are byond mouse events beyond the window passed in to the ui - var/mouse_hooked = FALSE + /// The id of any ByondUi elements that we have opened + var/list/open_byondui_elements /// The map z-level to display. var/map_z_level = 1 /// The Parent UI @@ -50,6 +50,7 @@ /// If the window should be closed with other windows when requested var/closeable = TRUE + /** * public * @@ -128,8 +129,6 @@ window.send_message("update", get_payload( with_data = TRUE, with_static_data = TRUE)) - if(mouse_hooked) - window.set_mouse_macro() SStgui.on_open(src) return TRUE @@ -172,12 +171,29 @@ window.close(can_be_suspended, logout) src_object.tgui_close(user) SStgui.on_close(src) + + if(user.client) + terminate_byondui_elements() + state = null if(parent_ui) parent_ui.children -= src parent_ui = null qdel(src) +/** + * public + * + * Closes all ByondUI elements, left dangling by a forceful TGUI exit, + * such as via Alt+F4, closing in non-fancy mode, or terminating the process + * + */ +/datum/tgui/proc/terminate_byondui_elements() + set waitfor = FALSE + + for(var/byondui_element in open_byondui_elements) + winset(user.client, byondui_element, list("parent" = "")) + /** * public * @@ -188,17 +204,6 @@ /datum/tgui/proc/set_autoupdate(autoupdate) src.autoupdate = autoupdate -/** - * public - * - * Enable/disable passing through byond mouse events to the window - * - * required value bool Enable/disable hooking. - */ -/datum/tgui/proc/set_mouse_hook(value) - src.mouse_hooked = value - //Handle unhooking/hooking on already open windows ? - /** * public * @@ -426,6 +431,18 @@ log_tgui(user, "Fallback Triggered: [href_list["payload"]], Window: [window.id], Source: [src_object]") #endif src_object.tgui_fallback(payload) + if(TGUI_MANAGED_BYONDUI_TYPE_RENDER) + var/byond_ui_id = payload[TGUI_MANAGED_BYONDUI_PAYLOAD_ID] + if(!byond_ui_id || LAZYLEN(open_byondui_elements) > TGUI_MANAGED_BYONDUI_LIMIT) + return + + LAZYOR(open_byondui_elements, byond_ui_id) + if(TGUI_MANAGED_BYONDUI_TYPE_UNMOUNT) + var/byond_ui_id = payload[TGUI_MANAGED_BYONDUI_PAYLOAD_ID] + if(!byond_ui_id) + return + + LAZYREMOVE(open_byondui_elements, byond_ui_id) /// Wrapper for behavior to potentially wait until the next tick if the server is overloaded /datum/tgui/proc/on_act_message(act_type, payload, state) diff --git a/code/modules/tgui/tgui_window.dm b/code/modules/tgui/tgui_window.dm index 06ebd09478..38675b150d 100644 --- a/code/modules/tgui/tgui_window.dm +++ b/code/modules/tgui/tgui_window.dm @@ -27,19 +27,6 @@ var/initial_inline_css var/list/oversized_payloads = list() - var/mouse_event_macro_set = FALSE - - /** - * Static list used to map in macros that will then emit execute events to the tgui window - * A small disclaimer though I'm no tech wiz: I don't think it's possible to map in right or middle - * clicks in the current state, as they're keywords rather than modifiers. - */ - var/static/list/byondToTguiEventMap = list( - "MouseDown" = "byond/mousedown", - "MouseUp" = "byond/mouseup", - "Ctrl" = "byond/ctrldown", - "Ctrl+UP" = "byond/ctrlup", - ) /** * public @@ -235,8 +222,6 @@ /datum/tgui_window/proc/close(can_be_suspended = TRUE) if(!client) return - if(mouse_event_macro_set) - remove_mouse_macro() if(can_be_suspended && can_be_suspended()) #ifdef TGUI_DEBUGGING log_tgui(client, "[id]/close: suspending") @@ -441,32 +426,3 @@ /datum/tgui_window/proc/remove_oversized_payload(payload_id) oversized_payloads -= payload_id - - -/datum/tgui_window/proc/set_mouse_macro() - if(mouse_event_macro_set) - return - - for(var/mouseMacro in byondToTguiEventMap) - var/command_template = ".output CONTROL PAYLOAD" - var/event_message = TGUI_CREATE_MESSAGE(byondToTguiEventMap[mouseMacro], null) - var target_control = is_browser \ - ? "[id]:update" \ - : "[id].browser:update" - var/with_id = replacetext(command_template, "CONTROL", target_control) - var/full_command = replacetext(with_id, "PAYLOAD", event_message) - - var/list/params = list() - params["parent"] = "default" //Technically this is external to tgui but whatever - params["name"] = mouseMacro - params["command"] = full_command - - winset(client, "[mouseMacro]Window[id]Macro", params) - mouse_event_macro_set = TRUE - -/datum/tgui_window/proc/remove_mouse_macro() - if(!mouse_event_macro_set) - stack_trace("Unsetting mouse macro on tgui window that has none") - for(var/mouseMacro in byondToTguiEventMap) - winset(client, null, "[mouseMacro]Window[id]Macro.parent=null") - mouse_event_macro_set = FALSE diff --git a/code/modules/xenoarcheaology/effect.dm b/code/modules/xenoarcheaology/effect.dm index 66572c858f..c1e32de412 100644 --- a/code/modules/xenoarcheaology/effect.dm +++ b/code/modules/xenoarcheaology/effect.dm @@ -20,7 +20,7 @@ // The last time the effect was toggled. var/last_activation = 0 - // If we can start activated or not! + // If we can start activated or not! Note: This is only really disabled on artifacts that can REALLY do some MAJOR DAMAGE to the server itself. See: Atmos & temperature artifacts destroying an entire Z-level's atmos. var/can_start_activated = TRUE /datum/artifact_effect/Destroy() @@ -51,19 +51,28 @@ artifact_id = "[pick("kappa","sigma","antaeres","beta","omicron","iota","epsilon","omega","gamma","delta","tau","alpha")]-[rand(100,999)]" //random charge time and distance - switch(pick(100;1, 50;2, 25;3)) - if(1) - //short range, short charge time - chargelevelmax = rand(3, 20) - effectrange = rand(1, 3) - if(2) - //medium range, medium charge time - chargelevelmax = rand(15, 40) - effectrange = rand(5, 15) - if(3) - //large range, long charge time - chargelevelmax = rand(20, 120) - effectrange = rand(20, 100) + switch(effect) + if(EFFECT_PULSE) + switch(pick(100;1, 50;2, 25;3)) + if(1) + //short range, short charge time + chargelevelmax = rand(3, 20) + effectrange = rand(1, 3) + if(2) + //medium range, medium charge time + chargelevelmax = rand(15, 40) + effectrange = rand(5, 15) + if(3) + //large range, long charge time + chargelevelmax = rand(20, 120) + effectrange = rand(20, 100) + if(EFFECT_AURA) + if(prob(1)) //1% chance for a BIG range. + effectrange = rand(1, 100) + else + effectrange = rand(2,7) + if(EFFECT_TOUCH) + effectrange = 1 if(can_start_activated && prob(50)) ToggleActivate(TRUE, TRUE) diff --git a/code/modules/xenoarcheaology/effects/dnaswitch.dm b/code/modules/xenoarcheaology/effects/dnaswitch.dm index b035748b3c..1fddd43457 100644 --- a/code/modules/xenoarcheaology/effects/dnaswitch.dm +++ b/code/modules/xenoarcheaology/effects/dnaswitch.dm @@ -1,7 +1,8 @@ /datum/artifact_effect/dnaswitch name = "DNA Mutator" effect_type = EFFECT_DNASWITCH - var/severity + var/effect_strength //This is the % chance PER GENE to MUTATE IT. + can_start_activated = FALSE effect_state = "smoke" effect_color = "#77ff83" @@ -9,29 +10,26 @@ /datum/artifact_effect/dnaswitch/New() ..() effect = pick(EFFECT_TOUCH, EFFECT_AURA, EFFECT_PULSE) - if(effect == EFFECT_AURA) - severity = rand(10,50) - else if(effect == EFFECT_PULSE) - severity = rand(5,25) + if(effect == EFFECT_AURA) //Quite dangerous. + effect_strength = rand(2,5) + else if(effect == EFFECT_PULSE) //This only happens every 40 to 240 seconds. + effect_strength = rand(1,10) else - severity = rand(20,90) + effect_strength = rand(10,20) //This one is SUPER beneficial to the geneticist, as they can mutate monkeys. /datum/artifact_effect/dnaswitch/DoEffectTouch(var/mob/toucher) var/weakness = GetAnomalySusceptibility(toucher) if(ishuman(toucher) && prob(weakness * 100)) - to_chat(toucher, span_notice(span_green("[pick( - "You feel a little different.", - "You feel very strange.", - "Your stomach churns.", - "Your skin feels loose.", - "You feel a stabbing pain in your head.", - "You feel a tingling sensation in your chest.", - "Your entire body vibrates.")]"))) - - if(prob(75)) - scramble(1, toucher, weakness * severity) - else - scramble(0, toucher, weakness * severity) + if(prob(effect_strength)) + to_chat(toucher, span_notice(span_green("[pick( + "You feel a little different.", + "You feel very strange.", + "Your stomach churns.", + "Your skin feels loose.", + "You feel a stabbing pain in your head.", + "You feel a tingling sensation in your chest.", + "Your entire body vibrates.")]"))) + scramble(1, toucher, weakness * effect_strength) return 1 /datum/artifact_effect/dnaswitch/DoEffectAura() @@ -46,7 +44,7 @@ for(var/mob/living/carbon/human/H in range(src.effectrange,T)) var/weakness = GetAnomalySusceptibility(H) if(prob(weakness * 100)) - if(prob(30)) + if(prob(effect_strength)) to_chat(H, span_notice(span_green("[pick( "You feel a little different.", "You feel very strange.", @@ -55,10 +53,7 @@ "You feel a stabbing pain in your head.", "You feel a tingling sensation in your chest.", "Your entire body vibrates.")]"))) - if(prob(50)) - scramble(1, H, weakness * severity) - else - scramble(0, H, weakness * severity) + scramble(1, H, weakness * effect_strength) /datum/artifact_effect/dnaswitch/DoEffectPulse() var/atom/holder = get_master_holder() @@ -72,7 +67,7 @@ for(var/mob/living/carbon/human/H in range(200, T)) var/weakness = GetAnomalySusceptibility(H) if(prob(weakness * 100)) - if(prob(75)) + if(prob(effect_strength)) to_chat(H, span_notice(span_green("[pick( "You feel a little different.", "You feel very strange.", @@ -82,7 +77,4 @@ "You feel a tingling sensation in your chest.", "Your entire body vibrates.")]"))) if(prob(25)) - if(prob(75)) - scramble(1, H, weakness * severity) - else - scramble(0, H, weakness * severity) + scramble(1, H, weakness * effect_strength) diff --git a/code/modules/xenoarcheaology/effects/electric_field.dm b/code/modules/xenoarcheaology/effects/electric_field.dm index 3289616e2b..4cc0ac66ac 100644 --- a/code/modules/xenoarcheaology/effects/electric_field.dm +++ b/code/modules/xenoarcheaology/effects/electric_field.dm @@ -9,6 +9,7 @@ /datum/artifact_effect/electric_field/DoEffectTouch(var/mob/user) var/atom/holder = get_master_holder() + var/weakness = GetAnomalySusceptibility(user) if(last_used >= world.time + use_delay) return else @@ -73,6 +74,9 @@ light.flicker() for(var/mob/living/L in nearby_mobs) + var/weakness = GetAnomalySusceptibility(L) + if(!weakness) //We have protection on! + continue if(L.isSynthetic()) to_chat(L, span_danger("ERROR: Electrical fault detected!")) L.stuttering += 3 @@ -80,12 +84,12 @@ if(ishuman(L)) var/mob/living/carbon/human/H = L var/obj/item/organ/external/affected = H.get_organ(check_zone(BP_TORSO)) - H.electrocute_act(rand(1, 10), holder, H.get_siemens_coefficient_organ(affected), affected) + H.electrocute_act(rand(1, 10) * weakness, holder, H.get_siemens_coefficient_organ(affected), affected) var/turf/T = get_turf(L) if(istype(T)) lightning_strike(T, TRUE) else - L.electrocute_act(rand(1, 10), holder, 0.75, BP_TORSO) + L.electrocute_act(rand(1, 10) * weakness, holder, 0.75, BP_TORSO) var/turf/T = get_turf(L) if(istype(T)) lightning_strike(T, TRUE) @@ -115,6 +119,9 @@ light.flicker() for(var/mob/living/L in nearby_mobs) + var/weakness = GetAnomalySusceptibility(L) + if(!weakness) //We have protection on! + continue if(L.isSynthetic()) to_chat(L, span_danger("ERROR: Electrical fault detected!")) L.stuttering += 3 @@ -122,12 +129,12 @@ if(ishuman(L)) var/mob/living/carbon/human/H = L var/obj/item/organ/external/affected = H.get_organ(check_zone(BP_TORSO)) - H.electrocute_act(rand(10, 30), holder, H.get_siemens_coefficient_organ(affected), affected) + H.electrocute_act(rand(10, 30) * weakness, holder, H.get_siemens_coefficient_organ(affected), affected) var/turf/T = get_turf(L) if(istype(T)) lightning_strike(T, TRUE) else - L.electrocute_act(rand(10, 30), holder, 0.75, BP_TORSO) + L.electrocute_act(rand(10, 30) * weakness, holder, 0.75, BP_TORSO) var/turf/T = get_turf(L) if(istype(T)) lightning_strike(T, TRUE) diff --git a/tgui/packages/tgui-bench/package.json b/tgui/packages/tgui-bench/package.json index 674ba315bb..172befcaee 100644 --- a/tgui/packages/tgui-bench/package.json +++ b/tgui/packages/tgui-bench/package.json @@ -11,7 +11,7 @@ "react": "^19.1.0", "react-dom": "^19.1.0", "tgui": "workspace:*", - "tgui-core": "^4.0.1" + "tgui-core": "^4.0.3" }, "devDependencies": { "@types/react": "^19.1.0", diff --git a/tgui/packages/tgui-panel/package.json b/tgui/packages/tgui-panel/package.json index 15b171b3d7..55e41a34e6 100644 --- a/tgui/packages/tgui-panel/package.json +++ b/tgui/packages/tgui-panel/package.json @@ -8,7 +8,7 @@ "react": "^19.1.0", "react-dom": "^19.1.0", "tgui": "workspace:*", - "tgui-core": "^4.0.1", + "tgui-core": "^4.0.3", "tgui-dev-server": "workspace:*" }, "devDependencies": { diff --git a/tgui/packages/tgui-say/package.json b/tgui/packages/tgui-say/package.json index bb1cb416e4..ac308cbba5 100644 --- a/tgui/packages/tgui-say/package.json +++ b/tgui/packages/tgui-say/package.json @@ -7,7 +7,7 @@ "react": "^19.1.0", "react-dom": "^19.1.0", "tgui": "workspace:*", - "tgui-core": "^4.0.1" + "tgui-core": "^4.0.3" }, "devDependencies": { "@types/react": "^19.1.0", diff --git a/tgui/packages/tgui/backend.ts b/tgui/packages/tgui/backend.ts index bc8c4eed68..33e6ae9dfc 100644 --- a/tgui/packages/tgui/backend.ts +++ b/tgui/packages/tgui/backend.ts @@ -13,7 +13,6 @@ import { perf } from 'common/perf'; import { createAction } from 'common/redux'; -import { globalEvents } from 'tgui-core/events'; import type { BooleanLike } from 'tgui-core/react'; import { setupDrag } from './drag'; @@ -97,14 +96,6 @@ export const backendReducer = (state = initialState, action) => { }; } - if (type === 'byond/ctrldown') { - globalEvents.emit('byond/ctrldown'); - } - - if (type === 'byond/ctrlup') { - globalEvents.emit('byond/ctrlup'); - } - if (type === 'backend/suspendStart') { return { ...state, @@ -154,22 +145,6 @@ export const backendMiddleware = (store) => { return; } - if (type === 'byond/mousedown') { - globalEvents.emit('byond/mousedown'); - } - - if (type === 'byond/mouseup') { - globalEvents.emit('byond/mouseup'); - } - - if (type === 'byond/ctrldown') { - globalEvents.emit('byond/ctrldown'); - } - - if (type === 'byond/ctrlup') { - globalEvents.emit('byond/ctrlup'); - } - if (type === 'backend/suspendStart' && !suspendInterval) { logger.log(`suspending (${Byond.windowId})`); // Keep sending suspend messages until it succeeds. diff --git a/tgui/packages/tgui/interfaces/DNAModifier/DNAModifierBlocks.tsx b/tgui/packages/tgui/interfaces/DNAModifier/DNAModifierBlocks.tsx index 1cd1909461..fb70fcba87 100644 --- a/tgui/packages/tgui/interfaces/DNAModifier/DNAModifierBlocks.tsx +++ b/tgui/packages/tgui/interfaces/DNAModifier/DNAModifierBlocks.tsx @@ -40,10 +40,7 @@ export const DNAModifierBlocks = (props: { ); } dnaBlocks.push( - + ) : null} - { - - - - } + + +