TGUI Backend Tweaks & Fixes

This commit is contained in:
ShadowLarkens
2020-08-07 00:17:11 -07:00
parent dd7754514c
commit dc6c47841d
43 changed files with 405 additions and 267 deletions

View File

@@ -289,6 +289,11 @@ Turf and target are seperate in case you want to teleport some distance from a t
/proc/format_frequency(var/f)
return "[round(f / 10)].[f % 10]"
//Opposite of format, returns as a number
/proc/unformat_frequency(frequency)
frequency = text2num(frequency)
return frequency * 10
//This will update a mob's name, real_name, mind.name, data_core records, pda and id

View File

@@ -148,6 +148,41 @@ var/list/radiochannels = list(
"Talon" = TALON_FREQ //VOREStation Add
)
// Hey, if anyone ever needs to update tgui/packages/tgui/constants.js with new radio channels
// I've kept this around just for you.
/* /client/verb/generate_tgui_radio_constants()
set name = "Generate TGUI Radio Constants"
set category = "Generate TGUI Radio Constants"
var/list/channel_info = list()
for(var/i in RADIO_LOW_FREQ to RADIO_HIGH_FREQ)
for(var/key in radiochannels)
if(i == radiochannels[key])
channel_info.Add(list(list("name" = key, "freq" = i, "color" = frequency_span_class(i))))
for(var/list/channel in channel_info)
switch(channel["color"])
if("deadsay") channel["color"] = "#530FAD"
if("radio") channel["color"] = "#008000"
if("deptradio") channel["color"] = "#ff00ff"
if("newscaster") channel["color"] = "#750000"
if("comradio") channel["color"] = "#193A7A"
if("syndradio") channel["color"] = "#6D3F40"
if("centradio") channel["color"] = "#5C5C8A"
if("airadio") channel["color"] = "#FF00FF"
if("entradio") channel["color"] = "#339966"
if("secradio") channel["color"] = "#A30000"
if("engradio") channel["color"] = "#A66300"
if("medradio") channel["color"] = "#008160"
if("sciradio") channel["color"] = "#993399"
if("supradio") channel["color"] = "#5F4519"
if("srvradio") channel["color"] = "#6eaa2c"
if("expradio") channel["color"] = "#555555"
to_chat(src, json_encode(channel_info)) */
// central command channels, i.e deathsquid & response teams
var/list/CENT_FREQS = list(ERT_FREQ, DTH_FREQ)

View File

@@ -332,6 +332,19 @@ var/global/list/PDA_Manifest = list()
var/datum/job/J = SSjob.get_job(assignment)
hidden = J?.offmap_spawn
/* Note: Due to cached_character_icon, a number of emergent properties occur due to the initialization
* order of readied-up vs latejoiners. Namely, latejoiners will get a uniform in their datacore picture, but readied-up will
* not. This is due to the fact that SSticker calls data_core.manifest_inject() inside of ticker/proc/create_characters(),
* but does not equip them until ticker/proc/equip_characters(), which is called later. So, this proc is literally called before
* they ever get their equipment, and so it can't get a picture of them in their equipment.
* Latejoiners do not have this problem, because /mob/new_player/proc/AttemptLateSpawn calls EquipRank() before it calls
* this proc, which means that they're already clothed by the time they get their picture taken here.
* The COMPILE_OVERLAYS() here is just to bypass SSoverlays taking for-fucking-ever to update the mob, since we're about to
* take a picture of them, we want all the overlays.
*/
COMPILE_OVERLAYS(H)
SSoverlays.queue -= H
var/id = generate_record_id()
//General Record
var/datum/data/record/G = CreateGeneralRecord(H, id, hidden)
@@ -418,8 +431,8 @@ var/global/list/PDA_Manifest = list()
var/icon/side
if(H)
var/icon/charicon = cached_character_icon(H)
front = icon(charicon, dir = SOUTH)
side = icon(charicon, dir = WEST)
front = icon(charicon, dir = SOUTH, frame = 1)
side = icon(charicon, dir = WEST, frame = 1)
else // Sending null things through browse_rsc() makes a runtime and breaks the console trying to view the record.
front = icon('html/images/no_image32.png')
side = icon('html/images/no_image32.png')

View File

@@ -154,7 +154,7 @@
/datum/wires/tgui_act(action, list/params)
if(..())
return
return TRUE
var/mob/user = usr
if(!interactable(user))

View File

