mirror of
https://github.com/Bubberstation/Bubberstation.git
synced 2026-08-23 13:10:02 +01:00
R&D Monitoring console TGUI + Can see RD consoles (#72987)
## About The Pull Request I wrote this while constantly rushing lol This PR does many things, the largest is that the R&D Monitoring console (the RD's one) is now TGUI It also changes how researching loggings work, bringing the RD console and NtosRD app on par with eachother The type of person is also logged differently, instead of ``Cyborg: [name]`` and ``User: [name]``, humans do not have a prefix and cyborgs will say ``CYBORG [name]``. ``research_logs`` also works differently now to make it easier to reference each needed data from the list. Lastly, I added the ability to see R&D consoles from the console, and the ability to remotely un/lock them down. This currently is pretty useless as it can't control the tablet app variant, and anyone with Science access can just unlock it, however with some minor future changes I think this can be turned into a good way for the RD to get control of their department. Video demonstration, mostly (I made a few edits after this): https://user-images.githubusercontent.com/53777086/215005387-817106f4-5237-4f2e-b0ac-da28e6a17f9c.mp4 ## Why It's Good For The Game This console is overhyped by the game, being hidden behind an RD-locked Command-colored door, in the same room as one of the most damaging theft objectives, yet it is one of the most useless and forgotten consoles in R&D if you don't count everything outside of researching, experiments and robotics. This adds a nice TGUI menu while making it a little more worthwhile to use. ## Changelog 🆑 balance: The R&D monitoring console now shows R&D consoles and their locations. refactor: The R&D monitoring console now has a nice TGUI menu. /🆑
This commit is contained in:
@@ -204,21 +204,26 @@
|
||||
computer.say("Successfully researched [tech_node.display_name].")
|
||||
var/logname = "Unknown"
|
||||
if(isAI(user))
|
||||
logname = "AI: [user.name]"
|
||||
logname = "AI [user.name]"
|
||||
if(iscyborg(user))
|
||||
logname = "Cyborg: [user.name]"
|
||||
logname = "CYBORG [user.name]"
|
||||
if(iscarbon(user))
|
||||
var/obj/item/card/id/idcard = user.get_active_held_item()
|
||||
if(istype(idcard))
|
||||
logname = "User: [idcard.registered_name]"
|
||||
logname = "[idcard.registered_name]"
|
||||
if(ishuman(user))
|
||||
var/mob/living/carbon/human/human_user = user
|
||||
var/obj/item/worn = human_user.wear_id
|
||||
if(istype(worn))
|
||||
var/obj/item/card/id/id_card_of_human_user = worn.GetID()
|
||||
if(istype(id_card_of_human_user))
|
||||
logname = "User: [id_card_of_human_user.registered_name]"
|
||||
stored_research.research_logs += list(list(tech_node.display_name, price["General Research"], logname, "[get_area(computer)] ([user.x],[user.y],[user.z])"))
|
||||
logname = "[id_card_of_human_user.registered_name]"
|
||||
stored_research.research_logs += list(list(
|
||||
"node_name" = tech_node.display_name,
|
||||
"node_cost" = price["General Research"],
|
||||
"node_researcher" = logname,
|
||||
"node_research_location" = "[get_area(computer)] ([user.x],[user.y],[user.z])",
|
||||
))
|
||||
return TRUE
|
||||
else
|
||||
computer.say("Failed to research node: Internal database error!")
|
||||
|
||||
@@ -113,23 +113,26 @@ Nothing else in the console has ID requirements.
|
||||
say("Successfully researched [TN.display_name].")
|
||||
var/logname = "Unknown"
|
||||
if(isAI(user))
|
||||
logname = "AI: [user.name]"
|
||||
logname = "AI [user.name]"
|
||||
if(iscyborg(user))
|
||||
logname = "Cyborg: [user.name]"
|
||||
logname = "CYBORG [user.name]"
|
||||
if(iscarbon(user))
|
||||
var/obj/item/card/id/idcard = user.get_active_held_item()
|
||||
if(istype(idcard))
|
||||
logname = "User: [idcard.registered_name]"
|
||||
logname = "[idcard.registered_name]"
|
||||
if(ishuman(user))
|
||||
var/mob/living/carbon/human/H = user
|
||||
var/obj/item/I = H.wear_id
|
||||
if(istype(I))
|
||||
var/obj/item/card/id/ID = I.GetID()
|
||||
if(istype(ID))
|
||||
logname = "User: [ID.registered_name]"
|
||||
var/i = stored_research.research_logs.len
|
||||
stored_research.research_logs += null
|
||||
stored_research.research_logs[++i] = list(TN.display_name, price["General Research"], logname, "[get_area(src)] ([src.x],[src.y],[src.z])")
|
||||
logname = "[ID.registered_name]"
|
||||
stored_research.research_logs += list(list(
|
||||
"node_name" = TN.display_name,
|
||||
"node_cost" = price["General Research"],
|
||||
"node_researcher" = logname,
|
||||
"node_research_location" = "[get_area(src)] ([src.x],[src.y],[src.z])",
|
||||
))
|
||||
return TRUE
|
||||
else
|
||||
say("Failed to research node: Internal database error!")
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
/// The ninja has blown the HDD up.
|
||||
#define HDD_OVERLOADED 4
|
||||
|
||||
#define SERVER_NOMINAL_TEXT "<font color='lightgreen'>Nominal</font>"
|
||||
#define SERVER_NOMINAL_TEXT "Nominal"
|
||||
|
||||
/obj/machinery/rnd/server
|
||||
name = "\improper R&D Server"
|
||||
@@ -87,15 +87,15 @@
|
||||
/// Gets status text based on this server's status for the computer.
|
||||
/obj/machinery/rnd/server/proc/get_status_text()
|
||||
if(machine_stat & EMPED)
|
||||
return "<font color=red>O&F@I*$ - R3*&O$T R@U!R%D</font>"
|
||||
return "O&F@I*$ - R3*&O$T R@U!R%D"
|
||||
else if(machine_stat & NOPOWER)
|
||||
return "<font color=red>Offline - Server Unpowered</font>"
|
||||
return "Offline - Server Unpowered"
|
||||
else if(research_disabled)
|
||||
return "<font color=red>Offline - Server Control Disabled</font>"
|
||||
return "Offline - Server Control Disabled"
|
||||
else if(!working)
|
||||
// If, for some reason, working is FALSE even though we're not emp'd or powerless,
|
||||
// We need something to update our working state - such as rebooting the server
|
||||
return "<font color=red>Offline - Reboot Required</font>"
|
||||
return "Offline - Reboot Required"
|
||||
|
||||
return SERVER_NOMINAL_TEXT
|
||||
|
||||
@@ -106,86 +106,6 @@
|
||||
to_chat(user, span_notice("Stored [src]'s techweb information in [tool]."))
|
||||
return TRUE
|
||||
|
||||
/obj/machinery/computer/rdservercontrol
|
||||
name = "R&D Server Controller"
|
||||
desc = "Used to manage access to research and manufacturing databases."
|
||||
icon_screen = "rdcomp"
|
||||
icon_keyboard = "rd_key"
|
||||
circuit = /obj/item/circuitboard/computer/rdservercontrol
|
||||
req_access = list(ACCESS_RD)
|
||||
var/list/servers = list()
|
||||
///Connected techweb node the server is connected to.
|
||||
var/datum/techweb/stored_research
|
||||
|
||||
/obj/machinery/computer/rdservercontrol/Initialize(mapload, obj/item/circuitboard/C)
|
||||
. = ..()
|
||||
if(!CONFIG_GET(flag/no_default_techweb_link) && !stored_research)
|
||||
stored_research = SSresearch.science_tech
|
||||
|
||||
/obj/machinery/computer/rdservercontrol/Topic(href, href_list)
|
||||
if(..())
|
||||
return
|
||||
|
||||
add_fingerprint(usr)
|
||||
if (href_list["toggle"])
|
||||
if(allowed(usr) || obj_flags & EMAGGED)
|
||||
var/obj/machinery/rnd/server/S = locate(href_list["toggle"]) in stored_research.techweb_servers
|
||||
S.toggle_disable(usr)
|
||||
else
|
||||
to_chat(usr, span_danger("Access Denied."))
|
||||
|
||||
updateUsrDialog()
|
||||
return
|
||||
|
||||
/obj/machinery/computer/rdservercontrol/ui_interact(mob/user)
|
||||
. = ..()
|
||||
var/list/dat = list()
|
||||
|
||||
dat += "<b>Connected Servers:</b>"
|
||||
dat += "<table><tr><td style='width:25%'><b>Server</b></td><td style='width:25%'><b>Status</b></td><td style='width:25%'><b>Control</b></td>"
|
||||
for(var/obj/machinery/rnd/server/server as anything in stored_research.techweb_servers)
|
||||
var/server_info = ""
|
||||
|
||||
var/status_text = server.get_status_text()
|
||||
var/disable_text = server.research_disabled ? "<font color=red>Disabled</font>" : "<font color=lightgreen>Online</font>"
|
||||
|
||||
server_info += "<tr><td style='width:25%'>[server.name]</td>"
|
||||
server_info += "<td style='width:25%'>[status_text]</td>"
|
||||
server_info += "<td style='width:25%'><a href='?src=[REF(src)];toggle=[REF(server)]'>([disable_text])</a></td><br>"
|
||||
|
||||
dat += server_info
|
||||
|
||||
dat += "</table></br>"
|
||||
|
||||
dat += "<b>Research Log</b></br>"
|
||||
if(stored_research && length(stored_research.research_logs))
|
||||
dat += "<table BORDER=\"1\">"
|
||||
dat += "<tr><td><b>Entry</b></td><td><b>Research Name</b></td><td><b>Cost</b></td><td><b>Researcher Name</b></td><td><b>Console Location</b></td></tr>"
|
||||
for(var/i = stored_research.research_logs.len, i>0, i--)
|
||||
dat += "<tr><td>[i]</td>"
|
||||
for(var/j in stored_research.research_logs[i])
|
||||
dat += "<td>[j]</td>"
|
||||
dat +="</tr>"
|
||||
dat += "</table>"
|
||||
|
||||
else
|
||||
dat += "</br>No history found."
|
||||
|
||||
var/datum/browser/popup = new(user, "server_com", src.name, 900, 620)
|
||||
popup.set_content(dat.Join())
|
||||
popup.open()
|
||||
|
||||
/obj/machinery/computer/rdservercontrol/attackby(obj/item/D, mob/user, params)
|
||||
. = ..()
|
||||
src.updateUsrDialog()
|
||||
|
||||
/obj/machinery/computer/rdservercontrol/emag_act(mob/user)
|
||||
if(obj_flags & EMAGGED)
|
||||
return
|
||||
playsound(src, SFX_SPARKS, 75, TRUE, SHORT_RANGE_SOUND_EXTRARANGE)
|
||||
obj_flags |= EMAGGED
|
||||
to_chat(user, span_notice("You disable the security protocols."))
|
||||
|
||||
/// Master R&D server. As long as this still exists and still holds the HDD for the theft objective, research points generate at normal speed. Destroy it or an antag steals the HDD? Half research speed.
|
||||
/obj/machinery/rnd/server/master
|
||||
max_integrity = 1800 //takes roughly ~15s longer to break then full deconstruction.
|
||||
|
||||
@@ -0,0 +1,84 @@
|
||||
/obj/machinery/computer/rdservercontrol
|
||||
name = "R&D Server Controller"
|
||||
desc = "Manages access to research databases and consoles."
|
||||
icon_screen = "rdcomp"
|
||||
icon_keyboard = "rd_key"
|
||||
circuit = /obj/item/circuitboard/computer/rdservercontrol
|
||||
req_access = list(ACCESS_RD)
|
||||
|
||||
///Connected techweb node the server is connected to.
|
||||
var/datum/techweb/stored_research
|
||||
|
||||
/obj/machinery/computer/rdservercontrol/Initialize(mapload, obj/item/circuitboard/C)
|
||||
. = ..()
|
||||
if(!CONFIG_GET(flag/no_default_techweb_link) && !stored_research)
|
||||
stored_research = SSresearch.science_tech
|
||||
|
||||
/obj/machinery/computer/rdservercontrol/multitool_act(mob/living/user, obj/item/multitool/tool)
|
||||
if(!QDELETED(tool.buffer) && istype(tool.buffer, /datum/techweb))
|
||||
stored_research = tool.buffer
|
||||
balloon_alert(user, "techweb connected")
|
||||
return TRUE
|
||||
|
||||
/obj/machinery/computer/rdservercontrol/emag_act(mob/user)
|
||||
if(obj_flags & EMAGGED)
|
||||
return
|
||||
obj_flags |= EMAGGED
|
||||
playsound(src, SFX_SPARKS, 75, TRUE, SHORT_RANGE_SOUND_EXTRARANGE)
|
||||
balloon_alert(user, "console emagged")
|
||||
|
||||
/obj/machinery/computer/rdservercontrol/ui_interact(mob/user, datum/tgui/ui)
|
||||
. = ..()
|
||||
ui = SStgui.try_update_ui(user, src, ui)
|
||||
if(!ui)
|
||||
ui = new(user, src, "ServerControl", name)
|
||||
ui.open()
|
||||
|
||||
/obj/machinery/computer/rdservercontrol/ui_data(mob/user)
|
||||
var/list/data = list()
|
||||
|
||||
data["server_connected"] = !!stored_research
|
||||
|
||||
if(stored_research)
|
||||
data["logs"] += stored_research.research_logs
|
||||
|
||||
for(var/obj/machinery/rnd/server/server as anything in stored_research.techweb_servers)
|
||||
data["servers"] += list(list(
|
||||
"server_name" = server,
|
||||
"server_details" = server.get_status_text(),
|
||||
"server_disabled" = server.research_disabled,
|
||||
"server_ref" = REF(server),
|
||||
))
|
||||
|
||||
for(var/obj/machinery/computer/rdconsole/console as anything in stored_research.consoles_accessing)
|
||||
data["consoles"] += list(list(
|
||||
"console_name" = console,
|
||||
"console_location" = get_area(console),
|
||||
"console_locked" = console.locked,
|
||||
"console_ref" = REF(console),
|
||||
))
|
||||
|
||||
return data
|
||||
|
||||
/obj/machinery/computer/rdservercontrol/ui_act(action, params)
|
||||
. = ..()
|
||||
if(.)
|
||||
return TRUE
|
||||
if(!allowed(usr) && !(obj_flags & EMAGGED))
|
||||
balloon_alert(usr, "access denied!")
|
||||
playsound(src, 'sound/machines/click.ogg', 20, TRUE)
|
||||
return TRUE
|
||||
|
||||
switch(action)
|
||||
if("lockdown_server")
|
||||
var/obj/machinery/rnd/server/server_selected = locate(params["selected_server"]) in stored_research.techweb_servers
|
||||
if(!server_selected)
|
||||
return FALSE
|
||||
server_selected.toggle_disable(usr)
|
||||
return TRUE
|
||||
if("lock_console")
|
||||
var/obj/machinery/computer/rdconsole/console_selected = locate(params["selected_console"]) in stored_research.consoles_accessing
|
||||
if(!console_selected)
|
||||
return FALSE
|
||||
console_selected.locked = !console_selected.locked
|
||||
return TRUE
|
||||
@@ -30,7 +30,7 @@
|
||||
var/list/deconstructed_items = list()
|
||||
/// Available research points, type = number
|
||||
var/list/research_points = list()
|
||||
/// IC logs
|
||||
/// Game logs of research nodes, "node_name" "node_cost" "node_researcher" "node_research_location"
|
||||
var/list/research_logs = list()
|
||||
/// Current per-second production, used for display only.
|
||||
var/list/last_bitcoins = list()
|
||||
|
||||
@@ -4503,6 +4503,7 @@
|
||||
#include "code\modules\research\rdmachines.dm"
|
||||
#include "code\modules\research\research_disk.dm"
|
||||
#include "code\modules\research\server.dm"
|
||||
#include "code\modules\research\server_control.dm"
|
||||
#include "code\modules\research\stock_parts.dm"
|
||||
#include "code\modules\research\anomaly\anomaly_core.dm"
|
||||
#include "code\modules\research\anomaly\anomaly_refinery.dm"
|
||||
|
||||
@@ -0,0 +1,152 @@
|
||||
import { BooleanLike } from 'common/react';
|
||||
import { useBackend } from '../backend';
|
||||
import { Button, Collapsible, Section, Table, NoticeBox } from '../components';
|
||||
import { Window } from '../layouts';
|
||||
|
||||
type Data = {
|
||||
server_connected: BooleanLike;
|
||||
servers: ServerData[];
|
||||
consoles: ConsoleData[];
|
||||
logs: LogData[];
|
||||
};
|
||||
|
||||
type ServerData = {
|
||||
server_name: string;
|
||||
server_details: string;
|
||||
server_disabled: string;
|
||||
server_ref: string;
|
||||
};
|
||||
|
||||
type ConsoleData = {
|
||||
console_name: string;
|
||||
console_location: string;
|
||||
console_locked: string;
|
||||
console_ref: string;
|
||||
};
|
||||
|
||||
type LogData = {
|
||||
node_name: string;
|
||||
node_cost: string;
|
||||
node_researcher: string;
|
||||
node_research_location: string;
|
||||
};
|
||||
|
||||
export const ServerControl = (props, context) => {
|
||||
const { act, data } = useBackend<Data>(context);
|
||||
const { server_connected, servers, consoles, logs } = data;
|
||||
if (!server_connected) {
|
||||
return (
|
||||
<Window width={575} height={450}>
|
||||
<Window.Content>
|
||||
<NoticeBox textAlign="center" danger>
|
||||
Not connected to a Server. Please sync one using a multitool.
|
||||
</NoticeBox>
|
||||
</Window.Content>
|
||||
</Window>
|
||||
);
|
||||
}
|
||||
return (
|
||||
<Window width={575} height={400} scrollable fill>
|
||||
<Window.Content scrollable>
|
||||
{!servers ? (
|
||||
<NoticeBox mt={2} info>
|
||||
No servers found.
|
||||
</NoticeBox>
|
||||
) : (
|
||||
<Section>
|
||||
<Table cellpadding="3" textAlign="center">
|
||||
<Table.Row header>
|
||||
<Table.Cell>Research Servers</Table.Cell>
|
||||
</Table.Row>
|
||||
{servers.map((server) => (
|
||||
<>
|
||||
<Table.Row header key={server} className="candystripe" />
|
||||
<Table.Cell> {server.server_name}</Table.Cell>
|
||||
<Button
|
||||
mt={1}
|
||||
tooltip={server.server_details}
|
||||
color={server.server_disabled ? 'bad' : 'good'}
|
||||
content={server.server_disabled ? 'Offline' : 'Online'}
|
||||
fluid
|
||||
textAlign="center"
|
||||
onClick={() =>
|
||||
act('lockdown_server', {
|
||||
selected_server: server.server_ref,
|
||||
})
|
||||
}
|
||||
/>
|
||||
</>
|
||||
))}
|
||||
</Table>
|
||||
</Section>
|
||||
)}
|
||||
|
||||
{!consoles ? (
|
||||
<NoticeBox mt={2} info>
|
||||
No consoles found.
|
||||
</NoticeBox>
|
||||
) : (
|
||||
<Section align="right">
|
||||
<Table cellpadding="3" textAlign="center">
|
||||
<Table.Row header>
|
||||
<Table.Cell>Research Consoles</Table.Cell>
|
||||
</Table.Row>
|
||||
{consoles.map((console) => (
|
||||
<>
|
||||
<Table.Row header key={console} className="candystripe" />
|
||||
<Table.Cell>
|
||||
{' '}
|
||||
{console.console_name} - Location:{' '}
|
||||
{console.console_location}{' '}
|
||||
</Table.Cell>
|
||||
<Button
|
||||
mt={1}
|
||||
color={console.console_locked ? 'bad' : 'good'}
|
||||
content={console.console_locked ? 'LOCKED' : 'UNLOCKED'}
|
||||
fluid
|
||||
textAlign="center"
|
||||
onClick={() =>
|
||||
act('lock_console', {
|
||||
selected_console: console.console_ref,
|
||||
})
|
||||
}
|
||||
/>
|
||||
</>
|
||||
))}
|
||||
</Table>
|
||||
</Section>
|
||||
)}
|
||||
|
||||
<Collapsible title="Research History">
|
||||
{!logs.length ? (
|
||||
<NoticeBox mt={2} info>
|
||||
No history found.
|
||||
</NoticeBox>
|
||||
) : (
|
||||
<Section>
|
||||
<Table>
|
||||
<Table.Row header>
|
||||
<Table.Cell>Research Name</Table.Cell>
|
||||
<Table.Cell>Cost</Table.Cell>
|
||||
<Table.Cell>Researcher Name</Table.Cell>
|
||||
<Table.Cell>Console Location</Table.Cell>
|
||||
</Table.Row>
|
||||
{logs.map((server_log) => (
|
||||
<Table.Row
|
||||
mt={1}
|
||||
key={server_log.node_name}
|
||||
className="candystripe">
|
||||
<Table.Cell>{server_log.node_name}</Table.Cell>
|
||||
<Table.Cell>{server_log.node_cost}</Table.Cell>
|
||||
<Table.Cell>{server_log.node_researcher}</Table.Cell>
|
||||
<Table.Cell>{server_log.node_research_location}</Table.Cell>
|
||||
</Table.Row>
|
||||
))}
|
||||
</Table>
|
||||
</Section>
|
||||
)}
|
||||
</Collapsible>
|
||||
</Window.Content>
|
||||
</Window>
|
||||
);
|
||||
};
|
||||
Reference in New Issue
Block a user