mirror of
https://github.com/Bubberstation/Bubberstation.git
synced 2026-08-23 13:10:02 +01:00
[MIRROR] Research queue (#28846)
* Research queue (#84731) ## About The Pull Request <img alt="2dZbpr8MK1" src="https://github.com/tgstation/tgstation/assets/3625094/dd78feba-224a-41a1-8d4a-83af3a8b68df"> Added an ability to queue up to one node per player in a techweb for an automatic research. You can queue up a node only when all requirements are met, but there are not enough points. People can't research when there is something in the queue, only add things to the queue. So a 40 points node can't be researched if someone queued up a 200 points node ahead of it. When a node is enqueued by RD, it is placed in front of the queue. The research button is available when the queue is empty. TODO: - [x] Bypass queue when the node cost is zero ## Why It's Good For The Game No need to stay at the console to wait for the points. No "Research" button spamming. ## Changelog 🆑 qol: Research nodes can be queued, one per player. RDs can place their node at the beginning of the queue. /🆑 * Research queue --------- Co-authored-by: Andrew <mt.forspam@gmail.com>
This commit is contained in:
@@ -36,7 +36,7 @@ SUBSYSTEM_DEF(research)
|
||||
var/list/techweb_nodes_experimental = list()
|
||||
///path = list(point type = value)
|
||||
var/list/techweb_point_items = list(
|
||||
/obj/item/assembly/signaler/anomaly = list(TECHWEB_POINT_TYPE_GENERIC = 10000)
|
||||
/obj/item/assembly/signaler/anomaly = list(TECHWEB_POINT_TYPE_GENERIC = TECHWEB_TIER_5_POINTS)
|
||||
)
|
||||
var/list/errored_datums = list()
|
||||
///Associated list of all point types that techwebs will have and their respective 'abbreviated' name.
|
||||
@@ -104,6 +104,13 @@ SUBSYSTEM_DEF(research)
|
||||
|
||||
techweb_list.last_income = world.time
|
||||
|
||||
if(techweb_list.research_queue_nodes.len)
|
||||
techweb_list.research_node_id(techweb_list.research_queue_nodes[1]) // Attempt to research the first node in queue if possible
|
||||
|
||||
for(var/datum/techweb_node/node as anything in techweb_list.research_queue_nodes)
|
||||
if(node.is_free(techweb_list)) // Automatically research all free nodes in queue if any
|
||||
techweb_list.research_node(node)
|
||||
|
||||
/datum/controller/subsystem/research/proc/autosort_categories()
|
||||
for(var/i in techweb_nodes)
|
||||
var/datum/techweb_node/I = techweb_nodes[i]
|
||||
|
||||
@@ -50,6 +50,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,
|
||||
@@ -64,6 +65,10 @@
|
||||
// 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])
|
||||
@@ -71,8 +76,11 @@
|
||||
|
||||
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
|
||||
@@ -111,6 +119,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(
|
||||
@@ -188,6 +202,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!")
|
||||
|
||||
@@ -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!")
|
||||
@@ -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,
|
||||
@@ -194,6 +209,10 @@ 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])
|
||||
@@ -201,8 +220,11 @@ Nothing else in the console has ID requirements.
|
||||
|
||||
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
|
||||
@@ -322,6 +344,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
|
||||
|
||||
@@ -70,6 +70,12 @@
|
||||
* 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
|
||||
@@ -325,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)
|
||||
|
||||
@@ -377,6 +417,10 @@
|
||||
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)
|
||||
|
||||
@@ -95,6 +95,17 @@
|
||||
|
||||
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))
|
||||
|
||||
|
||||
@@ -10,6 +10,7 @@ import {
|
||||
Flex,
|
||||
Icon,
|
||||
Input,
|
||||
LabeledList,
|
||||
Modal,
|
||||
ProgressBar,
|
||||
Section,
|
||||
@@ -147,6 +148,8 @@ export const TechwebContent = (props) => {
|
||||
t_disk,
|
||||
d_disk,
|
||||
locked,
|
||||
queue_nodes = [],
|
||||
node_cache,
|
||||
} = data;
|
||||
const [techwebRoute, setTechwebRoute] = useLocalState('techwebRoute', null);
|
||||
const [lastPoints, setLastPoints] = useState({});
|
||||
@@ -156,27 +159,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} label="Points">
|
||||
<b>{points[k]}</b>
|
||||
{!!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>
|
||||
@@ -493,9 +504,17 @@ const TechNode = (props) => {
|
||||
points = [],
|
||||
nodes,
|
||||
point_types_abbreviations = [],
|
||||
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,
|
||||
@@ -555,6 +574,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"
|
||||
@@ -566,15 +619,6 @@ const TechNode = (props) => {
|
||||
Details
|
||||
</Button>
|
||||
)}
|
||||
{tier > 0 && (
|
||||
<Button
|
||||
icon="lightbulb"
|
||||
disabled={!can_unlock || tier > 1}
|
||||
onClick={() => act('researchNode', { node_id: id })}
|
||||
>
|
||||
Research
|
||||
</Button>
|
||||
)}
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user