@@ -455,13 +455,13 @@
/obj/machinery/computer/scan_consolenew/tgui_act(action, params)
if(..())
return FALSE // don't update uis
return TRUE
if(!istype(usr.loc, /turf))
return FALSE // don't update uis
return TRUE
if(!src || !src.connected)
return FALSE // don't update uis
return TRUE
if(irradiating) // Make sure that it isn't already irradiating someone...
return FALSE // don't update uis
return TRUE
add_fingerprint(usr)

View File

@@ -293,7 +293,7 @@
/obj/machinery/sleeper/tgui_act(action, params, datum/tgui/ui, datum/tgui_state/state)
if(..())
return
return TRUE
if(!controls_inside && usr == occupant)
return
if(panel_open)

View File

@@ -323,7 +323,7 @@
/obj/machinery/bodyscanner/tgui_act(action, params)
if(..())
return
return TRUE
. = TRUE
switch(action)

View File

@@ -129,7 +129,7 @@
/obj/machinery/computer/operating/tgui_act(action, params)
if(..())
return
return TRUE
if((usr.contents.Find(src) || (in_range(src, usr) && istype(src.loc, /turf))) || (istype(usr, /mob/living/silicon)))
usr.set_machine(src)

View File

@@ -198,7 +198,7 @@
/obj/machinery/computer/cloning/tgui_act(action, params)
if(..())
return
return TRUE
. = TRUE
switch(tgui_modal_act(src, action, params))

View File

@@ -198,7 +198,7 @@
/obj/machinery/computer/med_data/tgui_act(action, params)
if(..())
return
return TRUE
if(!data_core.general.Find(active1))
active1 = null
@@ -508,3 +508,6 @@
icon_screen = "medlaptop"
circuit = /obj/item/weapon/circuitboard/med_data/laptop
density = 0
#undef FIELD
#undef MED_FIELD

View File

@@ -141,7 +141,7 @@
/obj/machinery/atmospherics/unary/cryo_cell/tgui_act(action, params)
if(..() || usr == occupant)
return
return TRUE
. = TRUE
switch(action)

View File

@@ -213,6 +213,13 @@ Class Procs:
/obj/machinery/proc/inoperable(var/additional_flags = 0)
return (stat & (NOPOWER | BROKEN | additional_flags))
// Duplicate of below because we don't want to fuck around with CanUseTopic in TGUI
// TODO: Replace this with can_interact from /tg/
/obj/machinery/tgui_status(mob/user)
if(!interact_offline && (stat & (NOPOWER | BROKEN)))
return STATUS_CLOSE
return ..()
/obj/machinery/CanUseTopic(var/mob/user)
if(!interact_offline && (stat & (NOPOWER | BROKEN)))
return STATUS_CLOSE

View File

@@ -42,6 +42,9 @@
/datum/computer_file/program/nano_host()
return computer.nano_host()
/datum/computer_file/program/tgui_host()
return computer.tgui_host()
/datum/computer_file/program/clone()
var/datum/computer_file/program/temp = ..()
temp.required_access = required_access

View File

@@ -379,7 +379,7 @@
/obj/machinery/chem_master/tgui_act(action, params, datum/tgui/ui, datum/tgui_state/state)
if(..())
return
return TRUE
if(tgui_act_modal(action, params, ui, state))
return TRUE

View File

@@ -156,7 +156,7 @@
/obj/machinery/chemical_dispenser/tgui_act(action, params)
if(..())
return
return TRUE
. = TRUE
switch(action)

View File

@@ -260,18 +260,18 @@
/obj/machinery/disposal/tgui_act(action, list/params, datum/tgui/ui, datum/tgui_state/state)
if(..())
return
return TRUE
if(usr.loc == src)
to_chat(usr, "<span class='warning'>You cannot reach the controls from inside.</span>")
return
return TRUE
if(mode==-1 && action != "eject") // If the mode is -1, only allow ejection
to_chat(usr, "<span class='warning'>The disposal units power is disabled.</span>")
return
return TRUE
if(stat & BROKEN)
return
return TRUE
add_fingerprint(usr)

View File

@@ -195,7 +195,7 @@
/obj/machinery/computer/transhuman/resleeving/tgui_act(action, params)
if(..())
return
return TRUE
. = TRUE
switch(tgui_modal_act(src, action, params))

View File

