mirror of
https://github.com/yogstation13/Yogstation.git
synced 2025-02-26 09:04:50 +00:00
Adds new Master RND server, with a special hard drive that if removed, halves point generation. Add a new "Steal Master HDD" objective, where you must steal the hard drive and escape with it. Gives Ninja a different objective to sabotage research, and using their gloves on the server will drain all the points. Removes "Steal Research" objective as it's stupid easy.
285 lines
11 KiB
Plaintext
285 lines
11 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/ruin/ruin_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
|
|
var/techweb_pixel_size = 800
|
|
var/techweb_legacy = FALSE
|
|
|
|
//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! ^^^^^^^^
|
|
|
|
/// A list of all master servers. If none of these have a source code HDD, research point generation is lowered.
|
|
var/list/obj/machinery/rnd/server/master/master_servers = list()
|
|
/// The multiplier to research points when no source code HDD is present.
|
|
var/no_source_code_income_modifier = 0.5
|
|
|
|
//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
|
|
ruin_tech = new /datum/techweb/ruin
|
|
admin_tech = new /datum/techweb/admin
|
|
autosort_categories()
|
|
error_design = new
|
|
error_node = new
|
|
return SS_INIT_SUCCESS
|
|
|
|
/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 as anything 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 as anything in servers)
|
|
if(miner.working)
|
|
bitcoins = single_server_income.Copy()
|
|
break //Just need one to work.
|
|
var/bitcoin_multiplier = no_source_code_income_modifier
|
|
for(var/obj/machinery/rnd/server/master/master_server as anything in master_servers)
|
|
if(master_server.source_code_hdd)
|
|
bitcoin_multiplier = 1
|
|
break
|
|
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
|
|
if(science_tech.stored_research_points[i])
|
|
var/boost_amt = clamp(0, bitcoins[i], science_tech.stored_research_points[i]) //up to 2x research speed when burning stored research
|
|
bitcoins[i] += boost_amt * bitcoin_multiplier
|
|
science_tech.remove_stored_point_type(i, boost_amt)
|
|
science_tech.add_point_list(bitcoins)
|
|
//add RUIN_GENERATION_PER_TICK even without any servers, for things like freeminers
|
|
ruin_tech.add_point_list(list(TECHWEB_POINT_TYPE_GENERIC = RUIN_GENERATION_PER_TICK, TECHWEB_POINT_TYPE_NANITES = NANITES_RESEARCH_RUIN_PER_TICK))
|
|
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)
|
|
if(!techweb_nodes[id])
|
|
stack_trace("[id] node caused error node to appear!")
|
|
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! Path: [path]")
|
|
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! Path: [path]")
|
|
errored_datums[DN] = initial(DN.id)
|
|
continue
|
|
DN.InitializeMaterials() //Initialize the materials in the design
|
|
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
|