Skip to content

Commit

Permalink
Merge branch 'master' into tiny-fuck
Browse files Browse the repository at this point in the history
  • Loading branch information
goober3 authored Sep 13, 2023
2 parents 6736064 + e1f3bf2 commit e88f7d4
Show file tree
Hide file tree
Showing 31 changed files with 366 additions and 30 deletions.
2 changes: 1 addition & 1 deletion check_regex.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ standards:

- exactly:
[
297,
298,
"non-bitwise << uses",
'(?<!\d)(?<!\d\s)(?<!<)<<(?!=|\s\d|\d|<|\/)',
]
Expand Down
2 changes: 2 additions & 0 deletions code/__DEFINES/dcs/signals.dm
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@
#define COMPONENT_GLOB_BLOCK_CINEMATIC 1
/// ingame button pressed (/obj/machinery/button/button)
#define COMSIG_GLOB_BUTTON_PRESSED "!button_pressed"
/// a client (re)connected, after all /client/New() checks have passed : (client/connected_client)
#define COMSIG_GLOB_CLIENT_CONNECT "!client_connect"

// signals from globally accessible objects
/// from SSsun when the sun changes position : (azimuth)
Expand Down
24 changes: 24 additions & 0 deletions code/__DEFINES/lag_switch.dm
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
// All of the possible Lag Switch lag mitigation measures
// If you add more do not forget to update MEASURES_AMOUNT accordingly
/// Stops ghosts flying around freely, they can still jump and orbit, staff exempted
#define DISABLE_DEAD_KEYLOOP 1
/// Stops ghosts using zoom/t-ray verbs and resets their view if zoomed out, staff exempted
#define DISABLE_GHOST_ZOOM_TRAY 2
/// Disable runechat and enable the bubbles, speaking mobs with TRAIT_BYPASS_MEASURES exempted
#define DISABLE_RUNECHAT 3
/// Disable icon2html procs from verbs like examine, mobs calling with TRAIT_BYPASS_MEASURES exempted
#define DISABLE_USR_ICON2HTML 4
/// Prevents anyone from joining the game as anything but observer
#define DISABLE_NON_OBSJOBS 5
/// Limit IC/dchat spam to one message every x seconds per client, TRAIT_BYPASS_MEASURES exempted
#define SLOWMODE_SAY 6
/// Disables parallax, as if everyone had disabled their preference, TRAIT_BYPASS_MEASURES exempted
#define DISABLE_PARALLAX 7
/// Disables footsteps, TRAIT_BYPASS_MEASURES exempted
#define DISABLE_FOOTSTEPS 8
/// Disables planet deletion
#define DISABLE_PLANETDEL 9
/// Disables ALL new planet generation, TRAIT_BYPASS_MEASURES exempted
#define DISABLE_PLANETGEN 10

#define MEASURES_AMOUNT 10 // The total number of switches defined above
2 changes: 2 additions & 0 deletions code/__DEFINES/traits.dm
Original file line number Diff line number Diff line change
Expand Up @@ -263,6 +263,8 @@ Remember to update _globalvars/traits.dm if you're adding/removing/renaming trai
#define TRAIT_SCOOPABLE "scoopable"
//your smooches actually deal damage to their target
#define TRAIT_KISS_OF_DEATH "kiss_of_death"
/// This mob overrides certian SSlag_switch measures with this special trait
#define TRAIT_BYPASS_MEASURES "bypass_lagswitch_measures"
//non-mob traits
/// Used for limb-based paralysis, where replacing the limb will fix it.
#define TRAIT_PARALYSIS "paralysis"
Expand Down
4 changes: 4 additions & 0 deletions code/__HELPERS/icons.dm
Original file line number Diff line number Diff line change
Expand Up @@ -1244,6 +1244,8 @@ GLOBAL_DATUM_INIT(dummySave, /savefile, new("tmp/dummySave.sav")) //Cache of ico
/proc/icon2html(atom/thing, client/target, icon_state, dir = SOUTH, frame = 1, moving = FALSE, sourceonly = FALSE, extra_classes = null)
if (!thing)
return
if(SSlag_switch.measures[DISABLE_USR_ICON2HTML] && usr && !HAS_TRAIT(usr, TRAIT_BYPASS_MEASURES))
return

