Skip to content

[Mirror/Ports] Research queue #5918

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 8 commits into from
Mar 30, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions code/controllers/subsystem/research.dm
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,14 @@ SUBSYSTEM_DEF(research)

techweb_list.last_income = world.time

if(length(techweb_list.research_queue_nodes))
techweb_list.research_node_id(techweb_list.research_queue_nodes[1]) // Attempt to research the first node in queue if possible

for(var/node_id in techweb_list.research_queue_nodes)
var/datum/techweb_node/node = SSresearch.techweb_node_by_id(node_id)
if(node.is_free(techweb_list)) // Automatically research all free nodes in queue if any
techweb_list.research_node(node)

for(var/core_type in slime_core_prices)
var/obj/item/slime_extract/core = core_type
var/price_mod = rand(SLIME_RANDOM_MODIFIER_MIN * 1000000, SLIME_RANDOM_MODIFIER_MAX * 1000000) / 1000000
Expand Down
30 changes: 29 additions & 1 deletion code/modules/modular_computers/file_system/programs/techweb.dm
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@
return data
data += list(
"nodes" = list(),
"queue_nodes" = stored_research.research_queue_nodes,
"experiments" = list(),
"researched_designs" = stored_research.researched_designs,
"points" = stored_research.research_points,
Expand All @@ -61,15 +62,22 @@
// Serialize all nodes to display
for(var/tier in stored_research.tiers)
var/datum/techweb_node/node = SSresearch.techweb_node_by_id(tier)
var/enqueued_by_user = FALSE

if((tier in stored_research.research_queue_nodes) && stored_research.research_queue_nodes[tier] == user)
enqueued_by_user = TRUE

// Ensure node is supposed to be visible
if (stored_research.hidden_nodes[tier])
continue

data["nodes"] += list(list(
"id" = node.id,
"is_free" = node.is_free(stored_research),
"can_unlock" = stored_research.can_unlock_node(node),
"tier" = stored_research.tiers[node.id]
"have_experiments_done" = stored_research.have_experiments_for_node(node),
"tier" = stored_research.tiers[node.id],
"enqueued_by_user" = enqueued_by_user
))

// Get experiments and serialize them
Expand Down Expand Up @@ -107,6 +115,12 @@
if ("researchNode")
research_node(params["node_id"], usr)
return TRUE
if ("enqueueNode")
enqueue_node(params["node_id"], usr)
return TRUE
if ("dequeueNode")
dequeue_node(params["node_id"], usr)
return TRUE

/datum/computer_file/program/science/ui_static_data(mob/user)
. = list(
Expand Down Expand Up @@ -183,6 +197,20 @@
id_cache_seq += 1
return id_cache[id]

/datum/computer_file/program/science/proc/enqueue_node(id, mob/user)
if(!stored_research || !stored_research.available_nodes[id] || stored_research.researched_nodes[id])
computer.say("Node enqueue failed: Either no techweb is found, node is already researched or is not available!")
return FALSE
stored_research.enqueue_node(id, user)
return TRUE

/datum/computer_file/program/science/proc/dequeue_node(id, mob/user)
if(!stored_research || !stored_research.available_nodes[id] || stored_research.researched_nodes[id])
computer.say("Node dequeue failed: Either no techweb is found, node is already researched or is not available!")
return FALSE
stored_research.dequeue_node(id, user)
return TRUE

/datum/computer_file/program/science/proc/research_node(id, mob/user)
if(!stored_research || !stored_research.available_nodes[id] || stored_research.researched_nodes[id])
computer.say("Node unlock failed: Either no techweb is found, node is already researched or is not available!")
Expand Down
28 changes: 28 additions & 0 deletions code/modules/research/rdconsole.dm
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,20 @@ Nothing else in the console has ID requirements.
stored_research = tool.buffer
return TRUE

/obj/machinery/computer/rdconsole/proc/enqueue_node(id, mob/user)
if(!stored_research || !stored_research.available_nodes[id] || stored_research.researched_nodes[id])
say("Node enqueue failed: Either no techweb is found, node is already researched or is not available!")
return FALSE
stored_research.enqueue_node(id, user)
return TRUE

/obj/machinery/computer/rdconsole/proc/dequeue_node(id, mob/user)
if(!stored_research || !stored_research.available_nodes[id] || stored_research.researched_nodes[id])
say("Node dequeue failed: Either no techweb is found, node is already researched or is not available!")
return FALSE
stored_research.dequeue_node(id, user)
return TRUE

/obj/machinery/computer/rdconsole/proc/research_node(id, mob/user)
if(!stored_research || !stored_research.available_nodes[id] || stored_research.researched_nodes[id])
say("Node unlock failed: Either no techweb is found, node is already researched or is not available!")
Expand Down Expand Up @@ -171,6 +185,7 @@ Nothing else in the console has ID requirements.
return data
data += list(
"nodes" = list(),
"queue_nodes" = stored_research.research_queue_nodes,
"experiments" = list(),
"researched_designs" = stored_research.researched_designs,
"points" = stored_research.research_points,
Expand All @@ -194,15 +209,22 @@ Nothing else in the console has ID requirements.
// Serialize all nodes to display
for(var/v in stored_research.tiers)
var/datum/techweb_node/n = SSresearch.techweb_node_by_id(v)
var/enqueued_by_user = FALSE

if((v in stored_research.research_queue_nodes) && stored_research.research_queue_nodes[v] == user)
enqueued_by_user = TRUE

// Ensure node is supposed to be visible
if (stored_research.hidden_nodes[v])
continue

data["nodes"] += list(list(
"id" = n.id,
"is_free" = n.is_free(stored_research),
"can_unlock" = stored_research.can_unlock_node(n),
"have_experiments_done" = stored_research.have_experiments_for_node(n),
"tier" = stored_research.tiers[n.id],
"enqueued_by_user" = enqueued_by_user
))

// Get experiments and serialize them
Expand Down Expand Up @@ -321,6 +343,12 @@ Nothing else in the console has ID requirements.
if ("researchNode")
research_node(params["node_id"], usr)
return TRUE
if ("enqueueNode")
enqueue_node(params["node_id"], usr)
return TRUE
if ("dequeueNode")
dequeue_node(params["node_id"], usr)
return TRUE
if ("ejectDisk")
eject_disk(params["type"])
return TRUE
Expand Down
44 changes: 43 additions & 1 deletion code/modules/research/techweb/_techweb.dm
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,11 @@
* Filled with nulls on init, populated only on publication.
*/
var/list/published_papers
/**
* Assoc list of nodes queued for automatic research when there are enough points available
* research_queue_nodes[node_id] = user_enqueued
*/
var/list/research_queue_nodes = list()

/datum/techweb/New()
SSresearch.techwebs += src
Expand Down Expand Up @@ -326,6 +331,40 @@
/datum/techweb/proc/printout_points()
return techweb_point_display_generic(research_points)

/datum/techweb/proc/enqueue_node(id, mob/user)
var/mob/living/carbon/human/human_user = user
var/is_rd = FALSE
if(human_user.wear_id)
var/list/access = human_user.wear_id.GetAccess()
if(ACCESS_RD in access)
is_rd = TRUE

if(id in research_queue_nodes)
if(is_rd)
research_queue_nodes.Remove(id)
else
return FALSE

for(var/node_id in research_queue_nodes)
if(research_queue_nodes[node_id] == user)
research_queue_nodes.Remove(node_id)

if (is_rd)
research_queue_nodes.Insert(1, id)
research_queue_nodes[id] = user

return TRUE

/datum/techweb/proc/dequeue_node(id, mob/user)
if(!(id in research_queue_nodes))
return FALSE
if(research_queue_nodes[id] != user)
return FALSE

research_queue_nodes.Remove(id)

return TRUE

/datum/techweb/proc/research_node_id(id, force, auto_update_points, get_that_dosh_id)
return research_node(SSresearch.techweb_node_by_id(id), force, auto_update_points, get_that_dosh_id)

Expand Down Expand Up @@ -373,7 +412,10 @@
// Avoid logging the same 300+ lines at the beginning of every round
if (MC_RUNNING())
log_research(log_message)


// Dequeue
if(node.id in research_queue_nodes)
research_queue_nodes.Remove(node.id)
return TRUE

/datum/techweb/proc/unresearch_node_id(id)
Expand Down
13 changes: 12 additions & 1 deletion code/modules/research/techweb/_techweb_node.dm
Original file line number Diff line number Diff line change
Expand Up @@ -88,9 +88,20 @@
if(actual_costs[booster])
var/delta = max(0, actual_costs[booster] - 250)
actual_costs[booster] -= min(boostlist[booster], delta)

return actual_costs

/datum/techweb_node/proc/is_free(datum/techweb/host)
var/list/costs = get_price(host)
var/total_points = 0

for(var/point_type in costs)
total_points += costs[point_type]

if(total_points == 0)
return TRUE
return FALSE

/datum/techweb_node/proc/price_display(datum/techweb/TN)
return techweb_point_display_generic(get_price(TN))

Expand Down
114 changes: 82 additions & 32 deletions tgui/packages/tgui/interfaces/Techweb.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import {
Tabs,
Box,
Input,
LabeledList,
Flex,
ProgressBar,
Collapsible,
Expand Down Expand Up @@ -152,6 +153,8 @@ export const TechwebContent = (props) => {
t_disk,
d_disk,
locked,
queue_nodes = [],
node_cache,
} = data;
const [techwebRoute, setTechwebRoute] = useLocalState('techwebRoute', null);
const [lastPoints, setLastPoints] = useLocalState('lastPoints', {});
Expand All @@ -161,27 +164,35 @@ export const TechwebContent = (props) => {
<Flex.Item className="Techweb__HeaderSection">
<Flex className="Techweb__HeaderContent">
<Flex.Item>
<Box>
Available points:
<ul className="Techweb__PointSummary">
{Object.keys(points).map((k) => (
<li key={k}>
<b>{k}</b>: {points[k]}
{!!points_last_tick[k] && ` (+${points_last_tick[k]}/sec)`}
</li>
))}
</ul>
</Box>
<Box>
Security protocols:
<span
className={`Techweb__SecProtocol ${
!!sec_protocols && 'engaged'
}`}
>
{sec_protocols ? 'Engaged' : 'Disengaged'}
</span>
</Box>
<LabeledList>
<LabeledList.Item label="Security">
<span
className={`Techweb__SecProtocol ${
!!sec_protocols && 'engaged'
}`}
>
{sec_protocols ? 'Engaged' : 'Disengaged'}
</span>
</LabeledList.Item>
{Object.keys(points).map((k) => (
<LabeledList.Item key={k}>
<b>{k}</b>: {points[k]}
{!!points_last_tick[k] && ` (+${points_last_tick[k]}/sec)`}
</LabeledList.Item>
))}
<LabeledList.Item label="Queue">
{queue_nodes.length !== 0
? Object.keys(queue_nodes).map((node_id) => (
<Button
key={node_id}
tooltip={`Added by: ${queue_nodes[node_id]}`}
>
{node_cache[node_id].name}
</Button>
))
: 'Empty'}
</LabeledList.Item>
</LabeledList>
</Flex.Item>
<Flex.Item grow={1} />
<Flex.Item>
Expand Down Expand Up @@ -488,9 +499,23 @@ const TechNodeDetail = (props) => {

const TechNode = (props) => {
const { act, data } = useRemappedBackend();
const { node_cache, design_cache, experiments, points, nodes } = data;
const {
node_cache,
design_cache,
experiments,
points,
nodes,
queue_nodes = [],
} = data;
const { node, nodetails, nocontrols } = props;
const { id, can_unlock, tier } = node;
const {
id,
can_unlock,
have_experiments_done,
tier,
enqueued_by_user,
is_free,
} = node;
const {
name,
description,
Expand Down Expand Up @@ -550,6 +575,40 @@ const TechNode = (props) => {
buttons={
!nocontrols && (
<>
{tier > 0 &&
(!!can_unlock && (is_free || queue_nodes.length === 0) ? (
<Button
icon="lightbulb"
disabled={!can_unlock || tier > 1 || queue_nodes.length > 0}
onClick={() => act('researchNode', { node_id: id })}
>
Research
</Button>
) : enqueued_by_user ? (
<Button
icon="trash"
color="bad"
onClick={() => act('dequeueNode', { node_id: id })}
>
Dequeue
</Button>
) : id in queue_nodes && !enqueued_by_user ? (
<Button icon="check" color="good">
Queued
</Button>
) : (
<Button
icon="lightbulb"
disabled={
!have_experiments_done ||
id in queue_nodes ||
techcompl < prereq_ids.length
}
onClick={() => act('enqueueNode', { node_id: id })}
>
Enqueue
</Button>
))}
{!nodetails && (
<Button
icon="tasks"
Expand All @@ -561,15 +620,6 @@ const TechNode = (props) => {
Details
</Button>
)}
{tier > 0 && (
<Button
icon="lightbulb"
disabled={!can_unlock || tier > 1}
onClick={() => act('researchNode', { node_id: id })}
>
Research
</Button>
)}
</>
)
}
Expand Down
Loading