-
-
Notifications
You must be signed in to change notification settings - Fork 444
/
Copy pathresearch.dm
284 lines (260 loc) · 10.8 KB
/
research.dm
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
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