var/key
var/icon/icon2collapse = thing
Expand Down Expand Up @@ -1354,6 +1356,8 @@ GLOBAL_DATUM_INIT(dummySave, /savefile, new("tmp/dummySave.sav")) //Cache of ico
/proc/costly_icon2html(thing, target, sourceonly = FALSE)
if (!thing)
return
if(SSlag_switch.measures[DISABLE_USR_ICON2HTML] && usr && !HAS_TRAIT(usr, TRAIT_BYPASS_MEASURES))
return

if (isicon(thing))
return icon2html(thing, target)
Expand Down
1 change: 1 addition & 0 deletions code/_globalvars/lists/mobs.dm
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ GLOBAL_LIST_EMPTY(stealthminID) //reference list with IDs that store ckeys,
//This is for procs to replace all the goddamn 'in world's that are chilling around the code

GLOBAL_LIST_EMPTY(player_list) //all mobs **with clients attached**.
GLOBAL_LIST_EMPTY(keyloop_list) //as above but can be limited to boost performance
GLOBAL_LIST_EMPTY(mob_list) //all mobs, including clientless
GLOBAL_LIST_EMPTY(mob_directory) //mob_id -> mob
GLOBAL_LIST_EMPTY(alive_mob_list) //all alive mobs, including clientless. Excludes /mob/dead/new_player
Expand Down
1 change: 1 addition & 0 deletions code/_globalvars/traits.dm
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@ GLOBAL_LIST_INIT(traits_by_type, list(
"TRAIT_CANNOT_OPEN_PRESENTS" = TRAIT_CANNOT_OPEN_PRESENTS,
"TRAIT_PRESENT_VISION" = TRAIT_PRESENT_VISION,
"TRAIT_DISK_VERIFIER" = TRAIT_DISK_VERIFIER,
"TRAIT_BYPASS_MEASURES" = TRAIT_BYPASS_MEASURES,
"TRAIT_NOMOBSWAP" = TRAIT_NOMOBSWAP,
"TRAIT_XRAY_VISION" = TRAIT_XRAY_VISION,
"TRAIT_THERMAL_VISION" = TRAIT_THERMAL_VISION,
Expand Down
4 changes: 4 additions & 0 deletions code/_onclick/hud/parallax.dm
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,10 @@

/datum/hud/proc/apply_parallax_pref(mob/viewmob)
var/mob/screenmob = viewmob || mymob

if (SSlag_switch.measures[DISABLE_PARALLAX] && !HAS_TRAIT(viewmob, TRAIT_BYPASS_MEASURES))
return FALSE

var/client/C = screenmob.client
if(C.prefs)
var/pref = C.prefs.parallax
Expand Down
4 changes: 4 additions & 0 deletions code/controllers/configuration/entries/general.dm
Original file line number Diff line number Diff line change
Expand Up @@ -325,6 +325,10 @@

/datum/config_entry/flag/maprotation

/datum/config_entry/number/auto_lag_switch_pop //Number of clients at which drastic lag mitigation measures kick in
config_entry_value = null
min_val = 0

/datum/config_entry/number/soft_popcap
config_entry_value = null
min_val = 0
Expand Down
6 changes: 2 additions & 4 deletions code/controllers/subsystem/input.dm
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,5 @@ SUBSYSTEM_DEF(input)
user.set_macros()

/datum/controller/subsystem/input/fire()
var/list/clients = GLOB.clients // Let's sing the list cache song
for(var/i in 1 to clients.len)
var/client/C = clients[i]
C.keyLoop()
for(var/mob/user as anything in GLOB.keyloop_list)
user.focus?.keyLoop(user.client)
156 changes: 156 additions & 0 deletions code/controllers/subsystem/lag_switch.dm
Original file line number Diff line number Diff line change
@@ -0,0 +1,156 @@
/// The subsystem for controlling drastic performance enhancements aimed at reducing server load for a smoother albeit slightly duller gaming experience
SUBSYSTEM_DEF(lag_switch)
name = "Lag Switch"
flags = SS_NO_FIRE

/// If the lag switch measures should attempt to trigger automatically, TRUE if a config value exists
var/auto_switch = FALSE
/// Amount of connected clients at which the Lag Switch should engage, set via config or admin panel
var/trigger_pop = INFINITY - 1337
/// List of bools corresponding to code/__DEFINES/lag_switch.dm
var/static/list/measures[MEASURES_AMOUNT]
/// List of measures that toggle automatically
var/list/auto_measures = list(DISABLE_GHOST_ZOOM_TRAY, DISABLE_RUNECHAT, DISABLE_USR_ICON2HTML, DISABLE_PARALLAX, DISABLE_FOOTSTEPS, DISABLE_PLANETDEL)
/// Timer ID for the automatic veto period
var/veto_timer_id
/// Cooldown between say verb uses when slowmode is enabled
var/slowmode_cooldown = 3 SECONDS

/datum/controller/subsystem/lag_switch/Initialize(start_timeofday)
for(var/i = 1, i <= measures.len, i++)
measures[i] = FALSE
var/auto_switch_pop = CONFIG_GET(number/auto_lag_switch_pop)
if(auto_switch_pop)
auto_switch = TRUE
trigger_pop = auto_switch_pop
RegisterSignal(SSdcs, COMSIG_GLOB_CLIENT_CONNECT, .proc/client_connected)
return ..()

/datum/controller/subsystem/lag_switch/proc/client_connected(datum/source, client/connected)
SIGNAL_HANDLER
if(TGS_CLIENT_COUNT < trigger_pop)
return

auto_switch = FALSE
UnregisterSignal(SSdcs, COMSIG_GLOB_CLIENT_CONNECT)
veto_timer_id = addtimer(CALLBACK(src, .proc/set_all_measures, TRUE, TRUE), 20 SECONDS, TIMER_STOPPABLE)
message_admins("Lag Switch population threshold reached. Automatic activation of lag mitigation measures occuring in 20 seconds. (<a href='?_src_=holder;[HrefToken()];change_lag_switch_option=CANCEL'>CANCEL</a>)")
log_admin("Lag Switch population threshold reached. Automatic activation of lag mitigation measures occuring in 20 seconds.")

/// (En/Dis)able automatic triggering of switches based on client count
/datum/controller/subsystem/lag_switch/proc/toggle_auto_enable()
auto_switch = !auto_switch
if(auto_switch)
RegisterSignal(SSdcs, COMSIG_GLOB_CLIENT_CONNECT, .proc/client_connected)
else
UnregisterSignal(SSdcs, COMSIG_GLOB_CLIENT_CONNECT)

/// Called from an admin chat link
/datum/controller/subsystem/lag_switch/proc/cancel_auto_enable_in_progress()
if(!veto_timer_id)
return FALSE

deltimer(veto_timer_id)
veto_timer_id = null
return TRUE

/// Update the slowmode timer length and clear existing ones if reduced
/datum/controller/subsystem/lag_switch/proc/change_slowmode_cooldown(length)
if(!length)
return FALSE

var/length_secs = length SECONDS
if(length_secs <= 0)
length_secs = 1 // one tick because cooldowns do not like 0

if(length_secs < slowmode_cooldown)
for(var/client/C as anything in GLOB.clients)
COOLDOWN_RESET(C, say_slowmode)

slowmode_cooldown = length_secs
if(measures[SLOWMODE_SAY])
to_chat(world, span_boldannounce("Slowmode timer has been changed to [length] seconds by an admin."))
return TRUE

/// Handle the state change for individual measures
/datum/controller/subsystem/lag_switch/proc/set_measure(measure_key, state)
if(isnull(measure_key) || isnull(state))
stack_trace("SSlag_switch.set_measure() was called with a null arg")
return FALSE
if(isnull(LAZYACCESS(measures, measure_key)))
stack_trace("SSlag_switch.set_measure() was called with a measure_key not in the list of measures")
return FALSE
if(measures[measure_key] == state)
return TRUE

measures[measure_key] = state

switch(measure_key)
if(DISABLE_DEAD_KEYLOOP)
if(state)
for(var/mob/user as anything in GLOB.player_list)
if(user.stat == DEAD && !user.client?.holder)
GLOB.keyloop_list -= user
deadchat_broadcast(span_big("To increase performance Observer freelook is now disabled. Please use Orbit, Teleport, and Jump to look around."), message_type = DEADCHAT_ANNOUNCEMENT)
else
GLOB.keyloop_list |= GLOB.player_list
deadchat_broadcast("Observer freelook has been re-enabled. Enjoy your wooshing.", message_type = DEADCHAT_ANNOUNCEMENT)
if(DISABLE_GHOST_ZOOM_TRAY)
if(state) // if enabling make sure current ghosts are updated
for(var/mob/dead/observer/ghost in GLOB.dead_mob_list)
if(!ghost.client)
continue
if(!ghost.client.holder && ghost.client.view_size.getView() != ghost.client.view_size.default)
ghost.client.view_size.resetToDefault()
if(SLOWMODE_SAY)
if(state)
to_chat(world, span_boldannounce("Slowmode for IC/dead chat has been enabled with [slowmode_cooldown/10] seconds between messages."))
else
for(var/client/C as anything in GLOB.clients)
COOLDOWN_RESET(C, say_slowmode)
to_chat(world, span_boldannounce("Slowmode for IC/dead chat has been disabled by an admin."))
if(DISABLE_NON_OBSJOBS)
world.update_status()
if(DISABLE_PARALLAX)
if (state)
to_chat(world, span_boldannounce("Parallax has been disabled for performance concerns."))
else
to_chat(world, span_boldannounce("Parallax has been re-enabled."))

for (var/mob/mob as anything in GLOB.mob_list)
mob.hud_used?.update_parallax_pref()
if(DISABLE_FOOTSTEPS)
if (state)
to_chat(world, span_boldannounce("Footstep sounds have been disabled for performance concerns."))
else
to_chat(world, span_boldannounce("Footstep sounds have been re-enabled."))
if(DISABLE_PLANETDEL)
if (state)
to_chat(world, span_boldannounce("Planet deletion and regeneration has been disabled for performance concerns."))
else
to_chat(world, span_boldannounce("Planet deletion has been re-enabled."))
if(DISABLE_PLANETGEN)
if (state)
to_chat(world, span_boldannounce("Planet generation has been disabled for performance concerns. You can still dock at already-generated planets."))
else
to_chat(world, span_boldannounce("Planet generation has been re-enabled."))

return TRUE

/// Helper to loop over all measures for mass changes
/datum/controller/subsystem/lag_switch/proc/set_all_measures(state, automatic = FALSE)
if(isnull(state))
stack_trace("SSlag_switch.set_all_measures() was called with a null state arg")
return FALSE

if(automatic)
message_admins("Lag Switch enabling automatic measures now.")
log_admin("Lag Switch enabling automatic measures now.")
veto_timer_id = null
for(var/i = 1, i <= auto_measures.len, i++)
set_measure(auto_measures[i], state)
return TRUE

for(var/i = 1, i <= measures.len, i++)
set_measure(i, state)
return TRUE
2 changes: 2 additions & 0 deletions code/datums/chatmessage.dm
Original file line number Diff line number Diff line change
Expand Up @@ -212,6 +212,8 @@
* * spans - Additional classes to be added to the message
*/
/mob/proc/create_chat_message(atom/movable/speaker, datum/language/message_language, raw_message, list/spans, runechat_flags = NONE)
if(SSlag_switch.measures[DISABLE_RUNECHAT] && !HAS_TRAIT(speaker, TRAIT_BYPASS_MEASURES))
return
// Ensure the list we are using, if present, is a copy so we don't modify the list provided to us
spans = spans ? spans.Copy() : list()

Expand Down
10 changes: 9 additions & 1 deletion code/datums/components/footstep.dm
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
#define SHOULD_DISABLE_FOOTSTEPS(source) ((SSlag_switch.measures[DISABLE_FOOTSTEPS] && !(HAS_TRAIT(source, TRAIT_BYPASS_MEASURES))) || HAS_TRAIT(source, TRAIT_SILENT_FOOTSTEPS))

///Footstep component. Plays footsteps at parents location when it is appropriate.
/datum/component/footstep
///How many steps the parent has taken since the last time a footstep was played.
Expand Down Expand Up @@ -71,6 +73,9 @@
/datum/component/footstep/proc/play_simplestep()
SIGNAL_HANDLER

if (SHOULD_DISABLE_FOOTSTEPS(parent))
return

var/turf/open/T = prepare_step()
if(!T)
return
Expand All @@ -94,8 +99,9 @@
/datum/component/footstep/proc/play_humanstep()
SIGNAL_HANDLER

if(HAS_TRAIT(parent, TRAIT_SILENT_FOOTSTEPS))
if (SHOULD_DISABLE_FOOTSTEPS(parent))
return

var/turf/open/T = prepare_step()
if(!T)
return
Expand All @@ -115,3 +121,5 @@
GLOB.barefootstep[T.barefootstep][2] * volume,
TRUE,
GLOB.barefootstep[T.barefootstep][3] + e_range, falloff_distance = 1)

#undef SHOULD_DISABLE_FOOTSTEPS
3 changes: 1 addition & 2 deletions code/datums/world_topic.dm
Original file line number Diff line number Diff line change
Expand Up @@ -152,8 +152,7 @@
.["version"] = GLOB.game_version
.["mode"] = GLOB.master_mode
.["respawn"] = config ? !CONFIG_GET(flag/norespawn) : FALSE
.["enter"] = GLOB.enter_allowed
.["vote"] = CONFIG_GET(flag/allow_vote_mode)
.["enter"] = !LAZYACCESS(SSlag_switch.measures, DISABLE_NON_OBSJOBS)
.["ai"] = CONFIG_GET(flag/allow_ai)
.["host"] = world.host ? world.host : null
.["round_id"] = GLOB.round_id
Expand Down
5 changes: 1 addition & 4 deletions code/game/world.dm
Original file line number Diff line number Diff line change
Expand Up @@ -289,10 +289,7 @@ GLOBAL_VAR(restart_counter)

var/list/features = list()

if(GLOB.master_mode)
features += GLOB.master_mode

if (!GLOB.enter_allowed)
if(LAZYACCESS(SSlag_switch.measures, DISABLE_NON_OBSJOBS))
features += "closed"

var/s = ""
Expand Down
47 changes: 38 additions & 9 deletions code/modules/admin/admin.dm
Original file line number Diff line number Diff line change
Expand Up @@ -624,15 +624,12 @@
set category = "Server"
set desc="People can't enter"
set name="Toggle Entering"
GLOB.enter_allowed = !(GLOB.enter_allowed)
if (!(GLOB.enter_allowed))
to_chat(world, "<B>New players may no longer enter the game.</B>", confidential = TRUE)
else
to_chat(world, "<B>New players may now enter the game.</B>", confidential = TRUE)
log_admin("[key_name(usr)] toggled new player game entering.")
message_admins("<span class='adminnotice'>[key_name_admin(usr)] toggled new player game entering.</span>")
world.update_status()
SSblackbox.record_feedback("nested tally", "admin_toggle", 1, list("Toggle Entering", "[GLOB.enter_allowed ? "Enabled" : "Disabled"]")) //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
if(!SSlag_switch.initialized)
return
SSlag_switch.set_measure(DISABLE_NON_OBSJOBS, !SSlag_switch.measures[DISABLE_NON_OBSJOBS])
log_admin("[key_name(usr)] toggled new player game entering. Lag Switch at index ([DISABLE_NON_OBSJOBS])")
message_admins("[key_name_admin(usr)] toggled new player game entering [SSlag_switch.measures[DISABLE_NON_OBSJOBS] ? "OFF" : "ON"].")
SSblackbox.record_feedback("nested tally", "admin_toggle", 1, list("Toggle Entering", "[!SSlag_switch.measures[DISABLE_NON_OBSJOBS] ? "Enabled" : "Disabled"]")) //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!

/datum/admins/proc/toggleAI()
set category = "Server"
Expand Down Expand Up @@ -984,3 +981,35 @@
"Admin login: [key_name(src)]")
if(string)
message_admins("[string]")

