diff --git a/code/_helpers/unsorted.dm b/code/_helpers/unsorted.dm index 99a313e454..eba949e02d 100644 --- a/code/_helpers/unsorted.dm +++ b/code/_helpers/unsorted.dm @@ -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 diff --git a/code/controllers/communications.dm b/code/controllers/communications.dm index b99ab68064..c1d87d7ef3 100644 --- a/code/controllers/communications.dm +++ b/code/controllers/communications.dm @@ -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) diff --git a/code/datums/datacore.dm b/code/datums/datacore.dm index ff483432ed..bb9372749a 100644 --- a/code/datums/datacore.dm +++ b/code/datums/datacore.dm @@ -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') diff --git a/code/datums/wires/wires.dm b/code/datums/wires/wires.dm index d37fbff0fe..83ebb65fa8 100644 --- a/code/datums/wires/wires.dm +++ b/code/datums/wires/wires.dm @@ -154,7 +154,7 @@ /datum/wires/tgui_act(action, list/params) if(..()) - return + return TRUE var/mob/user = usr if(!interactable(user)) diff --git a/code/game/dna/dna_modifier.dm b/code/game/dna/dna_modifier.dm index a72c92d47c..eb0ad7000c 100644 --- a/code/game/dna/dna_modifier.dm +++ b/code/game/dna/dna_modifier.dm @@ -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) diff --git a/code/game/machinery/Sleeper.dm b/code/game/machinery/Sleeper.dm index d7d8761db7..a97fbf986f 100644 --- a/code/game/machinery/Sleeper.dm +++ b/code/game/machinery/Sleeper.dm @@ -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) diff --git a/code/game/machinery/adv_med.dm b/code/game/machinery/adv_med.dm index 3e5b2bcd53..a3e4d2eeb3 100644 --- a/code/game/machinery/adv_med.dm +++ b/code/game/machinery/adv_med.dm @@ -323,7 +323,7 @@ /obj/machinery/bodyscanner/tgui_act(action, params) if(..()) - return + return TRUE . = TRUE switch(action) diff --git a/code/game/machinery/computer/Operating.dm b/code/game/machinery/computer/Operating.dm index cf041a74fc..aa76f23077 100644 --- a/code/game/machinery/computer/Operating.dm +++ b/code/game/machinery/computer/Operating.dm @@ -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) diff --git a/code/game/machinery/computer/cloning.dm b/code/game/machinery/computer/cloning.dm index 07fac6fb0d..9bf3235d8d 100644 --- a/code/game/machinery/computer/cloning.dm +++ b/code/game/machinery/computer/cloning.dm @@ -198,7 +198,7 @@ /obj/machinery/computer/cloning/tgui_act(action, params) if(..()) - return + return TRUE . = TRUE switch(tgui_modal_act(src, action, params)) diff --git a/code/game/machinery/computer/medical.dm b/code/game/machinery/computer/medical.dm index 40e8152340..c2bfdc7b8e 100644 --- a/code/game/machinery/computer/medical.dm +++ b/code/game/machinery/computer/medical.dm @@ -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 diff --git a/code/game/machinery/cryo.dm b/code/game/machinery/cryo.dm index d279a9773b..d822bcb739 100644 --- a/code/game/machinery/cryo.dm +++ b/code/game/machinery/cryo.dm @@ -141,7 +141,7 @@ /obj/machinery/atmospherics/unary/cryo_cell/tgui_act(action, params) if(..() || usr == occupant) - return + return TRUE . = TRUE switch(action) diff --git a/code/game/machinery/machinery.dm b/code/game/machinery/machinery.dm index 0d2c4e78e8..1afa9910f4 100644 --- a/code/game/machinery/machinery.dm +++ b/code/game/machinery/machinery.dm @@ -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 diff --git a/code/modules/modular_computers/file_system/program.dm b/code/modules/modular_computers/file_system/program.dm index 7a63d49576..9e011f442d 100644 --- a/code/modules/modular_computers/file_system/program.dm +++ b/code/modules/modular_computers/file_system/program.dm @@ -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 diff --git a/code/modules/reagents/Chemistry-Machinery.dm b/code/modules/reagents/Chemistry-Machinery.dm index 517385757b..1b1964a79b 100644 --- a/code/modules/reagents/Chemistry-Machinery.dm +++ b/code/modules/reagents/Chemistry-Machinery.dm @@ -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 diff --git a/code/modules/reagents/dispenser/dispenser2.dm b/code/modules/reagents/dispenser/dispenser2.dm index 1fdf6a24af..7f2fb13f40 100644 --- a/code/modules/reagents/dispenser/dispenser2.dm +++ b/code/modules/reagents/dispenser/dispenser2.dm @@ -156,7 +156,7 @@ /obj/machinery/chemical_dispenser/tgui_act(action, params) if(..()) - return + return TRUE . = TRUE switch(action) diff --git a/code/modules/recycling/disposal.dm b/code/modules/recycling/disposal.dm index fa19b46e1f..3437c8b582 100644 --- a/code/modules/recycling/disposal.dm +++ b/code/modules/recycling/disposal.dm @@ -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, "You cannot reach the controls from inside.") - return + return TRUE if(mode==-1 && action != "eject") // If the mode is -1, only allow ejection to_chat(usr, "The disposal units power is disabled.") - return + return TRUE if(stat & BROKEN) - return + return TRUE add_fingerprint(usr) diff --git a/code/modules/resleeving/computers.dm b/code/modules/resleeving/computers.dm index acaa13f9a1..1d5b5a707e 100644 --- a/code/modules/resleeving/computers.dm +++ b/code/modules/resleeving/computers.dm @@ -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)) diff --git a/code/modules/tgui/external.dm b/code/modules/tgui/external.dm index 7e75f9343c..19f039869e 100644 --- a/code/modules/tgui/external.dm +++ b/code/modules/tgui/external.dm @@ -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. /** diff --git a/code/modules/tgui/modules/_base.dm b/code/modules/tgui/modules/_base.dm index 23b12b8bd1..46dbc655ff 100644 --- a/code/modules/tgui/modules/_base.dm +++ b/code/modules/tgui/modules/_base.dm @@ -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 \ No newline at end of file + 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() \ No newline at end of file diff --git a/code/modules/tgui/modules/camera.dm b/code/modules/tgui/modules/camera.dm index b7305ca165..e1223fad74 100644 --- a/code/modules/tgui/modules/camera.dm +++ b/code/modules/tgui/modules/camera.dm @@ -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 diff --git a/code/modules/tgui/modules/crew_monitor.dm b/code/modules/tgui/modules/crew_monitor.dm index 247db8cb6c..86e039222c 100644 --- a/code/modules/tgui/modules/crew_monitor.dm +++ b/code/modules/tgui/modules/crew_monitor.dm @@ -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 diff --git a/code/modules/tgui/states/default.dm b/code/modules/tgui/states/default.dm index 9ccc9c751e..ba8d132e0b 100644 --- a/code/modules/tgui/states/default.dm +++ b/code/modules/tgui/states/default.dm @@ -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) diff --git a/code/modules/tgui/states/ntos.dm b/code/modules/tgui/states/ntos.dm deleted file mode 100644 index d6a5533e1e..0000000000 --- a/code/modules/tgui/states/ntos.dm +++ /dev/null @@ -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. diff --git a/code/modules/tgui/tgui.dm b/code/modules/tgui/tgui.dm index 9af1296ab0..7d4c85cecb 100644 --- a/code/modules/tgui/tgui.dm +++ b/code/modules/tgui/tgui.dm @@ -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) diff --git a/code/modules/tgui/tgui_window.dm b/code/modules/tgui/tgui_window.dm index 26533447d4..a5a6c88e99 100644 --- a/code/modules/tgui/tgui_window.dm +++ b/code/modules/tgui/tgui_window.dm @@ -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) diff --git a/tgui/.eslintrc.yml b/tgui/.eslintrc.yml index 9fd4db9fd2..fe11b8a34c 100644 --- a/tgui/.eslintrc.yml +++ b/tgui/.eslintrc.yml @@ -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, diff --git a/tgui/docs/tutorial-and-examples.md b/tgui/docs/tutorial-and-examples.md index 00d5546d91..c0e32ebf8e 100644 --- a/tgui/docs/tutorial-and-examples.md +++ b/tgui/docs/tutorial-and-examples.md @@ -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"] diff --git a/tgui/packages/common/string.js b/tgui/packages/common/string.js index d05dbfb6fc..1a06c67ecf 100644 --- a/tgui/packages/common/string.js +++ b/tgui/packages/common/string.js @@ -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; }; diff --git a/tgui/packages/tgui/components/Dropdown.js b/tgui/packages/tgui/components/Dropdown.js index c561a9557e..6296d7c55c 100644 --- a/tgui/packages/tgui/components/Dropdown.js +++ b/tgui/packages/tgui/components/Dropdown.js @@ -52,16 +52,18 @@ export class Dropdown extends Component { {option} )); - ops.unshift(( -
{ - this.setSelected(null); - }}> - -- {placeholder} -- -
- )); + if (placeholder) { + ops.unshift(( +
{ + this.setSelected(null); + }}> + -- {placeholder} -- +
+ )); + } 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', diff --git a/tgui/packages/tgui/components/NanoMap.js b/tgui/packages/tgui/components/NanoMap.js index 8ee21ef4a9..261fb8b1d3 100644 --- a/tgui/packages/tgui/components/NanoMap.js +++ b/tgui/packages/tgui/components/NanoMap.js @@ -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 ( -
- - - - -
+ + + + ); }; diff --git a/tgui/packages/tgui/components/Tooltip.js b/tgui/packages/tgui/components/Tooltip.js index c46f3c45f7..1cc6ed51cc 100644 --- a/tgui/packages/tgui/components/Tooltip.js +++ b/tgui/packages/tgui/components/Tooltip.js @@ -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} /> ); diff --git a/tgui/packages/tgui/components/index.js b/tgui/packages/tgui/components/index.js index 0d2b2ddab6..71fe763ef8 100644 --- a/tgui/packages/tgui/components/index.js +++ b/tgui/packages/tgui/components/index.js @@ -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'; \ No newline at end of file diff --git a/tgui/packages/tgui/constants.js b/tgui/packages/tgui/constants.js index 20ba00cb75..c8155e1229 100644 --- a/tgui/packages/tgui/constants.js +++ b/tgui/packages/tgui/constants.js @@ -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) => { diff --git a/tgui/packages/tgui/interfaces/BodyScanner.js b/tgui/packages/tgui/interfaces/BodyScanner.js index 4daba982f7..b250082473 100644 --- a/tgui/packages/tgui/interfaces/BodyScanner.js +++ b/tgui/packages/tgui/interfaces/BodyScanner.js @@ -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'], diff --git a/tgui/packages/tgui/interfaces/CrewMonitor.js b/tgui/packages/tgui/interfaces/CrewMonitor.js index e5d8dff2ba..1776aa065e 100644 --- a/tgui/packages/tgui/interfaces/CrewMonitor.js +++ b/tgui/packages/tgui/interfaces/CrewMonitor.js @@ -103,6 +103,9 @@ export const CrewMonitorContent = (props, context) => { ); } 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 = ( 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 diff --git a/tgui/packages/tgui/interfaces/common/FullscreenNotice.js b/tgui/packages/tgui/interfaces/common/FullscreenNotice.js new file mode 100644 index 0000000000..124318d0fb --- /dev/null +++ b/tgui/packages/tgui/interfaces/common/FullscreenNotice.js @@ -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 ( +
+ + + {children} + + +
+ ); +}; diff --git a/tgui/packages/tgui/interfaces/common/LoginScreen.js b/tgui/packages/tgui/interfaces/common/LoginScreen.js index ada5c2d89d..441705e6a0 100644 --- a/tgui/packages/tgui/interfaces/common/LoginScreen.js +++ b/tgui/packages/tgui/interfaces/common/LoginScreen.js @@ -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 ( -
- - - - - Guest - - - ID: -
+ + + + Guest + + + ID: +