mirror of
https://github.com/yogstation13/Yogstation.git
synced 2025-02-26 09:04:50 +00:00
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.
262 lines
9.7 KiB
Plaintext
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
|