diff --git a/code/__DEFINES/misc.dm b/code/__DEFINES/misc.dm index 34c89a4e9e2f..3bcf1b5c46be 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 fed283adcddb..5640d6b109fc 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 30502de64434..d29d2e958444 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() @@ -76,6 +86,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 1b2414a320c1..b338069e1ce6 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 73fdcd5e8bae..ebe3516ab84e 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 8a0658fd0f81..9954f57b52e4 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 01e304872f16..ffa57b81ebe8 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 9d264c87e029..255b861f8bc9 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 e1eb97696671..7244ccea79f7 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 a004a6ae0d09..48c2f03d8c82 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 f3ccc31fcb72..0ec0cda375b3 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 491aa63e56b5..5cbe9a6f163f 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 5cc26381dd0e..ac76e8b9fea2 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 ebd386513ed1..71c92a4690d8 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 d3cd399635b1..6a18191af1f3 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 81c5a44527d7..13f8cb980755 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 fb3c5908f5b4..bfcd184bbfbd 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 1e90f0f28d92..6c967c09245b 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 c910f3c8964a..a5d3afd3fb52 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 @@ -155,21 +158,27 @@ return FALSE 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(datum/design/design) +/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, 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 @@ -187,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)) @@ -198,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) @@ -212,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)) @@ -223,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) @@ -240,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) @@ -256,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) @@ -268,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) @@ -287,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 @@ -338,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 875329a89c28..bd6aea0a3301 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]