@@ -12,9 +12,10 @@
*
* required user mob The mob who opened/is using the UI.
* optional ui datum/tgui The UI to be updated, if it exists.
* optional parent_ui datum/tgui A parent UI that, when closed, closes this UI as well.
*/
/datum/proc/tgui_interact(mob/user, datum/tgui/ui = null)
/datum/proc/tgui_interact(mob/user, datum/tgui/ui = null, datum/tgui/parent_ui = null)
return FALSE // Not implemented.
/**
@@ -27,7 +28,7 @@
*
* return list Data to be sent to the UI.
*/
/datum/proc/tgui_data(mob/user)
/datum/proc/tgui_data(mob/user, datum/tgui/ui, datum/tgui_state/state)
return list() // Not implemented.
/**

View File

@@ -12,12 +12,15 @@ Code is pretty much ripped verbatim from nano modules, but with un-needed stuff
var/list/using_access
var/tgui_id
var/ntos = FALSE
/datum/tgui_module/New(var/host)
src.host = host
if(ntos)
tgui_id = "Ntos" + tgui_id
/datum/tgui_module/tgui_host()
return host ? host : src
return host ? host.tgui_host() : src
/datum/tgui_module/tgui_close(mob/user)
if(host)
@@ -43,4 +46,34 @@ Code is pretty much ripped verbatim from nano modules, but with un-needed stuff
if(access in I.access)
return 1
return 0
return 0
/datum/tgui_module/tgui_static_data()
. = ..()
var/obj/item/modular_computer/host = tgui_host()
if(istype(host))
. += host.get_header_data()
/datum/tgui_module/tgui_act(action, params)
if(..())
return TRUE
var/obj/item/modular_computer/host = tgui_host()
if(istype(host))
if(action == "PC_exit")
host.kill_program()
return TRUE
if(action == "PC_shutdown")
host.shutdown_computer()
return TRUE
if(action == "PC_minimize")
host.minimize_program(usr)
return TRUE
// Just a nice little default interact in case the subtypes don't need any special behavior here
/datum/tgui_module/tgui_interact(mob/user, datum/tgui/ui = null)
ui = SStgui.try_update_ui(user, src, ui)
if(!ui)
ui = new(user, src, tgui_id, name)
ui.open()

View File

@@ -144,7 +144,7 @@
return data
/datum/tgui_module/camera/tgui_static_data(mob/user)
var/list/data = list()
var/list/data = ..()
data["mapRef"] = map_name
var/list/cameras = get_available_cameras(user)
data["cameras"] = list()
@@ -160,11 +160,11 @@
/datum/tgui_module/camera/tgui_act(action, params)
if(..())
return
return TRUE
if(action && !issilicon(usr))
playsound(tgui_host(), "terminal_type", 50, 1)
if(action == "switch_camera")
var/c_tag = params["name"]
var/list/cameras = get_available_cameras(usr)
@@ -287,33 +287,7 @@
// If/when that is done, just move all the PC_ specific data and stuff to the modular computers themselves
// instead of copying this approach here.
/datum/tgui_module/camera/ntos
tgui_id = "NtosCameraConsole"
/datum/tgui_module/camera/ntos/tgui_state()
return GLOB.tgui_ntos_state
/datum/tgui_module/camera/ntos/tgui_static_data()
. = ..()
var/datum/computer_file/program/host = tgui_host()
if(istype(host) && host.computer)
. += host.computer.get_header_data()
/datum/tgui_module/camera/ntos/tgui_act(action, params)
if(..())
return
var/datum/computer_file/program/host = tgui_host()
if(istype(host) && host.computer)
if(action == "PC_exit")
host.computer.kill_program()
return TRUE
if(action == "PC_shutdown")
host.computer.shutdown_computer()
return TRUE
if(action == "PC_minimize")
host.computer.minimize_program(usr)
return TRUE
ntos = TRUE
// ERT Version provides some additional networks.
/datum/tgui_module/camera/ntos/ert

View File

@@ -24,7 +24,7 @@
return TRUE
if("setZLevel")
ui.set_map_z_level(params["mapZLevel"])
SStgui.update_uis(src)
return TRUE
/datum/tgui_module/crew_monitor/tgui_interact(mob/user, datum/tgui/ui = null)
var/z = get_z(user)
@@ -43,7 +43,7 @@
ui.open()
/datum/tgui_module/crew_monitor/tgui_data(mob/user, ui_key = "main", datum/tgui_state/state = GLOB.tgui_default_state)
/datum/tgui_module/crew_monitor/tgui_data(mob/user)
var/data[0]
data["isAI"] = isAI(user)
@@ -59,33 +59,7 @@
return data
/datum/tgui_module/crew_monitor/ntos
tgui_id = "NtosCrewMonitor"
/datum/tgui_module/crew_monitor/ntos/tgui_state(mob/user)
return GLOB.tgui_ntos_state
/datum/tgui_module/crew_monitor/ntos/tgui_static_data()
. = ..()
var/datum/computer_file/program/host = tgui_host()
if(istype(host) && host.computer)
. += host.computer.get_header_data()
/datum/tgui_module/crew_monitor/ntos/tgui_act(action, params)
if(..())
return
var/datum/computer_file/program/host = tgui_host()
if(istype(host) && host.computer)
if(action == "PC_exit")
host.computer.kill_program()
return TRUE
if(action == "PC_shutdown")
host.computer.shutdown_computer()
return TRUE
if(action == "PC_minimize")
host.computer.minimize_program(usr)
return TRUE
ntos = TRUE
// Subtype for glasses_state
/datum/tgui_module/crew_monitor/glasses

View File

@@ -36,13 +36,29 @@ GLOBAL_DATUM_INIT(tgui_default_state, /datum/tgui_state/default, new)
return STATUS_DISABLED // Otherwise they can keep the UI open.
/mob/living/silicon/ai/default_can_use_tgui_topic(src_object)
. = shared_tgui_interaction(src_object)
if(. < STATUS_INTERACTIVE)
. = shared_tgui_interaction()
if(. != STATUS_INTERACTIVE)
return
// The AI can interact with anything it can see nearby, or with cameras while wireless control is enabled.
if(!control_disabled && can_see(src_object))
// Prevents the AI from using Topic on admin levels (by for example viewing through the court/thunderdome cameras)
// unless it's on the same level as the object it's interacting with.
var/turf/T = get_turf(src_object)
if(!T || !(z == T.z || (T.z in using_map.player_levels)))
return STATUS_CLOSE
// If an object is in view then we can interact with it
if(src_object in view(client.view, src))
return STATUS_INTERACTIVE
// If we're installed in a chassi, rather than transfered to an inteliCard or other container, then check if we have camera view
if(is_in_chassis())
//stop AIs from leaving windows open and using then after they lose vision
if(cameranet && !cameranet.checkTurfVis(get_turf(src_object)))
return STATUS_CLOSE
return STATUS_INTERACTIVE
else if(get_dist(src_object, src) <= client.view) // View does not return what one would expect while installed in an inteliCard
return STATUS_INTERACTIVE
return STATUS_CLOSE
/mob/living/simple_animal/default_can_use_tgui_topic(src_object)

View File

@@ -1,15 +0,0 @@
/**
* tgui state: ntos_state
*
* Checks a number of things -- mostly physical distance for humans and view for robots.
* This is basically the same as default, except instead of src_object, it uses the computer
* it's attached to.
**/
GLOBAL_DATUM_INIT(tgui_ntos_state, /datum/tgui_state/ntos, new)
/datum/tgui_state/ntos/can_use_topic(src_object, mob/user)
var/datum/computer_file/program/P = src_object
if(!istype(P) || !P.computer)
return FALSE
return user.default_can_use_tgui_topic(P.computer) // Call the individual mob-overridden procs.

