diff --git a/citadel.dme b/citadel.dme index 3ad214a67c5..21588de57a1 100644 --- a/citadel.dme +++ b/citadel.dme @@ -33,6 +33,7 @@ #include "code\__DEFINES\ability.dm" #include "code\__DEFINES\access.dm" #include "code\__DEFINES\actionspeed_modification.dm" +#include "code\__DEFINES\admin_verb.dm" #include "code\__DEFINES\appearance.dm" #include "code\__DEFINES\assert.dm" #include "code\__DEFINES\automata.dm" @@ -56,6 +57,7 @@ #include "code\__DEFINES\holidays.dm" #include "code\__DEFINES\holomap.dm" #include "code\__DEFINES\holospheres.dm" +#include "code\__DEFINES\html_assistant.dm" #include "code\__DEFINES\icon_smoothing.dm" #include "code\__DEFINES\ingredients.dm" #include "code\__DEFINES\instruments.dm" @@ -93,6 +95,7 @@ #include "code\__DEFINES\spaceman_dmm.dm" #include "code\__DEFINES\spans.dm" #include "code\__DEFINES\spells.dm" +#include "code\__DEFINES\stack_trace.dm" #include "code\__DEFINES\stat_tracking.dm" #include "code\__DEFINES\statpanel.dm" #include "code\__DEFINES\supply.dm" @@ -411,6 +414,7 @@ #include "code\__HELPERS\shell.dm" #include "code\__HELPERS\spatial_info.dm" #include "code\__HELPERS\stack_trace.dm" +#include "code\__HELPERS\stat_tracking.dm" #include "code\__HELPERS\stoplag.dm" #include "code\__HELPERS\storage.dm" #include "code\__HELPERS\text.dm" diff --git a/code/__DEFINES/_core.dm b/code/__DEFINES/_core.dm index 086fb81f628..c90a3c5c705 100644 --- a/code/__DEFINES/_core.dm +++ b/code/__DEFINES/_core.dm @@ -6,12 +6,6 @@ /proc/___rethrow_exception(exception/E) throw E -/// Gives us the stack trace from CRASH() without ending the current proc. -/// Unlike STACK_TRACE, this will: -/// * call a new proc so the originating trace isn't from the original file anymore -/// * put the stack trace in stack trace storage -#define stack_trace(message) _stack_trace(message, __FILE__, __LINE__) - /// get variable if not null or #define VALUE_OR_DEFAULT(VAL, DEFAULT) (isnull(VAL)? (DEFAULT) : (VAL)) diff --git a/code/__DEFINES/_lists.dm b/code/__DEFINES/_lists.dm index 5369a21c3af..ab183129bd8 100644 --- a/code/__DEFINES/_lists.dm +++ b/code/__DEFINES/_lists.dm @@ -25,13 +25,28 @@ #define LAZYLEN(L) length(L) ///Sets a list to null #define LAZYNULL(L) L = null -/// Null-safe L.Cut() +///Adds to the item K the value V, if the list is null it will initialize it +#define LAZYADDASSOC(L, K, V) if(!L) { L = list(); } L[K] += V; +///This is used to add onto lazy assoc list when the value you're adding is a /list/. This one has extra safety over lazyaddassoc because the value could be null (and thus cant be used to += objects) +#define LAZYADDASSOCLIST(L, K, V) if(!L) { L = list(); } L[K] += list(V); +///Removes the value V from the item K, if the item K is empty will remove it from the list, if the list is empty will set the list to null +#define LAZYREMOVEASSOC(L, K, V) if(L) { if(L[K]) { L[K] -= V; if(!length(L[K])) L -= K; } if(!length(L)) L = null; } +///Accesses an associative list, returns null if nothing is found +#define LAZYACCESSASSOC(L, I, K) L ? L[I] ? L[I][K] ? L[I][K] : null : null : null +//These methods don't null the list +///Use LAZYLISTDUPLICATE instead if you want it to null with no entries +#define LAZYCOPY(L) (L ? L.Copy() : list() ) +/// Consider LAZYNULL instead #define LAZYCLEARLIST(L) if(L) L.Cut() -/// Null-safe L.Copy() -#define LAZYCOPY(L) (L? L.Copy() : null) -/// Reads L or an empty list if L is not a list. Note: Does NOT assign, L may be an expression. +///Returns the list if it's actually a valid list, otherwise will initialize it #define SANITIZE_LIST(L) ( islist(L) ? L : list() ) #define SANITIZE_TO_LIST(L) ( islist(L) ? L : list(L) ) +/// Performs an insertion on the given lazy list with the given key and value. If the value already exists, a new one will not be made. +#define LAZYORASSOCLIST(lazy_list, key, value) \ + LAZYINITLIST(lazy_list); \ + LAZYINITLIST(lazy_list[key]); \ + lazy_list[key] |= value; + #define reverseList(L) reverseRange(L.Copy()) #define SAFEPICK(L) (length(L)? pick(L) : null) diff --git a/code/__DEFINES/admin_verb.dm b/code/__DEFINES/admin_verb.dm new file mode 100644 index 00000000000..4c73d57ccff --- /dev/null +++ b/code/__DEFINES/admin_verb.dm @@ -0,0 +1,24 @@ +// This port is currently half-assed, we do not include the entire avd stuff + +/// Use this to mark your verb as not having a description. Should ONLY be used if you are also hiding the verb! +#define ADMIN_VERB_NO_DESCRIPTION "" +/// Used to verbs you do not want to show up in the master verb panel. +#define ADMIN_CATEGORY_HIDDEN null + +// Admin verb categories +#define ADMIN_CATEGORY_MAIN "Admin" +#define ADMIN_CATEGORY_EVENTS "Admin.Events" +#define ADMIN_CATEGORY_FUN "Admin.Fun" +#define ADMIN_CATEGORY_GAME "Admin.Game" +#define ADMIN_CATEGORY_SHUTTLE "Admin.Shuttle" + +// Special categories that are separated +#define ADMIN_CATEGORY_DEBUG "Debug" +#define ADMIN_CATEGORY_SERVER "Server" +#define ADMIN_CATEGORY_OBJECT "Object" +#define ADMIN_CATEGORY_MAPPING "Mapping" +#define ADMIN_CATEGORY_PROFILE "Profile" +#define ADMIN_CATEGORY_IPINTEL "Admin.IPIntel" + +// Visibility flags +#define ADMIN_VERB_VISIBLITY_FLAG_MAPPING_DEBUG "Map-Debug" diff --git a/code/__DEFINES/html_assistant.dm b/code/__DEFINES/html_assistant.dm new file mode 100644 index 00000000000..91af96a95c7 --- /dev/null +++ b/code/__DEFINES/html_assistant.dm @@ -0,0 +1,5 @@ +#define HTML_SKELETON_INTERNAL(head, body) \ +"[head][body]" + +#define HTML_SKELETON_TITLE(title, body) HTML_SKELETON_INTERNAL("[title]", body) +#define HTML_SKELETON(body) HTML_SKELETON_INTERNAL("", body) diff --git a/code/__DEFINES/stack_trace.dm b/code/__DEFINES/stack_trace.dm new file mode 100644 index 00000000000..4911b4a0d57 --- /dev/null +++ b/code/__DEFINES/stack_trace.dm @@ -0,0 +1,4 @@ +/// gives us the stack trace from CRASH() without ending the current proc. +#define stack_trace(message) _stack_trace(message, __FILE__, __LINE__) + +#define WORKAROUND_IDENTIFIER "%//%" diff --git a/code/__DEFINES/stat_tracking.dm b/code/__DEFINES/stat_tracking.dm index 79337bda5cc..9bd69744040 100644 --- a/code/__DEFINES/stat_tracking.dm +++ b/code/__DEFINES/stat_tracking.dm @@ -1,17 +1,67 @@ -// -// Defines used for advanced performance profiling of subsystems. -// Currently used only by SSoverlays (2018-02-24 ~Leshana) -// #define STAT_ENTRY_TIME 1 #define STAT_ENTRY_COUNT 2 #define STAT_ENTRY_LENGTH 2 + #define STAT_START_STOPWATCH var/STAT_STOP_WATCH = TICK_USAGE #define STAT_STOP_STOPWATCH var/STAT_TIME = TICK_USAGE_TO_MS(STAT_STOP_WATCH) #define STAT_LOG_ENTRY(entrylist, entryname) \ var/list/STAT_ENTRY = entrylist[entryname] || (entrylist[entryname] = new /list(STAT_ENTRY_LENGTH));\ STAT_ENTRY[STAT_ENTRY_TIME] += STAT_TIME;\ - var/STAT_INCR_AMOUNT = min(1, 2**round((STAT_ENTRY[STAT_ENTRY_COUNT] || 0)/SHORT_REAL_LIMIT));\ - if (STAT_INCR_AMOUNT == 1 || prob(100/STAT_INCR_AMOUNT)) {\ - STAT_ENTRY[STAT_ENTRY_COUNT] += STAT_INCR_AMOUNT;\ - };\ + STAT_ENTRY[STAT_ENTRY_COUNT] += 1; + +// Cost tracking macros, to be used in one proc. If you're using this raw you'll want to use global lists +// If you don't you'll need another way of reading it +#define INIT_COST(costs, counting) \ + var/list/_costs = costs; \ + var/list/_counting = counting; \ + var/_usage = TICK_USAGE; + +// STATIC cost tracking macro. Uses static lists instead of the normal global ones +// Good for debug stuff, and for running before globals init +#define INIT_COST_STATIC(...) \ + var/static/list/hidden_static_list_for_fun1 = list(); \ + var/static/list/hidden_static_list_for_fun2 = list(); \ + INIT_COST(hidden_static_list_for_fun1, hidden_static_list_for_fun2) + +// Cost tracking macro for global lists, prevents erroring if GLOB has not yet been initialized +#define INIT_COST_GLOBAL(costs, counting) \ + INIT_COST_STATIC() \ + if(GLOB){\ + costs = hidden_static_list_for_fun1; \ + counting = hidden_static_list_for_fun2 ; \ + } \ + _usage = TICK_USAGE; + + +#define SET_COST(category) \ + do { \ + var/_cost = TICK_USAGE; \ + _costs[category] += TICK_DELTA_TO_MS(_cost - _usage);\ + _counting[category] += 1; \ + } while(FALSE); \ + _usage = TICK_USAGE; + +#define SET_COST_LINE(...) SET_COST("[__LINE__]") + +/// A quick helper for running the code as a statement and profiling its cost. +/// For example, `SET_COST_STMT(var/x = do_work())` +#define SET_COST_STMT(code...) ##code; SET_COST("[__LINE__] - [#code]") + +#define EXPORT_STATS_TO_JSON_LATER(filename, costs, counts) EXPORT_STATS_TO_FILE_LATER(filename, costs, counts, stat_tracking_export_to_json_later) +#define EXPORT_STATS_TO_CSV_LATER(filename, costs, counts) EXPORT_STATS_TO_FILE_LATER(filename, costs, counts, stat_tracking_export_to_csv_later) + +#define EXPORT_STATS_TO_FILE_LATER(filename, costs, counts, proc) \ + do { \ + var/static/last_export = 0; \ + /* Need to always run if we haven't yet, since this code can be placed ANYWHERE */ \ + if (world.time - last_export > 1.1 SECONDS || (last_export == 0)) { \ + last_export = world.time; \ + /* spawn() is used here because this is often used to track init times, where timers act oddly. */ \ + /* I was making timers and even after init times were complete, the timers didn't run :shrug: */ \ + spawn (1 SECONDS) { \ + ##proc(filename, costs, counts); \ + } \ + } \ + } while (FALSE); \ + _usage = TICK_USAGE; diff --git a/code/__DEFINES/vv.dm b/code/__DEFINES/vv.dm index 0ba4477f7b8..188133bd93e 100644 --- a/code/__DEFINES/vv.dm +++ b/code/__DEFINES/vv.dm @@ -153,3 +153,5 @@ // /obj/item/card/id #define VV_HK_ID_MOD "id_mod" + +#define VV_HK_WEAKREF_RESOLVE "weakref_resolve" diff --git a/code/__HELPERS/do_after.dm b/code/__HELPERS/do_after.dm index a0365eeb132..1d2ed78d1ec 100644 --- a/code/__HELPERS/do_after.dm +++ b/code/__HELPERS/do_after.dm @@ -19,7 +19,7 @@ . = TRUE while (world.time < endtime) stoplag(1) - if (progress) + if (progress && !QDELETED(progbar)) progbar.update(world.time - starttime) if(!user || !target) . = FALSE @@ -52,7 +52,7 @@ break if(!QDELETED(progbar)) - qdel(progbar) + progbar.end_progress() STOP_INTERACTING_WITH(user, target, INTERACTING_FOR_DO_AFTER) @@ -71,7 +71,7 @@ * * progress_instance - override progressbar instance */ /proc/do_after(mob/user, delay, atom/target, flags, mobility_flags = MOBILITY_CAN_USE, max_distance, datum/callback/additional_checks, atom/progress_anchor, datum/progressbar/progress_instance) - if(isnull(user)) + if(isnull(user) || QDELETED(user)) return FALSE if(!delay) return \ @@ -111,7 +111,8 @@ while(world.time < (start_time + delay)) stoplag(1) - progress?.update((world.time - start_time) * delay_factor) + if (progress && !QDELETED(progress)) + progress.update((world.time - start_time) * delay_factor) // check if deleted if(QDELETED(user)) @@ -172,7 +173,7 @@ //* end if(!QDELETED(progress)) - qdel(progress) + progress.end_progress() if(!isnull(target)) STOP_INTERACTING_WITH(user, target, INTERACTING_FOR_DO_AFTER) diff --git a/code/__HELPERS/game.dm b/code/__HELPERS/game.dm index 171e1fde992..be6d5fc3afa 100644 --- a/code/__HELPERS/game.dm +++ b/code/__HELPERS/game.dm @@ -567,3 +567,23 @@ return hear +///Get active players who are playing in the round +/proc/get_active_player_count(alive_check = FALSE, afk_check = FALSE, human_check = FALSE) + var/active_players = 0 + for(var/mob/player_mob as anything in GLOB.player_list) + if(!player_mob?.client) + continue + if(alive_check && player_mob.stat == DEAD) + continue + if(afk_check && player_mob.client.is_afk()) + continue + if(human_check && !ishuman(player_mob)) + continue + if(isnewplayer(player_mob)) // exclude people in the lobby + continue + if(isobserver(player_mob)) // Ghosts are fine if they were playing once (didn't start as observers) + // var/mob/dead/observer/ghost_player = player_mob + // if(ghost_player.started_as_observer) // Exclude people who started as observers + continue + active_players++ + return active_players diff --git a/code/__HELPERS/icons.dm b/code/__HELPERS/icons.dm index 44c21c2b069..460fdecab41 100644 --- a/code/__HELPERS/icons.dm +++ b/code/__HELPERS/icons.dm @@ -635,6 +635,32 @@ GLOBAL_LIST_EMPTY(icon_exists_cache) stack_trace("Icon Lookup for state: [state] in file [file] failed.") return FALSE +/** + * Returns the size of the sprite in tiles. + * Takes the icon size and divides it by the world icon size (default 32). + * This gives the size of the sprite in tiles. + * + * @return size of the sprite in tiles + */ +/proc/get_size_in_tiles(obj/target) + var/icon/size_check = icon(target.icon, target.icon_state) + var/size = size_check.Width() / 32 + + return size + +/// Returns a list containing the width and height of an icon file +/proc/get_icon_dimensions(icon_path) + // Icons can be a real file(), a rsc backed file(), a dynamic rsc (dyn.rsc) reference (known as a cache reference in byond docs), or an /icon which is pointing to one of those. + // Runtime generated dynamic icons are an unbounded concept cache identity wise, the same icon can exist millions of ways and holding them in a list as a key can lead to unbounded memory usage if called often by consumers. + // Check distinctly that this is something that has this unspecified concept, and thus that we should not cache. + if (!isfile(icon_path) || !length("[icon_path]")) + var/icon/my_icon = icon(icon_path) + return list("width" = my_icon.Width(), "height" = my_icon.Height()) + if (isnull(GLOB.icon_dimensions[icon_path])) + var/icon/my_icon = icon(icon_path) + GLOB.icon_dimensions[icon_path] = list("width" = my_icon.Width(), "height" = my_icon.Height()) + return GLOB.icon_dimensions[icon_path] + /// VSTATION SPECIFIC /// /proc/adjust_brightness(color, value) diff --git a/code/__HELPERS/mobs.dm b/code/__HELPERS/mobs.dm index 5851e9a63a3..f367e7ea005 100644 --- a/code/__HELPERS/mobs.dm +++ b/code/__HELPERS/mobs.dm @@ -164,3 +164,13 @@ /// Gets the client of the mob, allowing for mocking of the client. /// You only need to use this if you know you're going to be mocking clients somewhere else. #define GET_CLIENT(mob) (##mob.client || ##mob.mock_client) + +///Makes a call in the context of a different usr. Use sparingly +/world/proc/push_usr(mob/user_mob, datum/callback/invoked_callback, ...) + var/temp = usr + usr = user_mob + if (length(args) > 2) + . = invoked_callback.Invoke(arglist(args.Copy(3))) + else + . = invoked_callback.Invoke() + usr = temp diff --git a/code/__HELPERS/stack_trace.dm b/code/__HELPERS/stack_trace.dm index e36cffcfb35..07a7d4b51bc 100644 --- a/code/__HELPERS/stack_trace.dm +++ b/code/__HELPERS/stack_trace.dm @@ -3,12 +3,4 @@ *! Do not call directly, use the [stack_trace] macro instead. */ /proc/_stack_trace(message, file, line) - CRASH("[message] ([file]:[line])") - -GLOBAL_REAL_VAR(list/stack_trace_storage) -/proc/gib_stack_trace() - stack_trace_storage = list() - stack_trace("") - stack_trace_storage.Cut(1, min(3,stack_trace_storage.len)) - . = stack_trace_storage - stack_trace_storage = null + CRASH("[message][WORKAROUND_IDENTIFIER][json_encode(list(file, line))][WORKAROUND_IDENTIFIER]") diff --git a/code/__HELPERS/stat_tracking.dm b/code/__HELPERS/stat_tracking.dm new file mode 100644 index 00000000000..8bcf4bbb5d2 --- /dev/null +++ b/code/__HELPERS/stat_tracking.dm @@ -0,0 +1,41 @@ +// For use with the stopwatch defines +/proc/render_stats(list/stats, user, sort = GLOBAL_PROC_REF(cmp_generic_stat_item_time)) + tim_sort(stats, sort, TRUE) + + var/list/lines = list() + + for (var/entry in stats) + var/list/data = stats[entry] + lines += "[entry] => [num2text(data[STAT_ENTRY_TIME], 10)]ms ([data[STAT_ENTRY_COUNT]]) (avg:[num2text(data[STAT_ENTRY_TIME]/(data[STAT_ENTRY_COUNT] || 1), 99)])" + + if (user) + user << browse(HTML_SKELETON("
  1. [lines.Join("
  2. ")]
"), "window=[url_encode("stats:[REF(stats)]")]") + + . = lines.Join("\n") + +// For use with the set_cost defines +/proc/stat_tracking_export_to_json_later(filename, costs, counts) + if (IsAdminAdvancedProcCall()) + return + + var/list/output = list() + + for (var/key in costs) + output[key] = list( + "cost" = costs[key], + "count" = counts[key], + ) + + rustg_file_write(json_encode(output), "[GLOB.log_directory]/[filename]") + +/proc/stat_tracking_export_to_csv_later(filename, costs, counts) + if (IsAdminAdvancedProcCall()) + return + + var/list/output = list() + + output += "key, cost, count" + for (var/key in costs) + output += "[replacetext(key, ",", "")], [costs[key]], [counts[key]]" + + rustg_file_write(output.Join("\n"), "[GLOB.log_directory]/[filename]") diff --git a/code/__HELPERS/unsorted.dm b/code/__HELPERS/unsorted.dm index 0b4a527fc43..8f976b32649 100644 --- a/code/__HELPERS/unsorted.dm +++ b/code/__HELPERS/unsorted.dm @@ -1429,3 +1429,15 @@ var/list/WALLITEMS = list( if(sender) query_string += "&from=[url_encode(sender)]" world.Export("[config_legacy.chat_webhook_url]?[query_string]") + +/// Returns an x and y value require to reverse the transformations made to center an oversized icon +/atom/proc/get_oversized_icon_offsets() + if (pixel_x == 0 && pixel_y == 0) + return list("x" = 0, "y" = 0) + var/list/icon_dimensions = get_icon_dimensions(icon) + var/icon_width = icon_dimensions["width"] + var/icon_height = icon_dimensions["height"] + return list( + "x" = icon_width > 32 && pixel_x != 0 ? (icon_width - 32) * 0.5 : 0, + "y" = icon_height > 32 && pixel_y != 0 ? (icon_height - 32) * 0.5 : 0, + ) diff --git a/code/_globals/lists/misc.dm b/code/_globals/lists/misc.dm index 72e591d35e5..50633060ed1 100644 --- a/code/_globals/lists/misc.dm +++ b/code/_globals/lists/misc.dm @@ -9,3 +9,6 @@ GLOBAL_LIST_EMPTY(wire_color_directory) // This is an associative list with the // Reference list for disposal sort junctions. Filled up by sorting junction's New() GLOBAL_LIST_EMPTY(tagger_locations) + +/// Cache of the width and height of icon files, to avoid repeating the same expensive operation +GLOBAL_LIST_EMPTY(icon_dimensions) diff --git a/code/datums/browser/_browser.dm b/code/datums/browser/_browser.dm index e06f9902c92..df8553b0473 100644 --- a/code/datums/browser/_browser.dm +++ b/code/datums/browser/_browser.dm @@ -4,7 +4,7 @@ var/window_id // window_id is used as the window name for browse and onclose var/width = 0 var/height = 0 - var/atom/ref = null + var/datum/weakref/ref = null var/window_options = "can_close=1;can_minimize=1;can_maximize=0;can_resize=1;titlebar=1;" // window option is set using window_id var/stylesheets[0] var/scripts[0] @@ -15,8 +15,8 @@ var/datum/asset_pack/simple/common/common_asset /datum/browser/New(nuser, nwindow_id, ntitle = 0, nwidth = 0, nheight = 0, atom/nref = null) - user = nuser + RegisterSignal(user, COMSIG_PARENT_QDELETING, PROC_REF(user_deleted)) window_id = nwindow_id if (ntitle) title = format_text(ntitle) @@ -25,19 +25,20 @@ if (nheight) height = nheight if (nref) - ref = nref + ref = WEAKREF(nref) common_asset = SSassets.ready_asset_pack(/datum/asset_pack/simple/common) +/datum/browser/proc/user_deleted(datum/source) + SIGNAL_HANDLER + user = null + /datum/browser/proc/add_head_content(nhead_content) head_content = nhead_content /datum/browser/proc/set_window_options(nwindow_options) window_options = nwindow_options -/datum/browser/proc/set_title_image(ntitle_image) - //title_image = ntitle_image - /datum/browser/proc/add_stylesheet(name, file) name = "[sanitize_filename(name)].css" stylesheets |= name @@ -93,9 +94,9 @@ /datum/browser/proc/open(use_onclose = TRUE) - if(isnull(window_id)) //null check because this can potentially nuke goonchat + if(isnull(window_id)) //null check because this can potentially nuke goonchat WARNING("Browser [title] tried to open with a null ID") - to_chat(user, "The [title] browser you tried to open failed a sanity check! Please report this on github!") + to_chat(user, SPAN_USERDANGER("The [title] browser you tried to open failed a sanity check! Please report this on GitHub!")) return var/window_size = "" if(width && height) @@ -110,8 +111,13 @@ /datum/browser/proc/setup_onclose() set waitfor = 0 //winexists sleeps, so we don't need to. for (var/i in 1 to 10) - if (user && winexists(user, window_id)) - onclose(user, window_id, ref) + if (user?.client && winexists(user, window_id)) + var/atom/send_ref + if(ref) + send_ref = ref.resolve() + if(!send_ref) + ref = null + onclose(user, window_id, send_ref) break /datum/browser/proc/close() diff --git a/code/datums/browser/_onclose.dm b/code/datums/browser/_onclose.dm index a6949734e9f..778f425d81b 100644 --- a/code/datums/browser/_onclose.dm +++ b/code/datums/browser/_onclose.dm @@ -5,8 +5,8 @@ // e.g. canisters, timers, etc. // // windowid should be the specified window name -// e.g. code is : user << browse(text, "window=fred") -// then use : onclose(user, "fred") +// e.g. code is : user << browse(text, "window=fred") +// then use : onclose(user, "fred") // // Optionally, specify the "ref" parameter as the controlled atom (usually src) // to pass a "close=1" parameter to the atom's Topic() proc for special handling. @@ -27,18 +27,19 @@ // otherwise, just reset the client mob's machine var. // /client/verb/windowclose(atomref as text) - set hidden = 1 // hide this verb from the user's panel - set name = ".windowclose" // no autocomplete on cmd line + set hidden = TRUE // hide this verb from the user's panel + set name = ".windowclose" // no autocomplete on cmd line - if(atomref!="null") // if passed a real atomref - var/hsrc = locate(atomref) // find the reffed atom + if(atomref != "null") // if passed a real atomref + var/hsrc = locate(atomref) // find the reffed atom var/href = "close=1" if(hsrc) usr = src.mob - src.Topic(href, params2list(href), hsrc) // this will direct to the atom's - return // Topic() proc via client.Topic() + src.Topic(href, params2list(href), hsrc) // this will direct to the atom's + return // Topic() proc via client.Topic() // no atomref specified (or not found) // so just reset the user mob's machine var + // legacy code for handling client.machine if(src && src.mob) src.mob.unset_machine() diff --git a/code/datums/browser/alert.dm b/code/datums/browser/alert.dm index b8fe412c4a4..653325b8209 100644 --- a/code/datums/browser/alert.dm +++ b/code/datums/browser/alert.dm @@ -2,15 +2,15 @@ if (!User) return - var/output = {"
[Message]

+ var/output = {"
[Message]

- [Button1]"} + [Button1]"} if (Button2) - output += {"[Button2]"} + output += {"[Button2]"} if (Button3) - output += {"[Button3]"} + output += {"[Button3]"} output += {"
"} @@ -28,8 +28,21 @@ opentime = 0 close() -//designed as a drop in replacement for alert(); functions the same. (outside of needing User specified) -/proc/tgalert(var/mob/User, Message, Title, Button1="Ok", Button2, Button3, StealFocus = 1, Timeout = 6000) +/** + * **DEPRECATED: USE tgui_alert(...) INSTEAD** + * + * Designed as a drop in replacement for alert(); functions the same. (outside of needing User specified) + * Arguments: + * * User - The user to show the alert to. + * * Message - The textual body of the alert. + * * Title - The title of the alert's window. + * * Button1 - The first button option. + * * Button2 - The second button option. + * * Button3 - The third button option. + * * StealFocus - Boolean operator controlling if the alert will steal the user's window focus. + * * Timeout - The timeout of the window, after which no responses will be valid. + */ +/proc/tgalert(mob/User, Message, Title, Button1="Ok", Button2, Button3, StealFocus = TRUE, Timeout = 6000) if (!User) User = usr switch(askuser(User, Message, Title, Button1, Button2, Button3, StealFocus, Timeout)) @@ -41,7 +54,7 @@ return Button3 //Same shit, but it returns the button number, could at some point support unlimited button amounts. -/proc/askuser(var/mob/User,Message, Title, Button1="Ok", Button2, Button3, StealFocus = 1, Timeout = 6000) +/proc/askuser(mob/User,Message, Title, Button1="Ok", Button2, Button3, StealFocus = 1, Timeout = 6000) if (!istype(User)) if (istype(User, /client/)) var/client/C = User diff --git a/code/datums/browser/listpicker.dm b/code/datums/browser/listpicker.dm index 8aaa6f6a048..6b7fc668027 100644 --- a/code/datums/browser/listpicker.dm +++ b/code/datums/browser/listpicker.dm @@ -5,7 +5,7 @@ if (!User) return - var/output = {"