/datum/admins/proc/show_lag_switch_panel()
set category = "Admin.Game"
set name = "Show Lag Switches"
set desc="Display the controls for drastic lag mitigation measures."

if(!SSlag_switch.initialized)
to_chat(usr, span_notice("The Lag Switch subsystem has not yet been initialized."))
return
if(!check_rights())
return

var/list/dat = list("<html><head><meta http-equiv='Content-Type' content='text/html; charset=UTF-8'><title>Lag Switches</title></head><body><h2><B>Lag (Reduction) Switches</B></h2>")
dat += "Automatic Trigger: <a href='?_src_=holder;[HrefToken()];change_lag_switch_option=TOGGLE_AUTO'><b>[SSlag_switch.auto_switch ? "On" : "Off"]</b></a><br/>"
dat += "Population Threshold: <a href='?_src_=holder;[HrefToken()];change_lag_switch_option=NUM'><b>[SSlag_switch.trigger_pop]</b></a><br/>"
dat += "Slowmode Cooldown (toggle On/Off below): <a href='?_src_=holder;[HrefToken()];change_lag_switch_option=SLOWCOOL'><b>[SSlag_switch.slowmode_cooldown/10] seconds</b></a><br/>"
dat += "<br/><b>SET ALL MEASURES: <a href='?_src_=holder;[HrefToken()];change_lag_switch=ALL_ON'>ON</a> | <a href='?_src_=holder;[HrefToken()];change_lag_switch=ALL_OFF'>OFF</a></b><br/>"
dat += "<br/>Disable ghosts zoom and t-ray verbs (except staff): <a href='?_src_=holder;[HrefToken()];change_lag_switch=[DISABLE_GHOST_ZOOM_TRAY]'><b>[SSlag_switch.measures[DISABLE_GHOST_ZOOM_TRAY] ? "On" : "Off"]</b></a><br/>"
dat += "Disable planet deletion: <a href='?_src_=holder;[HrefToken()];change_lag_switch=[DISABLE_PLANETDEL]'><b>[SSlag_switch.measures[DISABLE_PLANETDEL] ? "On" : "Off"]</b></a><br/>"
dat += "Disable <b>ALL</b> planet GENERATION: <a href='?_src_=holder;[HrefToken()];change_lag_switch=[DISABLE_PLANETGEN]'><b>[SSlag_switch.measures[DISABLE_PLANETGEN] ? "On" : "Off"]</b></a><br/>"
dat += "Disable late joining: <a href='?_src_=holder;[HrefToken()];change_lag_switch=[DISABLE_NON_OBSJOBS]'><b>[SSlag_switch.measures[DISABLE_NON_OBSJOBS] ? "On" : "Off"]</b></a><br/>"
dat += "<br/>============! MAD GHOSTS ZONE !============<br/>"
dat += "Disable deadmob keyLoop (except staff, informs dchat): <a href='?_src_=holder;[HrefToken()];change_lag_switch=[DISABLE_DEAD_KEYLOOP]'><b>[SSlag_switch.measures[DISABLE_DEAD_KEYLOOP] ? "On" : "Off"]</b></a><br/>"
dat += "==========================================<br/>"
dat += "<br/><b>Measures below can be bypassed with a <abbr title='TRAIT_BYPASS_MEASURES'><u>special trait</u></abbr></b><br/>"
dat += "Slowmode say verb (informs world): <a href='?_src_=holder;[HrefToken()];change_lag_switch=[SLOWMODE_SAY]'><b>[SSlag_switch.measures[SLOWMODE_SAY] ? "On" : "Off"]</b></a><br/>"
dat += "Disable runechat: <a href='?_src_=holder;[HrefToken()];change_lag_switch=[DISABLE_RUNECHAT]'><b>[SSlag_switch.measures[DISABLE_RUNECHAT] ? "On" : "Off"]</b></a> - <span style='font-size:80%'>trait applies to speaker</span><br/>"
dat += "Disable examine icons: <a href='?_src_=holder;[HrefToken()];change_lag_switch=[DISABLE_USR_ICON2HTML]'><b>[SSlag_switch.measures[DISABLE_USR_ICON2HTML] ? "On" : "Off"]</b></a> - <span style='font-size:80%'>trait applies to examiner</span><br/>"
dat += "Disable parallax: <a href='?_src_=holder;[HrefToken()];change_lag_switch=[DISABLE_PARALLAX]'><b>[SSlag_switch.measures[DISABLE_PARALLAX] ? "On" : "Off"]</b></a> - <span style='font-size:80%'>trait applies to character</span><br />"
dat += "Disable footsteps: <a href='?_src_=holder;[HrefToken()];change_lag_switch=[DISABLE_FOOTSTEPS]'><b>[SSlag_switch.measures[DISABLE_FOOTSTEPS] ? "On" : "Off"]</b></a> - <span style='font-size:80%'>trait applies to character</span><br />"
dat += "</body></html>"
usr << browse(dat.Join(), "window=lag_switch_panel;size=420x480")
Loading

0 comments on commit e88f7d4

Please sign in to comment.