-
-
Notifications
You must be signed in to change notification settings - Fork 444
/
Copy pathreactor.dm
1074 lines (951 loc) · 53.2 KB
/
reactor.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
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
/// See code/__DEFINES/reactor.dm for all the defines used
//Remember kids. If the reactor itself is not physically powered by an APC, it cannot shove coolant in!
//Helper proc to set a new looping ambience, and play it to any mobs already inside of that area.
/obj/machinery/atmospherics/components/trinary/nuclear_reactor
name = "\improper Advanced Gas-Cooled Nuclear Reactor"
desc = "A tried and tested design which can output stable power at an acceptably low risk. The moderator can be changed to provide different effects."
icon = 'icons/obj/machines/reactor.dmi'
icon_state = "reactor_map"
pixel_x = -32
pixel_y = -32
density = FALSE //It burns you if you're stupid enough to walk over it.
anchored = TRUE
resistance_flags = INDESTRUCTIBLE | LAVA_PROOF | FIRE_PROOF | UNACIDABLE | ACID_PROOF | FREEZE_PROOF
light_color = LIGHT_COLOR_CYAN
dir = 2 //Less headache inducing
startingvolume = 600 // 3x base
var/id = null //Change me mappers
//Variables essential to operation
var/active = FALSE
var/temperature = T20C //Lose control of this -> Meltdown
var/vessel_integrity = 400 //How long can the reactor withstand overpressure / meltdown? This gives you a fair chance to react to even a massive pipe fire
var/pressure = 0 //Lose control of this -> Blowout
var/K = 0 //Rate of reaction.
var/desired_k = 0
var/control_rod_effectiveness = 0.65 //Starts off with a lot of control over K. If you flood this thing with plasma, you lose your ability to control K as easily.
var/power = 0 //0-100%. A function of the maximum heat you can achieve within operating temperature
var/power_modifier = 1 //Upgrade me with parts, science! Flat out increase to physical power output when loaded with plasma.
var/list/fuel_rods = list()
//Secondary variables.
var/gas_absorption_effectiveness = 0.5
var/gas_absorption_constant = 0.5 //We refer to this one as it's set on init, randomized.
var/minimum_coolant_level = MINIMUM_MOLE_COUNT
var/integrity_restoration = 0
var/next_warning = 0 //To avoid spam.
var/last_power_produced = 0 //For logging purposes
var/next_flicker = 0 //Light flicker timer
var/base_power_modifier = REACTOR_POWER_FLAVOURISER
var/slagged = FALSE //Is this reactor even usable any more?
var/explosion_power = 7 //The explosion strength
//Console statistics.
var/last_coolant_temperature = 0
var/last_output_temperature = 0
var/last_heat_delta = 0 //For administrative cheating only. Knowing the delta lets you know EXACTLY what to set K at.
var/last_user = null
var/current_desired_k = null
var/obj/item/radio/radio
var/key_type = /obj/item/encryptionkey/headset_eng
//Which channels should it broadcast to?
var/engi_channel = RADIO_CHANNEL_ENGINEERING
var/crew_channel = RADIO_CHANNEL_COMMON
var/has_hit_emergency = FALSE
var/evacuation_procedures = FALSE
//Data, because graphs are cool
var/list/kpaData = list()
var/list/powerData = list()
var/list/tempCoreData = list()
var/list/tempInputData = list()
var/list/tempOutputData = list()
//Use this in your maps if you want everything to be preset.
/obj/machinery/atmospherics/components/trinary/nuclear_reactor/preset
id = "default_reactor_for_lazy_mappers"
/obj/machinery/atmospherics/components/trinary/nuclear_reactor/syndie_base
id = "syndie_base_reactor"
// uses syndicate comms
engi_channel = RADIO_CHANNEL_SYNDICATE
crew_channel = RADIO_CHANNEL_SYNDICATE
key_type = /obj/item/encryptionkey/syndicate
/obj/machinery/atmospherics/components/trinary/nuclear_reactor/New()
. = ..()
if(isnull(id))
id = getnewid()
/obj/machinery/atmospherics/components/trinary/nuclear_reactor/get_integrity()
return round(100 * vessel_integrity / initial(vessel_integrity), 0.01)
/obj/machinery/atmospherics/components/trinary/nuclear_reactor/examine(mob/user)
. = ..()
if(Adjacent(src, user) || isobserver(user))
var/msg
if(slagged)
msg = span_boldwarning("The reactor is destroyed. Its core lies exposed!")
else
msg = span_warning("The reactor looks operational.")
switch(get_integrity())
if(0 to 10)
msg = span_boldwarning("[src]'s seals are dangerously warped and you can see cracks all over the reactor vessel!")
if(10 to 40)
msg = span_boldwarning("[src]'s seals are heavily warped and cracked!")
if(40 to 60)
msg = span_warning("[src]'s seals are holding, but barely. You can see some micro-fractures forming in the reactor vessel.")
if(60 to 80)
msg = span_warning("[src]'s seals are in-tact, but slightly worn. There are no visible cracks in the reactor vessel.")
if(80 to 90)
msg = span_notice("[src]'s seals are in good shape, and there are no visible cracks in the reactor vessel.")
if(95 to 100)
msg = span_notice("[src]'s seals look factory new, and the reactor's in excellent shape.")
. += msg
/obj/machinery/atmospherics/components/trinary/nuclear_reactor/attackby(obj/item/W, mob/user, params)
if(istype(W, /obj/item/fuel_rod))
return try_insert_fuel(W, user)
if(istype(W, /obj/item/sealant))
if(slagged)
to_chat(user, span_warning("The reactor has been critically damaged!"))
return FALSE
if(temperature > REACTOR_TEMPERATURE_MINIMUM)
to_chat(user, span_warning("You cannot repair [src] while the core temperature is above [REACTOR_TEMPERATURE_MINIMUM] kelvin."))
return FALSE
if(vessel_integrity >= 350)
to_chat(user, span_warning("[src]'s seals are already in-tact, repairing them further would require a new set of seals."))
return FALSE
if(get_integrity() <= 50) //Heavily damaged.
to_chat(user, span_warning("[src]'s reactor vessel is cracked and worn, you need to repair the cracks with a welder before you can repair the seals."))
return FALSE
while(do_after(user, 1 SECONDS, target=src))
playsound(src, 'sound/effects/spray2.ogg', 50, 1, -6)
vessel_integrity += 10
vessel_integrity = clamp(vessel_integrity, 0, initial(vessel_integrity))
if(vessel_integrity >= 350) // Check if it's done
to_chat(user, span_warning("[src]'s seals are already in-tact, repairing them further would require a new set of seals."))
return FALSE
user.visible_message(span_warning("[user] applies sealant to some of [src]'s worn out seals."), span_notice("You apply sealant to some of [src]'s worn out seals."))
return TRUE
return ..()
/obj/machinery/atmospherics/components/trinary/nuclear_reactor/MouseDrop_T(atom/A, mob/living/user)
if(user.incapacitated())
return
if(!user.IsAdvancedToolUser())
to_chat(user, span_warning("You don't have the dexterity to do this!"))
return
if(istype(A, /obj/item/fuel_rod))
try_insert_fuel(A, user)
/obj/machinery/atmospherics/components/trinary/nuclear_reactor/proc/try_insert_fuel(obj/item/fuel_rod/rod, mob/user)
if(!istype(rod))
return FALSE
if(slagged)
to_chat(user, span_warning("The reactor has been critically damaged"))
return FALSE
if(temperature > REACTOR_TEMPERATURE_MINIMUM)
to_chat(user, span_warning("You cannot insert fuel into [src] with the core temperature above [REACTOR_TEMPERATURE_MINIMUM] kelvin."))
return FALSE
if(fuel_rods.len >= REACTOR_MAX_FUEL_RODS)
to_chat(user, span_warning("[src] is already at maximum fuel load."))
return FALSE
to_chat(user, span_notice("You start to insert [rod] into [src]..."))
radiation_pulse(src, temperature)
if(do_after(user, 2 SECONDS, target=src))
fuel_rods += rod
rod.forceMove(src)
radiation_pulse(src, temperature) //Wear protective equipment when even breathing near a reactor!
investigate_log("Rod added to reactor by [key_name(user)] at [AREACOORD(src)]", INVESTIGATE_REACTOR)
return TRUE
/obj/machinery/atmospherics/components/trinary/nuclear_reactor/crowbar_act(mob/living/user, obj/item/I)
if(slagged)
to_chat(user, span_warning("The fuel rods have melted into a radioactive lump."))
var/removal_time = 5 SECONDS
if(temperature > REACTOR_TEMPERATURE_MINIMUM)
if(istype(I, /obj/item/jawsoflife)) // Snatch the reactor from the jaws of death!
removal_time *= 2
else
to_chat(user, span_warning("You can't remove fuel rods while the reactor is operating above [REACTOR_TEMPERATURE_MINIMUM] kelvin!"))
return TRUE
if(!has_fuel())
to_chat(user, span_notice("The reactor has no fuel rods!"))
return TRUE
var/obj/item/fuel_rod/rod = tgui_input_list(usr, "Select a fuel rod to remove", "Fuel Rods", fuel_rods)
if(rod && istype(rod) && I.use_tool(src, user, removal_time, volume=50))
if(temperature > REACTOR_TEMPERATURE_MINIMUM)
var/turf/T = get_turf(src)
T.atmos_spawn_air("water_vapor=[pressure/100];TEMP=[temperature]")
user.rad_act(rod.fuel_power * 1000)
fuel_rods.Remove(rod)
if(ismecha(user.loc))
rod.forceMove(get_step(get_turf(user.loc), user.loc.dir))
return TRUE
if(!user.put_in_hands(rod))
rod.forceMove(user.loc)
return TRUE
/obj/machinery/atmospherics/components/trinary/nuclear_reactor/welder_act(mob/living/user, obj/item/I)
if(slagged)
to_chat(user, span_warning("The reactor has been critically damaged"))
return TRUE
if(temperature > REACTOR_TEMPERATURE_MINIMUM)
to_chat(user, span_warning("You can't repair [src] while it is running at above [REACTOR_TEMPERATURE_MINIMUM] kelvin."))
return TRUE
if(get_integrity() > 50)
to_chat(user, span_warning("[src] is free from cracks. Further repairs must be carried out with flexi-seal sealant."))
return TRUE
while(I.use_tool(src, user, 1 SECONDS, volume=40))
vessel_integrity += 20
if(get_integrity() > 50)
to_chat(user, span_warning("[src] is free from cracks. Further repairs must be carried out with flexi-seal sealant."))
return TRUE
to_chat(user, span_notice("You weld together some of [src]'s cracks. This'll do for now."))
return TRUE
/obj/machinery/atmospherics/components/trinary/nuclear_reactor/multitool_act(mob/living/user, obj/item/multitool/I)
to_chat(user, "<span class='notice'>You add \the [src]'s ID into the multitool's buffer.</span>")
multitool_set_buffer(user, I, src)
return TRUE
//Admin procs to mess with the reaction environment.
/obj/machinery/atmospherics/components/trinary/nuclear_reactor/proc/lazy_startup()
for(var/I=0;I<5;I++)
fuel_rods += new /obj/item/fuel_rod(src)
message_admins("Reactor started up by admins in [ADMIN_VERBOSEJMP(src)]")
start_up()
/obj/machinery/atmospherics/components/trinary/nuclear_reactor/proc/deplete()
for(var/obj/item/fuel_rod/FR in fuel_rods)
FR.depletion = 100
/obj/machinery/atmospherics/components/trinary/nuclear_reactor/Initialize(mapload)
. = ..()
icon_state = "reactor_off"
gas_absorption_effectiveness = rand(5, 6)/10 //All reactors are slightly different. This will result in you having to figure out what the balance is for K.
gas_absorption_constant = gas_absorption_effectiveness //And set this up for the rest of the round.
radio = new(src)
radio.keyslot = new key_type(radio)
radio.subspace_transmission = TRUE
radio.use_command = TRUE
radio.canhear_range = 0
radio.recalculateChannels()
connect_to_network()
STOP_PROCESSING(SSmachines, src) //We'll handle this one ourselves.
/obj/machinery/atmospherics/components/trinary/nuclear_reactor/Crossed(atom/movable/AM, oldloc)
. = ..()
if(isliving(AM) && temperature > T0C)
var/mob/living/L = AM
L.adjust_bodytemperature(clamp(temperature, BODYTEMP_COOLING_MAX, BODYTEMP_HEATING_MAX)) //If you're on fire, you heat up!
/obj/machinery/atmospherics/components/trinary/nuclear_reactor/process()
// Find a powernet
if(!powernet)
connect_to_network()
// Make some power!
add_avail(last_power_produced)
// You're overloading the reactor. Give a more subtle warning that power is getting out of control.
if(power >= 100 && world.time >= next_flicker)
next_flicker = world.time + 1.5 MINUTES
for(var/obj/machinery/light/L in GLOB.lights)
if(prob(25) && L.z == z) //If youre running the reactor cold though, no need to flicker the lights.
L.flicker()
investigate_log("Reactor overloading at [power]% power", INVESTIGATE_REACTOR)
// Meltdown this, blowout that, I just wanna grill for god's sake!
for(var/atom/movable/I in get_turf(src))
if(isliving(I))
var/mob/living/L = I
if(temperature > L.bodytemperature)
L.adjust_bodytemperature(clamp(temperature, BODYTEMP_COOLING_MAX, BODYTEMP_HEATING_MAX)) //If you're on fire, you heat up!
if(istype(I, /obj/item/reagent_containers/food) && !istype(I, /obj/item/reagent_containers/food/drinks) && temperature >= REACTOR_TEMPERATURE_MINIMUM)
playsound(src, pick('sound/machines/fryer/deep_fryer_1.ogg', 'sound/machines/fryer/deep_fryer_2.ogg'), 100, TRUE)
var/obj/item/reagent_containers/food/grilled_item = I
if(!(grilled_item.foodtype & FRIED))
if(prob(100 - power))
return //To give the illusion that it's actually cooking omegalul.
SEND_SIGNAL(grilled_item, COMSIG_ITEM_GRILLED, src, INFINITY)
switch(power)
if(0 to 39)
grilled_item.name = "grilled [initial(grilled_item.name)]"
grilled_item.desc = "[initial(I.desc)] It's been grilled over a nuclear reactor."
if(40 to 70)
grilled_item.name = "heavily grilled [initial(grilled_item.name)]"
grilled_item.desc = "[initial(I.desc)] It's been heavily grilled through the magic of nuclear fission."
if(70 to 95)
grilled_item.name = "\improper Three-Mile Nuclear-Grilled [initial(grilled_item.name)]"
grilled_item.desc = "A [initial(grilled_item.name)]. It's been put on top of a nuclear reactor running at extreme power by some badass engineer."
if(95 to INFINITY)
grilled_item.name = "\improper Ultimate Meltdown Grilled [initial(grilled_item.name)]"
grilled_item.desc = "A [initial(grilled_item.name)]. A grill this perfect is a rare technique only known by a few engineers who know how to perform a 'controlled' meltdown whilst also having the time to throw food on a reactor. I'll bet it tastes amazing."
grilled_item.foodtype |= FRIED
grilled_item.add_atom_colour(rgb(103,63,24), FIXED_COLOUR_PRIORITY)
/obj/machinery/atmospherics/components/trinary/nuclear_reactor/process_atmos(delta_time)
//Let's get our gasses sorted out.
var/datum/gas_mixture/coolant_input = airs[COOLANT_INPUT_GATE]
var/datum/gas_mixture/moderator_input = airs[MODERATOR_INPUT_GATE]
var/datum/gas_mixture/coolant_output = airs[COOLANT_OUTPUT_GATE]
var/power_produced = 0 // How much power we're producing from the moderator
var/radioactivity_spice_multiplier = 1 + get_fuel_power() //Some gasses make the reactor a bit spicy.
var/depletion_modifier = 0.035 //How rapidly do your rods decay
gas_absorption_effectiveness = gas_absorption_constant
last_power_produced = 0
//Make absolutely sure that pipe connections are updated
update_parents()
//First up, handle moderators!
if(active && moderator_input.total_moles() >= minimum_coolant_level)
// Fuel types: increases power and K
var/total_fuel_moles = 0
total_fuel_moles += moderator_input.get_moles(GAS_PLASMA) * PLASMA_FUEL_POWER
total_fuel_moles += moderator_input.get_moles(GAS_TRITIUM) * TRITIUM_FUEL_POWER
total_fuel_moles += moderator_input.get_moles(GAS_ANTINOB) * ANTINOBLIUM_FUEL_POWER
// Power modifier types: increases fuel effectiveness
var/power_mod_moles = 0
power_mod_moles += moderator_input.get_moles(GAS_O2) * OXYGEN_POWER_MOD
power_mod_moles += moderator_input.get_moles(GAS_H2) * HYDROGEN_POWER_MOD
// Now make some actual power!
if(total_fuel_moles >= minimum_coolant_level) //You at least need SOME fuel.
var/fuel_power = max((total_fuel_moles * 10 / moderator_input.total_moles()), 1)
var/power_modifier = max(power_mod_moles * 10 / moderator_input.total_moles(), 1) //You can never have negative IPM. For now.
power_produced = max(0,((fuel_power*power_modifier)*moderator_input.total_moles())) / delta_time
if(active)
coolant_output.adjust_moles(GAS_PLUONIUM, total_fuel_moles/20) //Shove out pluonium into the air when it's fuelled. You need to filter this off, or you're gonna have a bad time.
// Control types: increases control of K
var/total_control_moles = 0
total_control_moles += moderator_input.get_moles(GAS_N2) * NITROGEN_CONTROL_MOD
total_control_moles += moderator_input.get_moles(GAS_CO2) * CARBON_CONTROL_MOD
total_control_moles += moderator_input.get_moles(GAS_PLUOXIUM) * PLUOXIUM_CONTROL_MOD
if(total_control_moles >= minimum_coolant_level)
var/control_bonus = total_control_moles / REACTOR_CONTROL_FACTOR //1 mol of n2 -> 0.002 bonus control rod effectiveness, if you want a super controlled reaction, you'll have to sacrifice some power.
control_rod_effectiveness = initial(control_rod_effectiveness) + control_bonus
// Permeability types: increases cooling efficiency
var/total_permeability_moles = 0
total_permeability_moles += moderator_input.get_moles(GAS_BZ) * BZ_PERMEABILITY_MOD
total_permeability_moles += moderator_input.get_moles(GAS_H2O) * WATER_PERMEABILITY_MOD
total_permeability_moles += moderator_input.get_moles(GAS_HYPERNOB) * NOBLIUM_PERMEABILITY_MOD
if(total_permeability_moles >= minimum_coolant_level)
gas_absorption_effectiveness = clamp(gas_absorption_constant + (total_permeability_moles / REACTOR_PERMEABILITY_FACTOR), 0, 1)
// Radiation types: increases radiation
radioactivity_spice_multiplier += moderator_input.get_moles(GAS_N2) * NITROGEN_RAD_MOD //An example setup of 50 moles of n2 (for dealing with spent fuel) leaves us with a radioactivity spice multiplier of 3.
radioactivity_spice_multiplier += moderator_input.get_moles(GAS_CO2) * CARBON_RAD_MOD
radioactivity_spice_multiplier += moderator_input.get_moles(GAS_H2) * HYDROGEN_RAD_MOD
radioactivity_spice_multiplier += moderator_input.get_moles(GAS_TRITIUM) * TRITIUM_RAD_MOD
radioactivity_spice_multiplier += moderator_input.get_moles(GAS_ANTINOB) * ANTINOBLIUM_RAD_MOD
// Integrity modification
var/healium_moles = moderator_input.get_moles(GAS_HEALIUM)
if(healium_moles > minimum_coolant_level)
integrity_restoration = max((2400-max(TCMB, temperature))/300) * delta_time //At 1800K integrity_restoration should be around 1, which then it cant keep up with the heat damage (around 1.1 maximum in temp_damage) to restore integrity
// Degradation types: degrades the fuel rods
var/total_degradation_moles = moderator_input.get_moles(GAS_PLUONIUM) //Because it's quite hard to get.
if(total_degradation_moles >= minimum_coolant_level) //I'll be nice.
depletion_modifier += total_degradation_moles / 15 //Oops! All depletion. This causes your fuel rods to get SPICY.
if(prob(total_degradation_moles)) // don't spam the sound so much please
playsound(src, pick('sound/machines/sm/accent/normal/1.ogg','sound/machines/sm/accent/normal/2.ogg','sound/machines/sm/accent/normal/3.ogg','sound/machines/sm/accent/normal/4.ogg','sound/machines/sm/accent/normal/5.ogg'), 100, TRUE)
//From this point onwards, we clear out the remaining gasses.
moderator_input.remove_ratio(REACTOR_MODERATOR_DECAY_RATE) //Remove about 10% of the gases
K += total_fuel_moles / 1000
else // if there's not enough to do anything, just clear it
moderator_input.clear()
var/fuel_power = 0 //So that you can't magically generate K with your control rods.
if(active)
if(!has_fuel()) //Reactor must be fuelled and ready to go before we can heat it up.
shut_down() // shut it down!!!
else
for(var/obj/item/fuel_rod/FR in fuel_rods)
K += FR.fuel_power
fuel_power += FR.fuel_power
FR.deplete(depletion_modifier)
radioactivity_spice_multiplier += fuel_power
// Firstly, find the difference between the two numbers.
var/difference = abs(K - desired_k)
// Then, hit as much of that goal with our cooling per tick as we possibly can.
difference = clamp(difference, 0, control_rod_effectiveness) //And we can't instantly zap the K to what we want, so let's zap as much of it as we can manage....
if(difference > fuel_power && desired_k > K)
investigate_log("Reactor does not have enough fuel to get [difference]. We have [fuel_power] fuel power.", INVESTIGATE_REACTOR)
difference = fuel_power //Again, to stop you being able to run off of 1 fuel rod.
// If K isn't what we want it to be, let's try to change that
if(K != desired_k)
if(desired_k > K)
K += difference
else if(desired_k < K)
K -= difference
if(last_user && current_desired_k != desired_k) // Tell admins about it if it's done by a player
current_desired_k = desired_k
message_admins("Reactor desired criticality set to [desired_k] by [ADMIN_LOOKUPFLW(last_user)] in [ADMIN_VERBOSEJMP(src)]")
investigate_log("reactor desired criticality set to [desired_k] by [key_name(last_user)] at [AREACOORD(src)]", INVESTIGATE_REACTOR)
// Now, clamp K and heat up the reactor based on it.
K = clamp(K, 0, REACTOR_MAX_CRITICALITY)
var/particle_chance = min(power * K, 1000)
while(particle_chance >= 100)
fire_nuclear_particle()
particle_chance -= 100
if(prob(particle_chance))
fire_nuclear_particle()
if(active && has_fuel())
temperature += REACTOR_HEAT_FACTOR * delta_time * has_fuel() * ((REACTOR_HEAT_EXPONENT**K) - 1) // heating from K has to be exponential to make higher K more dangerous
// Cooling time!
var/input_moles = coolant_input.total_moles() //Firstly. Do we have enough moles of coolant?
if(input_moles >= minimum_coolant_level)
last_coolant_temperature = coolant_input.return_temperature()
//Important thing to remember, once you slot in the fuel rods, this thing will not stop making heat, at least, not unless you can live to be thousands of years old which is when the spent fuel finally depletes fully.
var/heat_delta = (last_coolant_temperature - temperature) * gas_absorption_effectiveness //Take in the gas as a cooled input, cool the reactor a bit. The optimum, 100% balanced reaction sits at K=1, coolant input temp of 200K / -73 celsius.
var/coolant_heat_factor = coolant_input.heat_capacity() / (coolant_input.heat_capacity() + REACTOR_HEAT_CAPACITY + (REACTOR_ROD_HEAT_CAPACITY * has_fuel())) //What percent of the total heat capacity is in the coolant
last_heat_delta = heat_delta
temperature += heat_delta * coolant_heat_factor
coolant_input.set_temperature(last_coolant_temperature - (heat_delta * (1 - coolant_heat_factor))) //Heat the coolant output gas that we just had pass through us.
coolant_output.merge(coolant_input) //And now, shove the input into the output.
coolant_input.clear() //Clear out anything left in the input gate.
color = null
// And finally, set our pressure.
last_output_temperature = coolant_output.return_temperature()
pressure = coolant_output.return_pressure()
power = ((temperature / REACTOR_TEMPERATURE_CRITICAL)**3) * 100
// Make some power!
if(power_produced > 0)
last_power_produced = power_produced
last_power_produced *= (max(0,power)/100) //Aaaand here comes the cap. Hotter reactor => more power.
last_power_produced *= base_power_modifier //Finally, we turn it into actual usable numbers.
// Let's check if they're about to die, and let them know.
handle_alerts(delta_time)
update_icon()
// Finally, our beautiful radiation!
radiation_pulse(src, K*temperature*radioactivity_spice_multiplier*has_fuel()/(REACTOR_MAX_CRITICALITY*REACTOR_MAX_FUEL_RODS))
// I FUCKING LOVE DATA!!!!!!
kpaData += pressure
if(kpaData.len > 100) //Only lets you track over a certain timeframe.
kpaData.Cut(1, 2)
powerData += last_power_produced //We scale up the figure for a consistent:tm: scale
if(powerData.len > 100) //Only lets you track over a certain timeframe.
powerData.Cut(1, 2)
tempCoreData += temperature //We scale up the figure for a consistent:tm: scale
if(tempCoreData.len > 100) //Only lets you track over a certain timeframe.
tempCoreData.Cut(1, 2)
tempInputData += last_coolant_temperature //We scale up the figure for a consistent:tm: scale
if(tempInputData.len > 100) //Only lets you track over a certain timeframe.
tempInputData.Cut(1, 2)
tempOutputData += last_output_temperature //We scale up the figure for a consistent:tm: scale
if(tempOutputData.len > 100) //Only lets you track over a certain timeframe.
tempOutputData.Cut(1, 2)
/obj/machinery/atmospherics/components/trinary/nuclear_reactor/proc/has_fuel()
return length(fuel_rods)
/obj/machinery/atmospherics/components/trinary/nuclear_reactor/proc/get_fuel_power()
var/total_fuel_power = 0
for(var/obj/item/fuel_rod/rod in fuel_rods)
total_fuel_power += rod.fuel_power
return total_fuel_power
/obj/machinery/atmospherics/components/trinary/nuclear_reactor/proc/relay(sound, message=null, loop = FALSE, channel = null) //Sends a sound + text message to the crew of a ship
for(var/mob/M in GLOB.player_list)
if(M.z == z)
if(!isinspace(M))
if(sound)
if(channel) //Doing this forbids overlapping of sounds
SEND_SOUND(M, sound(sound, repeat = loop, wait = 0, volume = 70, channel = channel))
else
SEND_SOUND(M, sound(sound, repeat = loop, wait = 0, volume = 70))
if(message)
to_chat(M, message)
/obj/machinery/atmospherics/components/trinary/nuclear_reactor/proc/stop_relay(channel) //Stops all playing sounds for crewmen on N channel.
for(var/mob/M in GLOB.player_list)
if(M.z == z)
M.stop_sound_channel(channel)
//Method to handle sound effects, reactor warnings, all that jazz.
/obj/machinery/atmospherics/components/trinary/nuclear_reactor/proc/handle_alerts(delta_time)
var/alert = FALSE //If we have an alert condition, we'd best let people know.
//First alert condition: Overheat
if(temperature >= REACTOR_TEMPERATURE_CRITICAL)
alert = TRUE
for(var/i in 1 to min((temperature-REACTOR_TEMPERATURE_CRITICAL)/100, 10))
src.fire_nuclear_particle()
if(temperature >= REACTOR_TEMPERATURE_MELTDOWN || prob(10))
var/temp_damage = min(temperature/300, initial(vessel_integrity)/180) * delta_time //3 minutes to meltdown from full integrity, worst-case.
vessel_integrity -= temp_damage
else if(temperature < 73) //That's as cold as I'm letting you get it, engineering.
color = COLOR_CYAN
else
color = null
vessel_integrity += integrity_restoration
if(vessel_integrity > initial(vessel_integrity)) //hey you cant go above
vessel_integrity = initial(vessel_integrity)
//Second alert condition: Overpressurized (the more lethal one)
if(pressure >= REACTOR_PRESSURE_CRITICAL)
alert = TRUE
Shake(6, 6, (delta_time/2) SECONDS)
playsound(loc, 'sound/machines/clockcult/steam_whoosh.ogg', 100, TRUE)
var/turf/T = get_turf(src)
T.atmos_spawn_air("water_vapor=[pressure/100];TEMP=[temperature]")
var/pressure_damage = min(pressure/300, initial(vessel_integrity)/180) * delta_time //You get 60 seconds (if you had full integrity), worst-case. But hey, at least it can't be instantly nuked with a pipe-fire.. though it's still very difficult to save.
vessel_integrity -= pressure_damage
if(vessel_integrity <= 0) //It wouldn't be able to tank another hit.
investigate_log("Reactor blowout at [pressure] kPa with desired criticality at [desired_k]", INVESTIGATE_REACTOR)
blowout()
return
// Yikes, that's no good
if(vessel_integrity <= 0)
investigate_log("Reactor melted down at [temperature] kelvin with desired criticality at [desired_k]", INVESTIGATE_REACTOR)
meltdown() //Oops! All meltdown
return
if(!alert) //Congrats! You stopped the meltdown / blowout.
if(!next_warning)
return // don't bother if the reactor wasn't in trouble
stop_relay(CHANNEL_REACTOR_ALERT)
next_warning = 0 // there's no next warning if the reactor is fine
set_light(0)
light_color = LIGHT_COLOR_CYAN
set_light(10)
var/msg = "Reactor returning to safe operating parameters."
if(vessel_integrity <= 350)
msg += " Maintenance required."
msg += " Structural integrity: [get_integrity()]%."
radio.talk_into(src, msg, engi_channel)
if(evacuation_procedures)
radio.talk_into(src, "Attention: Reactor has been stabilized. Please return to your workplaces.", crew_channel)
evacuation_procedures = FALSE
return
if(world.time < next_warning) // we're not ready for another warning yet
return
next_warning = world.time + 30 SECONDS //To avoid engis pissing people off when reaaaally trying to stop the meltdown or whatever.
if(get_integrity() < 40 && !evacuation_procedures)
evacuation_procedures = TRUE
radio.talk_into(src, "WARNING: Reactor failure imminent. Integrity: [get_integrity()]%", engi_channel)
radio.talk_into(src, "Reactor failure imminent. Please remain calm and evacuate the facility immediately.", crew_channel)
playsound(src, 'sound/machines/reactor_alert_3.ogg', 100, extrarange=100, pressure_affected=FALSE, ignore_walls=TRUE)
relay('sound/effects/reactor/alarm.ogg', null, TRUE, channel = CHANNEL_REACTOR_ALERT)
else if(get_integrity() < 95)
radio.talk_into(src, "WARNING: Reactor structural integrity faltering. Integrity: [get_integrity()]%", engi_channel)
playsound(src, 'sound/machines/reactor_alert_1.ogg', 75, extrarange=50, pressure_affected=FALSE, ignore_walls=TRUE)
set_light(0)
light_color = LIGHT_COLOR_RED
set_light(10)
//PANIC
//Failure condition 1: Meltdown. Achieved by having heat go over tolerances. This is less devastating because it's easier to achieve.
//Results: Engineering becomes unusable and your engine irreparable
/obj/machinery/atmospherics/components/trinary/nuclear_reactor/proc/meltdown()
set waitfor = FALSE
SSair.stop_processing_machine(src)
vessel_integrity = null // this makes it show up weird on the monitor to even further emphasize something's gone horribly wrong
slagged = TRUE
color = null
update_icon()
STOP_PROCESSING(SSmachines, src)
icon_state = "reactor_slagged"
AddComponent(/datum/component/radioactive, 15000 , src, 0)
var/obj/effect/landmark/nuclear_waste_spawner/NSW = new /obj/effect/landmark/nuclear_waste_spawner/strong(get_turf(src))
relay('sound/effects/reactor/meltdown.ogg', "<span class='userdanger'>You hear a horrible metallic hissing.</span>")
stop_relay(CHANNEL_REACTOR_ALERT)
NSW.fire() //This will take out engineering for a decent amount of time as they have to clean up the sludge.
for(var/obj/machinery/power/apc/apc in GLOB.apcs_list)
if((apc.z == z) && prob(70))
apc.overload_lighting()
var/datum/gas_mixture/coolant_input = airs[COOLANT_INPUT_GATE]
var/datum/gas_mixture/moderator_input = airs[MODERATOR_INPUT_GATE]
var/datum/gas_mixture/coolant_output = airs[COOLANT_OUTPUT_GATE]
var/turf/T = get_turf(src)
coolant_input.set_temperature(temperature*2)
moderator_input.set_temperature(temperature*2)
coolant_output.set_temperature(temperature*2)
T.assume_air(coolant_input)
T.assume_air(moderator_input)
T.assume_air(coolant_output)
var/turf/lower_turf = GET_TURF_BELOW(T)
if(lower_turf) // reactor fuel will melt down into the lower levels on multi-z maps like icemeta
new /obj/structure/reactor_corium(lower_turf)
var/turf/lowest_turf = GET_TURF_BELOW(lower_turf)
if(lowest_turf) // WE NEED TO GO DEEPER
new /obj/structure/reactor_corium(lower_turf)
explosion(get_turf(src), GLOB.MAX_EX_DEVESTATION_RANGE, GLOB.MAX_EX_HEAVY_RANGE, GLOB.MAX_EX_LIGHT_RANGE, GLOB.MAX_EX_FLASH_RANGE)
radiation_pulse(src, (K+1)*temperature*get_fuel_power()*has_fuel()/(REACTOR_MAX_CRITICALITY*REACTOR_MAX_FUEL_RODS))
shockwave()
//Failure condition 2: Blowout. Achieved by reactor going over-pressured. This is a round-ender because it requires more fuckery to achieve.
/obj/machinery/atmospherics/components/trinary/nuclear_reactor/proc/blowout()
var/explosion_mod = clamp(log(10, pressure), 1, 10)
explosion(get_turf(src), explosion_power * explosion_mod * 0.5, explosion_power * explosion_mod + 2, explosion_power * explosion_mod + 4, explosion_power * explosion_mod + 6, 1, 1)
meltdown() //Double kill.
relay('sound/effects/reactor/explode.ogg')
priority_announce("Level 10 radiation hazard alert! Clouds of nuclear ash are forming near the reactor and expanding rapidly. Maintenance is the best shield against the ash storm.", "Radiation Alert", 'sound/misc/airraid.ogg', color_override="yellow")
SSweather.run_weather("nuclear fallout", src.z)
for(var/X in GLOB.landmarks_list)
if(istype(X, /obj/effect/landmark/nuclear_waste_spawner))
var/obj/effect/landmark/nuclear_waste_spawner/WS = X
if(is_station_level(WS.z)) //Begin the SLUDGING
WS.range *= log(temperature)+K
WS.fire()
/obj/machinery/atmospherics/components/trinary/nuclear_reactor/proc/shockwave()
var/atom/movable/gravity_lens/shockwave = new(src)
shockwave.transform = matrix().Scale(0.5)
shockwave.pixel_x = -240
shockwave.pixel_y = -240
animate(shockwave, alpha = 0, transform = matrix().Scale(20), time = 10 SECONDS, easing = QUAD_EASING)
QDEL_IN(shockwave, 10.5 SECONDS)
/obj/machinery/atmospherics/components/trinary/nuclear_reactor/update_icon(updates=ALL)
. = ..()
icon_state = "reactor_off"
switch(temperature)
if(0 to REACTOR_TEMPERATURE_MINIMUM)
icon_state = "reactor_on"
if(REACTOR_TEMPERATURE_MINIMUM to REACTOR_TEMPERATURE_OPERATING)
icon_state = "reactor_hot"
if(REACTOR_TEMPERATURE_OPERATING to REACTOR_TEMPERATURE_CRITICAL)
icon_state = "reactor_veryhot"
if(REACTOR_TEMPERATURE_CRITICAL to REACTOR_TEMPERATURE_MELTDOWN) //Point of no return.
icon_state = "reactor_overheat"
if(REACTOR_TEMPERATURE_MELTDOWN to INFINITY)
icon_state = "reactor_meltdown"
if(!has_fuel())
icon_state = "reactor_off"
if(slagged)
icon_state = "reactor_slagged"
//Startup, shutdown
/obj/machinery/atmospherics/components/trinary/nuclear_reactor/proc/start_up()
START_PROCESSING(SSmachines, src)
desired_k = 1
active = TRUE
set_light(10)
var/startup_sound = pick('sound/effects/reactor/startup.ogg', 'sound/effects/reactor/startup2.ogg')
playsound(loc, startup_sound, 100)
update_parents() // double-check all the pipes are connected on startup
if(!powernet)
connect_to_network()
//Shuts off the fuel rods, ambience, etc. Keep in mind that your temperature may still go up!
/obj/machinery/atmospherics/components/trinary/nuclear_reactor/proc/shut_down()
STOP_PROCESSING(SSmachines, src)
set_light(0)
K = 0
desired_k = 0
power = 0
active = FALSE
update_icon()
//Controlling the reactor.
/obj/machinery/computer/reactor
name = "reactor control console"
desc = "A computer which monitors and controls a reactor"
light_color = "#55BA55"
light_power = 1
light_range = 3
icon_state = "oldcomp"
icon_screen = "oldcomp_broken"
icon_keyboard = null
circuit = /obj/item/circuitboard/computer/reactor // we have the technology
var/obj/machinery/atmospherics/components/trinary/nuclear_reactor/reactor = null
var/id = null
var/next_stat_interval = 0
/obj/machinery/computer/reactor/multitool_act(mob/living/user, obj/item/multitool/I)
if(isnull(id) || isnum(id))
var/obj/machinery/atmospherics/components/trinary/nuclear_reactor/N = multitool_get_buffer(user, I)
if(!istype(N))
user.balloon_alert(user, "invalid reactor ID!")
return TRUE
reactor = N
id = N.id
user.balloon_alert(user, "linked!")
return TRUE
return ..()
/obj/machinery/computer/reactor/preset
id = "default_reactor_for_lazy_mappers"
/obj/machinery/computer/reactor/syndie_base
id = "syndie_base_reactor"
/obj/item/circuitboard/computer/reactor
name = "Reactor Control (Computer Board)"
greyscale_colors = CIRCUIT_COLOR_ENGINEERING
build_path = /obj/machinery/computer/reactor
/obj/machinery/computer/reactor/Initialize(mapload, obj/item/circuitboard/C)
. = ..()
return INITIALIZE_HINT_LATELOAD
/obj/machinery/computer/reactor/LateInitialize()
. = ..()
link_to_reactor()
/obj/machinery/computer/reactor/attack_hand(mob/living/user)
. = ..()
ui_interact(user)
/obj/machinery/computer/reactor/ui_interact(mob/user, datum/tgui/ui)
ui = SStgui.try_update_ui(user, src, ui)
if(!ui)
ui = new(user, src, "ReactorComputer")
ui.open()
ui.set_autoupdate(TRUE)
/obj/machinery/computer/reactor/ui_act(action, params)
if(..())
return
if(!reactor)
return
switch(action)
if("power")
if(reactor.active)
if(reactor.K <= 0 && reactor.temperature <= REACTOR_TEMPERATURE_MINIMUM)
reactor.shut_down()
else if(reactor.fuel_rods.len)
reactor.start_up()
message_admins("Reactor started up by [ADMIN_LOOKUPFLW(usr)] in [ADMIN_VERBOSEJMP(src)]")
investigate_log("Reactor started by [key_name(usr)] at [AREACOORD(src)]", INVESTIGATE_REACTOR)
if("input")
var/input = text2num(params["target"])
reactor.last_user = usr
reactor.desired_k = reactor.active ? clamp(input, 0, REACTOR_MAX_CRITICALITY) : 0
if("eject")
if(reactor?.temperature > REACTOR_TEMPERATURE_MINIMUM)
return
if(reactor?.slagged)
return
var/rod_index = text2num(params["rod_index"])
if(rod_index < 1 || rod_index > reactor.fuel_rods.len)
return
var/obj/item/fuel_rod/rod = reactor.fuel_rods[rod_index]
if(!rod)
return
playsound(src, pick('sound/effects/reactor/switch.ogg','sound/effects/reactor/switch2.ogg','sound/effects/reactor/switch3.ogg'), 100, FALSE)
playsound(reactor, 'sound/effects/reactor/crane_1.wav', 100, FALSE)
rod.forceMove(get_turf(reactor))
reactor.fuel_rods.Remove(rod)
/obj/machinery/computer/reactor/ui_data(mob/user)
var/list/data = list()
data["control_rods"] = 0
data["k"] = 0
data["desiredK"] = 0
if(reactor)
data["k"] = reactor.K
data["desiredK"] = reactor.desired_k
data["control_rods"] = 100 - (100 * reactor.desired_k / REACTOR_MAX_CRITICALITY) //Rod insertion is extrapolated as a function of the percentage of K
data["integrity"] = reactor.get_integrity()
data["powerData"] = reactor ? reactor.powerData : list()
data["kpaData"] = reactor ? reactor.kpaData : list()
data["tempCoreData"] = reactor ? reactor.tempCoreData : list()
data["tempInputData"] = reactor ? reactor.tempInputData : list()
data["tempOutputData"] = reactor ? reactor.tempOutputData : list()
data["coreTemp"] = reactor ? round(reactor.temperature) : 0
data["coolantInput"] = reactor ? round(reactor.last_coolant_temperature) : T20C
data["coolantOutput"] = reactor ? round(reactor.last_output_temperature) : T20C
data["power"] = reactor ? reactor.last_power_produced : 0
data["kpa"] = reactor ? reactor.pressure : 0
data["active"] = reactor ? reactor.active : FALSE
data["shutdownTemp"] = REACTOR_TEMPERATURE_MINIMUM
var/list/rod_data = list()
if(reactor)
var/cur_index = 0
for(var/obj/item/fuel_rod/rod in reactor.fuel_rods)
cur_index++
rod_data.Add(
list(
"name" = rod.name,
"depletion" = rod.depletion,
"rod_index" = cur_index
)
)
data["rods"] = rod_data
return data
/obj/machinery/computer/reactor/wrench_act(mob/living/user, obj/item/I)
to_chat(user, span_notice("You start [anchored ? "un" : ""]securing [name]..."))
if(I.use_tool(src, user, 40, volume=75))
to_chat(user, span_notice("You [anchored ? "un" : ""]secure [name]."))
setAnchored(!anchored)
return TRUE
return FALSE
/obj/machinery/computer/reactor/proc/link_to_reactor()
for(var/obj/machinery/atmospherics/components/trinary/nuclear_reactor/asdf in GLOB.machines)
if(asdf.id && asdf.id == id)
reactor = asdf
return TRUE
return FALSE
#define FREQ_REACTOR_CONTROL 1439.69
//Preset pumps for mappers. You can also set the id tags yourself.
/obj/machinery/atmospherics/components/binary/pump/reactor_input
id = "reactor_input"
frequency = FREQ_REACTOR_CONTROL
/obj/machinery/atmospherics/components/binary/pump/reactor_output
id = "reactor_output"
frequency = FREQ_REACTOR_CONTROL
/obj/machinery/atmospherics/components/binary/pump/reactor_moderator
id = "reactor_moderator"
frequency = FREQ_REACTOR_CONTROL
/obj/machinery/computer/reactor/pump
name = "Reactor inlet valve computer"
desc = "A computer which controls valve settings on an advanced gas cooled reactor. Alt click it to remotely set pump pressure."
icon_screen = "reactor_input"
id = "reactor_input"
var/datum/radio_frequency/radio_connection
var/on = FALSE
/obj/machinery/computer/reactor/pump/AltClick(mob/user)
. = ..()
var/newPressure = input(user, "Set new output pressure (kPa)", "Remote pump control", null) as num
if(!newPressure)
return
newPressure = clamp(newPressure, 0, MAX_OUTPUT_PRESSURE) //Number sanitization is not handled in the pumps themselves, only during their ui_act which this doesn't use.
signal(on, newPressure)
/obj/machinery/computer/reactor/attack_robot(mob/user)
. = ..()
attack_hand(user)
/obj/machinery/computer/reactor/attack_ai(mob/user)
. = ..()
attack_hand(user)
/obj/machinery/computer/reactor/pump/attack_hand(mob/living/user)
. = ..()
if(!is_operational())
return FALSE
playsound(loc, pick('sound/effects/reactor/switch.ogg','sound/effects/reactor/switch2.ogg','sound/effects/reactor/switch3.ogg'), 100, FALSE)
visible_message(span_notice("[src]'s switch flips [on ? "off" : "on"]."))
on = !on
signal(on)
/obj/machinery/computer/reactor/pump/Initialize(mapload, obj/item/circuitboard/C)
. = ..()
radio_connection = SSradio.add_object(src, FREQ_REACTOR_CONTROL,filter=RADIO_ATMOSIA)
/obj/machinery/computer/reactor/pump/proc/signal(power, set_output_pressure=null)
var/datum/signal/signal
if(!set_output_pressure) //Yes this is stupid, but technically if you pass through "set_output_pressure" onto the signal, it'll always try and set its output pressure and yeahhh...
signal = new(list(
"tag" = id,
"frequency" = FREQ_REACTOR_CONTROL,
"timestamp" = world.time,
"power" = power,
"sigtype" = "command"
))
else
signal = new(list(
"tag" = id,
"frequency" = FREQ_REACTOR_CONTROL,
"timestamp" = world.time,
"power" = power,
"set_output_pressure" = set_output_pressure,
"sigtype" = "command"
))
radio_connection.post_signal(src, signal, filter=RADIO_ATMOSIA)
//Preset subtypes for mappers
/obj/machinery/computer/reactor/pump/reactor_input
name = "Reactor inlet valve computer"
icon_screen = "reactor_input"
id = "reactor_input"
/obj/machinery/computer/reactor/pump/reactor_output
name = "Reactor output valve computer"
icon_screen = "reactor_output"
id = "reactor_output"
/obj/machinery/computer/reactor/pump/reactor_moderator
name = "Reactor moderator valve computer"
icon_screen = "reactor_moderator"
id = "reactor_moderator"
/obj/effect/decal/nuclear_waste
name = "plutonium sludge"
desc = "A writhing pool of heavily irradiated, spent reactor fuel. You probably shouldn't step through this..."
icon = 'icons/obj/machines/reactor_parts.dmi'
icon_state = "nuclearwaste"
alpha = 150
light_color = LIGHT_COLOR_GREEN
obj_flags = RAD_NO_CONTAMINATE_1 // already making rads, don't contaminate it further
color = "#ff9eff"
/obj/effect/decal/nuclear_waste/Initialize(mapload)
. = ..()
for(var/obj/A in get_turf(src))
if(istype(A, /obj/structure))
qdel(src) //It is more processing efficient to do this here rather than when searching for available turfs.
set_light(1)
START_PROCESSING(SSobj, src)
/obj/effect/decal/nuclear_waste/process(delta_time)
if(prob(10)) // woah there, don't overload the radiation subsystem
radiation_pulse(src, 1000, RAD_DISTANCE_COEFFICIENT*2)
/obj/effect/decal/nuclear_waste/Destroy(force)
STOP_PROCESSING(SSobj, src)
return ..()
/obj/effect/landmark/nuclear_waste_spawner //Clean way of spawning nuclear gunk after a reactor core meltdown.
name = "Nuclear waste spawner"
var/range = 15 //15 tile radius to spawn goop
/obj/effect/landmark/nuclear_waste_spawner/strong
range = 30
/obj/effect/landmark/nuclear_waste_spawner/proc/fire()
playsound(loc, 'sound/effects/gib_step.ogg', 100)
for(var/turf/open/floor in orange(range, get_turf(src)))
if(prob(35)) //Scatter the sludge, don't smear it everywhere
new /obj/effect/decal/nuclear_waste (floor)
qdel(src)
/obj/effect/decal/nuclear_waste/Crossed(atom/movable/AM)
. = ..()
if(isliving(AM))
var/mob/living/L = AM
playsound(loc, 'sound/effects/gib_step.ogg', HAS_TRAIT(L, TRAIT_LIGHT_STEP) ? 20 : 50, 1)
AM.rad_act(500) //MORE RADS
/obj/effect/decal/nuclear_waste/attackby(obj/item/tool, mob/user)
if(tool.tool_behaviour == TOOL_SHOVEL)
to_chat(user, span_notice("You start to clear [src]..."))
if(tool.use_tool(src, user, 50, volume=100))
radiation_pulse(src, 1000, 5) //MORE RADS
to_chat(user, span_notice("You clear [src]. "))
qdel(src)
return
. = ..()
/datum/weather/nuclear_fallout
name = "nuclear fallout"
desc = "Irradiated dust falls down everywhere."
telegraph_duration = 20 SECONDS
telegraph_message = "<span class='boldwarning'>The air suddenly becomes dusty..</span>"
weather_message = "<span class='userdanger'><i>You feel a wave of hot ash fall down on you.</i></span>"
weather_overlay = "light_ash"
telegraph_overlay = "light_snow"
weather_duration_lower = 600
weather_duration_upper = 1500
weather_color = "green"
telegraph_sound = null
weather_sound = 'sound/effects/reactor/falloutwind.ogg'
end_duration = 200
area_type = /area
protected_areas = list(/area/maintenance, /area/ai_monitored/turret_protected/ai_upload, /area/ai_monitored/turret_protected/ai_upload_foyer,
/area/ai_monitored/turret_protected/ai, /area/shuttle)
end_message = "<span class='notice'>The ash stops falling.</span>"
immunity_type = WEATHER_RAD
/datum/weather/nuclear_fallout/weather_act(mob/living/L)
L.rad_act(2000)
/datum/weather/nuclear_fallout/telegraph()
..()
if(SSsecurity_level.get_current_level_as_number() < SEC_LEVEL_GAMMA)//if for some reason, it's already gamma, don't bother making it gamma
SSsecurity_level.set_level(SEC_LEVEL_GAMMA) //gamma is cool and good (also lets people powergame to save their lives)
status_alarm(TRUE)
/datum/weather/nuclear_fallout/proc/status_alarm(active) //Makes the status displays show the radiation warning for those who missed the announcement.
var/datum/radio_frequency/frequency = SSradio.return_frequency(FREQ_STATUS_DISPLAYS)
if(!frequency)
return
var/datum/signal/signal = new
if (active)