Files
Yogstation/code/controllers/subsystem/research.dm
kevinz000 bcf88a2064 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.
2018-10-05 19:51:10 +01:00

262 lines
9.7 KiB
Plaintext

SUBSYSTEM_DEF(research)
name = "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/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() //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)
)
var/list/errored_datums = list()
var/list/point_types = list() //typecache style type = TRUE list
//----------------------------------------------
var/list/single_server_income = list(TECHWEB_POINT_TYPE_GENERIC = 54.3)
var/multiserver_calculation = FALSE
var/last_income = 0
//^^^^^^^^ ALL OF THESE ARE PER SECOND! ^^^^^^^^
//Aiming for 1.5 hours to max R&D
//[88nodes * 5000points/node] / [1.5hr * 90min/hr * 60s/min]
//Around 450000 points max???
/datum/controller/subsystem/research/Initialize()
point_types = TECHWEB_POINT_TYPE_LIST_ASSOCIATIVE_NAMES
initialize_all_techweb_designs()
initialize_all_techweb_nodes()
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()
handle_research_income()
/datum/controller/subsystem/research/proc/handle_research_income()
var/list/bitcoins = list()
if(multiserver_calculation)
var/eff = calculate_server_coefficient()
for(var/obj/machinery/rnd/server/miner in servers)
var/list/result = (miner.mine()) //SLAVE AWAY, SLAVE.
for(var/i in result)
result[i] *= eff
bitcoins[i] = bitcoins[i]? bitcoins[i] + result[i] : result[i]
else
for(var/obj/machinery/rnd/server/miner in servers)
if(miner.working)
bitcoins = single_server_income.Copy()
break //Just need one to work.
var/income_time_difference = world.time - last_income
science_tech.last_bitcoins = bitcoins // Doesn't take tick drift into account
for(var/i in bitcoins)
bitcoins[i] *= income_time_difference / 10
science_tech.add_point_list(bitcoins)
last_income = world.time
/datum/controller/subsystem/research/proc/calculate_server_coefficient() //Diminishing returns.
var/amt = servers.len
if(!amt)
return 0
var/coeff = 100
coeff = sqrt(coeff / amt)
return coeff
/datum/controller/subsystem/research/proc/autosort_categories()
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] = TRUE
else
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