diff --git a/code/modules/modular_computers/file_system/programs/techweb.dm b/code/modules/modular_computers/file_system/programs/techweb.dm index c01c865fbf7..3f9afa61079 100644 --- a/code/modules/modular_computers/file_system/programs/techweb.dm +++ b/code/modules/modular_computers/file_system/programs/techweb.dm @@ -80,7 +80,8 @@ "can_unlock" = stored_research.can_unlock_node(node), "have_experiments_done" = stored_research.have_experiments_for_node(node), "tier" = stored_research.tiers[node.id], - "enqueued_by_user" = enqueued_by_user + "enqueued_by_user" = enqueued_by_user, + "discount_boosted" = node.discount_boosted )) // Get experiments and serialize them @@ -156,6 +157,8 @@ node_cache[compressed_id]["required_experiments"] = node.required_experiments if (LAZYLEN(node.discount_experiments)) node_cache[compressed_id]["discount_experiments"] = node.discount_experiments + if (LAZYLEN(node.discount_boosts)) + node_cache[compressed_id]["discount_boosts"] = node.discount_boosts // Build design cache var/design_cache = list() diff --git a/code/modules/research/ordnance/_scipaper.dm b/code/modules/research/ordnance/_scipaper.dm index e5fa3c3c8f0..17cab50c6d2 100644 --- a/code/modules/research/ordnance/_scipaper.dm +++ b/code/modules/research/ordnance/_scipaper.dm @@ -289,6 +289,14 @@ /// Associative list of which technology the partner might be able to boost and by how much. var/list/boostable_nodes = list() +/datum/scientific_partner/New() + . = ..() + // Convey boosts to their associated nodes so that they can then be passed + // to techweb UIs as static data. + for(var/node_id in boostable_nodes) + var/datum/techweb_node/node = SSresearch.techweb_node_by_id(node_id) + node.discount_boosts[TECHWEB_POINT_TYPE_GENERIC] = boostable_nodes[node_id] + /datum/scientific_partner/proc/purchase_boost(datum/techweb/purchasing_techweb, datum/techweb_node/node) var/possible_boost = allowed_to_boost(purchasing_techweb, node.id) if(!possible_boost) @@ -301,9 +309,10 @@ return TRUE /datum/scientific_partner/proc/allowed_to_boost(datum/techweb/purchasing_techweb, node_id) + var/datum/techweb_node/boosting_node = SSresearch.techweb_node_by_id(node_id) if(purchasing_techweb.scientific_cooperation[type] < (boostable_nodes[node_id] * SCIENTIFIC_COOPERATION_PURCHASE_MULTIPLIER)) // Too expensive return FALSE - if((TECHWEB_POINT_TYPE_GENERIC in purchasing_techweb.boosted_nodes[node_id]) && (purchasing_techweb.boosted_nodes[node_id][TECHWEB_POINT_TYPE_GENERIC] >= boostable_nodes[node_id])) // Already bought or we have a bigger discount + if((boosting_node.discount_boosted) && (boosting_node.discount_boosts[TECHWEB_POINT_TYPE_GENERIC] >= boostable_nodes[node_id])) // Already bought or we have a bigger discount return FALSE if(node_id in purchasing_techweb.researched_nodes) return SCIPAPER_ALREADY_BOUGHT diff --git a/code/modules/research/rdconsole.dm b/code/modules/research/rdconsole.dm index 36c3a43a603..60fa5907556 100644 --- a/code/modules/research/rdconsole.dm +++ b/code/modules/research/rdconsole.dm @@ -243,7 +243,8 @@ Nothing else in the console has ID requirements. "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 + "enqueued_by_user" = enqueued_by_user, + "discount_boosted" = n.discount_boosted )) // Get experiments and serialize them @@ -305,6 +306,8 @@ Nothing else in the console has ID requirements. node_cache[compressed_id]["required_experiments"] = node.required_experiments if (LAZYLEN(node.discount_experiments)) node_cache[compressed_id]["discount_experiments"] = node.discount_experiments + if (LAZYLEN(node.discount_boosts)) + node_cache[compressed_id]["discount_boosts"] = node.discount_boosts // Build design cache var/design_cache = list() diff --git a/code/modules/research/techweb/_techweb.dm b/code/modules/research/techweb/_techweb.dm index ade382a0265..8d492aa4af9 100644 --- a/code/modules/research/techweb/_techweb.dm +++ b/code/modules/research/techweb/_techweb.dm @@ -22,8 +22,6 @@ var/list/researched_designs = list() /// Custom inserted designs like from disks that should survive recalculation. var/list/custom_designs = list() - /// Already boosted nodes that can't be boosted again. node id = path of boost object. - var/list/boosted_nodes = list() /// Hidden nodes. id = TRUE. Used for unhiding nodes when requirements are met by removing the entry of the node. var/list/hidden_nodes = list() /// List of items already deconstructed for research points, preventing infinite research point generation. @@ -433,9 +431,10 @@ /datum/techweb/proc/boost_techweb_node(datum/techweb_node/node, list/pointlist) if(!istype(node)) return FALSE - LAZYINITLIST(boosted_nodes[node.id]) - for(var/point_type in pointlist) - boosted_nodes[node.id][point_type] = max(boosted_nodes[node.id][point_type], pointlist[point_type]) + LAZYINITLIST(node.discount_boosts) + for(var/point_type in pointlist) // Essentially applies the greater boost(s) between the newer and any existing. + node.discount_boosts[point_type] = max(node.discount_boosts[point_type], pointlist[point_type]) + node.discount_boosted = TRUE unhide_node(node) update_node_status(node) return TRUE diff --git a/code/modules/research/techweb/_techweb_node.dm b/code/modules/research/techweb/_techweb_node.dm index 104e475b7e5..0eccb61c4ec 100644 --- a/code/modules/research/techweb/_techweb_node.dm +++ b/code/modules/research/techweb/_techweb_node.dm @@ -36,6 +36,13 @@ var/list/required_experiments = list() /// If completed, these experiments give a specific point amount discount to the node. var/list/discount_experiments = list() + /// Boost quantities from non-experiment sources (i.e., toxins papers). + /// Indexed by point type to boost amount (with only one boost per point type). + var/list/discount_boosts = list() + /// Boolean indicating whether or not this node is boosted by non-experiments. + /// This will need to be changed to a list of point types boosted if boosts + /// should ever need to vary by point type. + var/discount_boosted = FALSE /// When this node is completed, allows these experiments to be performed. var/list/experiments_to_unlock = list() /// Whether or not this node should show on the wiki @@ -92,11 +99,10 @@ if(host.completed_experiments[experiment_type]) //do we have this discount_experiment unlocked? actual_costs[cost_type] -= discount_experiments[experiment_type] - if(host.boosted_nodes[id]) // Boosts should be subservient to experiments. - var/list/boostlist = host.boosted_nodes[id] - for(var/booster in boostlist) + if(discount_boosts && discount_boosted) // Boosts should be subservient to experiments. + for(var/booster in discount_boosts) if(actual_costs[booster]) - actual_costs[booster] = max(actual_costs[booster] - boostlist[booster], 0) + actual_costs[booster] = max(actual_costs[booster] - discount_boosts[booster], 0) return actual_costs diff --git a/tgui/packages/tgui/interfaces/Techweb/helpers.ts b/tgui/packages/tgui/interfaces/Techweb/helpers.ts index 12e042963d7..8215572d64f 100644 --- a/tgui/packages/tgui/interfaces/Techweb/helpers.ts +++ b/tgui/packages/tgui/interfaces/Techweb/helpers.ts @@ -51,6 +51,7 @@ function selectRemappedStaticData(data: TechWebData) { unlock_ids: map(node.unlock_ids || [], remapId), required_experiments: node.required_experiments || [], discount_experiments: node.discount_experiments || [], + discount_boosts: node.discount_boosts || [], }; } diff --git a/tgui/packages/tgui/interfaces/Techweb/nodes/TechNode.tsx b/tgui/packages/tgui/interfaces/Techweb/nodes/TechNode.tsx index 6e4d7aadb40..613fe82708d 100644 --- a/tgui/packages/tgui/interfaces/Techweb/nodes/TechNode.tsx +++ b/tgui/packages/tgui/interfaces/Techweb/nodes/TechNode.tsx @@ -40,6 +40,7 @@ export function TechNode(props: Props) { tier, enqueued_by_user, is_free, + discount_boosted, } = node; const { name, @@ -49,6 +50,7 @@ export function TechNode(props: Props) { prereq_ids, required_experiments, discount_experiments, + discount_boosts, } = node_cache[id]; const [techwebRoute, setTechwebRoute] = useTechWebRoute(); @@ -86,12 +88,20 @@ export function TechNode(props: Props) { // Notice that this logic will have to be changed if we make the discounts // pool-specific - const nodeDiscount = Object.keys(discount_experiments) + const nodeDiscountExperiments = Object.keys(discount_experiments) .filter((x) => experiments[x]?.completed) .reduce((tot, curr) => { return tot + discount_experiments[curr]; }, 0); + // Will need to be changed (along with some backend/DM code) if boosts should + // ever vary by point type. As is, this simply adds up all discount boosts. + const nodeDiscountBoosts = discount_boosted + ? Object.keys(discount_boosts).reduce((tot, curr) => { + return tot + discount_boosts[curr]; + }, 0) + : 0; + return (
{costs.map((k) => { - const reqPts = Math.max(0, k.value - nodeDiscount); + const reqPts = Math.max( + 0, + k.value - nodeDiscountExperiments - nodeDiscountBoosts, + ); const nodeProg = Math.min(reqPts, points[k.type]) || 0; return ( diff --git a/tgui/packages/tgui/interfaces/Techweb/types.ts b/tgui/packages/tgui/interfaces/Techweb/types.ts index 0c40c46f47d..9ccfd0d3991 100644 --- a/tgui/packages/tgui/interfaces/Techweb/types.ts +++ b/tgui/packages/tgui/interfaces/Techweb/types.ts @@ -16,6 +16,7 @@ export type NodeCache = { description: string; design_ids: string[]; discount_experiments: Record; + discount_boosts: Record; name: string; prereq_ids: string[]; required_experiments?: string[]; @@ -32,6 +33,7 @@ export type TechwebNode = { can_unlock: BooleanLike; enqueued_by_user: BooleanLike; have_experiments_done: BooleanLike; + discount_boosted: BooleanLike; id: string; is_free: BooleanLike; tier: number;