[MIRROR] browse to browser part 1 (#11017)

Co-authored-by: Kashargul <144968721+Kashargul@users.noreply.github.com>
This commit is contained in:
CHOMPStation2StaffMirrorBot
2025-06-06 07:18:23 -07:00
committed by GitHub
parent d7cd22d2d0
commit 0fc7bb29d1
36 changed files with 428 additions and 423 deletions

View File

@@ -112,7 +112,9 @@ var/global/vs_control/vsc = new
if("[ch]_NAME" in vars) vw_name = vars["[ch]_NAME"]
dat += span_bold("[vw_name] = [vw]") + " <A href='byond://?src=\ref[src];[HrefToken()];changevar=[ch]'>\[Change\]</A><br>"
dat += "<i>[vw_desc]</i><br><br>"
user << browse("<html>[dat]</html>","window=settings")
var/datum/browser/popup = new(user, "settings", "Settings")
popup.set_content(dat)
popup.open()
/vs_control/Topic(href,href_list)
if("changevar" in href_list)

2
code/__defines/client.dm Normal file
View File

@@ -0,0 +1,2 @@
/// Checks if the given target is either a client or a mock client, for now removed: || istype(target, /datum/client_interface)
#define IS_CLIENT_OR_MOCK(target) (istype(target, /client))

View File

@@ -16,6 +16,17 @@ GLOBAL_LIST_INIT(bitfields, generate_bitfields())
bitfields[bitfield.variable] = bitfield.flags
return bitfields
/// Returns an associative list of bitflag name -> number for all valid bitflags in the passed in field
/proc/get_valid_bitflags(var_name)
return GLOB.bitfields[var_name] || list()
/proc/get_random_bitflag(var_name)
var/list/flags = get_valid_bitflags(var_name)
if(!length(flags))
return
var/name = pick(flags)
return flags[name]
DEFINE_BITFIELD(admin_flags, list(
"ADMIN" = R_ADMIN,
"REJUVINATE" = R_REJUVINATE,

View File

@@ -1,40 +1,48 @@
/datum/browser
var/mob/user
var/title
var/window_id // window_id is used as the window name for browse and onclose
var/title = ""
/// window_id is used as the window name for browse and onclose
var/window_id
var/width = 0
var/height = 0
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]
var/datum/weakref/source_ref = null
/// window option is set using window_id
var/window_options = "can_close=1;can_minimize=1;can_maximize=0;can_resize=1;titlebar=1;"
var/list/stylesheets = list()
var/list/scripts = list()
var/head_elements
var/body_elements
var/head_content = ""
var/content = ""
/datum/browser/New(nuser, nwindow_id, ntitle = 0, nwidth = 0, nheight = 0, atom/nref = null)
user = nuser
/datum/browser/New(mob/user, window_id, title = "", width = 0, height = 0, atom/source = null)
if(IS_CLIENT_OR_MOCK(user))
var/client/client_user = user
user = client_user.mob
src.user = user
RegisterSignal(user, COMSIG_PARENT_QDELETING, PROC_REF(user_deleted))
window_id = nwindow_id
if (ntitle)
title = format_text(ntitle)
if (nwidth)
width = nwidth
if (nheight)
height = nheight
if (nref)
ref = WEAKREF(nref)
src.window_id = window_id
if (title)
src.title = format_text(title)
if (width)
src.width = width
if (height)
src.height = height
if (source)
src.source_ref = WEAKREF(source)
/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/add_head_content(head_content)
src.head_content += head_content
/datum/browser/proc/set_window_options(nwindow_options)
window_options = nwindow_options
/datum/browser/proc/set_head_content(head_content)
src.head_content = head_content
/datum/browser/proc/set_window_options(window_options)
src.window_options = window_options
/datum/browser/proc/add_stylesheet(name, file)
if (istype(name, /datum/asset/spritesheet))
@@ -55,24 +63,24 @@
scripts["[ckey(name)].js"] = file
SSassets.transport.register_asset("[ckey(name)].js", file)
/datum/browser/proc/set_content(ncontent)
content = ncontent
/datum/browser/proc/set_content(content)
src.content = content
/datum/browser/proc/add_content(ncontent)
content += ncontent
/datum/browser/proc/add_content(content)
src.content += content
/datum/browser/proc/get_header()
var/datum/asset/simple/namespaced/common/common_asset = get_asset_datum(/datum/asset/simple/namespaced/common)
var/file
var/list/new_head_content = list()
// If a client exists, but they have disabled fancy windowing, disable it!
if(user?.client?.prefs?.read_preference(/datum/preference/toggle/browser_style))
head_content += "<link rel='stylesheet' type='text/css' href='[common_asset.get_url_mappings()["common.css"]]'>"
for (file in stylesheets)
head_content += "<link rel='stylesheet' type='text/css' href='[SSassets.transport.get_asset_url(file)]'>"
new_head_content += "<link rel='stylesheet' type='text/css' href='[common_asset.get_url_mappings()["common.css"]]'>"
for (var/file in stylesheets)
new_head_content += "<link rel='stylesheet' type='text/css' href='[SSassets.transport.get_asset_url(file)]'>"
if(user.client?.window_scaling && user.client?.window_scaling != 1 && !user.client?.prefs.read_preference(/datum/preference/toggle/ui_scale) && width && height)
head_content += {"
new_head_content += {"
<style>
body {
zoom: [100 / user.client?.window_scaling]%;
@@ -80,9 +88,10 @@
</style>
"}
for (file in scripts)
head_content += "<script type='text/javascript' src='[SSassets.transport.get_asset_url(file)]'></script>"
for (var/file in scripts)
new_head_content += "<script type='text/javascript' src='[SSassets.transport.get_asset_url(file)]'></script>"
head_content += new_head_content.Join()
return {"<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
@@ -95,6 +104,7 @@
[title ? "<div class='uiTitleWrapper'><div class='uiTitle'><tt>[title]</tt></div></div>" : ""]
<div class='uiContent'>
"}
//" This is here because else the rest of the file looks like a string in notepad++.
/datum/browser/proc/get_footer()
return {"
@@ -105,16 +115,17 @@
/datum/browser/proc/get_content()
return {"
[get_header()]
[content]
[get_footer()]
[get_header()]
[content]
[get_footer()]
"}
/datum/browser/proc/open(use_onclose = TRUE)
/datum/browser/proc/open(use_on_close = TRUE)
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, 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)
if(user.client?.prefs?.read_preference(/datum/preference/toggle/ui_scale))
@@ -122,27 +133,28 @@
window_size = "size=[width * scaling]x[height * scaling];"
else
window_size = "size=[width]x[height];"
var/datum/asset/simple/namespaced/common/common_asset = get_asset_datum(/datum/asset/simple/namespaced/common)
common_asset.send(user)
if (stylesheets.len)
if (length(stylesheets))
SSassets.transport.send_assets(user, stylesheets)
if (scripts.len)
if (length(scripts))
SSassets.transport.send_assets(user, scripts)
user << browse(get_content(), "window=[window_id];[window_size][window_options]")
if (use_onclose)
DIRECT_OUTPUT(user, browse(get_content(), "window=[window_id];[window_size][window_options]"))
if (use_on_close)
setup_onclose()
/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?.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
if (!user?.client || !winexists(user, window_id))
continue
var/atom/send_ref
if(source_ref)
send_ref = source_ref.resolve()
if(!send_ref)
source_ref = null
onclose(user, window_id, send_ref)
/datum/browser/proc/close()
if(!isnull(window_id))//null check because this can potentially nuke goonchat
@@ -150,106 +162,106 @@
else
WARNING("Browser [title] tried to close with a null ID")
/datum/browser/modal/alert/New(User,Message,Title,Button1="Ok",Button2,Button3,StealFocus = 1,Timeout=6000)
if (!User)
/datum/browser/modal/alert/New(user, message, title, button_1 = "Ok", button_2, button_3, steal_focus = TRUE, timeout = 600 SECONDS)
if (!user)
return
var/output = {"<center><b>[Message]</b></center><br />
var/list/display_list = list()
display_list += {"<center><b>[message]</b></center><br />
<div style="text-align:center">
<a style="font-size:large;float:[( Button2 ? "left" : "right" )]" href='byond://?src=[REF(src)];button=1'>[Button1]</a>"}
<a style="font-size:large;float:[( button_2 ? "left" : "right" )]" href='byond://?src=[REF(src)];button=1'>[button_1]</a>"}
if (Button2)
output += {"<a style="font-size:large;[( Button3 ? "" : "float:right" )]" href='byond://?src=[REF(src)];button=2'>[Button2]</a>"}
if (button_2)
display_list += {"<a style="font-size:large;[( button_3 ? "" : "float:right" )]" href='byond://?src=[REF(src)];button=2'>[button_2]</a>"}
if (Button3)
output += {"<a style="font-size:large;float:right" href='byond://?src=[REF(src)];button=3'>[Button3]</a>"}
if (button_3)
display_list += {"<a style="font-size:large;float:right" href='byond://?src=[REF(src)];button=3'>[button_3]</a>"}
output += {"</div>"}
display_list += {"</div>"}
..(User, ckey("[User]-[Message]-[Title]-[world.time]-[rand(1,10000)]"), Title, 350, 150, src, StealFocus, Timeout)
set_content(output)
..(user, ckey("[user]-[message]-[title]-[world.time]-[rand(1,10000)]"), title, 350, 150, src, steal_focus, timeout)
set_content(display_list.Join())
/datum/browser/modal/alert/Topic(href,href_list)
if (href_list["close"] || !user || !user.client)
opentime = 0
open_time = 0
return
if (href_list["button"])
var/button = text2num(href_list["button"])
if (button <= 3 && button >= 1)
selectedbutton = button
opentime = 0
selected_button = button
open_time = 0
close()
/**
* **DEPRECATED: USE tgui_alert(...) INSTEAD**
*
* Designed as a drop in replacement for alert(); functions the same. (outside of needing User specified)
* 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.
* * user - The user to show the alert to.
* * message - The textual body of the alert.
* * title - The title of the alert's window.
* * button_1 - The first button option.
* * button_2 - The second button option.
* * button_3 - The third button option.
* * steal_focus - 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
if (!istype(User))
if (istype(User, /client))
var/client/client = User
User = client.mob
else
/proc/tg_alert(mob/user, message, title, button_1 = "Ok", button_2, button_3, steal_focus = TRUE, timeout = 600 SECONDS)
if (!user)
user = usr
if (!ismob(user))
if (!istype(user, /client))
return
var/client/user_client = user
user = user_client.mob
// Get user's response using a modal
var/datum/browser/modal/alert/A = new(User, Message, Title, Button1, Button2, Button3, StealFocus, Timeout)
A.open()
A.wait()
switch(A.selectedbutton)
var/datum/browser/modal/alert/window = new(user, message, title, button_1, button_2, button_3, steal_focus, timeout)
window.open()
window.wait()
switch(window.selected_button)
if (1)
return Button1
return button_1
if (2)
return Button2
return button_2
if (3)
return Button3
return button_3
/datum/browser/modal
var/opentime = 0
var/open_time = 0
var/timeout
var/selectedbutton = 0
var/stealfocus
var/selected_button = 0
var/steal_focus
/datum/browser/modal/New(nuser, nwindow_id, ntitle = 0, nwidth = 0, nheight = 0, atom/nref = null, StealFocus = 1, Timeout = 6000)
/datum/browser/modal/New(user, window_id, title = 0, width = 0, height = 0, atom/source = null, steal_focus = TRUE, timeout = 600 SECONDS)
..()
stealfocus = StealFocus
if (!StealFocus)
src.steal_focus = steal_focus
if (!src.steal_focus)
window_options += "focus=false;"
timeout = Timeout
src.timeout = timeout
/datum/browser/modal/close()
.=..()
opentime = 0
. = ..()
open_time = 0
/datum/browser/modal/open(use_onclose)
/datum/browser/modal/open(use_on_close)
set waitfor = FALSE
opentime = world.time
open_time = world.time
use_on_close = TRUE
if (stealfocus)
. = ..(use_onclose = 1)
if (steal_focus)
. = ..()
else
var/focusedwindow = winget(user, null, "focus")
. = ..(use_onclose = 1)
var/focused_window = winget(user, null, "focus")
. = ..()
//waits for the window to show up client side before attempting to un-focus it
//winexists sleeps until it gets a reply from the client, so we don't need to bother sleeping
for (var/i in 1 to 10)
if (user && winexists(user, window_id))
if (focusedwindow)
winset(user, focusedwindow, "focus=true")
if (focused_window)
winset(user, focused_window, "focus=true")
else
winset(user, "mapwindow", "focus=true")
break
@@ -257,126 +269,237 @@
addtimer(CALLBACK(src, PROC_REF(close)), timeout)
/datum/browser/modal/proc/wait()
while (opentime && selectedbutton <= 0 && (!timeout || opentime+timeout > world.time))
while (open_time && selected_button <= 0 && (!timeout || open_time + timeout > world.time))
stoplag(1)
/datum/browser/modal/listpicker
var/valueslist = list()
/datum/browser/modal/list_picker
var/values_list = list()
/datum/browser/modal/listpicker/New(User,Message,Title,Button1="Ok",Button2,Button3,StealFocus = 1, Timeout = FALSE,list/values,inputtype="checkbox", width, height, slidecolor)
if (!User)
/datum/browser/modal/list_picker/New(user, message, title, button_1 = "Ok", button_2, button_3, steal_focus = TRUE, timeout = FALSE, list/values, input_type = "checkbox", width, height, slide_color)
if (!user)
return
var/output = {"<form><input type="hidden" name="src" value="[REF(src)]"><ul class="sparse">"}
if (inputtype == "checkbox" || inputtype == "radio")
for (var/i in values)
var/div_slider = slidecolor
if(!i["allowed_edit"])
var/list/display_list = list()
display_list += {"<form><input type="hidden" name="src" value="[REF(src)]"><ul class="sparse">"}
if (input_type == "checkbox" || input_type == "radio")
for (var/option in values)
var/div_slider = slide_color
if(!option["allowed_edit"])
div_slider = "locked"
output += {"<li>
display_list += {"<li>
<label class="switch">
<input type="[inputtype]" value="1" name="[i["name"]]"[i["checked"] ? " checked" : ""][i["allowed_edit"] ? "" : " onclick='return false' onkeydown='return false'"]>
<input type="[input_type]" value="1" name="[option["name"]]"[option["checked"] ? " checked" : ""][option["allowed_edit"] ? "" : " onclick='return false' onkeydown='return false'"]>
<div class="slider [div_slider ? "[div_slider]" : ""]"></div>
<span>[i["name"]]</span>
<span>[option["name"]]</span>
</label>
</li>"}
else
for (var/i in values)
output += {"<li><input id="name="[i["name"]]"" style="width: 50px" type="[type]" name="[i["name"]]" value="[i["value"]]">
<label for="[i["name"]]">[i["name"]]</label></li>"}
output += {"</ul><div style="text-align:center">
<button type="submit" name="button" value="1" style="font-size:large;float:[( Button2 ? "left" : "right" )]">[Button1]</button>"}
for (var/option in values)
display_list += {"<li><input id="name="[option["name"]]"" style="width: 50px" type="[type]" name="[option["name"]]" value="[option["value"]]">
<label for="[option["name"]]">[option["name"]]</label></li>"}
display_list += {"</ul><div style="text-align:center">
<button type="submit" name="button" value="1" style="font-size:large;float:[( button_2 ? "left" : "right" )]">[button_1]</button>"}
if (Button2)
output += {"<button type="submit" name="button" value="2" style="font-size:large;[( Button3 ? "" : "float:right" )]">[Button2]</button>"}
if (button_2)
display_list += {"<button type="submit" name="button" value="2" style="font-size:large;[( button_3 ? "" : "float:right" )]">[button_2]</button>"}
if (Button3)
output += {"<button type="submit" name="button" value="3" style="font-size:large;float:right">[Button3]</button>"}
if (button_3)
display_list += {"<button type="submit" name="button" value="3" style="font-size:large;float:right">[button_3]</button>"}
output += {"</form></div>"}
..(User, ckey("[User]-[Message]-[Title]-[world.time]-[rand(1,10000)]"), Title, width, height, src, StealFocus, Timeout)
set_content(output)
display_list += {"</form></div>"}
..(user, ckey("[user]-[message]-[title]-[world.time]-[rand(1,10000)]"), title, width, height, src, steal_focus, timeout)
set_content(display_list.Join())
/datum/browser/modal/listpicker/Topic(href,href_list)
/datum/browser/modal/list_picker/Topic(href, list/href_list)
if (href_list["close"] || !user || !user.client)
opentime = 0
open_time = 0
return
if (href_list["button"])
var/button = text2num(href_list["button"])
if (button <= 3 && button >= 1)
selectedbutton = button
for (var/item in href_list)
switch(item)
if ("close", "button", "src")
continue
else
valueslist[item] = href_list[item]
opentime = 0
selected_button = button
values_list = href_list.Copy()
values_list -= list("close", "button", "src")
open_time = 0
close()
/proc/presentpicker(mob/User,Message, Title, Button1="Ok", Button2, Button3, StealFocus = 1,Timeout = 6000,list/values, inputtype = "checkbox", width, height, slidecolor)
if (!istype(User))
if (istype(User, /client/))
var/client/C = User
User = C.mob
else
/proc/present_picker(mob/user, message, title, button_1 = "Ok", button_2, button_3, steal_focus = TRUE, timeout = 600 SECONDS, list/values, input_type = "checkbox", width, height, slide_color)
if (!ismob(user))
if (!istype(user, /client))
return
var/datum/browser/modal/listpicker/A = new(User, Message, Title, Button1, Button2, Button3, StealFocus,Timeout, values, inputtype, width, height, slidecolor)
A.open()
A.wait()
if (A.selectedbutton)
return list("button" = A.selectedbutton, "values" = A.valueslist)
var/client/user_client = user
user = user_client.mob
var/datum/browser/modal/list_picker/window = new(user, message, title, button_1, button_2, button_3, steal_focus, timeout, values, input_type, width, height, slide_color)
window.open()
window.wait()
if (window.selected_button)
return list("button" = window.selected_button, "values" = window.values_list)
/proc/input_bitfield(var/mob/User, title, bitfield, current_value, nwidth = 350, nheight = 350, nslidecolor, allowed_edit_list = null)
if (!User || !(bitfield in GLOB.bitfields))
/proc/input_bitfield(mob/user, title, bitfield, current_value, width = 350, height = 350, slide_color, allowed_edit_field = ALL)
var/list/bitflags = get_valid_bitflags(bitfield)
if (!user || !length(bitflags))
return
var/list/pickerlist = list()
for (var/i in GLOB.bitfields[bitfield])
var/can_edit = 1
if(!isnull(allowed_edit_list) && !(allowed_edit_list & GLOB.bitfields[bitfield][i]))
can_edit = 0
if (current_value & GLOB.bitfields[bitfield][i])
pickerlist += list(list("checked" = 1, "value" = GLOB.bitfields[bitfield][i], "name" = i, "allowed_edit" = can_edit))
var/list/picker_list = list()
for (var/bit_name in bitflags)
var/bit_value = bitflags[bit_name]
// Gotta make it TRUE/FALSE sorry brother
var/can_edit = !!(allowed_edit_field & bit_value)
var/enabled = !!(current_value & bit_value)
picker_list += list(list("checked" = enabled, "value" = bit_value, "name" = bit_name, "allowed_edit" = can_edit))
var/list/result = present_picker(user, "", title, button_1 = "Save", button_2 = "Cancel", timeout = FALSE, values = picker_list, width = width, height = height, slide_color = slide_color)
if (!islist(result))
return
if (result["button"] == 2) // If the user pressed the cancel button
return
var/result_bitfield = NONE
for (var/flag_name in result["values"])
result_bitfield |= bitflags[flag_name]
return result_bitfield
/datum/browser/modal/pref_like_picker
var/settings = list()
var/icon/preview_icon = null
var/datum/callback/preview_update
/datum/browser/modal/pref_like_picker/New(mob/user, message, title, steal_focus = TRUE, timeout = 600 SECONDS, list/settings, width, height)
if (!user)
return
src.settings = settings
..(user, ckey("[user]-[message]-[title]-[world.time]-[rand(1,10000)]"), title, width, height, src, steal_focus, timeout)
set_content(show_choices(user))
/datum/browser/modal/pref_like_picker/proc/show_choices(mob/user)
if (settings["preview_callback"])
var/datum/callback/callback = settings["preview_callback"]
preview_icon = callback.Invoke(settings)
if (preview_icon)
user << browse_rsc(preview_icon, "previewicon.png")
var/list/display_list = list()
for (var/name in settings["mainsettings"])
var/setting = settings["mainsettings"][name]
if (setting["type"] == "datum")
if (setting["subtypesonly"])
display_list += "<b>[setting["desc"]]:</b> <a href='byond://?src=[REF(src)];setting=[name];task=input;subtypesonly=1;type=datum;path=[setting["path"]]'>[setting["value"]]</a><BR>"
else
display_list += "<b>[setting["desc"]]:</b> <a href='byond://?src=[REF(src)];setting=[name];task=input;type=datum;path=[setting["path"]]'>[setting["value"]]</a><BR>"
else
pickerlist += list(list("checked" = 0, "value" = GLOB.bitfields[bitfield][i], "name" = i, "allowed_edit" = can_edit))
var/list/result = presentpicker(User, "", title, Button1="Save", Button2 = "Cancel", Timeout=FALSE, values = pickerlist, width = nwidth, height = nheight, slidecolor = nslidecolor)
if (islist(result))
if (result["button"] == 2) // If the user pressed the cancel button
return
. = 0
for (var/flag in result["values"])
. |= GLOB.bitfields[bitfield][flag]
else
display_list += "<b>[setting["desc"]]:</b> <a href='byond://?src=[REF(src)];setting=[name];task=input;type=[setting["type"]]'>[setting["value"]]</a><BR>"
if (preview_icon)
display_list += "<td valign='center'>"
display_list += "<div class='statusDisplay'><center><img src=previewicon.png width=[preview_icon.Width()] height=[preview_icon.Height()]></center></div>"
display_list += "</td>"
display_list += "</tr></table>"
display_list += "<hr><center><a href='byond://?src=[REF(src)];button=1'>Ok</a> "
display_list += "</center>"
return display_list.Join()
/datum/browser/modal/pref_like_picker/Topic(href,href_list)
if (href_list["close"] || !user || !user.client)
open_time = 0
return
//
/proc/onclose(mob/user, windowid, atom/ref=null)
if (href_list["task"] == "input")
var/setting_key = href_list["setting"]
var/list/setting = settings["mainsettings"][setting_key]
switch (href_list["type"])
if ("datum")
var/parent_path = text2path(href_list["path"])
var/list/paths
if (href_list["subtypesonly"])
paths = subtypesof(parent_path)
else
paths = typesof(parent_path)
var/new_value = pick_closest_path(null, make_types_fancy(paths))
if (!isnull(new_value))
setting["value"] = new_value
if ("string")
setting["value"] = stripped_input(user, "Enter new value for [setting["desc"]]", "Enter new value for [setting["desc"]]", setting["value"])
if ("number")
setting["value"] = input(user, "Enter new value for [setting["desc"]]", "Enter new value for [setting["desc"]]") as num
if ("color")
setting["value"] = input(user, "Enter new value for [setting["desc"]]", "Enter new value for [setting["desc"]]", setting["value"]) as color
if ("boolean")
setting["value"] = (setting["value"] == "Yes") ? "No" : "Yes"
if ("ckey")
setting["value"] = input(user, "[setting["desc"]]?") in (list("none") + GLOB.directory)
if (setting["callback"])
var/datum/callback/callback = setting["callback"]
settings = callback.Invoke(settings)
if (href_list["button"])
var/button = text2num(href_list["button"])
if (button <= 3 && button >= 1)
selected_button = button
if (selected_button != 1)
set_content(show_choices(user))
open()
return
open_time = 0
close()
/proc/present_pref_like_picker(mob/user, message, title, steal_focus = TRUE, timeout = 600 SECONDS, list/settings, width, height)
if (!ismob(user))
if (!istype(user, /client))
return
var/client/user_client = user
user = user_client.mob
var/datum/browser/modal/pref_like_picker/window = new(user, message, title, steal_focus, timeout, settings, width, height)
window.open()
window.wait()
if (window.selected_button)
return list("button" = window.selected_button, "settings" = window.settings)
/// Registers the on-close verb for a browse window (client/verb/windowclose)
/// this will be called when the close-button of a window is pressed.
///
/// This is usually only needed for devices that regularly update the browse window,
/// 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")
///
/// Optionally, specify the "source" parameter as the controlled atom (usually src)
// to pass a "close=1" parameter to the atom's Topic() proc for special handling.
/// Otherwise, the user mob's machine var will be reset directly.
///
/proc/onclose(mob/user, windowid, atom/source = null)
if(!user.client)
return
var/param = "null"
if(ref)
param = "[REF(ref)]"
if(source)
param = "[REF(source)]"
winset(user, windowid, "on-close=\".windowclose [param]\"")
// the on-close client verb
// called when a browser popup window is closed after registering with proc/onclose()
// if a valid atom reference is supplied, call the atom's Topic() with "close=1"
// otherwise, just reset the client mob's machine var.
//
/// the on-close client verb
/// called when a browser popup window is closed after registering with proc/onclose()
/// if a valid atom reference is supplied, call the atom's Topic() with "close=1"
/// otherwise, just reset the client mob's machine var.
/client/verb/windowclose(atomref as text)
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
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()
if(atomref == "null")
return
// if passed a real atomref
var/atom/hsrc = locate(atomref) // find the reffed atom
var/href = "close=1"
if(!hsrc)
return
usr = src.mob
src.Topic(href, params2list(href), hsrc) // this will direct to the atom's
/datum/browser/modal/color_matrix_picker
var/color_matrix
@@ -426,12 +549,12 @@
/datum/browser/modal/color_matrix_picker/Topic(href, list/href_list)
if(href_list["close"] || !user)
opentime = 0
open_time = 0
return
if(href_list["button"])
var/button = text2num(href_list["button"])
if(ISINRANGE(button, 1, 3))
selectedbutton = button
selected_button = button
var/list/cm = rgb_construct_color_matrix(
text2num(href_list["rr"]),
text2num(href_list["rg"]),
@@ -448,7 +571,7 @@
)
if(cm)
color_matrix = cm
opentime = 0
open_time = 0
close()
/proc/color_matrix_picker(mob/user, message, title, button1 = "Ok", button2, button3, stealfocus, timeout = 10 MINUTES, list/values)
@@ -461,4 +584,4 @@
var/datum/browser/modal/color_matrix_picker/B = new(user, message, title, button1, button2, button3, stealfocus, timeout, values)
B.open()
B.wait()
return list("button" = B.selectedbutton, "matrix" = B.color_matrix)
return list("button" = B.selected_button, "matrix" = B.color_matrix)

View File

@@ -114,7 +114,10 @@
if(ambitions)
output += "<HR><B>Ambitions:</B> [ambitions]<br>"
recipient << browse("<html>[output]</html>","window=memory")
var/datum/browser/popup = new(recipient, "memory", "Memory")
popup.set_content(output)
popup.open()
/datum/mind/proc/edit_memory()
if(!ticker || !ticker.mode)
@@ -149,7 +152,10 @@
out += "None."
out += "<br><a href='byond://?src=\ref[src];[HrefToken()];obj_add=1'>\[add\]</a><br><br>"
out += span_bold("Ambitions:") + " [ambitions ? ambitions : "None"] <a href='byond://?src=\ref[src];[HrefToken()];amb_edit=\ref[src]'>\[edit\]</a></br>"
usr << browse("<html>[out]</html>", "window=edit_memory[src]")
var/datum/browser/popup = new(usr, "edit_memory[src]", "Edit Memory")
popup.set_content(out)
popup.open()
/datum/mind/Topic(href, href_list)
if(!check_rights(R_ADMIN|R_FUN|R_EVENT)) return

View File

@@ -72,8 +72,10 @@
dat += "<A href='byond://?src=\ref[src];rune=armor'>Sa tatha najin</A> - Allows you to summon armoured robes and an unholy blade<BR>"
dat += "<A href='byond://?src=\ref[src];rune=soulstone'>Kal om neth</A> - Summons a soul stone<BR>"
dat += "<A href='byond://?src=\ref[src];rune=construct'>Da A'ig Osk</A> - Summons a construct shell for use with captured souls. It is too large to carry on your person.<BR>"
usr << browse("<html>[dat]</html>", "window=id_com;size=350x200")
return
var/datum/browser/popup = new(usr, "id_com", "Talisman", 350, 200)
popup.set_content(dat)
popup.open()
/obj/item/paper/talisman/Topic(href, href_list)

View File

@@ -68,7 +68,9 @@
if(!help)
help = "Error loading help (file /ingame_manuals/malf_ai.html is probably missing). Please report this to server administration staff."
user << browse(help, "window=malf_ai_help;size=600x500")
var/datum/browser/popup = new(user, "malf_ai_help", "Malf AI Help", 600, 500)
popup.set_content(help)
popup.open()
// Verb: ai_select_research()

View File

@@ -43,7 +43,10 @@ mob
hsbpanel += "- <a href=\"?\ref[src];hsb=[T]\">[hrefs[T]]</a><br>"
if(hsboxspawn)
hsbpanel += "- <a href=\"?\ref[src];hsb=hsbobj\">Spawn Object</a><br><br>"
usr << browse("<html>[hsbpanel]</html>", "window=hsbpanel")
var/datum/browser/popup = new(usr, "hsbpanel", "HSB Panel")
popup.set_content(hsbpanel)
popup.open()
Topic(href, href_list)
if(!(src.owner == usr.ckey)) return
if(!usr) return //I guess this is possible if they log out or die with the panel open? It happened.

View File

@@ -83,8 +83,8 @@
t += text("Dispenser [] - <A href='byond://?src=\ref[];toggleOn=1'>[]?</a><br>\n", disabled?"deactivated":"activated", src, disabled?"Enable":"Disable")
t += text("Uses Left: [uses]. <A href='byond://?src=\ref[src];toggleUse=1'>Activate the dispenser?</A><br>\n")
user << browse("<html>[t]</html>", "window=computer;size=575x450")
onclose(user, "computer")
user << browse("<html>[t]</html>", "window=ai_slipper;size=575x450")
onclose(user, "ai_slipper")
return
/obj/machinery/ai_slipper/Topic(href, href_list)

View File

@@ -113,7 +113,7 @@
if(..())
return
var/dat = "<HTML><BODY><TT><B>[title]</B>"
var/dat = "<TT><B>[title]</B>"
user.set_machine(src)
if(connected)
var/d2
@@ -134,11 +134,11 @@
dat += "<HR>\nPower Level: [temp]<BR>\n<A href = 'byond://?src=\ref[src];alarm=1'>Firing Sequence</A><BR>\n<A href = 'byond://?src=\ref[src];drive=1'>Test Fire Driver</A><BR>\n<A href = 'byond://?src=\ref[src];door=1'>Toggle Outer Door</A><BR>"
else
dat += "<BR>\n<A href = 'byond://?src=\ref[src];door=1'>Toggle Outer Door</A><BR>"
dat += "<BR><BR><A href='byond://?src=\ref[user];mach_close=computer'>Close</A></TT></BODY></HTML>"
user << browse(dat, "window=computer;size=400x500")
dat += "<BR><BR><A href='byond://?src=\ref[user];mach_close=computer'>Close</A></TT>"
add_fingerprint(user)
onclose(user, "computer")
return
var/datum/browser/popup = new(user, "pod_computer", "Pod Computer", 400, 500)
popup.set_content(dat)
popup.open()
/obj/machinery/computer/pod/process()

View File

@@ -270,9 +270,9 @@ var/specops_shuttle_timeleft = 0
[specops_shuttle_moving_to_station || specops_shuttle_moving_to_centcom ? "\n*The Special Ops. shuttle is already leaving.*<BR>\n<BR>":specops_shuttle_at_station ? "\n<A href='byond://?src=\ref[src];sendtodock=1'>Shuttle standing by...</A><BR>\n<BR>":"\n<A href='byond://?src=\ref[src];sendtostation=1'>Depart to [station_name()]</A><BR>\n<BR>"]
\n<A href='byond://?src=\ref[user];mach_close=computer'>Close</A>"}
user << browse("<html>[dat]</html>", "window=computer;size=575x450")
onclose(user, "computer")
return
var/datum/browser/popup = new(usr, "computer", "Computer", 575, 450)
popup.set_content(dat)
popup.open()
/obj/machinery/computer/specops_shuttle/Topic(href, href_list)
if(..())

View File

@@ -137,9 +137,9 @@ Transponder Codes:<UL>"}
t += "<small><A href='byond://?src=\ref[src];add=1;'>(add new)</A></small><BR>"
t+= "<UL></TT>"
user << browse("<html>[t]</html>", "window=navbeacon")
onclose(user, "navbeacon")
return
var/datum/browser/popup = new(user, "navbeacon", "Navbeacon")
popup.set_content(t)
popup.open()
/obj/machinery/navbeacon/Topic(href, href_list)
..()

View File

@@ -111,13 +111,11 @@
else
dat += "<a href='byond://?src=\ref[src];operation=togglerun'>NEVER</a>"
user << browse("<html>[dat]</html>", "window=traffic_control;size=575x400")
onclose(user, "server_control")
var/datum/browser/popup = new(user, "traffic_control", "Traffic Control", 575, 400)
popup.set_content(dat)
popup.open()
temp = ""
return
/obj/machinery/computer/telecomms/traffic/Topic(href, href_list)
if(..())

View File

@@ -76,8 +76,9 @@ var/global/datum/book_manager/book_mgr = new()
dat += "</table>"
qdel(query)
usr << browse("<html>[dat]</html>", "window=library")
onclose(usr, "library")
var/datum/browser/popup = new(usr, "library", "Library")
popup.set_content(dat)
popup.open()
//VOREStation Edit End
// delete a book

View File

@@ -78,10 +78,10 @@
/obj/item/blueprints/interact()
var/area/A = get_area()
var/text = {"<HTML><head><title>[src]</title></head><BODY>
<h2>[station_name()] blueprints</h2>
<small>Property of [using_map.company_name]. For heads of staff only. Store in high-secure storage.</small><hr>
"}
var/text = {"
<h2>[station_name()] blueprints</h2>
<small>Property of [using_map.company_name]. For heads of staff only. Store in high-secure storage.</small><hr>
"}
var/curAreaType = get_area_type()
switch (curAreaType)
if (AREA_SPACE)
@@ -105,10 +105,10 @@
if(curAreaType & can_rename_areas_in)
text += "<p>You can <a href='byond://?src=\ref[src];action=edit_area'>rename the area</a>.</p>"
text += "</BODY></HTML>"
usr << browse(text, "window=blueprints")
onclose(usr, "blueprints")
var/datum/browser/popup = new(usr, "blueprints", "Blueprints")
popup.add_head_content("<title>[src]</title>")
popup.set_content(text)
popup.open()
/obj/item/blueprints/proc/get_area()
var/turf/T = get_turf(usr)

View File

@@ -1,7 +1,7 @@
// I placed this here because of how relevant it is.
// You place this in your uplinkable item to check if an uplink is active or not.
// If it is, it will display the uplink menu and return 1, else it'll return false.
// If it returns true, I recommend closing the item's normal menu with "user << browse(null, "window=name")"
// If it returns true, I recommend closing the item's normal menu
/obj/item/proc/active_uplink_check(mob/user as mob)
// Activates the uplink if it's active
if(hidden_uplink)
@@ -42,7 +42,7 @@
*
* 1. All obj/item 's have a hidden_uplink var. By default it's null. Give the item one with "new(src)", it must be in it's contents. Feel free to add "uses".
*
* 2. Code in the triggers. Use check_trigger for this, I recommend closing the item's menu with "usr << browse(null, "window=windowname") if it returns true.
* 2. Code in the triggers. Use check_trigger for this, I recommend closing the item's menu if it returns true.
* The var/value is the value that will be compared with the var/target. If they are equal it will activate the menu.
*
* 3. If you want the menu to stay until the users locks his uplink, add an active_uplink_check(mob/user as mob) in your interact/attack_hand proc.

View File

@@ -378,7 +378,7 @@ var/list/tape_roll_applications = list()
if(user.a_intent == I_HELP)
to_chat(user, span_warning("You refrain from breaking \the [src]."))
return
user.visible_message(span_bold("\The [user]") + "breaks \the [src]!",span_notice("You break \the [src]."))
user.visible_message(span_bold("\The [user]") + " breaks \the [src]!",span_notice("You break \the [src]."))
for (var/obj/item/tape/T in gettapeline())
if(T == src)

View File

@@ -228,8 +228,6 @@
if(gurgled && clean_types & CLEAN_WASH)
gurgled = FALSE
cut_overlay(gurgled_overlays[gurgled_color])
name = initial(name)
desc = initial(desc)
if(contaminated && clean_types & CLEAN_RAD) // Phoron and stuff, washing machine needed
contaminated = FALSE
cut_overlay(contamination_overlay)

View File

@@ -467,7 +467,7 @@
admin_holder.rank_flags(),
350,
590,
allowed_edit_list = usr.client.holder.can_edit_rights_flags(),
allowed_edit_field = usr.client.holder.can_edit_rights_flags(),
)
admin_holder.disassociate()

View File

@@ -77,7 +77,9 @@ GLOBAL_VAR_INIT(global_vantag_hud, 0)
to_chat(src, "Some accounts did not have proper ages set in their clients. This function requires database to be present.")
if(msg != "")
src << browse("<html>[msg]</html>", "window=Player_age_check")
var/datum/browser/popup = new(src, "Player_age_check", "Player Age Check")
popup.set_content(msg)
popup.open()
else
to_chat(src, "No matches for that age range found.")

View File

@@ -61,7 +61,7 @@
if(..())
return
user.machine = src
var/dat = "<head><title>Engine Computer</title></head><body>"
var/dat = ""
switch(src.state)
if(STATE_DEFAULT)
if (src.authenticated)
@@ -85,8 +85,11 @@
dat += "<BR>Contents:<br>[src.connected_E.H_fuel]kg of Hydrogen<br>[src.connected_E.antiH_fuel]kg of Anti-Hydrogen<br>"
dat += "<BR>\[ [(src.state != STATE_DEFAULT) ? "<A href='byond://?src=\ref[src];operation=main'>Main Menu</A> | " : ""]<A href='byond://?src=\ref[user];mach_close=communications'>Close</A> \]"
user << browse("<html>[dat]</html>", "window=communications;size=400x500")
onclose(user, "communications")
var/datum/browser/popup = new(user, "communications", "Communications", 400, 500)
popup.add_head_content("<title>Engine Computer</title>")
popup.set_content(dat)
popup.open()
#undef STATE_DEFAULT
#undef STATE_INJECTOR

View File

@@ -31,91 +31,6 @@
monitor.tgui_interact(user)
/*
/obj/machinery/computer/gyrotron_control/attack_hand(var/mob/user)
add_fingerprint(user)
interact(user)
/obj/machinery/computer/gyrotron_control/interact(var/mob/user)
if(stat & (BROKEN|NOPOWER))
user.unset_machine()
user << browse(null, "window=gyrotron_controller_[id_tag]")
return
if(!id_tag)
to_chat(user, span_warning("This console has not been assigned an ident tag. Please contact your system administrator or conduct a manual update with a standard multitool."))
return
var/dat = "<td>" + span_bold("Gyrotron controller #[id_tag]")
dat = "<table><tr>"
dat += "<td>" + span_bold("Mode") + "</td>"
dat += "<td>" + span_bold("Fire Delay") + "</td>"
dat += "<td>" + span_bold("Power") + "</td>"
dat += "</tr>"
for(var/obj/machinery/power/emitter/gyrotron/G in gyrotrons)
if(!G || G.id_tag != id_tag || get_dist(src, G) > scan_range)
continue
dat += "<tr>"
if(G.state != 2 || (G.stat & (NOPOWER | BROKEN))) //Error data not found.
dat += "<td>" + span_red("ERROR") + "</td>"
dat += "<td>" + span_red("ERROR") + "</td>"
dat += "<td>" + span_red("ERROR") + "</td>"
else
dat += "<td><a href='byond://?src=\ref[src];machine=\ref[G];toggle=1'>[G.active ? "Emitting" : "Standing By"]</a></td>"
dat += "<td><a href='byond://?src=\ref[src];machine=\ref[G];modifyrate=1'>[G.rate]</a></td>"
dat += "<td><a href='byond://?src=\ref[src];machine=\ref[G];modifypower=1'>[G.mega_energy]</a></td>"
dat += "</tr></table>"
var/datum/browser/popup = new(user, "gyrotron_controller_[id_tag]", "Gyrotron Remote Control Console", 500, 400, src)
popup.set_content(dat)
popup.open()
add_fingerprint(user)
user.set_machine(src)
/obj/machinery/computer/gyrotron_control/Topic(var/href, var/list/href_list)
. = ..()
if(.)
return
if(stat & (NOPOWER | BROKEN))
return
var/obj/machinery/power/emitter/gyrotron/G = locate(href_list["machine"])
if(!G || G.id_tag != id_tag || get_dist(src, G) > scan_range)
return
if(href_list["modifypower"])
var/new_val = tgui_input_number(usr, "Enter new emission power level (1 - 50)", "Modifying power level", G.mega_energy, 50, 1)
if(!new_val)
to_chat(usr, span_warning("That's not a valid number."))
return 1
G.mega_energy = CLAMP(new_val, 1, 50)
G.update_active_power_usage(G.mega_energy * 1500)
updateUsrDialog(usr)
return 1
if(href_list["modifyrate"])
var/new_val = tgui_input_number(usr, "Enter new emission delay between 1 and 10 seconds.", "Modifying emission rate", G.rate, 10, 1)
if(!new_val)
to_chat(usr, span_warning("That's not a valid number."))
return 1
G.rate = CLAMP(new_val, 1, 10)
updateUsrDialog(usr)
return 1
if(href_list["toggle"])
G.activate(usr)
updateUsrDialog(usr)
return 1
return 0
*/
/obj/machinery/computer/gyrotron_control/attackby(var/obj/item/W, var/mob/user)
..()
if(istype(W, /obj/item/multitool))

View File

@@ -162,8 +162,9 @@
dat += span_red("The dart cartridge is empty!")
dat += " \[<A href='byond://?src=\ref[src];eject_cart=1'>Eject</A>\]"
user << browse("<html>[dat]</html>", "window=dartgun")
onclose(user, "dartgun", src)
var/datum/browser/popup = new(user, "dartgun", "Dartgun")
popup.set_content(dat)
popup.open()
/obj/item/gun/projectile/dartgun/proc/check_beaker_mixing(var/obj/item/B)
if(!mixing || !beakers)

View File

@@ -25,4 +25,6 @@ GLOBAL_LIST_EMPTY(chemical_reaction_logs)
for(var/entry in GLOB.chemical_reaction_logs)
html += "[entry]<br>"
usr << browse("<html>[html]</html>", "window=chemlogs")
var/datum/browser/popup = new(usr, "chemlogs", "Chemlogs")
popup.set_content(html)
popup.open()

View File

@@ -301,84 +301,6 @@
return TRUE
// src.add_fingerprint(user)
// if(stat & BROKEN)
// user.unset_machine()
// return
// var/dat = "<head><title>Waste Disposal Unit</title></head><body><TT>" + span_bold("Waste Disposal Unit") + "<HR>"
// if(!ai) // AI can't pull flush handle
// if(flush)
// dat += "Disposal handle: <A href='byond://?src=\ref[src];handle=0'>Disengage</A> " + span_bold("Engaged")
// else
// dat += "Disposal handle: " + span_bold("Disengaged") + " <A href='byond://?src=\ref[src];handle=1'>Engage</A>"
// dat += "<BR><HR><A href='byond://?src=\ref[src];eject=1'>Eject contents</A><HR>"
// if(mode <= 0)
// dat += "Pump: " + span_bold("Off") + " <A href='byond://?src=\ref[src];pump=1'>On</A><BR>"
// else if(mode == 1)
// dat += "Pump: <A href='byond://?src=\ref[src];pump=0'>Off</A> " + span_bold("On") + " (pressurizing)<BR>"
// else
// dat += "Pump: <A href='byond://?src=\ref[src];pump=0'>Off</A> " + span_bold("On") + " (idle)<BR>"
// var/per = 100* air_contents.return_pressure() / (SEND_PRESSURE)
// dat += "Pressure: [round(per, 1)]%<BR></body>"
// user.set_machine(src)
// user << browse("<html>[dat]</html>", "window=disposal;size=360x170")
// onclose(user, "disposal")
// handle machine interaction
// /obj/machinery/disposal/Topic(href, href_list)
// if(usr.loc == src)
// to_chat(usr, span_red("You cannot reach the controls from inside."))
// return
// if(mode==-1 && !href_list["eject"]) // only allow ejecting if mode is -1
// to_chat(usr, span_red("The disposal units power is disabled."))
// return
// if(..())
// return
// if(stat & BROKEN)
// return
// if(usr.stat || usr.restrained() || src.flushing)
// return
// if(istype(src.loc, /turf))
// usr.set_machine(src)
// if(href_list["close"])
// usr.unset_machine()
// usr << browse(null, "window=disposal")
// return
// if(href_list["pump"])
// if(text2num(href_list["pump"]))
// mode = 1
// else
// mode = 0
// update()
// if(!isAI(usr))
// if(href_list["handle"])
// flush = text2num(href_list["handle"])
// update()
// if(href_list["eject"])
// eject()
// else
// usr << browse(null, "window=disposal")
// usr.unset_machine()
// return
// return
// eject the contents of the disposal unit
/obj/machinery/disposal/verb/force_eject()

View File

@@ -78,9 +78,10 @@
// END AUTOFIX
if(op)
dat += "<A href='byond://?src=\ref[src];spell_choice=rememorize'>Re-memorize Spells</A><BR>"
user << browse("<html>[dat]</html>", "window=radio")
onclose(user, "radio")
return
var/datum/browser/popup = new(user, "radio", "Spellbook")
popup.set_content(dat)
popup.open()
/obj/item/spellbook/Topic(href, href_list)
..()

View File

@@ -124,7 +124,7 @@
GLOBAL_DATUM_INIT(stockExchange, /datum/stockMarket, new)
/proc/plotBarGraph(var/list/points, var/base_text, var/width=400, var/height=400)
var/output = "<html><table style='border:1px solid black; border-collapse: collapse; width: [width]px; height: [height]px'>"
var/output = "<table style='border:1px solid black; border-collapse: collapse; width: [width]px; height: [height]px'>"
if (points.len && height > 20 && width > 20)
var/min = points[1]
var/max = points[1]
@@ -165,4 +165,4 @@ GLOBAL_DATUM_INIT(stockExchange, /datum/stockMarket, new)
output += "<tr><td style='width:[width]px; height:[height]px; background: black'></td></tr>"
output += "<tr><td style='font-size:10px; background:black; color:green; text-align:center'>[base_text]</td></tr>"
return "[output]</table></html>"
return "[output]</table>"

View File

@@ -305,4 +305,6 @@
return 0
/datum/stock/proc/displayValues(var/mob/user)
user << browse(plotBarGraph(values, "[name] share value per share"), "window=stock_[name];size=450x450")
var/datum/browser/popup = new(user, "stock_[name]", "Share Value", 450, 450)
popup.set_content(plotBarGraph(values, "[name] share value per share"))
popup.open()

View File

@@ -238,7 +238,9 @@
if(index == page)
dat = span_bold(dat)
usr << browse("<html>[dat]</html>", "window=player_notes;size=400x400")
var/datum/browser/popup = new(usr, "player_notes", "Admin Playernotes", 480, 480)
popup.set_content(dat)
popup.open()
/datum/admins/proc/player_has_info_legacy(var/key as text)
var/savefile/info = new("data/player_saves/[copytext(key, 1, 2)]/[key]/info.sav")
@@ -253,8 +255,7 @@
if (!istype(src,/datum/admins))
to_chat(usr, "Error: you are not an admin!")
return
var/dat = "<html><head><title>Info on [key]</title></head>"
dat += "<body>"
var/dat = ""
var/p_age = "unknown"
for(var/client/C in GLOB.clients)
@@ -288,8 +289,10 @@
dat += "<br>"
dat += "<A href='byond://?src=\ref[src];[HrefToken()];add_player_info_legacy=[key]'>Add Comment</A><br>"
dat += "</body></html>"
usr << browse(dat, "window=adminplayerinfo;size=480x480")
var/datum/browser/popup = new(usr, "adminplayerinfo", "Admin Playerinfo", 480, 480)
popup.add_head_content("<title>Info on [key]</title>")
popup.set_content(dat)
popup.open()
/datum/admins/Topic(href, href_list)
..()

View File

@@ -17,7 +17,7 @@
nuke_chat()
// Failed to fix, using tgalert as fallback
action = tgalert(src, "Did that work?", "", "Yes", "No, switch to old ui")
action = tg_alert(src, "Did that work?", "", "Yes", "No, switch to old ui")
if (action == "No, switch to old ui")
winset(src, "legacy_output_selector", "left=output_legacy")
log_tgui(src, "Failed to fix.", context = "verb/fix_tgui_panel")

View File

@@ -180,6 +180,7 @@
if(dat)
last_data = dat
dat += "<br><br>\[<a href='byond://?src=\ref[src];print=1'>print report</a>\]"
user << browse("<html>[dat]</html>","window=xeno_analyzer")
return
var/datum/browser/popup = new(user, "xeno_analyzer", "Xeno Analyzer")
popup.set_content(dat)
popup.open()

View File

@@ -1,4 +1,4 @@
<html><h1>Malfunctioning AI guide</h1><br>
<h1>Malfunctioning AI guide</h1><br>
This guide contains most important OOC information for malfunctioning AIs.<br>
@@ -19,4 +19,4 @@ Software are abilities that have to be unlocked via research menu (Hardware tab)
<b>Interdiction</b> - Sabotage-oriented abilities. T1 ability allows you to recall emergency shuttle. Higher level abilities allow you to unlock cyborgs even without access to robotics console, and T4 ability allows you to hack other AIs to slave them under your control.<br>
<b>Manipulation</b> - Physical-oriented abilities. T1 ability allows you to break few lights, and rarely even APCs. T2 ability allows you to apply upgrade of your choice to camera, or reactivate broken camera. T3 ability allows you to create weak forcefield, that holds air, but won't last for long. And T4 ability allows you to overload machines, detonating them in weak explosion.<br>
<h2>End</h2><br>
If you still have some questions, either check the wiki, ask on IRC, or adminhelp and ask your friendly administration staff.</html>
If you still have some questions, either check the wiki, ask on IRC, or adminhelp and ask your friendly administration staff.

View File

@@ -73,7 +73,7 @@ export const VoreSelectedBellyInteractions = (props: {
action="set_attribute"
subAction="b_digestchance"
editMode={editMode}
value={interacts.escapechance}
value={interacts.digestchance}
minValue={0}
maxValue={100}
unit="%"

View File

@@ -18,7 +18,7 @@ export const VoreUserPreferencesAesthetic = (props: {
active_belly: string | null;
our_bellies: bellyData[];
belly_rub_target: string | null;
vore_sprite_color: Record<string, string>;
vore_sprite_color: Record<string, string | undefined>;
vore_sprite_multiply: Record<string, BooleanLike>;
vore_icon_options: string[];
aestethicMessages: aestMessageData;
@@ -46,6 +46,10 @@ export const VoreUserPreferencesAesthetic = (props: {
const capitalizedName = active_belly && capitalize(active_belly);
const possibleIconOptions = vore_icon_options.filter(
(entry) => !!vore_sprite_color[entry],
);
return (
<Section
fill
@@ -64,7 +68,7 @@ export const VoreUserPreferencesAesthetic = (props: {
<Stack>
<Stack.Item basis="49%" grow>
<LabeledList>
{vore_icon_options.map((entry) => (
{possibleIconOptions.map((entry) => (
<LabeledList.Item key={entry} label={capitalize(entry)}>
<Stack align="center">
<VorePanelEditColor
@@ -73,7 +77,7 @@ export const VoreUserPreferencesAesthetic = (props: {
editMode={editMode}
action="set_vs_color"
subAction={entry}
back_color={vore_sprite_color[entry]}
back_color={vore_sprite_color[entry] || ''}
tooltip={
"Modify the sprite color of your '" +
entry +

View File

@@ -373,7 +373,7 @@ export type generalPrefData = {
active_belly: string | null;
belly_rub_target: string | null;
aestethic_messages: aestMessageData;
vore_sprite_color: Record<string, string>;
vore_sprite_color: Record<string, string | undefined>;
vore_sprite_multiply: Record<string, BooleanLike>;
vore_icon_options: string[];
};

View File

@@ -56,6 +56,7 @@
#include "code\__defines\chemistry_vr.dm"
#include "code\__defines\circuitboard.dm"
#include "code\__defines\cleaning.dm"
#include "code\__defines\client.dm"
#include "code\__defines\cloning.dm"
#include "code\__defines\clothing.dm"
#include "code\__defines\color.dm"