View File

@@ -34,8 +34,12 @@
var/status = STATUS_INTERACTIVE
/// Topic state used to determine status/interactability.
var/datum/tgui_state/state = null
// The map z-level to display.
/// The map z-level to display.
var/map_z_level = 1
/// The Parent UI
var/datum/tgui/parent_ui
/// Children of this UI
var/list/children = list()
/**
* public
@@ -46,12 +50,13 @@
* required src_object datum The object or datum which owns the UI.
* required interface string The interface used to render the UI.
* optional title string The title of the UI.
* optional parent_ui datum/tgui The parent of this UI.
* optional ui_x int Deprecated: Window width.
* optional ui_y int Deprecated: Window height.
*
* return datum/tgui The requested UI.
*/
/datum/tgui/New(mob/user, datum/src_object, interface, title, ui_x, ui_y)
/datum/tgui/New(mob/user, datum/src_object, interface, title, datum/tgui/parent_ui, ui_x, ui_y)
src.user = user
src.src_object = src_object
src.window_key = "[REF(src_object)]-main"
@@ -59,6 +64,9 @@
if(title)
src.title = title
src.state = src_object.tgui_state()
src.parent_ui = parent_ui
if(parent_ui)
parent_ui.children += src
// Deprecated
if(ui_x && ui_y)
src.window_size = list(ui_x, ui_y)
@@ -104,6 +112,9 @@
if(closing)
return
closing = TRUE
for(var/datum/tgui/child in children)
child.close()
children.Cut()
// If we don't have window_id, open proc did not have the opportunity
// to finish, therefore it's safe to skip this whole block.
if(window)
@@ -115,6 +126,7 @@
src_object.tgui_close(user)
SStgui.on_close(src)
state = null
parent_ui = null
qdel(src)
/**
@@ -209,7 +221,7 @@
"observer" = isobserver(user),
),
)
var/data = custom_data || with_data && src_object.tgui_data(user)
var/data = custom_data || with_data && src_object.tgui_data(user, src, state)
if(data)
json_data["data"] = data
var/static_data = with_static_data && src_object.tgui_static_data(user)
@@ -244,7 +256,7 @@
return
// Update through a normal call to ui_interact
if(status != STATUS_DISABLED && (autoupdate || force))
src_object.tgui_interact(user, src)
src_object.tgui_interact(user, src, parent_ui)
return
// Update status only
var/needs_update = process_status()
@@ -262,6 +274,8 @@
/datum/tgui/proc/process_status()
var/prev_status = status
status = src_object.tgui_status(user, state)
if(parent_ui)
status = min(status, parent_ui.status)
return prev_status != status
/datum/tgui/proc/log_message(message)

View File

@@ -190,9 +190,9 @@
/datum/tgui_window/proc/send_asset(datum/asset/asset)
if(!client || !asset)
return
// if(istype(asset, /datum/asset/spritesheet))
// var/datum/asset/spritesheet/spritesheet = asset
// send_message("asset/stylesheet", spritesheet.css_filename())
if(istype(asset, /datum/asset/spritesheet))
var/datum/asset/spritesheet/spritesheet = asset
send_message("asset/stylesheet", spritesheet.css_filename())
send_message("asset/mappings", asset.get_url_mappings())
sent_assets += list(asset)
asset.send(client)

View File

@@ -369,7 +369,7 @@ rules:
# max-depth: error
## Enforce a maximum line length
max-len: [error, {
code: 80,
code: 120, # Bump to 140 if this is still too in the way
## Ignore imports
ignorePattern: '^(import\s.+\sfrom\s|.*require\()',
ignoreUrls: true,

View File

@@ -77,7 +77,7 @@ input. The input's `action` and `params` are passed to the proc.
```dm
/obj/machinery/my_machine/tgui_act(action, params)
if(..())
return
return TRUE
if(action == "change_color")
var/new_color = params["color"]
if(!(color in allowed_coors))
@@ -305,7 +305,7 @@ upon code review):
/obj/copypasta/tgui_act(action, params)
if(..())
return
return TRUE
switch(action)
if("copypasta")
var/newvar = params["var"]

View File

@@ -91,7 +91,7 @@ export const toTitleCase = str => {
return str;
}
// Handle string
const WORDS_UPPER = ['Id', 'Tv'];
const WORDS_UPPER = ['Id', 'Tv', 'Rcd'];
const WORDS_LOWER = [
'A', 'An', 'And', 'As', 'At', 'But', 'By', 'For', 'For', 'From', 'In',
'Into', 'Near', 'Nor', 'Of', 'On', 'Onto', 'Or', 'The', 'To', 'With',
@@ -105,7 +105,7 @@ export const toTitleCase = str => {
}
for (let word of WORDS_UPPER) {
const regex = new RegExp('\\b' + word + '\\b', 'g');
currentStr = currentStr.replace(regex, str => str.toLowerCase());
currentStr = currentStr.replace(regex, str => str.toUpperCase());
}
return currentStr;
};

View File

@@ -52,16 +52,18 @@ export class Dropdown extends Component {
{option}
</div>
));
ops.unshift((
<div
key={placeholder}
className="Dropdown__menuentry"
onClick={() => {
this.setSelected(null);
}}>
-- {placeholder} --
</div>
));
if (placeholder) {
ops.unshift((
<div
key={placeholder}
className="Dropdown__menuentry"
onClick={() => {
this.setSelected(null);
}}>
-- {placeholder} --
</div>
));
}
return ops;
}
@@ -73,6 +75,7 @@ export class Dropdown extends Component {
noscroll,
nochevron,
width,
maxHeight,
onClick,
selected,
disabled,
@@ -92,6 +95,7 @@ export class Dropdown extends Component {
tabIndex="-1"
style={{
'width': width,
'max-height': maxHeight,
}}
className={classes([
noscroll && 'Dropdown__menu-noscroll' || 'Dropdown__menu',

View File

@@ -2,16 +2,15 @@ import { Box, Icon, Tooltip } from '.';
import { Component } from 'inferno';
import { useBackend } from "../backend";
import { resolveAsset } from '../assets';
import { logger } from '../logging';
export class NanoMap extends Component {
constructor(props) {
super(props);
// Auto center based on window size
const Xcenter = (window.innerWidth / 2) - 256;
this.state = {
offsetX: Xcenter,
offsetX: 0,
offsetY: 0,
transform: 'none',
dragging: false,
@@ -42,8 +41,8 @@ export class NanoMap extends Component {
const newOffsetX = e.screenX - state.originX;
const newOffsetY = e.screenY - state.originY;
if (prevState.dragging) {
state.offsetX += newOffsetX;
state.offsetY += newOffsetY;
state.offsetX += (newOffsetX / this.props.zoom);
state.offsetY += (newOffsetY / this.props.zoom);
state.originX = e.screenX;
state.originY = e.screenY;
} else {
@@ -71,11 +70,12 @@ export class NanoMap extends Component {
const { offsetX, offsetY } = this.state;
const { children, zoom, reset } = this.props;
let matrix
= `matrix(${zoom}, 0, 0, ${zoom}, ${offsetX * zoom}, ${offsetY * zoom})`;
const newStyle = {
width: '512px',
height: '512px',
"margin-top": offsetY + 'px',
"margin-left": offsetX + 'px',
width: '560px',
height: '560px',
"overflow": "hidden",
"position": "relative",
"padding": "0px",
@@ -83,8 +83,7 @@ export class NanoMap extends Component {
"url("+config.map+"_nanomap_z"+config.mapZLevel+".png)",
"background-size": "cover",
"text-align": "center",
"transform-origin": "center center",
"transform": "scale(" + zoom + ")",
"transform": matrix,
};
return (
@@ -110,32 +109,26 @@ const NanoMapMarker = (props, context) => {
icon,
tooltip,
color,
onClick,
} = props;
// Please note, the horrifying `3.65714285714` is just the ratio of the
// width/height of the minimap *element* (not image)
// to the actual turf size of the map
const rx = (-256 * (zoom - 1)
+ (x * (3.65714285714 * zoom))
- 1.5 * zoom - 3);
const ry = (512 * zoom
- (y * (3.65714285714 * zoom))
+ zoom - 1.5);
const rx = (x * 4) - 5;
const ry = (y * 4) - 4;
return (
<div style={"transform: scale(" + 1 / zoom + ")"}>
<Box
position="absolute"
className="NanoMap__marker"
lineHeight="0"
top={ry + 'px'}
left={rx + 'px'} >
<Icon
name={icon}
color={color}
fontSize="6px"
/>
<Tooltip content={tooltip} />
</Box>
</div>
<Box
position="absolute"
className="NanoMap__marker"
lineHeight="0"
bottom={ry + 'px'}
left={rx + 'px'}
onMouseDown={onClick} >
<Icon
name={icon}
color={color}
fontSize="4px"
/>
<Tooltip content={tooltip} scale={zoom} />
</Box>
);
};

View File

@@ -4,6 +4,7 @@ export const Tooltip = props => {
const {
content,
position = 'bottom',
scale,
} = props;
// Empirically calculated length of the string,
// at which tooltip text starts to overflow.
@@ -14,6 +15,7 @@ export const Tooltip = props => {
'Tooltip',
long && 'Tooltip--long',
position && 'Tooltip--' + position,
scale && 'Tooltip--scale--' + Math.floor(scale),
])}
data-tooltip={content} />
);

View File

@@ -26,4 +26,4 @@ export { Section } from './Section';
export { Slider } from './Slider';
export { Table } from './Table';
export { Tabs } from './Tabs';
export { Tooltip } from './Tooltip';
export { Tooltip } from './Tooltip';

View File

@@ -4,6 +4,10 @@ export const UI_UPDATE = 1;
export const UI_DISABLED = 0;
export const UI_CLOSE = -1;
// Atmospheric helpers
/** 0.0 Degrees Celsius in Kelvin */
export const T0C = 273.15;
// All game related colors are stored here
export const COLORS = {
// Department colors
@@ -48,77 +52,105 @@ export const CSS_COLORS = [
'label',
];
// If you ever add a new radio channel, you can either manually update this, or
// go use /client/verb/generate_tgui_radio_constants() in communications.dm.
export const RADIO_CHANNELS = [
{
name: 'Syndicate',
freq: 1213,
color: '#a52a2a',
"name": "Mercenary",
"freq": 1213,
"color": "#6D3F40",
},
{
name: 'Red Team',
freq: 1215,
color: '#ff4444',
"name": "Raider",
"freq": 1277,
"color": "#6D3F40",
},
{
name: 'Blue Team',
freq: 1217,
color: '#3434fd',
"name": "Special Ops",
"freq": 1341,
"color": "#5C5C8A",
},
{
name: 'CentCom',
freq: 1337,
color: '#2681a5',
"name": "AI Private",
"freq": 1343,
"color": "#FF00FF",
},
{
name: 'Supply',
freq: 1347,
color: '#b88646',
"name": "Response Team",
"freq": 1345,
"color": "#5C5C8A",
},
{
name: 'Service',
freq: 1349,
color: '#6ca729',
"name": "Supply",
"freq": 1347,
"color": "#5F4519",
},
{
name: 'Science',
freq: 1351,
color: '#c68cfa',
"name": "Service",
"freq": 1349,
"color": "#6eaa2c",
},
{
name: 'Command',
freq: 1353,
color: '#5177ff',
"name": "Science",
"freq": 1351,
"color": "#993399",
},
{
name: 'Medical',
freq: 1355,
color: '#57b8f0',
"name": "Command",
"freq": 1353,
"color": "#193A7A",
},
{
name: 'Engineering',
freq: 1357,
color: '#f37746',
"name": "Medical",
"freq": 1355,
"color": "#008160",
},
{
name: 'Security',
freq: 1359,
color: '#dd3535',
"name": "Engineering",
"freq": 1357,
"color": "#A66300",
},
{
name: 'AI Private',
freq: 1447,
color: '#d65d95',
"name": "Security",
"freq": 1359,
"color": "#A30000",
},
{
name: 'Common',
freq: 1459,
color: '#1ecc43',
"name": "Explorer",
"freq": 1361,
"color": "#555555",
},
{
"name": "Talon",
"freq": 1363,
"color": "#555555",
},
{
"name": "Common",
"freq": 1459,
"color": "#008000",
},
{
"name": "Entertainment",
"freq": 1461,
"color": "#339966",
},
{
"name": "Security(I)",
"freq": 1475,
"color": "#008000",
},
{
"name": "Medical(I)",
"freq": 1485,
"color": "#008000",
},
];
const GASES = [
{
'id': 'o2',
'id': 'oxygen',
'name': 'Oxygen',
'label': 'O₂',
'color': 'blue',
@@ -130,15 +162,15 @@ const GASES = [
'color': 'red',
},
{
'id': 'co2',
'id': 'carbon dioxide',
'name': 'Carbon Dioxide',
'label': 'CO₂',
'color': 'grey',
},
{
'id': 'plasma',
'name': 'Plasma',
'label': 'Plasma',
'id': 'phoron',
'name': 'Phoron',
'label': 'Phoron',
'color': 'pink',
},
{
@@ -201,6 +233,24 @@ const GASES = [
'label': 'H₂',
'color': 'white',
},
{
'id': 'other',
'name': 'Other',
'label': 'Other',
'color': 'white',
},
{
'id': 'pressure',
'name': 'Pressure',
'label': 'Pressure',
'color': 'average',
},
{
'id': 'temperature',
'name': 'Temperature',
'label': 'Temperature',
'color': 'yellow',
},
];
export const getGasLabel = (gasId, fallbackValue) => {

View File

@@ -4,10 +4,6 @@ import { useBackend } from "../backend";
import { AnimatedNumber, Box, Button, Flex, Icon, LabeledList, ProgressBar, Section, Table, Tooltip } from "../components";
import { Window } from "../layouts";
import { createLogger } from '../logging';
const debugBodyScannerLogger = createLogger('debugBodyScanner');
const stats = [
['good', 'Alive'],
['average', 'Unconscious'],

View File

@@ -103,6 +103,9 @@ export const CrewMonitorContent = (props, context) => {
</Table>
);
} else if (tabIndex === 1) {
// Please note, if you ever change the zoom values,
// you MUST update styles/components/Tooltip.scss
// and change the @for scss to match.
body = (
<Box textAlign="center">
Zoom Level:
@@ -113,7 +116,7 @@ export const CrewMonitorContent = (props, context) => {
stepPixelSize="5"
value={mapZoom}
minValue={1}
maxValue={8}
maxValue={8}
onChange={(e, value) => setZoom(value)} />
Z-Level:
{data.map_levels

View File

@@ -0,0 +1,20 @@
import { Flex, Section } from '../../components';
/**
* Just a generic wrapper for fullscreen notices.
*/
export const FullscreenNotice = (props, context) => {
const {
children,
title = 'Welcome',
} = props;
return (
<Section title={title} height="100%" stretchContents>
<Flex height="100%" align="center" justify="center">
<Flex.Item textAlign="center" mt="-2rem">
{children}
</Flex.Item>
</Flex>
</Section>
);
};

View File

@@ -1,5 +1,6 @@
import { useBackend } from '../../backend';
import { Box, Button, Flex, Icon, Section } from '../../components';
import { FullscreenNotice } from './FullscreenNotice';
/**
* Displays a login screen that users can interact with
@@ -30,55 +31,51 @@ export const LoginScreen = (_properties, context) => {
isRobot,
} = data;
return (
<Section title="Welcome" height="100%" stretchContents>
<Flex height="100%" align="center" justify="center">
<Flex.Item textAlign="center" mt="-2rem">
<Box fontSize="1.5rem" bold>
<Icon
name="user-circle"
verticalAlign="middle"
size={3}
mr="1rem"
/>
Guest
</Box>
<Box color="label" my="1rem">
ID:
<Button
icon="id-card"
content={scan ? scan : "----------"}
ml="0.5rem"
onClick={() => act('scan')}
/>
</Box>
<Button
icon="sign-in-alt"
disabled={!scan}
content="Login"
onClick={() => act('login', {
login_type: 1,
})}
/>
{!!isAI && (
<Button
icon="sign-in-alt"
content="Login as AI"
onClick={() => act('login', {
login_type: 2,
})}
/>
)}
{!!isRobot && (
<Button
icon="sign-in-alt"
content="Login as Cyborg"
onClick={() => act('login', {
login_type: 3,
})}
/>
)}
</Flex.Item>
</Flex>
</Section>
<FullscreenNotice title="Welcome">
<Box fontSize="1.5rem" bold>
<Icon
name="user-circle"
verticalAlign="middle"
size={3}
mr="1rem"
/>
Guest
</Box>
<Box color="label" my="1rem">
ID:
<Button
icon="id-card"
content={scan ? scan : "----------"}
ml="0.5rem"
onClick={() => act('scan')}
/>
</Box>
<Button
icon="sign-in-alt"
disabled={!scan}
content="Login"
onClick={() => act('login', {
login_type: 1,
})}
/>
{!!isAI && (
<Button
icon="sign-in-alt"
content="Login as AI"
onClick={() => act('login', {
login_type: 2,
})}
/>
)}
{!!isRobot && (
<Button
icon="sign-in-alt"
content="Login as Cyborg"
onClick={() => act('login', {
login_type: 3,
})}
/>
)}
</FullscreenNotice>
);
};

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -259,7 +259,7 @@ A fatal exception has occurred at 002B:C562F1B7 in TGUI.
The current application will be terminated.
Please remain calm. Get to the nearest NTNet workstation
and send the copy of the following stack trace to:
www.github.com/tgstation/tgstation. Thank you for your cooperation.
www.github.com/VOREStation/VOREStation. Thank you for your cooperation.
</marquee>
<div id="FatalError__stack" class="FatalError__stack"></div>
<div class="FatalError__footer">

View File

@@ -125,3 +125,15 @@ $border-radius: base.$border-radius !default;
.Tooltip--right:hover::after {
transform: translateX(0.5em) translateY(-50%);
}
@for $i from 1 through 8 {
.Tooltip--scale--#{$i}::after {
top: 30%;
left: 50%;
transform: translateX(-50%) scale(1 / $i);
}
.Tooltip--scale--#{$i}:hover::after {
transform: translateX(-50%) scale(1 / $i);
}
}

View File

@@ -39,7 +39,6 @@
left: 0;
right: 0;
overflow: hidden;
margin: base.em(6px);
}
.Layout__content--flexRow {

View File

@@ -3504,7 +3504,6 @@
#include "code\modules\tgui\states\inventory_vr.dm"
#include "code\modules\tgui\states\not_incapacitated.dm"
#include "code\modules\tgui\states\notcontained.dm"
#include "code\modules\tgui\states\ntos.dm"
#include "code\modules\tgui\states\observer.dm"
#include "code\modules\tgui\states\physical.dm"
#include "code\modules\tgui\states\self.dm"