From 4116f7ec79a0bc0071ed38872c8e5eaad6546f97 Mon Sep 17 00:00:00 2001 From: kevinz000 <2003111+kevinz000@users.noreply.github.com> Date: Fri, 5 Oct 2018 11:52:07 -0700 Subject: [PATCH] Techwebs Backend Refactor - Removes references from techwebs and uses IDs instead (#40596) Yeah yeah I know no opening too many WIP PRs but this one's [ready] and I want to make sure any furthur techweb development doesn't keep using the old reference system which will make refactoring it harder, and this makes it easier for coders to do stuff in theory (at least for me), standardizes getting a node/design, and makes stuff actually GC properly. --- code/__DEFINES/misc.dm | 5 + code/__HELPERS/_lists.dm | 6 + code/controllers/subsystem/research.dm | 198 +++++++++++++++++- code/game/machinery/autolathe.dm | 6 +- code/game/machinery/computer/Operating.dm | 2 +- code/game/machinery/limbgrower.dm | 4 +- code/game/mecha/mech_fabricator.dm | 10 +- code/game/objects/items.dm | 4 +- code/modules/hydroponics/biogenerator.dm | 2 +- code/modules/mining/machine_processing.dm | 2 +- code/modules/mining/machine_redemption.dm | 2 +- code/modules/research/designs.dm | 7 +- code/modules/research/destructive_analyzer.dm | 4 +- code/modules/research/experimentor.dm | 12 +- .../modules/research/machinery/_production.dm | 8 +- .../research/nanites/nanite_program_hub.dm | 2 +- code/modules/research/rdconsole.dm | 113 +++++----- .../research/techweb/__techweb_helpers.dm | 170 --------------- code/modules/research/techweb/_techweb.dm | 131 ++++++------ .../modules/research/techweb/_techweb_node.dm | 75 ++++++- 20 files changed, 431 insertions(+), 332 deletions(-) diff --git a/code/__DEFINES/misc.dm b/code/__DEFINES/misc.dm index 34c89a4e9e2..3bcf1b5c46b 100644 --- a/code/__DEFINES/misc.dm +++ b/code/__DEFINES/misc.dm @@ -440,3 +440,8 @@ GLOBAL_LIST_INIT(pda_styles, list(MONO, VT, ORBITRON, SHARE)) #define AREASELECT_CORNERA "corner A" #define AREASELECT_CORNERB "corner B" + +#define VARSET_FROM_LIST(L, V) if(L && L[#V]) V = L[#V] +#define VARSET_FROM_LIST_IF(L, V, C...) if(L && L[#V] && (C)) V = L[#V] +#define VARSET_TO_LIST(L, V) if(L) L[#V] = V +#define VARSET_TO_LIST_IF(L, V, C...) if(L && (C)) L[#V] = V diff --git a/code/__HELPERS/_lists.dm b/code/__HELPERS/_lists.dm index fed283adcdd..5640d6b109f 100644 --- a/code/__HELPERS/_lists.dm +++ b/code/__HELPERS/_lists.dm @@ -565,3 +565,9 @@ L1[key] += other_value else L1[key] = other_value + +/proc/assoc_list_strip_value(list/input) + var/list/ret = list() + for(var/key in input) + ret += key + return ret diff --git a/code/controllers/subsystem/research.dm b/code/controllers/subsystem/research.dm index 295d5fe541f..127a76075eb 100644 --- a/code/controllers/subsystem/research.dm +++ b/code/controllers/subsystem/research.dm @@ -4,18 +4,26 @@ SUBSYSTEM_DEF(research) priority = FIRE_PRIORITY_RESEARCH wait = 10 init_order = INIT_ORDER_RESEARCH + //TECHWEB STATIC + var/list/techweb_nodes = list() //associative id = node datum + var/list/techweb_designs = list() //associative id = node datum + var/list/datum/techweb/techwebs = list() + var/datum/techweb/science/science_tech + var/datum/techweb/admin/admin_tech + var/datum/techweb_node/error_node/error_node //These two are what you get if a node/design is deleted and somehow still stored in a console. + var/datum/design/error_design/error_design + + //ERROR LOGGING var/list/invalid_design_ids = list() //associative id = number of times var/list/invalid_node_ids = list() //associative id = number of times var/list/invalid_node_boost = list() //associative id = error message + var/list/obj/machinery/rnd/server/servers = list() - var/datum/techweb/science/science_tech - var/datum/techweb/admin/admin_tech - var/list/techweb_nodes = list() //associative id = node datum - var/list/techweb_categories = list() //category name = list(node.id = node) - var/list/techweb_designs = list() //associative id = node datum - var/list/techweb_nodes_starting = list() //associative id = node datum + + var/list/techweb_nodes_starting = list() //associative id = TRUE + var/list/techweb_categories = list() //category name = list(node.id = TRUE) var/list/techweb_boost_items = list() //associative double-layer path = list(id = list(point_type = point_discount)) - var/list/techweb_nodes_hidden = list() //Nodes that should be hidden by default. + var/list/techweb_nodes_hidden = list() //Node ids that should be hidden by default. var/list/techweb_point_items = list( //path = list(point type = value) /obj/item/assembly/signaler/anomaly = list(TECHWEB_POINT_TYPE_GENERIC = 10000) ) @@ -38,6 +46,8 @@ SUBSYSTEM_DEF(research) science_tech = new /datum/techweb/science admin_tech = new /datum/techweb/admin autosort_categories() + error_design = new + error_node = new return ..() /datum/controller/subsystem/research/fire() @@ -74,6 +84,176 @@ SUBSYSTEM_DEF(research) for(var/i in techweb_nodes) var/datum/techweb_node/I = techweb_nodes[i] if(techweb_categories[I.category]) - techweb_categories[I.category][I.id] = I + techweb_categories[I.category][I.id] = TRUE else - techweb_categories[I.category] = list(I.id = I) + techweb_categories[I.category] = list(I.id = TRUE) + +/datum/controller/subsystem/research/proc/techweb_node_by_id(id) + return techweb_nodes[id] || error_node + +/datum/controller/subsystem/research/proc/techweb_design_by_id(id) + return techweb_designs[id] || error_design + +/datum/controller/subsystem/research/proc/on_design_deletion(datum/design/D) + for(var/i in techweb_nodes) + var/datum/techweb_node/TN = techwebs[i] + TN.on_design_deletion(TN) + for(var/i in techwebs) + var/datum/techweb/T = i + T.recalculate_nodes(TRUE) + +/datum/controller/subsystem/research/proc/on_node_deletion(datum/techweb_node/TN) + for(var/i in techweb_nodes) + var/datum/techweb_node/TN2 = techwebs[i] + TN2.on_node_deletion(TN) + for(var/i in techwebs) + var/datum/techweb/T = i + T.recalculate_nodes(TRUE) + +/datum/controller/subsystem/research/proc/initialize_all_techweb_nodes(clearall = FALSE) + if(islist(techweb_nodes) && clearall) + QDEL_LIST(techweb_nodes) + if(islist(techweb_nodes_starting && clearall)) + techweb_nodes_starting.Cut() + var/list/returned = list() + for(var/path in subtypesof(/datum/techweb_node)) + var/datum/techweb_node/TN = path + if(isnull(initial(TN.id))) + continue + TN = new path + if(returned[initial(TN.id)]) + stack_trace("WARNING: Techweb node ID clash with ID [initial(TN.id)] detected!") + errored_datums[TN] = initial(TN.id) + continue + returned[initial(TN.id)] = TN + if(TN.starting_node) + techweb_nodes_starting[TN.id] = TRUE + for(var/id in techweb_nodes) + var/datum/techweb_node/TN = techweb_nodes[id] + TN.Initialize() + techweb_nodes = returned + verify_techweb_nodes() //Verify all nodes have ids and such. + calculate_techweb_nodes() + calculate_techweb_boost_list() + verify_techweb_nodes() //Verify nodes and designs have been crosslinked properly. + +/datum/controller/subsystem/research/proc/initialize_all_techweb_designs(clearall = FALSE) + if(islist(techweb_designs) && clearall) + QDEL_LIST(techweb_designs) + var/list/returned = list() + for(var/path in subtypesof(/datum/design)) + var/datum/design/DN = path + if(isnull(initial(DN.id))) + stack_trace("WARNING: Design with null ID detected. Build path: [initial(DN.build_path)]") + continue + else if(initial(DN.id) == DESIGN_ID_IGNORE) + continue + DN = new path + if(returned[initial(DN.id)]) + stack_trace("WARNING: Design ID clash with ID [initial(DN.id)] detected!") + errored_datums[DN] = initial(DN.id) + continue + returned[initial(DN.id)] = DN + techweb_designs = returned + verify_techweb_designs() + +/datum/controller/subsystem/research/proc/verify_techweb_nodes() + for(var/n in techweb_nodes) + var/datum/techweb_node/N = techweb_nodes[n] + if(!istype(N)) + WARNING("Invalid research node with ID [n] detected and removed.") + techweb_nodes -= n + research_node_id_error(n) + for(var/p in N.prereq_ids) + var/datum/techweb_node/P = techweb_nodes[p] + if(!istype(P)) + WARNING("Invalid research prerequisite node with ID [p] detected in node [N.display_name]\[[N.id]\] removed.") + N.prereq_ids -= p + research_node_id_error(p) + for(var/d in N.design_ids) + var/datum/design/D = techweb_designs[d] + if(!istype(D)) + WARNING("Invalid research design with ID [d] detected in node [N.display_name]\[[N.id]\] removed.") + N.design_ids -= d + design_id_error(d) + for(var/u in N.unlock_ids) + var/datum/techweb_node/U = techweb_nodes[u] + if(!istype(U)) + WARNING("Invalid research unlock node with ID [u] detected in node [N.display_name]\[[N.id]\] removed.") + N.unlock_ids -= u + research_node_id_error(u) + for(var/p in N.boost_item_paths) + if(!ispath(p)) + N.boost_item_paths -= p + node_boost_error(N.id, "[p] is not a valid path.") + var/list/points = N.boost_item_paths[p] + if(islist(points)) + for(var/i in points) + if(!isnum(points[i])) + node_boost_error(N.id, "[points[i]] is not a valid number.") + else if(!point_types[i]) + node_boost_error(N.id, "[i] is not a valid point type.") + else if(!isnull(points)) + N.boost_item_paths -= p + node_boost_error(N.id, "No valid list.") + CHECK_TICK + +/datum/controller/subsystem/research/proc/verify_techweb_designs() + for(var/d in techweb_designs) + var/datum/design/D = techweb_designs[d] + if(!istype(D)) + stack_trace("WARNING: Invalid research design with ID [d] detected and removed.") + techweb_designs -= d + CHECK_TICK + +/datum/controller/subsystem/research/proc/research_node_id_error(id) + if(invalid_node_ids[id]) + invalid_node_ids[id]++ + else + invalid_node_ids[id] = 1 + +/datum/controller/subsystem/research/proc/design_id_error(id) + if(invalid_design_ids[id]) + invalid_design_ids[id]++ + else + invalid_design_ids[id] = 1 + +/datum/controller/subsystem/research/proc/calculate_techweb_nodes() + for(var/design_id in techweb_designs) + var/datum/design/D = techweb_designs[design_id] + D.unlocked_by.Cut() + for(var/node_id in techweb_nodes) + var/datum/techweb_node/node = techweb_nodes[node_id] + node.unlock_ids = list() + for(var/i in node.design_ids) + var/datum/design/D = techweb_designs[i] + node.design_ids[i] = TRUE + D.unlocked_by += node.id + if(node.hidden) + techweb_nodes_hidden[node.id] = TRUE + CHECK_TICK + generate_techweb_unlock_linking() + +/datum/controller/subsystem/research/proc/generate_techweb_unlock_linking() + for(var/node_id in techweb_nodes) //Clear all unlock links to avoid duplication. + var/datum/techweb_node/node = techweb_nodes[node_id] + node.unlock_ids = list() + for(var/node_id in techweb_nodes) + var/datum/techweb_node/node = techweb_nodes[node_id] + for(var/prereq_id in node.prereq_ids) + var/datum/techweb_node/prereq_node = techweb_node_by_id(prereq_id) + prereq_node.unlock_ids[node.id] = node + +/datum/controller/subsystem/research/proc/calculate_techweb_boost_list(clearall = FALSE) + if(clearall) + techweb_boost_items = list() + for(var/node_id in techweb_nodes) + var/datum/techweb_node/node = techweb_nodes[node_id] + for(var/path in node.boost_item_paths) + if(!ispath(path)) + continue + if(length(techweb_boost_items[path])) + techweb_boost_items[path][node.id] = node.boost_item_paths[path] + else + techweb_boost_items[path] = list(node.id = node.boost_item_paths[path]) + CHECK_TICK diff --git a/code/game/machinery/autolathe.dm b/code/game/machinery/autolathe.dm index 1b2414a320c..b338069e1ce 100644 --- a/code/game/machinery/autolathe.dm +++ b/code/game/machinery/autolathe.dm @@ -178,7 +178,7 @@ matching_designs.Cut() for(var/v in stored_research.researched_designs) - var/datum/design/D = stored_research.researched_designs[v] + var/datum/design/D = SSresearch.techweb_design_by_id(v) if(findtext(D.name,href_list["to_search"])) matching_designs.Add(D) updateUsrDialog() @@ -254,7 +254,7 @@ dat += materials_printout() for(var/v in stored_research.researched_designs) - var/datum/design/D = stored_research.researched_designs[v] + var/datum/design/D = SSresearch.techweb_design_by_id(v) if(!(selected_category in D.category)) continue @@ -368,7 +368,7 @@ /obj/machinery/autolathe/proc/adjust_hacked(state) hacked = state for(var/id in SSresearch.techweb_designs) - var/datum/design/D = SSresearch.techweb_designs[id] + var/datum/design/D = SSresearch.techweb_design_by_id(id) if((D.build_type & AUTOLATHE) && ("hacked" in D.category)) if(hacked) stored_research.add_design(D) diff --git a/code/game/machinery/computer/Operating.dm b/code/game/machinery/computer/Operating.dm index 73fdcd5e8ba..ebe3516ab84 100644 --- a/code/game/machinery/computer/Operating.dm +++ b/code/game/machinery/computer/Operating.dm @@ -32,7 +32,7 @@ /obj/machinery/computer/operating/proc/sync_surgeries() for(var/i in linked_techweb.researched_designs) - var/datum/design/surgery/D = linked_techweb.researched_designs[i] + var/datum/design/surgery/D = SSresearch.techweb_design_by_id(i) if(!istype(D)) continue advanced_surgeries |= D.surgery diff --git a/code/game/machinery/limbgrower.dm b/code/game/machinery/limbgrower.dm index 8a0658fd0f8..9954f57b52e 100644 --- a/code/game/machinery/limbgrower.dm +++ b/code/game/machinery/limbgrower.dm @@ -177,7 +177,7 @@ dat += materials_printout() for(var/v in stored_research.researched_designs) - var/datum/design/D = stored_research.researched_designs[v] + var/datum/design/D = SSresearch.techweb_design_by_id(v) if(!(selected_category in D.category)) continue if(disabled || !can_build(D)) @@ -219,7 +219,7 @@ if(obj_flags & EMAGGED) return for(var/id in SSresearch.techweb_designs) - var/datum/design/D = SSresearch.techweb_designs[id] + var/datum/design/D = SSresearch.techweb_design_by_id(id) if((D.build_type & LIMBGROWER) && ("emagged" in D.category)) stored_research.add_design(D) to_chat(user, "A warning flashes onto the screen, stating that safety overrides have been deactivated!") diff --git a/code/game/mecha/mech_fabricator.dm b/code/game/mecha/mech_fabricator.dm index 01e304872f1..ffa57b81ebe 100644 --- a/code/game/mecha/mech_fabricator.dm +++ b/code/game/mecha/mech_fabricator.dm @@ -80,7 +80,7 @@ /obj/machinery/mecha_part_fabricator/proc/output_parts_list(set_name) var/output = "" for(var/v in stored_research.researched_designs) - var/datum/design/D = stored_research.researched_designs[v] + var/datum/design/D = SSresearch.techweb_design_by_id(v) if(D.build_type & MECHFAB) if(!(set_name in D.category)) continue @@ -161,7 +161,7 @@ /obj/machinery/mecha_part_fabricator/proc/add_part_set_to_queue(set_name) if(set_name in part_sets) for(var/v in stored_research.researched_designs) - var/datum/design/D = stored_research.researched_designs[v] + var/datum/design/D = SSresearch.techweb_design_by_id(v) if(D.build_type & MECHFAB) if(set_name in D.category) add_to_queue(D) @@ -319,7 +319,7 @@ if(href_list["part"]) var/T = afilter.getStr("part") for(var/v in stored_research.researched_designs) - var/datum/design/D = stored_research.researched_designs[v] + var/datum/design/D = SSresearch.techweb_design_by_id(v) if(D.build_type & MECHFAB) if(D.id == T) if(!processing_queue) @@ -330,7 +330,7 @@ if(href_list["add_to_queue"]) var/T = afilter.getStr("add_to_queue") for(var/v in stored_research.researched_designs) - var/datum/design/D = stored_research.researched_designs[v] + var/datum/design/D = SSresearch.techweb_design_by_id(v) if(D.build_type & MECHFAB) if(D.id == T) add_to_queue(D) @@ -368,7 +368,7 @@ if(href_list["part_desc"]) var/T = afilter.getStr("part_desc") for(var/v in stored_research.researched_designs) - var/datum/design/D = stored_research.researched_designs[v] + var/datum/design/D = SSresearch.techweb_design_by_id(v) if(D.build_type & MECHFAB) if(D.id == T) var/obj/part = D.build_path diff --git a/code/game/objects/items.dm b/code/game/objects/items.dm index 9d264c87e02..255b861f8bc 100644 --- a/code/game/objects/items.dm +++ b/code/game/objects/items.dm @@ -202,7 +202,9 @@ GLOBAL_VAR_INIT(rpg_loot_items, FALSE) var/list/boostable_nodes = techweb_item_boost_check(src) if (boostable_nodes) for(var/id in boostable_nodes) - var/datum/techweb_node/node = SSresearch.techweb_nodes[id] + var/datum/techweb_node/node = SSresearch.techweb_node_by_id(id) + if(!node) + continue research_msg += sep research_msg += node.display_name sep = ", " diff --git a/code/modules/hydroponics/biogenerator.dm b/code/modules/hydroponics/biogenerator.dm index e1eb9769667..7244ccea79f 100644 --- a/code/modules/hydroponics/biogenerator.dm +++ b/code/modules/hydroponics/biogenerator.dm @@ -173,7 +173,7 @@ for(var/V in categories) categories[V] = list() for(var/V in stored_research.researched_designs) - var/datum/design/D = stored_research.researched_designs[V] + var/datum/design/D = SSresearch.techweb_design_by_id(V) for(var/C in categories) if(C in D.category) categories[C] += D diff --git a/code/modules/mining/machine_processing.dm b/code/modules/mining/machine_processing.dm index a004a6ae0d0..48c2f03d8c8 100644 --- a/code/modules/mining/machine_processing.dm +++ b/code/modules/mining/machine_processing.dm @@ -121,7 +121,7 @@ dat += "Smelt Alloys
" for(var/v in stored_research.researched_designs) - var/datum/design/D = stored_research.researched_designs[v] + var/datum/design/D = SSresearch.techweb_design_by_id(v) dat += "[D.name] " if (selected_alloy == D.id) dat += " Smelting" diff --git a/code/modules/mining/machine_redemption.dm b/code/modules/mining/machine_redemption.dm index f3ccc31fcb7..0ec0cda375b 100644 --- a/code/modules/mining/machine_redemption.dm +++ b/code/modules/mining/machine_redemption.dm @@ -221,7 +221,7 @@ data["alloys"] = list() for(var/v in stored_research.researched_designs) - var/datum/design/D = stored_research.researched_designs[v] + var/datum/design/D = SSresearch.techweb_design_by_id(v) data["alloys"] += list(list("name" = D.name, "id" = D.id, "amount" = can_smelt_alloy(D))) if (!mat_container) diff --git a/code/modules/research/designs.dm b/code/modules/research/designs.dm index 491aa63e56b..5cbe9a6f163 100644 --- a/code/modules/research/designs.dm +++ b/code/modules/research/designs.dm @@ -27,6 +27,7 @@ other types of metals and chemistry for reagents). */ //DESIGNS ARE GLOBAL. DO NOT CREATE OR DESTROY THEM AT RUNTIME OUTSIDE OF INIT, JUST REFERENCE THEM TO WHATEVER YOU'RE DOING! //why are you yelling? +//DO NOT REFERENCE OUTSIDE OF SSRESEARCH. USE THE PROCS IN SSRESEARCH TO OBTAIN A REFERENCE. /datum/design //Datum for object designs, used in construction var/name = "Name" //Name of the created object. @@ -48,8 +49,12 @@ other types of metals and chemistry for reagents). var/research_icon_state var/icon_cache +/datum/design/error_design + name = "ERROR" + desc = "This usually means something in the database has corrupted. If this doesn't go away automatically, inform Central Comamnd so their techs can fix this ASAP(tm)" + /datum/design/Destroy() - CRASH("DESIGN DATUMS SHOULD NOT EVER BE DESTROYED AS THEY ARE ONLY MEANT TO BE IN A GLOBAL LIST AND REFERENCED FOR US.") + SSresearch.techweb_designs -= id return ..() /datum/design/proc/icon_html(client/user) diff --git a/code/modules/research/destructive_analyzer.dm b/code/modules/research/destructive_analyzer.dm index 5cc26381dd0..ac76e8b9fea 100644 --- a/code/modules/research/destructive_analyzer.dm +++ b/code/modules/research/destructive_analyzer.dm @@ -102,7 +102,7 @@ Note: Must be placed within 3 tiles of the R&D Console return FALSE if (id && id != RESEARCH_MATERIAL_RECLAMATION_ID) - var/datum/techweb_node/TN = get_techweb_node_by_id(id) + var/datum/techweb_node/TN = SSresearch.techweb_node_by_id(id) if(!istype(TN)) return FALSE var/dpath = loaded_item.type @@ -123,7 +123,7 @@ Note: Must be placed within 3 tiles of the R&D Console return FALSE SSblackbox.record_feedback("nested tally", "item_deconstructed", 1, list("[TN.id]", "[loaded_item.type]")) if(destroy_item(loaded_item)) - linked_console.stored_research.boost_with_path(SSresearch.techweb_nodes[TN.id], dpath) + linked_console.stored_research.boost_with_path(SSresearch.techweb_node_by_id(TN.id), dpath) else var/list/point_value = techweb_item_point_check(loaded_item) diff --git a/code/modules/research/experimentor.dm b/code/modules/research/experimentor.dm index ebd386513ed..71c92a4690d 100644 --- a/code/modules/research/experimentor.dm +++ b/code/modules/research/experimentor.dm @@ -128,13 +128,13 @@ var/list/res = list("Already researched:") var/list/boosted = list("Already boosted:") for(var/node_id in listin) - var/datum/techweb_node/N = get_techweb_node_by_id(node_id) + var/datum/techweb_node/N = SSresearch.techweb_node_by_id(node_id) var/str = "[N.display_name]: [listin[N]] points." - if(SSresearch.science_tech.researched_nodes[N]) + if(SSresearch.science_tech.researched_nodes[N.id]) res += str - else if(SSresearch.science_tech.boosted_nodes[N]) + else if(SSresearch.science_tech.boosted_nodes[N.id]) boosted += str - if(SSresearch.science_tech.visible_nodes[N]) //JOY OF DISCOVERY! + if(SSresearch.science_tech.visible_nodes[N.id]) //JOY OF DISCOVERY! output += str output += boosted + res dat += output @@ -182,10 +182,10 @@ experiment(dotype,process) use_power(750) if(dotype != FAIL) - var/list/datum/techweb_node/nodes = techweb_item_boost_check(process) + var/list/nodes = techweb_item_boost_check(process) var/picked = pickweight(nodes) //This should work. if(linked_console) - linked_console.stored_research.boost_with_path(picked, process.type) + linked_console.stored_research.boost_with_path(SSresearch.techweb_node_by_id(picked), process.type) updateUsrDialog() /obj/machinery/rnd/experimentor/proc/matchReaction(matching,reaction) diff --git a/code/modules/research/machinery/_production.dm b/code/modules/research/machinery/_production.dm index d3cd399635b..6a18191af1f 100644 --- a/code/modules/research/machinery/_production.dm +++ b/code/modules/research/machinery/_production.dm @@ -37,7 +37,7 @@ /obj/machinery/rnd/production/proc/update_designs() cached_designs.Cut() for(var/i in stored_research.researched_designs) - var/datum/design/d = stored_research.researched_designs[i] + var/datum/design/d = SSresearch.techweb_design_by_id(i) if((isnull(allowed_department_flags) || (d.departmental_flags & allowed_department_flags)) && (d.build_type & allowed_buildtypes)) cached_designs |= d @@ -114,7 +114,7 @@ amount = text2num(amount) if(isnull(amount)) amount = 1 - var/datum/design/D = (linked_console || requires_console)? linked_console.stored_research.researched_designs[id] : get_techweb_design_by_id(id) + var/datum/design/D = (linked_console || requires_console)? (linked_console.stored_research.researched_designs[id]? SSresearch.techweb_design_by_id(id) : null) : SSresearch.techweb_design_by_id(id) if(!istype(D)) return FALSE if(!(isnull(allowed_department_flags) || (D.departmental_flags & allowed_department_flags))) @@ -161,7 +161,7 @@ /obj/machinery/rnd/production/proc/search(string) matching_designs.Cut() for(var/v in stored_research.researched_designs) - var/datum/design/D = stored_research.researched_designs[v] + var/datum/design/D = SSresearch.techweb_design_by_id(v) if(!(D.build_type & allowed_buildtypes) || !(isnull(allowed_department_flags) || (D.departmental_flags & allowed_department_flags))) continue if(findtext(D.name,string)) @@ -337,7 +337,7 @@ l += "

Browsing [selected_category]:

" var/coeff = efficiency_coeff for(var/v in stored_research.researched_designs) - var/datum/design/D = stored_research.researched_designs[v] + var/datum/design/D = SSresearch.techweb_design_by_id(v) if(!(selected_category in D.category)|| !(D.build_type & allowed_buildtypes)) continue if(!(isnull(allowed_department_flags) || (D.departmental_flags & allowed_department_flags))) diff --git a/code/modules/research/nanites/nanite_program_hub.dm b/code/modules/research/nanites/nanite_program_hub.dm index 81c5a44527d..13f8cb98075 100644 --- a/code/modules/research/nanites/nanite_program_hub.dm +++ b/code/modules/research/nanites/nanite_program_hub.dm @@ -69,7 +69,7 @@ if(current_category != "Main") var/list/program_list = list() for(var/i in linked_techweb.researched_designs) - var/datum/design/nanites/D = linked_techweb.researched_designs[i] + var/datum/design/nanites/D = SSresearch.techweb_design_by_id(i) if(!istype(D)) continue if(current_category in D.category) diff --git a/code/modules/research/rdconsole.dm b/code/modules/research/rdconsole.dm index fb3c5908f5b..bfcd184bbfb 100644 --- a/code/modules/research/rdconsole.dm +++ b/code/modules/research/rdconsole.dm @@ -36,10 +36,10 @@ Nothing else in the console has ID requirements. var/locked = FALSE var/tdisk_uple = FALSE var/ddisk_uple = FALSE - var/datum/techweb_node/selected_node - var/datum/design/selected_design + var/datum/selected_node_id + var/datum/selected_design_id var/selected_category - var/list/datum/design/matching_designs + var/list/matching_design_ids var/disk_slot_selected var/searchstring = "" var/searchtype = "" @@ -88,7 +88,7 @@ Nothing else in the console has ID requirements. . = ..() stored_research = SSresearch.science_tech stored_research.consoles_accessing[src] = TRUE - matching_designs = list() + matching_design_ids = list() SyncRDevices() /obj/machinery/computer/rdconsole/Destroy() @@ -109,9 +109,7 @@ Nothing else in the console has ID requirements. if(d_disk) d_disk.forceMove(get_turf(src)) d_disk = null - matching_designs = null - selected_node = null - selected_design = null + matching_design_ids = null return ..() /obj/machinery/computer/rdconsole/attackby(obj/item/D, mob/user, params) @@ -144,7 +142,7 @@ Nothing else in the console has ID requirements. if(!stored_research.available_nodes[id] || stored_research.researched_nodes[id]) say("Node unlock failed: Either already researched or not available!") return FALSE - var/datum/techweb_node/TN = SSresearch.techweb_nodes[id] + var/datum/techweb_node/TN = SSresearch.techweb_node_by_id(id) if(!istype(TN)) say("Node unlock failed: Unknown error.") return FALSE @@ -153,7 +151,7 @@ Nothing else in the console has ID requirements. investigate_log("[key_name(user)] researched [id]([json_encode(price)]) on techweb id [stored_research.id].", INVESTIGATE_RESEARCH) if(stored_research == SSresearch.science_tech) SSblackbox.record_feedback("associative", "science_techweb_unlock", 1, list("id" = "[id]", "name" = TN.display_name, "price" = "[json_encode(price)]", "time" = SQLtime())) - if(stored_research.research_node(SSresearch.techweb_nodes[id])) + if(stored_research.research_node_id(id)) say("Successfully researched [TN.display_name].") var/logname = "Unknown" if(isAI(user)) @@ -286,7 +284,7 @@ Nothing else in the console has ID requirements. l += ui_protolathe_header() l += "

Browsing [selected_category]:

" for(var/v in stored_research.researched_designs) - var/datum/design/D = stored_research.researched_designs[v] + var/datum/design/D = SSresearch.techweb_design_by_id(v) if(!(selected_category in D.category)|| !(D.build_type & PROTOLATHE)) continue if(!(isnull(linked_lathe.allowed_department_flags) || (D.departmental_flags & linked_lathe.allowed_department_flags))) @@ -341,7 +339,8 @@ Nothing else in the console has ID requirements. RDSCREEN_UI_LATHE_CHECK var/list/l = list() l += ui_protolathe_header() - for(var/datum/design/D in matching_designs) + for(var/id in matching_design_ids) + var/datum/design/D = SSresearch.techweb_design_by_id(id) if(!(isnull(linked_lathe.allowed_department_flags) || (D.departmental_flags & linked_lathe.allowed_department_flags))) continue var/temp_material @@ -437,7 +436,7 @@ Nothing else in the console has ID requirements. l += "

Browsing [selected_category]:

" for(var/v in stored_research.researched_designs) - var/datum/design/D = stored_research.researched_designs[v] + var/datum/design/D = SSresearch.techweb_design_by_id(v) if(!(selected_category in D.category) || !(D.build_type & IMPRINTER)) continue if(!(isnull(linked_imprinter.allowed_department_flags) || (D.departmental_flags & linked_imprinter.allowed_department_flags))) @@ -470,7 +469,8 @@ Nothing else in the console has ID requirements. l += ui_circuit_header() l += "

Search results:

" - for(var/datum/design/D in matching_designs) + for(var/id in matching_design_ids) + var/datum/design/D = SSresearch.techweb_design_by_id(id) if(!(isnull(linked_imprinter.allowed_department_flags) || (D.departmental_flags & linked_imprinter.allowed_department_flags))) continue var/temp_materials @@ -530,7 +530,7 @@ Nothing else in the console has ID requirements. l += "Load Technology to Disk
" l += "

Stored Technology Nodes:

" for(var/i in t_disk.stored_research.researched_nodes) - var/datum/techweb_node/N = t_disk.stored_research.researched_nodes[i] + var/datum/techweb_node/N = SSresearch.techweb_node_by_id(i) l += "[N.display_name]" l += "
" return l @@ -556,7 +556,7 @@ Nothing else in the console has ID requirements. l += "Return to Disk Operations
" l += "

Load Design to Disk:

" for(var/v in stored_research.researched_designs) - var/datum/design/D = stored_research.researched_designs[v] + var/datum/design/D = SSresearch.techweb_design_by_id(v) l += "[D.name] " l += "Copy to Disk" l += "
" @@ -577,7 +577,7 @@ Nothing else in the console has ID requirements. for(var/id in boostable_nodes) anything = TRUE var/list/worth = boostable_nodes[id] - var/datum/techweb_node/N = get_techweb_node_by_id(id) + var/datum/techweb_node/N = SSresearch.techweb_node_by_id(id) l += "
[RDSCREEN_NOBREAK]" if (stored_research.researched_nodes[N.id]) // already researched @@ -639,7 +639,7 @@ Nothing else in the console has ID requirements. var/list/columns = list() var/max_tier = 0 for (var/node_ in stored_research.tiers) - var/datum/techweb_node/node = node_ + var/datum/techweb_node/node = SSresearch.techweb_node_by_id(node_) var/tier = stored_research.tiers[node] LAZYINITLIST(columns["[tier]"]) // String hackery to make the numbers associative columns["[tier]"] += ui_techweb_single_node(node, minimal=(tier != 1)) @@ -656,15 +656,15 @@ Nothing else in the console has ID requirements. var/list/unavail = list() var/list/res = list() for(var/v in stored_research.researched_nodes) - res += stored_research.researched_nodes[v] + res += SSresearch.techweb_node_by_id(v) for(var/v in stored_research.available_nodes) if(stored_research.researched_nodes[v]) continue - avail += stored_research.available_nodes[v] + avail += SSresearch.techweb_node_by_id(v) for(var/v in stored_research.visible_nodes) if(stored_research.available_nodes[v]) continue - unavail += stored_research.visible_nodes[v] + unavail += SSresearch.techweb_node_by_id(v) l += "

Technology Nodes:

[RDSCREEN_NOBREAK]" l += "

Available for Research:

" for(var/datum/techweb_node/N in avail) @@ -706,13 +706,14 @@ Nothing else in the console has ID requirements. l += "
[node.price_display(stored_research)]" // red - missing prereqs if(ui_mode == RDCONSOLE_UI_MODE_NORMAL) l += "[node.description]" - for(var/i in node.designs) - var/datum/design/D = node.designs[i] + for(var/i in node.design_ids) + var/datum/design/D = SSresearch.techweb_design_by_id(i) l += "[D.icon_html(usr)][RDSCREEN_NOBREAK]" l += "
[RDSCREEN_NOBREAK]" return l /obj/machinery/computer/rdconsole/proc/ui_techweb_nodeview() + var/datum/techweb_node/selected_node = SSresearch.techweb_node_by_id(selected_node_id) RDSCREEN_UI_SNODE_CHECK var/list/l = list() if(stored_research.hidden_nodes[selected_node.id]) @@ -720,64 +721,64 @@ Nothing else in the console has ID requirements. return l += "[RDSCREEN_NOBREAK]" - if (length(selected_node.prerequisites)) + if (length(selected_node.prereq_ids)) l += "[RDSCREEN_NOBREAK]" l += "[RDSCREEN_NOBREAK]" - if (length(selected_node.unlocks)) + if (length(selected_node.unlock_ids)) l += "[RDSCREEN_NOBREAK]" l += "[RDSCREEN_NOBREAK]" - if (length(selected_node.prerequisites)) + if (length(selected_node.prereq_ids)) l += "[RDSCREEN_NOBREAK]" l += "[RDSCREEN_NOBREAK]" - if (length(selected_node.unlocks)) + if (length(selected_node.unlock_ids)) l += "[RDSCREEN_NOBREAK]" l += "
RequiresCurrent NodeUnlocks
[RDSCREEN_NOBREAK]" - for (var/i in selected_node.prerequisites) - l += ui_techweb_single_node(selected_node.prerequisites[i]) + for (var/i in selected_node.prereq_ids) + l += ui_techweb_single_node(SSresearch.techweb_node_by_id(i)) l += "[RDSCREEN_NOBREAK]" l += ui_techweb_single_node(selected_node, selflink=FALSE) l += "[RDSCREEN_NOBREAK]" - for (var/i in selected_node.unlocks) - l += ui_techweb_single_node(selected_node.unlocks[i]) + for (var/i in selected_node.unlock_ids) + l += ui_techweb_single_node(SSresearch.techweb_node_by_id(i)) l += "
[RDSCREEN_NOBREAK]" return l /obj/machinery/computer/rdconsole/proc/ui_techweb_designview() //Legacy code + var/datum/design/selected_design = SSresearch.techweb_design_by_id(selected_design_id) RDSCREEN_UI_SDESIGN_CHECK var/list/l = list() - var/datum/design/D = selected_design - l += "
[D.icon_html(usr)][D.name]
[RDSCREEN_NOBREAK]" - if(D.build_type) + l += "
[selected_design.icon_html(usr)][selected_design.name]
[RDSCREEN_NOBREAK]" + if(selected_design.build_type) var/lathes = list() - if(D.build_type & IMPRINTER) + if(selected_design.build_type & IMPRINTER) lathes += "[machine_icon(/obj/machinery/rnd/production/circuit_imprinter)][RDSCREEN_NOBREAK]" - if (linked_imprinter && D.id in stored_research.researched_designs) - l += "Imprint" - if(D.build_type & PROTOLATHE) + if (linked_imprinter && stored_research.researched_designs[selected_design.id]) + l += "Imprint" + if(selected_design.build_type & PROTOLATHE) lathes += "[machine_icon(/obj/machinery/rnd/production/protolathe)][RDSCREEN_NOBREAK]" - if (linked_lathe && D.id in stored_research.researched_designs) - l += "Construct" - if(D.build_type & AUTOLATHE) + if (linked_lathe && stored_research.researched_designs[selected_design.id]) + l += "Construct" + if(selected_design.build_type & AUTOLATHE) lathes += "[machine_icon(/obj/machinery/autolathe)][RDSCREEN_NOBREAK]" - if(D.build_type & MECHFAB) + if(selected_design.build_type & MECHFAB) lathes += "[machine_icon(/obj/machinery/mecha_part_fabricator)][RDSCREEN_NOBREAK]" - if(D.build_type & BIOGENERATOR) + if(selected_design.build_type & BIOGENERATOR) lathes += "[machine_icon(/obj/machinery/biogenerator)][RDSCREEN_NOBREAK]" - if(D.build_type & LIMBGROWER) + if(selected_design.build_type & LIMBGROWER) lathes += "[machine_icon(/obj/machinery/limbgrower)][RDSCREEN_NOBREAK]" - if(D.build_type & SMELTER) + if(selected_design.build_type & SMELTER) lathes += "[machine_icon(/obj/machinery/mineral/processing_unit)][RDSCREEN_NOBREAK]" l += "Construction types:" l += lathes l += "" l += "Required materials:" - var/all_mats = D.materials + D.reagents_list + var/all_mats = selected_design.materials + selected_design.reagents_list for(var/M in all_mats) l += "* [CallMaterialName(M)] x [all_mats[M]]" l += "Unlocked by:" - for (var/node in D.unlocked_by) + for (var/node in selected_design.unlocked_by) l += ui_techweb_single_node(node) l += "[RDSCREEN_NOBREAK]
" return l @@ -1003,12 +1004,12 @@ Nothing else in the console has ID requirements. return say("Uploading technology disk.") t_disk.stored_research.copy_research_to(stored_research) - if(ls["copy_design"]) //Copy design la from the research holder to the design disk. + if(ls["copy_design"]) //Copy design from the research holder to the design disk. if(QDELETED(d_disk)) say("No Design Disk Inserted!") return var/slot = text2num(ls["copy_design"]) - var/datum/design/D = stored_research.researched_designs[ls["copy_design_ID"]] + var/datum/design/D = SSresearch.techweb_design_by_id(ls["copy_design_ID"]) if(D) var/autolathe_friendly = TRUE if(D.reagents_list.len) @@ -1035,12 +1036,12 @@ Nothing else in the console has ID requirements. linked_destroy.unload_item() screen = RDSCREEN_MENU if(ls["view_node"]) - selected_node = SSresearch.techweb_nodes[ls["view_node"]] + selected_node_id = ls["view_node"] screen = RDSCREEN_TECHWEB_NODEVIEW if(ls["view_design"]) - selected_design = SSresearch.techweb_designs[ls["view_design"]] + selected_design_id = ls["view_design"] screen = RDSCREEN_TECHWEB_DESIGNVIEW - if(ls["updt_design"]) //Uples the research holder with design la from the design disk. + if(ls["updt_design"]) //Uploads a design from disk to the techweb. if(QDELETED(d_disk)) say("No design disk found.") return @@ -1048,9 +1049,9 @@ Nothing else in the console has ID requirements. if(!n) for(var/D in d_disk.blueprints) if(D) - stored_research.add_design(D) + stored_research.add_design(D, TRUE) else - stored_research.add_design(d_disk.blueprints[n]) + stored_research.add_design(d_disk.blueprints[n], TRUE) updateUsrDialog() @@ -1079,17 +1080,17 @@ Nothing else in the console has ID requirements. /obj/machinery/computer/rdconsole/proc/rescan_views() var/compare - matching_designs.Cut() + matching_design_ids.Cut() if(searchtype == "proto") compare = PROTOLATHE else if(searchtype == "imprint") compare = IMPRINTER for(var/v in stored_research.researched_designs) - var/datum/design/D = stored_research.researched_designs[v] + var/datum/design/D = SSresearch.techweb_design_by_id(v) if(!(D.build_type & compare)) continue if(findtext(D.name,searchstring)) - matching_designs.Add(D) + matching_design_ids.Add(D.id) /obj/machinery/computer/rdconsole/proc/check_canprint(datum/design/D, buildtype) var/amount = 50 diff --git a/code/modules/research/techweb/__techweb_helpers.dm b/code/modules/research/techweb/__techweb_helpers.dm index 1e90f0f28d9..6c967c09245 100644 --- a/code/modules/research/techweb/__techweb_helpers.dm +++ b/code/modules/research/techweb/__techweb_helpers.dm @@ -1,48 +1,3 @@ - -/proc/initialize_all_techweb_nodes(clearall = FALSE) - if(islist(SSresearch.techweb_nodes) && clearall) - QDEL_LIST(SSresearch.techweb_nodes) - if(islist(SSresearch.techweb_nodes_starting && clearall)) - QDEL_LIST(SSresearch.techweb_nodes_starting) - var/list/returned = list() - for(var/path in subtypesof(/datum/techweb_node)) - var/datum/techweb_node/TN = path - if(isnull(initial(TN.id))) - continue - TN = new path - if(returned[initial(TN.id)]) - stack_trace("WARNING: Techweb node ID clash with ID [initial(TN.id)] detected!") - SSresearch.errored_datums[TN] = initial(TN.id) - continue - returned[initial(TN.id)] = TN - if(TN.starting_node) - SSresearch.techweb_nodes_starting[TN.id] = TN - SSresearch.techweb_nodes = returned - verify_techweb_nodes() //Verify all nodes have ids and such. - calculate_techweb_nodes() - calculate_techweb_boost_list() - verify_techweb_nodes() //Verify nodes and designs have been crosslinked properly. - -/proc/initialize_all_techweb_designs(clearall = FALSE) - if(islist(SSresearch.techweb_designs) && clearall) - QDEL_LIST(SSresearch.techweb_designs) - var/list/returned = list() - for(var/path in subtypesof(/datum/design)) - var/datum/design/DN = path - if(isnull(initial(DN.id))) - stack_trace("WARNING: Design with null ID detected. Build path: [initial(DN.build_path)]") - continue - else if(initial(DN.id) == DESIGN_ID_IGNORE) - continue - DN = new path - if(returned[initial(DN.id)]) - stack_trace("WARNING: Design ID clash with ID [initial(DN.id)] detected!") - SSresearch.errored_datums[DN] = initial(DN.id) - continue - returned[initial(DN.id)] = DN - SSresearch.techweb_designs = returned - verify_techweb_designs() - /proc/count_unique_techweb_nodes() var/static/list/L = typesof(/datum/techweb_node) return L.len @@ -51,135 +6,10 @@ var/static/list/L = typesof(/datum/design) return L.len -/proc/get_techweb_node_by_id(id) - if(SSresearch.techweb_nodes[id]) - return SSresearch.techweb_nodes[id] - -/proc/get_techweb_design_by_id(id) - if(SSresearch.techweb_designs[id]) - return SSresearch.techweb_designs[id] - -/proc/research_node_id_error(id) - if(SSresearch.invalid_node_ids[id]) - SSresearch.invalid_node_ids[id]++ - else - SSresearch.invalid_node_ids[id] = 1 - -/proc/design_id_error(id) - if(SSresearch.invalid_design_ids[id]) - SSresearch.invalid_design_ids[id]++ - else - SSresearch.invalid_design_ids[id] = 1 - /proc/node_boost_error(id, message) WARNING("Invalid boost information for node \[[id]\]: [message]") SSresearch.invalid_node_boost[id] = message -/proc/verify_techweb_nodes() - for(var/n in SSresearch.techweb_nodes) - var/datum/techweb_node/N = SSresearch.techweb_nodes[n] - if(!istype(N)) - WARNING("Invalid research node with ID [n] detected and removed.") - SSresearch.techweb_nodes -= n - research_node_id_error(n) - for(var/p in N.prereq_ids) - var/datum/techweb_node/P = SSresearch.techweb_nodes[p] - if(!istype(P)) - WARNING("Invalid research prerequisite node with ID [p] detected in node [N.display_name]\[[N.id]\] removed.") - N.prereq_ids -= p - research_node_id_error(p) - for(var/d in N.design_ids) - var/datum/design/D = SSresearch.techweb_designs[d] - if(!istype(D)) - WARNING("Invalid research design with ID [d] detected in node [N.display_name]\[[N.id]\] removed.") - N.designs -= d - design_id_error(d) - for(var/p in N.prerequisites) - var/datum/techweb_node/P = N.prerequisites[p] - if(!istype(P)) - WARNING("Invalid research prerequisite node with ID [p] detected in node [N.display_name]\[[N.id]\] removed.") - N.prerequisites -= p - research_node_id_error(p) - for(var/u in N.unlocks) - var/datum/techweb_node/U = N.unlocks[u] - if(!istype(U)) - WARNING("Invalid research unlock node with ID [u] detected in node [N.display_name]\[[N.id]\] removed.") - N.unlocks -= u - research_node_id_error(u) - for(var/d in N.designs) - var/datum/design/D = N.designs[d] - if(!istype(D)) - WARNING("Invalid research design with ID [d] detected in node [N.display_name]\[[N.id]\] removed.") - N.designs -= d - design_id_error(d) - for(var/p in N.boost_item_paths) - if(!ispath(p)) - N.boost_item_paths -= p - node_boost_error(N.id, "[p] is not a valid path.") - var/list/points = N.boost_item_paths[p] - if(islist(points)) - for(var/i in points) - if(!isnum(points[i])) - node_boost_error(N.id, "[points[i]] is not a valid number.") - else if(!SSresearch.point_types[i]) - node_boost_error(N.id, "[i] is not a valid point type.") - else if(!isnull(points)) - N.boost_item_paths -= p - node_boost_error(N.id, "No valid list.") - CHECK_TICK - -/proc/verify_techweb_designs() - for(var/d in SSresearch.techweb_designs) - var/datum/design/D = SSresearch.techweb_designs[d] - if(!istype(D)) - stack_trace("WARNING: Invalid research design with ID [d] detected and removed.") - SSresearch.techweb_designs -= d - CHECK_TICK - -/proc/calculate_techweb_nodes() - for(var/design_id in SSresearch.techweb_designs) - var/datum/design/D = SSresearch.techweb_designs[design_id] - D.unlocked_by.Cut() - for(var/node_id in SSresearch.techweb_nodes) - var/datum/techweb_node/node = SSresearch.techweb_nodes[node_id] - node.prerequisites = list() - node.unlocks = list() - node.designs = list() - for(var/i in node.prereq_ids) - node.prerequisites[i] = SSresearch.techweb_nodes[i] - for(var/i in node.design_ids) - var/datum/design/D = SSresearch.techweb_designs[i] - node.designs[i] = D - D.unlocked_by += node - if(node.hidden) - SSresearch.techweb_nodes_hidden[node.id] = node - CHECK_TICK - generate_techweb_unlock_linking() - -/proc/generate_techweb_unlock_linking() - for(var/node_id in SSresearch.techweb_nodes) //Clear all unlock links to avoid duplication. - var/datum/techweb_node/node = SSresearch.techweb_nodes[node_id] - node.unlocks = list() - for(var/node_id in SSresearch.techweb_nodes) - var/datum/techweb_node/node = SSresearch.techweb_nodes[node_id] - for(var/prereq_id in node.prerequisites) - var/datum/techweb_node/prereq_node = node.prerequisites[prereq_id] - prereq_node.unlocks[node.id] = node - -/proc/calculate_techweb_boost_list(clearall = FALSE) - if(clearall) - SSresearch.techweb_boost_items = list() - for(var/node_id in SSresearch.techweb_nodes) - var/datum/techweb_node/node = SSresearch.techweb_nodes[node_id] - for(var/path in node.boost_item_paths) - if(!ispath(path)) - continue - if(length(SSresearch.techweb_boost_items[path])) - SSresearch.techweb_boost_items[path][node.id] = node.boost_item_paths[path] - else - SSresearch.techweb_boost_items[path] = list(node.id = node.boost_item_paths[path]) - CHECK_TICK - /proc/techweb_item_boost_check(obj/item/I) //Returns an associative list of techweb node datums with values of the boost it gives. var/list/returned = list() if(SSresearch.techweb_boost_items[I.type]) return SSresearch.techweb_boost_items[I.type] //It should already be formatted in node datum = list(point type = value) diff --git a/code/modules/research/techweb/_techweb.dm b/code/modules/research/techweb/_techweb.dm index 939798be7b6..a5d3afd3fb5 100644 --- a/code/modules/research/techweb/_techweb.dm +++ b/code/modules/research/techweb/_techweb.dm @@ -5,12 +5,13 @@ //Techweb datums are meant to store unlocked research, being able to be stored on research consoles, servers, and disks. They are NOT global. /datum/techweb - var/list/datum/techweb_node/researched_nodes = list() //Already unlocked and all designs are now available. Assoc list, id = datum - var/list/datum/techweb_node/visible_nodes = list() //Visible nodes, doesn't mean it can be researched. Assoc list, id = datum - var/list/datum/techweb_node/available_nodes = list() //Nodes that can immediately be researched, all reqs met. assoc list, id = datum - var/list/datum/design/researched_designs = list() //Designs that are available for use. Assoc list, id = datum - var/list/datum/techweb_node/boosted_nodes = list() //Already boosted nodes that can't be boosted again. node datum = path of boost object. - var/list/datum/techweb_node/hidden_nodes = list() //Hidden nodes. id = datum. Used for unhiding nodes when requirements are met by removing the entry of the node. + var/list/researched_nodes = list() //Already unlocked and all designs are now available. Assoc list, id = TRUE + var/list/visible_nodes = list() //Visible nodes, doesn't mean it can be researched. Assoc list, id = TRUE + var/list/available_nodes = list() //Nodes that can immediately be researched, all reqs met. assoc list, id = TRUE + var/list/researched_designs = list() //Designs that are available for use. Assoc list, id = TRUE + var/list/custom_designs = list() //Custom inserted designs like from disks that should survive recalculation. + var/list/boosted_nodes = list() //Already boosted nodes that can't be boosted again. node id = path of boost object. + var/list/hidden_nodes = list() //Hidden nodes. id = TRUE. Used for unhiding nodes when requirements are met by removing the entry of the node. var/list/deconstructed_items = list() //items already deconstructed for a generic point boost. path = list(point_type = points) var/list/research_points = list() //Available research points. type = number var/list/obj/machinery/computer/rdconsole/consoles_accessing = list() @@ -19,13 +20,14 @@ var/largest_bomb_value = 0 var/organization = "Third-Party" //Organization name, used for display. var/list/last_bitcoins = list() //Current per-second production, used for display only. - var/list/tiers = list() //Assoc list, datum = number, 1 is available, 2 is all reqs are 1, so on + var/list/tiers = list() //Assoc list, id = number, 1 is available, 2 is all reqs are 1, so on /datum/techweb/New() + SSresearch.techwebs += src for(var/i in SSresearch.techweb_nodes_starting) - var/datum/techweb_node/DN = SSresearch.techweb_nodes_starting[i] + var/datum/techweb_node/DN = SSresearch.techweb_node_by_id(i) research_node(DN, TRUE, FALSE) - hidden_nodes = SSresearch.techweb_nodes_hidden + hidden_nodes = SSresearch.techweb_nodes_hidden.Copy() return ..() /datum/techweb/admin @@ -50,23 +52,24 @@ researched_designs = null available_nodes = null visible_nodes = null + custom_designs = null + SSresearch.techwebs -= src return ..() -/datum/techweb/proc/recalculate_nodes(recalculate_designs = FALSE) +/datum/techweb/proc/recalculate_nodes(recalculate_designs = FALSE, wipe_custom_designs = FALSE) var/list/datum/techweb_node/processing = list() - for(var/i in researched_nodes) - processing[i] = researched_nodes[i] - for(var/i in visible_nodes) - processing[i] = visible_nodes[i] - for(var/i in available_nodes) - processing[i] = available_nodes[i] - for(var/i in processing) - update_node_status(processing[i]) - if(recalculate_designs) //Wipes custom added designs like from design disks or anything like that! - researched_designs = list() - for(var/i in processing) - var/datum/techweb_node/TN = processing[i] - update_node_status(TN, FALSE) + for(var/id in researched_nodes) + processing[id] = TRUE + for(var/id in visible_nodes) + processing[id] = TRUE + for(var/id in available_nodes) + processing[id] = TRUE + if(recalculate_designs) + researched_designs = custom_designs.Copy() + if(wipe_custom_designs) + custom_designs = list() + for(var/id in processing) + update_node_status(SSresearch.techweb_node_by_id(id), FALSE) CHECK_TICK for(var/v in consoles_accessing) var/obj/machinery/computer/rdconsole/V = v @@ -156,21 +159,26 @@ research_points[type] = max(0, research_points[type] - amount) return TRUE -/datum/techweb/proc/add_design_by_id(id) - return add_design(get_techweb_design_by_id(id)) +/datum/techweb/proc/add_design_by_id(id, custom = FALSE) + return add_design(SSresearch.techweb_design_by_id(id), custom) -/datum/techweb/proc/add_design(datum/design/design) +/datum/techweb/proc/add_design(datum/design/design, custom = FALSE) if(!istype(design)) return FALSE - researched_designs[design.id] = design + researched_designs[design.id] = TRUE + if(custom) + custom_designs[design.id] = TRUE return TRUE -/datum/techweb/proc/remove_design_by_id(id) - return remove_design(get_techweb_design_by_id(id)) +/datum/techweb/proc/remove_design_by_id(id, custom = FALSE) + return remove_design(SSresearch.techweb_design_by_id(id), custom) -/datum/techweb/proc/remove_design(datum/design/design) +/datum/techweb/proc/remove_design(datum/design/design, custom = FALSE) if(!istype(design)) return FALSE + if(custom_designs[design.id] && !custom) + return FALSE + custom_designs -= design.id researched_designs -= design.id return TRUE @@ -188,7 +196,7 @@ return techweb_point_display_generic(research_points) /datum/techweb/proc/research_node_id(id, force, auto_update_points) - return research_node(get_techweb_node_by_id(id), force, auto_update_points) + return research_node(SSresearch.techweb_node_by_id(id), force, auto_update_points) /datum/techweb/proc/research_node(datum/techweb_node/node, force = FALSE, auto_adjust_cost = TRUE) if(!istype(node)) @@ -199,12 +207,12 @@ return FALSE if(auto_adjust_cost) remove_point_list(node.get_price(src)) - researched_nodes[node.id] = node //Add to our researched list - for(var/i in node.unlocks) - visible_nodes[i] = node.unlocks[i] - update_node_status(node.unlocks[i]) - for(var/i in node.designs) - add_design(node.designs[i]) + researched_nodes[node.id] = TRUE //Add to our researched list + for(var/id in node.unlock_ids) + visible_nodes[id] = TRUE + update_node_status(SSresearch.techweb_node_by_id(id)) + for(var/id in node.design_ids) + add_design_by_id(id) update_node_status(node) if(!istype(src, /datum/techweb/admin)) var/datum/bank_account/D = SSeconomy.get_dep_account(ACCOUNT_SCI) @@ -213,7 +221,7 @@ return TRUE /datum/techweb/proc/unresearch_node_id(id) - return unresearch_node(get_techweb_node_by_id(id)) + return unresearch_node(SSresearch.techweb_node_by_id(id)) /datum/techweb/proc/unresearch_node(datum/techweb_node/node) if(!istype(node)) @@ -224,9 +232,9 @@ /datum/techweb/proc/boost_with_path(datum/techweb_node/N, itempath) if(!istype(N) || !ispath(itempath)) return FALSE - LAZYINITLIST(boosted_nodes[N]) + LAZYINITLIST(boosted_nodes[N.id]) for(var/i in N.boost_item_paths[itempath]) - boosted_nodes[N][i] = max(boosted_nodes[N][i], N.boost_item_paths[itempath][i]) + boosted_nodes[N.id][i] = max(boosted_nodes[N.id][i], N.boost_item_paths[itempath][i]) if(N.autounlock_by_boost) hidden_nodes -= N.id update_node_status(N) @@ -241,13 +249,13 @@ var/tier = 0 if (!researched_nodes[node.id]) // researched is tier 0 for (var/id in node.prereq_ids) - var/prereq_tier = tiers[node.prerequisites[id]] + var/prereq_tier = tiers[id] tier = max(tier, prereq_tier + 1) - if (tier != tiers[node]) - tiers[node] = tier - for (var/id in node.unlocks) - next += node.unlocks[id] + if (tier != tiers[node.id]) + tiers[node.id] = tier + for (var/id in node.unlock_ids) + next += SSresearch.techweb_node_by_id(id) current = next /datum/techweb/proc/update_node_status(datum/techweb_node/node, autoupdate_consoles = TRUE) @@ -257,8 +265,8 @@ if(researched_nodes[node.id]) researched = TRUE var/needed = node.prereq_ids.len - for(var/i in node.prereq_ids) - if(researched_nodes[i]) + for(var/id in node.prereq_ids) + if(researched_nodes[id]) visible = TRUE needed-- if(!needed) @@ -269,15 +277,15 @@ if(hidden_nodes[node.id]) //Hidden. return if(researched) - researched_nodes[node.id] = node - for(var/i in node.designs) - add_design(node.designs[i]) + researched_nodes[node.id] = TRUE + for(var/id in node.design_ids) + add_design(SSresearch.techweb_design_by_id(id)) else if(available) - available_nodes[node.id] = node + available_nodes[node.id] = TRUE else if(visible) - visible_nodes[node.id] = node + visible_nodes[node.id] = TRUE update_tiers(node) if(autoupdate_consoles) for(var/v in consoles_accessing) @@ -288,35 +296,34 @@ //Laggy procs to do specific checks, just in case. Don't use them if you can just use the vars that already store all this! /datum/techweb/proc/designHasReqs(datum/design/D) for(var/i in researched_nodes) - var/datum/techweb_node/N = researched_nodes[i] - for(var/I in N.designs) - if(D == N.designs[I]) - return TRUE + var/datum/techweb_node/N = SSresearch.techweb_node_by_id(i) + if(N.design_ids[D.id]) + return TRUE return FALSE /datum/techweb/proc/isDesignResearched(datum/design/D) return isDesignResearchedID(D.id) /datum/techweb/proc/isDesignResearchedID(id) - return researched_designs[id] + return researched_designs[id]? SSresearch.techweb_design_by_id(id) : FALSE /datum/techweb/proc/isNodeResearched(datum/techweb_node/N) return isNodeResearchedID(N.id) /datum/techweb/proc/isNodeResearchedID(id) - return researched_nodes[id] + return researched_nodes[id]? SSresearch.techweb_node_by_id(id) : FALSE /datum/techweb/proc/isNodeVisible(datum/techweb_node/N) return isNodeResearchedID(N.id) /datum/techweb/proc/isNodeVisibleID(id) - return visible_nodes[id] + return visible_nodes[id]? SSresearch.techweb_node_by_id(id) : FALSE /datum/techweb/proc/isNodeAvailable(datum/techweb_node/N) return isNodeAvailableID(N.id) /datum/techweb/proc/isNodeAvailableID(id) - return available_nodes[id] + return available_nodes[id]? SSresearch.techweb_node_by_id(id) : FALSE /datum/techweb/specialized var/allowed_buildtypes = ALL @@ -339,11 +346,11 @@ for(var/id in node_autounlock_ids) research_node_id(id, TRUE, FALSE) for(var/id in SSresearch.techweb_designs) - var/datum/design/D = SSresearch.techweb_designs[id] + var/datum/design/D = SSresearch.techweb_design_by_id(id) if(D.build_type & design_autounlock_buildtypes) for(var/i in D.category) if(i in design_autounlock_categories) - add_design(D) + add_design_by_id(D.id) break /datum/techweb/specialized/autounlocking/autolathe diff --git a/code/modules/research/techweb/_techweb_node.dm b/code/modules/research/techweb/_techweb_node.dm index 875329a89c2..bd6aea0a330 100644 --- a/code/modules/research/techweb/_techweb_node.dm +++ b/code/modules/research/techweb/_techweb_node.dm @@ -1,5 +1,6 @@ //Techweb nodes are GLOBAL, there should only be one instance of them in the game. Persistant changes should never be made to them in-game. +//USE SSRESEARCH PROCS TO OBTAIN REFERENCES. DO NOT REFERENCE OUTSIDE OF SSRESEARCH OR YOU WILL FUCK UP GC. /datum/techweb_node var/id @@ -9,20 +10,82 @@ var/starting_node = FALSE //Whether it's available without any research. var/list/prereq_ids = list() var/list/design_ids = list() - var/list/datum/techweb_node/prerequisites = list() //Assoc list id = datum - var/list/datum/techweb_node/unlocks = list() //CALCULATED FROM OTHER NODE'S PREREQUISITES. Assoc list id = datum. - var/list/datum/design/designs = list() //Assoc list id = datum + var/list/unlock_ids = list() //CALCULATED FROM OTHER NODE'S PREREQUISITES. Assoc list id = TRUE. var/list/boost_item_paths = list() //Associative list, path = list(point type = point_value). var/autounlock_by_boost = TRUE //boosting this will autounlock this node. var/export_price = 0 //Cargo export price. - var/list/research_costs = 0 //Point cost to research. type = amount + var/list/research_costs = list() //Point cost to research. type = amount var/category = "Misc" //Category +/datum/techweb_node/error_node + id = "ERROR" + display_name = "ERROR" + description = "This usually means something in the database has corrupted. If it doesn't go away automatically, inform Central Command for their techs to fix it ASAP(tm)" + +/datum/techweb_node/proc/Initialize() + //Make lists associative for lookup + for(var/id in prereq_ids) + prereq_ids[id] = TRUE + for(var/id in design_ids) + design_ids[id] = TRUE + for(var/id in unlock_ids) + unlock_ids[id] = TRUE + +/datum/techweb_node/Destroy() + SSresearch.techweb_nodes -= id + return ..() + +/datum/techweb_node/serialize_list(list/options) + . = list() + VARSET_TO_LIST(., id) + VARSET_TO_LIST(., display_name) + VARSET_TO_LIST(., hidden) + VARSET_TO_LIST(., starting_node) + VARSET_TO_LIST(., assoc_list_strip_value(prereq_ids)) + VARSET_TO_LIST(., assoc_list_strip_value(design_ids)) + VARSET_TO_LIST(., assoc_list_strip_value(unlock_ids)) + VARSET_TO_LIST(., boost_item_paths) + VARSET_TO_LIST(., autounlock_by_boost) + VARSET_TO_LIST(., export_price) + VARSET_TO_LIST(., research_costs) + VARSET_TO_LIST(., category) + +/datum/techweb_node/deserialize_list(list/input, list/options) + if(!input["id"]) + return + VARSET_FROM_LIST(input, id) + VARSET_FROM_LIST(input, display_name) + VARSET_FROM_LIST(input, hidden) + VARSET_FROM_LIST(input, starting_node) + VARSET_FROM_LIST(input, prereq_ids) + VARSET_FROM_LIST(input, design_ids) + VARSET_FROM_LIST(input, unlock_ids) + VARSET_FROM_LIST(input, boost_item_paths) + VARSET_FROM_LIST(input, autounlock_by_boost) + VARSET_FROM_LIST(input, export_price) + VARSET_FROM_LIST(input, research_costs) + VARSET_FROM_LIST(input, category) + Initialize() + return src + +/datum/techweb_node/proc/on_design_deletion(datum/design/D) + prune_design_id(D.id) + +/datum/techweb_node/proc/on_node_deletion(datum/techweb_node/TN) + prune_node_id(TN.id) + +/datum/techweb_node/proc/prune_design_id(design_id) + design_ids -= design_id + +/datum/techweb_node/proc/prune_node_id(node_id) + prereq_ids -= node_id + unlock_ids -= node_id + /datum/techweb_node/proc/get_price(datum/techweb/host) if(host) var/list/actual_costs = research_costs - if(host.boosted_nodes[src]) - var/list/L = host.boosted_nodes[src] + if(host.boosted_nodes[id]) + var/list/L = host.boosted_nodes[id] for(var/i in L) if(actual_costs[i]) actual_costs[i] -= L[i]