-
-
Notifications
You must be signed in to change notification settings - Fork 444
/
Copy pathnukeop.dm
465 lines (401 loc) · 18.6 KB
/
nukeop.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
/datum/antagonist/nukeop
name = "Nuclear Operative"
roundend_category = "syndicate operatives" //just in case
antagpanel_category = "NukeOp"
job_rank = ROLE_OPERATIVE
antag_hud_name = "synd"
antag_moodlet = /datum/mood_event/focused
show_to_ghosts = TRUE
count_towards_antag_cap = TRUE
var/datum/team/nuclear/nuke_team
var/always_new_team = FALSE //If not assigned a team by default ops will try to join existing ones, set this to TRUE to always create new team.
var/send_to_spawnpoint = TRUE //Should the user be moved to default spawnpoint.
var/nukeop_outfit = /datum/outfit/syndicate
can_hijack = HIJACK_HIJACKER //Alternative way to wipe out the station.
preview_outfit = /datum/outfit/nuclear_operative_elite
/// In the preview icon, the nukies who are behind the leader
var/preview_outfit_behind = /datum/outfit/nuclear_operative
/// the sound clip played during the greet proc
var/welcome_music = 'sound/ambience/antag/ops.ogg'
/datum/antagonist/nukeop/apply_innate_effects(mob/living/mob_override)
add_team_hud(mob_override || owner.current, /datum/antagonist/nukeop)
ADD_TRAIT(owner, TRAIT_DISK_VERIFIER, NUKEOP_TRAIT)
/datum/antagonist/nukeop/remove_innate_effects(mob/living/mob_override)
REMOVE_TRAIT(owner, TRAIT_DISK_VERIFIER, NUKEOP_TRAIT)
/datum/antagonist/nukeop/proc/equip_op()
if(!ishuman(owner.current))
return
var/mob/living/carbon/human/H = owner.current
H.set_species(/datum/species/human) //Plasamen burn up otherwise, and lizards are vulnerable to asimov AIs
H.equipOutfit(nukeop_outfit)
H.adjust_skill(SKILL_FITNESS, EXP_MID, max_skill = EXP_GENIUS) // base amount of fitness skill all operatives need to have
H.add_skill_points(EXP_GENIUS) // 5 skill points to allocate, you can put it all into fitness or specialize as a medic or pilot
ADD_TRAIT(owner, TRAIT_EXCEPTIONAL_SKILL, ROLE_OPERATIVE) // allowed to allocate 5 points into a single skill
return TRUE
/datum/antagonist/nukeop/greet()
owner.current.playsound_local(get_turf(owner.current), welcome_music,100,0)
to_chat(owner, span_notice("You are a [nuke_team ? nuke_team.syndicate_name : "syndicate"] agent!"))
owner.announce_objectives()
/datum/antagonist/nukeop/on_gain()
give_alias()
. = ..()
equip_op()
memorize_code()
if(send_to_spawnpoint)
move_to_spawnpoint()
// grant extra TC for the people who start in the nukie base ie. not the lone op
var/extra_tc = CEILING(GLOB.joined_player_list.len/5, 5)
var/datum/component/uplink/U = owner.find_syndicate_uplink()
if (U)
U.telecrystals += extra_tc
/datum/antagonist/nukeop/get_team()
return nuke_team
/datum/antagonist/nukeop/proc/assign_nuke()
if(nuke_team && !nuke_team.tracked_nuke)
nuke_team.memorized_code = random_nukecode()
var/obj/machinery/nuclearbomb/syndicate/nuke = find_nuke() //Yogs -- Puts find_nuke() here to fix bananium nukes fucking up normal nuke ops
if(nuke)
nuke_team.tracked_nuke = nuke
if(nuke.r_code == "ADMIN")
nuke.r_code = nuke_team.memorized_code
else //Already set by admins/something else?
nuke_team.memorized_code = nuke.r_code
for(var/obj/machinery/nuclearbomb/beer/beernuke in GLOB.nuke_list)
beernuke.r_code = nuke_team.memorized_code
else
stack_trace("Syndicate nuke not found during nuke team creation.")
nuke_team.memorized_code = null
var/obj/machinery/nuclearbomb/selfdestruct/humiliate_nuke = find_self_destruct()
if(humiliate_nuke && nuke_team.memorized_code)
humiliate_nuke.r_code = nuke_team.memorized_code
/datum/antagonist/nukeop/proc/give_alias()
if(nuke_team && nuke_team.syndicate_name)
var/mob/living/carbon/human/H = owner.current
if(istype(H)) // Reinforcements get a real name
var/chosen_name = H.dna.species.random_name(H.gender,0,nuke_team.syndicate_name)
H.fully_replace_character_name(H.real_name,chosen_name)
else
var/number = 1
number = nuke_team.members.Find(owner)
owner.current.real_name = "[nuke_team.syndicate_name] Operative #[number]"
/datum/antagonist/nukeop/proc/memorize_code()
if(nuke_team && nuke_team.tracked_nuke && nuke_team.memorized_code)
antag_memory += "<B>[nuke_team.tracked_nuke] Code</B>: [nuke_team.memorized_code]<br>"
to_chat(owner, "The nuclear authorization code is: <B>[nuke_team.memorized_code]</B>")
else
to_chat(owner, "Unfortunately the Syndicate was unable to provide you with the nuclear authorization code.")
/datum/antagonist/nukeop/proc/move_to_spawnpoint()
var/team_number = 1
if(nuke_team)
team_number = nuke_team.members.Find(owner)
owner.current.forceMove(GLOB.nukeop_start[((team_number - 1) % GLOB.nukeop_start.len) + 1])
/datum/antagonist/nukeop/leader/move_to_spawnpoint()
owner.current.forceMove(pick(GLOB.nukeop_leader_start))
/datum/antagonist/nukeop/create_team(datum/team/nuclear/new_team)
if(!new_team)
if(!always_new_team)
for(var/datum/antagonist/nukeop/N in GLOB.antagonists)
if(!N.owner)
continue
if(N.nuke_team)
nuke_team = N.nuke_team
return
nuke_team = new /datum/team/nuclear
nuke_team.update_objectives()
assign_nuke() //This is bit ugly
return
if(!istype(new_team))
stack_trace("Wrong team type passed to [type] initialization.")
nuke_team = new_team
/datum/antagonist/nukeop/admin_add(datum/mind/new_owner,mob/admin)
new_owner.assigned_role = ROLE_ANTAG
new_owner.add_antag_datum(src)
message_admins("[key_name_admin(admin)] has nuke op'ed [key_name_admin(new_owner)].")
log_admin("[key_name(admin)] has nuke op'ed [key_name(new_owner)].")
/datum/antagonist/nukeop/get_admin_commands()
. = ..()
.["Send to base"] = CALLBACK(src, PROC_REF(admin_send_to_base))
.["Tell code"] = CALLBACK(src, PROC_REF(admin_tell_code))
/datum/antagonist/nukeop/proc/admin_send_to_base(mob/admin)
owner.current.forceMove(pick(GLOB.nukeop_start))
/datum/antagonist/nukeop/proc/admin_tell_code(mob/admin)
var/code
for (var/obj/machinery/nuclearbomb/bombue in GLOB.machines)
if (length(bombue.r_code) <= 5 && bombue.r_code != initial(bombue.r_code))
code = bombue.r_code
break
if (code)
antag_memory += "<B>Syndicate Nuclear Bomb Code</B>: [code]<br>"
to_chat(owner.current, "The nuclear authorization code is: <B>[code]</B>")
else
to_chat(admin, span_danger("No valid nuke found!"))
/datum/antagonist/nukeop/get_preview_icon()
var/mob/living/carbon/human/dummy/consistent/captain = new
var/icon/final_icon = render_preview_outfit(preview_outfit, captain)
final_icon.Blend(make_assistant_icon(), ICON_UNDERLAY, -8, 0)
final_icon.Blend(make_assistant_icon(), ICON_UNDERLAY, 8, 0)
return finish_preview_icon(final_icon)
/datum/antagonist/nukeop/proc/make_assistant_icon()
var/mob/living/carbon/human/dummy/assistant = new
var/icon/assistant_icon = render_preview_outfit(preview_outfit_behind, assistant)
assistant_icon.ChangeOpacity(0.5)
return assistant_icon
/datum/outfit/nuclear_operative
name = "Nuclear Operative (Preview only)"
mask = /obj/item/clothing/mask/gas/syndicate
uniform = /obj/item/clothing/under/syndicate
suit = /obj/item/clothing/suit/space/hardsuit/syndi
head = /obj/item/clothing/head/helmet/space/hardsuit/syndi
/datum/outfit/nuclear_operative_elite
name = "Nuclear Operative (Elite, Preview only)"
mask = /obj/item/clothing/mask/gas/syndicate
uniform = /obj/item/clothing/under/syndicate
suit = /obj/item/clothing/suit/space/hardsuit/syndi/elite
head = /obj/item/clothing/head/helmet/space/hardsuit/syndi/elite
r_hand = /obj/item/shield/energy
/datum/outfit/nuclear_operative_elite/post_equip(mob/living/carbon/human/H, visualsOnly)
var/obj/item/shield/energy/shield = locate() in H.held_items
shield.icon_state = "[shield.base_icon_state]1"
H.update_inv_hands()
/datum/antagonist/nukeop/leader
name = "Nuclear Operative Leader"
nukeop_outfit = /datum/outfit/syndicate/leader
always_new_team = TRUE
var/title
preview_outfit = /datum/outfit/nuclear_operative/leader
preview_outfit_behind = null
/datum/antagonist/nukeop/leader/memorize_code()
..()
if(nuke_team && nuke_team.memorized_code)
var/obj/item/paper/P = new
P.info = "The nuclear authorization code is: <b>[nuke_team.memorized_code]</b>"
P.name = "nuclear bomb code"
var/mob/living/carbon/human/H = owner.current
if(!istype(H))
P.forceMove(get_turf(H))
else
H.put_in_hands(P, TRUE, no_sound = TRUE)
H.update_icons()
/datum/antagonist/nukeop/leader/give_alias()
title = pick("Czar", "Boss", "Commander", "Chief", "Kingpin", "Director", "Overlord")
if(nuke_team && nuke_team.syndicate_name)
owner.current.real_name = "[nuke_team.syndicate_name] [title]"
else
owner.current.real_name = "Syndicate [title]"
/datum/antagonist/nukeop/leader/greet()
owner.current.playsound_local(get_turf(owner.current), welcome_music,100,0)
to_chat(owner, "<B>You are the Syndicate [title] for this mission. You are responsible for the distribution of telecrystals and your ID is the only one who can open the launch bay doors.</B>")
to_chat(owner, "<B>If you feel you are not up to this task, give your ID to another operative.</B>")
to_chat(owner, "<B>In your hand you will find a special item capable of triggering a greater challenge for your team. Examine it carefully and consult with your fellow operatives before activating it.</B>")
owner.announce_objectives()
addtimer(CALLBACK(src, PROC_REF(nuketeam_name_assign)), 1)
/datum/antagonist/nukeop/leader/proc/nuketeam_name_assign()
if(!nuke_team)
return
nuke_team.rename_team(ask_name())
/datum/team/nuclear/proc/rename_team(new_name)
syndicate_name = new_name
name = "[syndicate_name] Team"
for(var/I in members)
var/datum/mind/synd_mind = I
var/mob/living/carbon/human/H = synd_mind.current
if(!istype(H))
continue
var/chosen_name = H.dna.species.random_name(H.gender,0,syndicate_name)
H.fully_replace_character_name(H.real_name,chosen_name)
/datum/antagonist/nukeop/leader/proc/ask_name()
var/randomname = pick(GLOB.last_names)
var/newname = stripped_input(owner.current,"You are the nuke operative [title]. Please choose a last name for your family.", "Name change",randomname)
if (!newname)
newname = randomname
else
newname = reject_bad_name(newname)
if(!newname)
newname = randomname
return capitalize(newname)
/datum/outfit/nuclear_operative/leader
name = "Nuclear Operative Leader (Preview only)"
neck = /obj/item/clothing/neck/cloak/nukie
/datum/antagonist/nukeop/lone
name = "Lone Operative"
always_new_team = TRUE
send_to_spawnpoint = FALSE //Handled by event
nukeop_outfit = /datum/outfit/syndicate/full
/datum/antagonist/nukeop/lone/assign_nuke()
if(nuke_team && !nuke_team.tracked_nuke)
nuke_team.memorized_code = random_nukecode()
var/obj/machinery/nuclearbomb/selfdestruct/nuke = locate() in GLOB.nuke_list
if(nuke)
nuke_team.tracked_nuke = nuke
if(nuke.r_code == "ADMIN")
nuke.r_code = nuke_team.memorized_code
else //Already set by admins/something else?
nuke_team.memorized_code = nuke.r_code
else
stack_trace("Station self destruct not found during lone op team creation.")
nuke_team.memorized_code = null
/datum/antagonist/nukeop/reinforcement
send_to_spawnpoint = FALSE
nukeop_outfit = /datum/outfit/syndicate/no_crystals
/datum/team/nuclear
var/syndicate_name
var/obj/machinery/nuclearbomb/tracked_nuke
var/core_objective = /datum/objective/nuclear
var/memorized_code
var/list/team_discounts
/datum/team/nuclear/New()
..()
syndicate_name = syndicate_name()
/datum/team/nuclear/proc/update_objectives()
if(core_objective)
var/datum/objective/O = new core_objective
O.team = src
objectives += O
/datum/team/nuclear/proc/disk_rescued()
for(var/obj/item/disk/nuclear/D in GLOB.poi_list)
//If emergency shuttle is in transit disk is only safe on it
if(SSshuttle.emergency.mode == SHUTTLE_ESCAPE)
if(!SSshuttle.emergency.is_in_shuttle_bounds(D))
return FALSE
//If shuttle escaped check if it's on centcom side
else if(SSshuttle.emergency.mode == SHUTTLE_ENDGAME)
if(!D.onCentCom())
return FALSE
else //Otherwise disk is safe when on station
var/turf/T = get_turf(D)
if(!T || !is_station_level(T.z))
return FALSE
return TRUE
/datum/team/nuclear/proc/operatives_dead()
for(var/I in members)
var/datum/mind/operative_mind = I
if(ishuman(operative_mind.current) && (operative_mind.current.stat != DEAD))
return FALSE
return TRUE
/datum/team/nuclear/proc/syndies_escaped()
var/obj/docking_port/mobile/S = SSshuttle.getShuttle("syndicate")
var/obj/docking_port/stationary/transit/T = locate() in S.loc
return S && (is_centcom_level(S.z) || T)
/datum/team/nuclear/proc/get_result()
var/evacuation = EMERGENCY_ESCAPED_OR_ENDGAMED
var/disk_rescued = disk_rescued()
var/syndies_didnt_escape = !syndies_escaped()
var/station_was_nuked = SSgamemode.station_was_nuked
var/nuke_off_station = SSgamemode.nuke_off_station
var/self_destructed = SSgamemode.nuke_self_destruct
if(nuke_off_station == NUKE_SYNDICATE_BASE)
return NUKE_RESULT_FLUKE
else if(station_was_nuked && self_destructed)
return NUKE_RESULT_SELF_DESTRUCT
else if(station_was_nuked && !nuke_off_station && !syndies_didnt_escape)
return NUKE_RESULT_NUKE_WIN
else if (station_was_nuked && !nuke_off_station && syndies_didnt_escape)
return NUKE_RESULT_NOSURVIVORS
else if (nuke_off_station && !syndies_didnt_escape)
return NUKE_RESULT_WRONG_STATION
else if (nuke_off_station && syndies_didnt_escape)
return NUKE_RESULT_WRONG_STATION_DEAD
else if ((disk_rescued && evacuation) && operatives_dead())
return NUKE_RESULT_CREW_WIN_SYNDIES_DEAD
else if (disk_rescued)
return NUKE_RESULT_CREW_WIN
else if (!disk_rescued && operatives_dead())
return NUKE_RESULT_DISK_LOST
else if (!disk_rescued && evacuation)
return NUKE_RESULT_DISK_STOLEN
else
return //Undefined result
/datum/team/nuclear/roundend_report()
var/list/parts = list()
parts += span_header("[syndicate_name] Operatives:")
switch(get_result())
if(NUKE_RESULT_FLUKE)
parts += "<span class='redtext big'>Humiliating Syndicate Defeat</span>"
parts += "<B>The crew of [station_name()] gave [syndicate_name] operatives back their bomb! The syndicate base was destroyed!</B> Next time, don't lose the nuke!"
if(NUKE_RESULT_SELF_DESTRUCT)
parts += "<span class='greentext big'>Humiliating Crew Defeat</span>"
parts += "<B>As far as Nanotrasen cares, the crew of [station_name()] activated their self destruct device for unknown reasons.</B> Surviving crew will be interrogated and heavily penalized."
if(NUKE_RESULT_NUKE_WIN)
parts += "<span class='greentext big'>Syndicate Major Victory!</span>"
parts += "<B>[syndicate_name] operatives have destroyed [station_name()]!</B>"
if(NUKE_RESULT_NOSURVIVORS)
parts += "<span class='neutraltext big'>Total Annihilation</span>"
parts += "<B>[syndicate_name] operatives destroyed [station_name()] but did not leave the area in time and got caught in the explosion.</B> Next time, don't lose the disk!"
if(NUKE_RESULT_WRONG_STATION)
parts += "<span class='redtext big'>Crew Minor Victory</span>"
parts += "<B>[syndicate_name] operatives secured the authentication disk but blew up something that wasn't [station_name()].</B> Next time, don't do that!"
if(NUKE_RESULT_WRONG_STATION_DEAD)
parts += "<span class='redtext big'>[syndicate_name] operatives have earned Darwin Award!</span>"
parts += "<B>[syndicate_name] operatives blew up something that wasn't [station_name()] and got caught in the explosion.</B> Next time, don't do that!"
if(NUKE_RESULT_CREW_WIN_SYNDIES_DEAD)
parts += "<span class='redtext big'>Crew Major Victory!</span>"
parts += "<B>The Research Staff has saved the disk and killed the [syndicate_name] Operatives</B>"
if(NUKE_RESULT_CREW_WIN)
parts += "<span class='redtext big'>Crew Major Victory</span>"
parts += "<B>The Research Staff has saved the disk and stopped the [syndicate_name] Operatives!</B>"
if(NUKE_RESULT_DISK_LOST)
parts += "<span class='neutraltext big'>Neutral Victory!</span>"
parts += "<B>The Research Staff failed to secure the authentication disk but did manage to kill most of the [syndicate_name] Operatives!</B>"
if(NUKE_RESULT_DISK_STOLEN)
parts += "<span class='greentext big'>Syndicate Minor Victory!</span>"
parts += "<B>[syndicate_name] operatives survived the assault but did not achieve the destruction of [station_name()].</B> Next time, don't lose the disk!"
else
parts += "<span class='neutraltext big'>Neutral Victory</span>"
parts += "<B>Mission aborted!</B>"
var/text = "<br>[span_header("The syndicate operatives were:")]"
var/purchases = ""
var/TC_uses = 0
LAZYINITLIST(GLOB.uplink_purchase_logs_by_key)
for(var/I in members)
var/datum/mind/syndicate = I
var/datum/uplink_purchase_log/H = GLOB.uplink_purchase_logs_by_key[syndicate.key]
if(H)
TC_uses += H.total_spent
purchases += H.generate_render(show_key = FALSE)
text += printplayerlist(members)
text += "<br>"
text += "(Syndicates used [TC_uses] TC) [purchases]"
if(TC_uses == 0 && SSgamemode.station_was_nuked && !operatives_dead())
text += "<BIG>[icon2html('icons/badass.dmi', world, "badass")]</BIG>"
parts += text
handle_achievements()
return "<div class='panel redborder'>[parts.Join("<br>")]</div>"
/datum/team/nuclear/proc/handle_achievements()
switch(get_result())
if(NUKE_RESULT_FLUKE)
for(var/mob/living/carbon/human/H in GLOB.player_list) //if you observe, too bad
if(!IS_NUKE_OP(H))
SSachievements.unlock_achievement(/datum/achievement/flukeops, H.client)
if(NUKE_RESULT_NUKE_WIN, NUKE_RESULT_DISK_LOST)
for(var/mob/living/carbon/human/H in GLOB.player_list)
var/datum/mind/M = H.mind
if(M && M.has_antag_datum(/datum/antagonist/nukeop))
if(M.has_antag_datum(/datum/antagonist/nukeop/clownop) || M.has_antag_datum(/datum/antagonist/nukeop/leader/clownop))
SSachievements.unlock_achievement(/datum/achievement/greentext/clownop, H.client)
else
SSachievements.unlock_achievement(/datum/achievement/greentext/nukewin, H.client)
/datum/team/nuclear/antag_listing_name()
if(syndicate_name)
return "[syndicate_name] Syndicates"
else
return "Syndicates"
/datum/team/nuclear/antag_listing_entry()
var/disk_report = "<b>Nuclear Disk(s)</b><br>"
disk_report += "<table cellspacing=5>"
for(var/obj/item/disk/nuclear/N in GLOB.poi_list)
disk_report += "<tr><td>[N.name], "
var/atom/disk_loc = N.loc
while(!isturf(disk_loc))
if(ismob(disk_loc))
var/mob/M = disk_loc
disk_report += "carried by <a href='?_src_=holder;[HrefToken()];adminplayeropts=[REF(M)]'>[M.real_name]</a> "
if(isobj(disk_loc))
var/obj/O = disk_loc
disk_report += "in \a [O.name] "
disk_loc = disk_loc.loc
disk_report += "in [disk_loc.loc] at ([disk_loc.x], [disk_loc.y], [disk_loc.z])</td><td><a href='?_src_=holder;[HrefToken()];adminplayerobservefollow=[REF(N)]'>FLW</a></td></tr>"
disk_report += "</table>"
var/common_part = ..()
return common_part + disk_report
/datum/team/nuclear/is_gamemode_hero()
return SSgamemode.name == "nuclear emergency"