From c5e6ea4c001e5b622f1b67a9db50b44297640c74 Mon Sep 17 00:00:00 2001 From: NovaBot <154629622+NovaBot13@users.noreply.github.com> Date: Sat, 2 Mar 2024 00:51:30 -0500 Subject: [PATCH] [MIRROR] Splits up a big file in the nukie antagonist folder (#1237) * Splits up a big file in the nukie antagonist folder * Deletes a file that should have been deleted --------- Co-authored-by: Rhials <28870487+Rhials@users.noreply.github.com> Co-authored-by: SomeRandomOwl <2568378+SomeRandomOwl@users.noreply.github.com> --- .../antagonists/nukeop/datums/operative.dm | 213 ++++++ .../nukeop/datums/operative_leader.dm | 55 ++ .../nukeop/datums/operative_lone.dm | 22 + .../nukeop/datums/operative_reinforcement.dm | 4 + .../nukeop/datums/operative_team.dm | 320 +++++++++ code/modules/antagonists/nukeop/nukeop.dm | 650 ------------------ code/modules/antagonists/nukeop/outfits.dm | 27 + tgstation.dme | 6 +- 8 files changed, 646 insertions(+), 651 deletions(-) create mode 100644 code/modules/antagonists/nukeop/datums/operative.dm create mode 100644 code/modules/antagonists/nukeop/datums/operative_leader.dm create mode 100644 code/modules/antagonists/nukeop/datums/operative_lone.dm create mode 100644 code/modules/antagonists/nukeop/datums/operative_reinforcement.dm create mode 100644 code/modules/antagonists/nukeop/datums/operative_team.dm delete mode 100644 code/modules/antagonists/nukeop/nukeop.dm diff --git a/code/modules/antagonists/nukeop/datums/operative.dm b/code/modules/antagonists/nukeop/datums/operative.dm new file mode 100644 index 00000000000..516108c5725 --- /dev/null +++ b/code/modules/antagonists/nukeop/datums/operative.dm @@ -0,0 +1,213 @@ +/datum/antagonist/nukeop + name = ROLE_NUCLEAR_OPERATIVE + roundend_category = "syndicate operatives" //just in case + antagpanel_category = ANTAG_GROUP_SYNDICATE + job_rank = ROLE_OPERATIVE + antag_hud_name = "synd" + antag_moodlet = /datum/mood_event/focused + show_to_ghosts = TRUE + hijack_speed = 2 //If you can't take out the station, take the shuttle instead. + suicide_cry = "FOR THE SYNDICATE!!" + /// Which nukie team are we on? + var/datum/team/nuclear/nuke_team + /// If not assigned a team by default ops will try to join existing ones, set this to TRUE to always create new team. + var/always_new_team = FALSE + /// Should the user be moved to default spawnpoint after being granted this datum. + var/send_to_spawnpoint = TRUE + /// The DEFAULT outfit we will give to players granted this datum + var/nukeop_outfit = /datum/outfit/syndicate + + 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 + /// In the preview icon, a nuclear fission explosive device, only appearing if there's an icon state for it. + var/nuke_icon_state = "nuclearbomb_base" + + /// The amount of discounts that the team get + var/discount_team_amount = 5 + /// The amount of limited discounts that the team get + var/discount_limited_amount = 10 + +/datum/antagonist/nukeop/greet() + owner.current.playsound_local(get_turf(owner.current), 'sound/ambience/antag/ops.ogg',100,0, use_reverb = FALSE) + to_chat(owner, span_big("You are a [nuke_team ? nuke_team.syndicate_name : "syndicate"] agent!")) + owner.announce_objectives() + +/datum/antagonist/nukeop/on_gain() + give_alias() + forge_objectives() + . = ..() + equip_op() + 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/uplink = owner.find_syndicate_uplink() + if (uplink) + uplink.uplink_handler.add_telecrystals(extra_tc) + + var/datum/component/uplink/uplink = owner.find_syndicate_uplink() + if(uplink) + var/datum/team/nuclear/nuke_team = get_team() + if(!nuke_team.team_discounts) + var/list/uplink_items = list() + for(var/datum/uplink_item/item as anything in SStraitor.uplink_items) + if(item.item && !item.cant_discount && (item.purchasable_from & uplink.uplink_handler.uplink_flag) && item.cost > 1) + uplink_items += item + nuke_team.team_discounts = list() + nuke_team.team_discounts += create_uplink_sales(discount_team_amount, /datum/uplink_category/discount_team_gear, -1, uplink_items) + nuke_team.team_discounts += create_uplink_sales(discount_limited_amount, /datum/uplink_category/limited_discount_team_gear, 1, uplink_items) + uplink.uplink_handler.extra_purchasable += nuke_team.team_discounts + + memorize_code() + +/datum/antagonist/nukeop/get_team() + return nuke_team + +/datum/antagonist/nukeop/apply_innate_effects(mob/living/mob_override) + add_team_hud(mob_override || owner.current, /datum/antagonist/nukeop) + +/datum/antagonist/nukeop/forge_objectives() + if(nuke_team) + objectives |= nuke_team.objectives + +/datum/antagonist/nukeop/leader/get_spawnpoint() + return 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) + stack_trace("Antagonist datum without owner in GLOB.antagonists: [N]") + 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.set_assigned_role(SSjob.GetJobType(/datum/job/nuclear_operative)) + 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/get_preview_icon() + if (!preview_outfit) + return null + + var/icon/final_icon = render_preview_outfit(preview_outfit) + + if (!isnull(preview_outfit_behind)) + var/icon/teammate = render_preview_outfit(preview_outfit_behind) + teammate.Blend(rgb(128, 128, 128, 128), ICON_MULTIPLY) + + final_icon.Blend(teammate, ICON_UNDERLAY, -world.icon_size / 4, 0) + final_icon.Blend(teammate, ICON_UNDERLAY, world.icon_size / 4, 0) + + if (!isnull(nuke_icon_state)) + var/icon/nuke = icon('icons/obj/machines/nuke.dmi', nuke_icon_state) + nuke.Shift(SOUTH, 6) + final_icon.Blend(nuke, ICON_OVERLAY) + + return finish_preview_icon(final_icon) + +/datum/antagonist/nukeop/proc/equip_op() + if(!ishuman(owner.current)) + return + + var/mob/living/carbon/human/operative = owner.current + ADD_TRAIT(operative, TRAIT_NOFEAR_HOLDUPS, INNATE_TRAIT) + + if(!nukeop_outfit) // this variable is null in instances where an antagonist datum is granted via enslaving the mind (/datum/mind/proc/enslave_mind_to_creator), like in golems. + return + + // If our nuke_ops_species pref is set to TRUE, (or we have no client) make us a human + if(isnull(operative.client) || operative.client.prefs.read_preference(/datum/preference/toggle/nuke_ops_species)) + operative.set_species(/datum/species/human) + + operative.equip_species_outfit(nukeop_outfit) + + return TRUE + +/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 as anything in SSmachines.get_machines_by_type_and_subtypes(/obj/machinery/nuclearbomb)) + if (length(bombue.r_code) <= 5 && bombue.r_code != initial(bombue.r_code)) + code = bombue.r_code + break + if (code) + antag_memory += "Syndicate Nuclear Bomb Code: [code]
" + to_chat(owner.current, "The nuclear authorization code is: [code]") + else + to_chat(admin, span_danger("No valid nuke found!")) + +/datum/antagonist/nukeop/proc/assign_nuke() + if(!nuke_team || nuke_team.tracked_nuke) + return + nuke_team.memorized_code = random_nukecode() + var/obj/machinery/nuclearbomb/syndicate/nuke = locate() in SSmachines.get_machines_by_type_and_subtypes(/obj/machinery/nuclearbomb/syndicate) + if(!nuke) + stack_trace("Syndicate nuke not found during nuke team creation.") + nuke_team.memorized_code = null + return + nuke_team.tracked_nuke = nuke + if(nuke.r_code == NUKE_CODE_UNSET) + 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 as anything in SSmachines.get_machines_by_type_and_subtypes(/obj/machinery/nuclearbomb/beer)) + beernuke.r_code = nuke_team.memorized_code + +/datum/antagonist/nukeop/proc/give_alias() + if(nuke_team?.syndicate_name) + var/mob/living/carbon/human/human_to_rename = owner.current + if(istype(human_to_rename)) // Reinforcements get a real name + var/first_name = owner.current.client?.prefs?.read_preference(/datum/preference/name/operative_alias) || pick(GLOB.operative_aliases) + var/chosen_name = "[first_name] [nuke_team.syndicate_name]" + human_to_rename.fully_replace_character_name(human_to_rename.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 += "[nuke_team.tracked_nuke] Code: [nuke_team.memorized_code]
" + owner.add_memory(/datum/memory/key/nuke_code, nuclear_code = nuke_team.memorized_code) + to_chat(owner, "The nuclear authorization code is: [nuke_team.memorized_code]") + else + to_chat(owner, "Unfortunately the syndicate was unable to provide you with nuclear authorization code.") + +/// Actually moves our nukie to where they should be +/datum/antagonist/nukeop/proc/move_to_spawnpoint() + // Ensure that the nukiebase is loaded, and wait for it if required + SSmapping.lazy_load_template(LAZY_TEMPLATE_KEY_NUKIEBASE) + var/turf/destination = get_spawnpoint() + owner.current.forceMove(destination) + if(!owner.current.onSyndieBase()) + message_admins("[ADMIN_LOOKUPFLW(owner.current)] is a NUKE OP and move_to_spawnpoint put them somewhere that isn't the syndie base, help please.") + stack_trace("Nuke op move_to_spawnpoint resulted in a location not on the syndicate base. (Was moved to: [destination])") + +/// Gets the position we spawn at +/datum/antagonist/nukeop/proc/get_spawnpoint() + var/team_number = 1 + if(nuke_team) + team_number = nuke_team.members.Find(owner) + + return GLOB.nukeop_start[((team_number - 1) % GLOB.nukeop_start.len) + 1] diff --git a/code/modules/antagonists/nukeop/datums/operative_leader.dm b/code/modules/antagonists/nukeop/datums/operative_leader.dm new file mode 100644 index 00000000000..76ca635158b --- /dev/null +++ b/code/modules/antagonists/nukeop/datums/operative_leader.dm @@ -0,0 +1,55 @@ +/datum/antagonist/nukeop/leader + name = "Nuclear Operative Leader" + nukeop_outfit = /datum/outfit/syndicate/leader + always_new_team = TRUE + /// Randomly chosen honorific, for distinction + var/title + /// The nuclear challenge remote we will spawn this player with. + var/challengeitem = /obj/item/nuclear_challenge + +/datum/antagonist/nukeop/leader/memorize_code() + ..() + if(nuke_team?.memorized_code) + var/obj/item/paper/nuke_code_paper = new + nuke_code_paper.add_raw_text("The nuclear authorization code is: [nuke_team.memorized_code]") + nuke_code_paper.name = "nuclear bomb code" + var/mob/living/carbon/human/H = owner.current + if(!istype(H)) + nuke_code_paper.forceMove(get_turf(H)) + else + H.put_in_hands(nuke_code_paper, TRUE) + H.update_icons() + +/datum/antagonist/nukeop/leader/greet() + owner.current.playsound_local(get_turf(owner.current), 'sound/ambience/antag/ops.ogg',100,0, use_reverb = FALSE) + to_chat(owner, "You are the Syndicate [title] for this mission. You are responsible for guiding the team and your ID is the only one who can open the launch bay doors.") + to_chat(owner, "If you feel you are not up to this task, give your ID and radio to another operative.") + if(!CONFIG_GET(flag/disable_warops)) + to_chat(owner, "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.") + owner.announce_objectives() + +/datum/antagonist/nukeop/leader/on_gain() + . = ..() + if(!CONFIG_GET(flag/disable_warops)) + var/mob/living/carbon/human/leader = owner.current + var/obj/item/war_declaration = new challengeitem(leader.drop_location()) + leader.put_in_hands(war_declaration) + nuke_team.war_button_ref = WEAKREF(war_declaration) + 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/antagonist/nukeop/leader/proc/ask_name() + var/randomname = pick(GLOB.last_names) + var/newname = tgui_input_text(owner.current, "You are the nuclear operative [title]. Please choose a last name for your family.", "Name change", randomname, MAX_NAME_LEN) + if (!newname) + newname = randomname + else + newname = reject_bad_name(newname) + if(!newname) + newname = randomname + + return capitalize(newname) diff --git a/code/modules/antagonists/nukeop/datums/operative_lone.dm b/code/modules/antagonists/nukeop/datums/operative_lone.dm new file mode 100644 index 00000000000..d0bc718a781 --- /dev/null +++ b/code/modules/antagonists/nukeop/datums/operative_lone.dm @@ -0,0 +1,22 @@ +/datum/antagonist/nukeop/lone + name = "Lone Operative" + always_new_team = TRUE + send_to_spawnpoint = FALSE //Handled by event + nukeop_outfit = /datum/outfit/syndicate/full + preview_outfit = /datum/outfit/nuclear_operative + preview_outfit_behind = null + nuke_icon_state = null + +/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 SSmachines.get_machines_by_type(/obj/machinery/nuclearbomb/selfdestruct) + if(nuke) + nuke_team.tracked_nuke = nuke + if(nuke.r_code == NUKE_CODE_UNSET) + 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 diff --git a/code/modules/antagonists/nukeop/datums/operative_reinforcement.dm b/code/modules/antagonists/nukeop/datums/operative_reinforcement.dm new file mode 100644 index 00000000000..eedaef3f720 --- /dev/null +++ b/code/modules/antagonists/nukeop/datums/operative_reinforcement.dm @@ -0,0 +1,4 @@ +/datum/antagonist/nukeop/reinforcement + show_in_antagpanel = FALSE + send_to_spawnpoint = FALSE + nukeop_outfit = /datum/outfit/syndicate/reinforcement diff --git a/code/modules/antagonists/nukeop/datums/operative_team.dm b/code/modules/antagonists/nukeop/datums/operative_team.dm new file mode 100644 index 00000000000..e42d65b42a8 --- /dev/null +++ b/code/modules/antagonists/nukeop/datums/operative_team.dm @@ -0,0 +1,320 @@ +#define SPAWN_AT_BASE "Nuke base" +#define SPAWN_AT_INFILTRATOR "Infiltrator" + +/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 + var/datum/weakref/war_button_ref + +/datum/team/nuclear/New() + ..() + syndicate_name = syndicate_name() + +/datum/team/nuclear/roundend_report() + var/list/parts = list() + parts += "[syndicate_name] Operatives:" + + switch(get_result()) + if(NUKE_RESULT_FLUKE) + parts += "Humiliating Syndicate Defeat" + parts += "The crew of [station_name()] gave [syndicate_name] operatives back their bomb! The syndicate base was destroyed! Next time, don't lose the nuke!" + if(NUKE_RESULT_NUKE_WIN) + parts += "Syndicate Major Victory!" + parts += "[syndicate_name] operatives have destroyed [station_name()]!" + if(NUKE_RESULT_NOSURVIVORS) + parts += "Total Annihilation!" + parts += "[syndicate_name] operatives destroyed [station_name()] but did not leave the area in time and got caught in the explosion. Next time, don't lose the disk!" + if(NUKE_RESULT_WRONG_STATION) + parts += "Crew Minor Victory!" + parts += "[syndicate_name] operatives secured the authentication disk but blew up something that wasn't [station_name()]. Next time, don't do that!" + if(NUKE_RESULT_WRONG_STATION_DEAD) + parts += "[syndicate_name] operatives have earned Darwin Award!" + parts += "[syndicate_name] operatives blew up something that wasn't [station_name()] and got caught in the explosion. Next time, don't do that!" + if(NUKE_RESULT_HIJACK_DISK) + parts += "Syndicate Miniscule Victory!" + parts += "[syndicate_name] operatives failed to destroy [station_name()], but they managed to secure the disk and hijack the emergency shuttle, causing it to land on the syndicate base. Good job?" + if(NUKE_RESULT_HIJACK_NO_DISK) + parts += "Syndicate Insignificant Victory!" + parts += "[syndicate_name] operatives failed to destroy [station_name()] or secure the disk, but they managed to hijack the emergency shuttle, causing it to land on the syndicate base. Good job?" + if(NUKE_RESULT_CREW_WIN_SYNDIES_DEAD) + parts += "Crew Major Victory!" + parts += "The Research Staff has saved the disk and killed the [syndicate_name] Operatives" + if(NUKE_RESULT_CREW_WIN) + parts += "Crew Major Victory!" + parts += "The Research Staff has saved the disk and stopped the [syndicate_name] Operatives!" + if(NUKE_RESULT_DISK_LOST) + parts += "Neutral Victory!" + parts += "The Research Staff failed to secure the authentication disk but did manage to kill most of the [syndicate_name] Operatives!" + if(NUKE_RESULT_DISK_STOLEN) + parts += "Syndicate Minor Victory!" + parts += "[syndicate_name] operatives survived the assault but did not achieve the destruction of [station_name()]. Next time, don't lose the disk!" + else + parts += "Neutral Victory" + parts += "Mission aborted!" + + var/text = "
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 += "
" + text += "(Syndicates used [TC_uses] TC) [purchases]" + if(TC_uses == 0 && GLOB.station_was_nuked && !are_all_operatives_dead()) + text += "[icon2html('icons/ui_icons/antags/badass.dmi', world, "badass")]" + + parts += text + + return "
[parts.Join("
")]
" + +/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 = "Nuclear Disk(s)
" + disk_report += "" + for(var/obj/item/disk/nuclear/N in SSpoints_of_interest.real_nuclear_disks) + disk_report += "" + disk_report += "
[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 [M.real_name] " + 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])FLW
" + + var/post_report + + var/war_declared = FALSE + for(var/obj/item/circuitboard/computer/syndicate_shuttle/board as anything in GLOB.syndicate_shuttle_boards) + if(board.challenge) + war_declared = TRUE + + var/force_war_button = "" + + if(war_declared) + post_report += "War declared." + force_war_button = "\[Force war\]" + else + post_report += "War not declared." + var/obj/item/nuclear_challenge/war_button = war_button_ref?.resolve() + if(war_button) + force_war_button = "\[Force war\]" + else + force_war_button = "\[Cannot declare war, challenge button missing!\]" + + post_report += "\n[force_war_button]" + post_report += "\n\[Send Reinforcement\]" + + var/final_report = ..() + final_report += disk_report + final_report += post_report + return final_report + +/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/human_to_rename = synd_mind.current + if(!istype(human_to_rename)) + continue + var/first_name = human_to_rename.client?.prefs?.read_preference(/datum/preference/name/operative_alias) || pick(GLOB.operative_aliases) + var/chosen_name = "[first_name] [syndicate_name]" + human_to_rename.fully_replace_character_name(human_to_rename.real_name, chosen_name) + +/datum/team/nuclear/proc/admin_spawn_reinforcement(mob/admin) + if(!check_rights_for(admin.client, R_ADMIN)) + return + + var/infil_or_nukebase = tgui_alert( + admin, + "Spawn them at the nuke base, or in the Infiltrator?", + "Where to reinforce?", + list(SPAWN_AT_BASE, SPAWN_AT_INFILTRATOR, "Cancel"), + ) + + if(!infil_or_nukebase || infil_or_nukebase == "Cancel") + return + + var/tc_to_spawn = tgui_input_number(admin, "How much TC to spawn with?", "TC", 0, 100) + + var/list/nuke_candidates = SSpolling.poll_ghost_candidates( + "Do you want to play as an emergency syndicate reinforcement?", + check_jobban = ROLE_OPERATIVE, + role = ROLE_OPERATIVE, + poll_time = 30 SECONDS, + ignore_category = POLL_IGNORE_SYNDICATE, + pic_source = /obj/structure/sign/poster/contraband/gorlex_recruitment, + role_name_text = "syndicate reinforcement", + ) + + nuke_candidates -= admin // may be easy to fat-finger say yes. so just don't + + if(!length(nuke_candidates)) + tgui_alert(admin, "No candidates found.", "Recruitment Shortage", list("OK")) + return + + + var/turf/spawn_loc + if(infil_or_nukebase == SPAWN_AT_INFILTRATOR) + var/area/spawn_in + // Prioritize EVA then hallway, if neither can be found default to the first area we can find + for(var/area_type in list(/area/shuttle/syndicate/eva, /area/shuttle/syndicate/hallway, /area/shuttle/syndicate)) + spawn_in = locate(area_type) in GLOB.areas // I'd love to use areas_by_type but the Infiltrator is a unique area + if(spawn_in) + break + + var/list/turf/options = list() + for(var/turf/open/open_turf in spawn_in?.get_turfs_from_all_zlevels()) + if(open_turf.is_blocked_turf()) + continue + options += open_turf + + if(length(options)) + spawn_loc = pick(options) + else + infil_or_nukebase = SPAWN_AT_BASE + + if(infil_or_nukebase == SPAWN_AT_BASE) + spawn_loc = pick(GLOB.nukeop_start) + + var/mob/dead/observer/picked = pick(nuke_candidates) + var/mob/living/carbon/human/nukie = new(spawn_loc) + picked.client.prefs.safe_transfer_prefs_to(nukie, is_antag = TRUE) + nukie.key = picked.key + + var/datum/antagonist/nukeop/antag_datum = new() + antag_datum.send_to_spawnpoint = FALSE + antag_datum.nukeop_outfit = /datum/outfit/syndicate/reinforcement + + nukie.mind.add_antag_datum(antag_datum, src) + + var/datum/component/uplink/uplink = nukie.mind.find_syndicate_uplink() + uplink?.uplink_handler.set_telecrystals(tc_to_spawn) + + // add some pizzazz + do_sparks(4, FALSE, spawn_loc) + new /obj/effect/temp_visual/teleport_abductor/syndi_teleporter(spawn_loc) + playsound(spawn_loc, SFX_SPARKS, 50, TRUE) + playsound(spawn_loc, 'sound/effects/phasein.ogg', 50, TRUE) + + tgui_alert(admin, "Reinforcement spawned at [infil_or_nukebase] with [tc_to_spawn].", "Reinforcements have arrived", list("God speed")) + +/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/is_disk_rescued() + for(var/obj/item/disk/nuclear/nuke_disk in SSpoints_of_interest.real_nuclear_disks) + //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(nuke_disk)) + return FALSE + //If shuttle escaped check if it's on centcom side + else if(SSshuttle.emergency.mode == SHUTTLE_ENDGAME) + if(!nuke_disk.onCentCom()) + return FALSE + else //Otherwise disk is safe when on station + var/turf/disk_turf = get_turf(nuke_disk) + if(!disk_turf || !is_station_level(disk_turf.z)) + return FALSE + return TRUE + +/datum/team/nuclear/proc/are_all_operatives_dead() + for(var/datum/mind/operative_mind as anything in members) + if(ishuman(operative_mind.current) && (operative_mind.current.stat != DEAD)) + return FALSE + return TRUE + +/datum/team/nuclear/proc/get_result() + var/shuttle_evacuated = EMERGENCY_ESCAPED_OR_ENDGAMED + var/shuttle_landed_base = SSshuttle.emergency.is_hijacked() + var/disk_rescued = is_disk_rescued() + var/syndies_didnt_escape = !is_infiltrator_docked_at_syndiebase() + var/team_is_dead = are_all_operatives_dead() + var/station_was_nuked = GLOB.station_was_nuked + var/station_nuke_source = GLOB.station_nuke_source + + // The nuke detonated on the syndicate base + if(station_nuke_source == DETONATION_HIT_SYNDIE_BASE) + return NUKE_RESULT_FLUKE + + // The station was nuked + if(station_was_nuked) + // The station was nuked and the infiltrator failed to escape + if(syndies_didnt_escape) + return NUKE_RESULT_NOSURVIVORS + // The station was nuked and the infiltrator escaped, and the nuke ops won + else + return NUKE_RESULT_NUKE_WIN + + // The station was not nuked, but something was + else if(station_nuke_source && !disk_rescued) + // The station was not nuked, but something was, and the syndicates didn't escape it + if(syndies_didnt_escape) + return NUKE_RESULT_WRONG_STATION_DEAD + // The station was not nuked, but something was, and the syndicates returned to their base + else + return NUKE_RESULT_WRONG_STATION + + // Nuke didn't blow, but nukies somehow hijacked the emergency shuttle to land at the base anyways. + else if(shuttle_landed_base) + if(disk_rescued) + return NUKE_RESULT_HIJACK_DISK + else + return NUKE_RESULT_HIJACK_NO_DISK + + // No nuke went off, the station rescued the disk + else if(disk_rescued) + // No nuke went off, the shuttle left, and the team is dead + if(shuttle_evacuated && team_is_dead) + return NUKE_RESULT_CREW_WIN_SYNDIES_DEAD + // No nuke went off, but the nuke ops survived + else + return NUKE_RESULT_CREW_WIN + + // No nuke went off, but the disk was left behind + else + // No nuke went off, the disk was left, but all the ops are dead + if(team_is_dead) + return NUKE_RESULT_DISK_LOST + // No nuke went off, the disk was left, there are living ops, but the shuttle left successfully + else if(shuttle_evacuated) + return NUKE_RESULT_DISK_STOLEN + + CRASH("[type] - got an undefined / unexpected result.") + +/// Returns whether or not syndicate operatives escaped. +/proc/is_infiltrator_docked_at_syndiebase() + var/obj/docking_port/mobile/infiltrator/infiltrator_port = SSshuttle.getShuttle("syndicate") + + var/datum/lazy_template/nukie_base/nukie_template = GLOB.lazy_templates[LAZY_TEMPLATE_KEY_NUKIEBASE] + if(!nukie_template) + return FALSE // if its not even loaded, cant be docked + + for(var/datum/turf_reservation/loaded_area as anything in nukie_template.reservations) + var/infiltrator_turf = get_turf(infiltrator_port) + if(infiltrator_turf in loaded_area.reserved_turfs) + return TRUE + return FALSE + +#undef SPAWN_AT_BASE +#undef SPAWN_AT_INFILTRATOR diff --git a/code/modules/antagonists/nukeop/nukeop.dm b/code/modules/antagonists/nukeop/nukeop.dm deleted file mode 100644 index b01d48d757e..00000000000 --- a/code/modules/antagonists/nukeop/nukeop.dm +++ /dev/null @@ -1,650 +0,0 @@ -/datum/antagonist/nukeop - name = ROLE_NUCLEAR_OPERATIVE - roundend_category = "syndicate operatives" //just in case - antagpanel_category = ANTAG_GROUP_SYNDICATE - job_rank = ROLE_OPERATIVE - antag_hud_name = "synd" - antag_moodlet = /datum/mood_event/focused - show_to_ghosts = TRUE - hijack_speed = 2 //If you can't take out the station, take the shuttle instead. - suicide_cry = "FOR THE SYNDICATE!!" - /// Which nukie team are we on? - var/datum/team/nuclear/nuke_team - /// If not assigned a team by default ops will try to join existing ones, set this to TRUE to always create new team. - var/always_new_team = FALSE - /// Should the user be moved to default spawnpoint after being granted this datum. - var/send_to_spawnpoint = TRUE - /// The DEFAULT outfit we will give to players granted this datum - var/nukeop_outfit = /datum/outfit/syndicate - - 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 - /// In the preview icon, a nuclear fission explosive device, only appearing if there's an icon state for it. - var/nuke_icon_state = "nuclearbomb_base" - - /// The amount of discounts that the team get - var/discount_team_amount = 5 - /// The amount of limited discounts that the team get - var/discount_limited_amount = 10 - -/datum/antagonist/nukeop/New() - if(send_to_spawnpoint) // lets get the loading started now, but don't block waiting for it - INVOKE_ASYNC(SSmapping, TYPE_PROC_REF(/datum/controller/subsystem/mapping, lazy_load_template), LAZY_TEMPLATE_KEY_NUKIEBASE) - return ..() - -/datum/antagonist/nukeop/proc/equip_op() - if(!ishuman(owner.current)) - return - - var/mob/living/carbon/human/operative = owner.current - ADD_TRAIT(operative, TRAIT_NOFEAR_HOLDUPS, INNATE_TRAIT) - - if(!nukeop_outfit) // this variable is null in instances where an antagonist datum is granted via enslaving the mind (/datum/mind/proc/enslave_mind_to_creator), like in golems. - return - - // If our nuke_ops_species pref is set to TRUE, (or we have no client) make us a human - if(isnull(operative.client) || operative.client.prefs.read_preference(/datum/preference/toggle/nuke_ops_species)) - operative.set_species(/datum/species/human) - - operative.equip_species_outfit(nukeop_outfit) - - return TRUE - -/datum/antagonist/nukeop/greet() - owner.current.playsound_local(get_turf(owner.current), 'sound/ambience/antag/ops.ogg',100,0, use_reverb = FALSE) - to_chat(owner, span_big("You are a [nuke_team ? nuke_team.syndicate_name : "syndicate"] agent!")) - owner.announce_objectives() - -/datum/antagonist/nukeop/on_gain() - give_alias() - forge_objectives() - . = ..() - equip_op() - 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/uplink = owner.find_syndicate_uplink() - if (uplink) - uplink.uplink_handler.add_telecrystals(extra_tc) - - var/datum/component/uplink/uplink = owner.find_syndicate_uplink() - if(uplink) - var/datum/team/nuclear/nuke_team = get_team() - if(!nuke_team.team_discounts) - var/list/uplink_items = list() - for(var/datum/uplink_item/item as anything in SStraitor.uplink_items) - if(item.item && !item.cant_discount && (item.purchasable_from & uplink.uplink_handler.uplink_flag) && item.cost > 1) - uplink_items += item - nuke_team.team_discounts = list() - nuke_team.team_discounts += create_uplink_sales(discount_team_amount, /datum/uplink_category/discount_team_gear, -1, uplink_items) - nuke_team.team_discounts += create_uplink_sales(discount_limited_amount, /datum/uplink_category/limited_discount_team_gear, 1, uplink_items) - uplink.uplink_handler.extra_purchasable += nuke_team.team_discounts - - memorize_code() - -/datum/antagonist/nukeop/get_team() - return nuke_team - -/datum/antagonist/nukeop/apply_innate_effects(mob/living/mob_override) - add_team_hud(mob_override || owner.current, /datum/antagonist/nukeop) - -/datum/antagonist/nukeop/proc/assign_nuke() - if(!nuke_team || nuke_team.tracked_nuke) - return - nuke_team.memorized_code = random_nukecode() - var/obj/machinery/nuclearbomb/syndicate/nuke = locate() in SSmachines.get_machines_by_type_and_subtypes(/obj/machinery/nuclearbomb/syndicate) - if(!nuke) - stack_trace("Syndicate nuke not found during nuke team creation.") - nuke_team.memorized_code = null - return - nuke_team.tracked_nuke = nuke - if(nuke.r_code == NUKE_CODE_UNSET) - 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 as anything in SSmachines.get_machines_by_type_and_subtypes(/obj/machinery/nuclearbomb/beer)) - beernuke.r_code = nuke_team.memorized_code - -/datum/antagonist/nukeop/proc/give_alias() - if(nuke_team?.syndicate_name) - var/mob/living/carbon/human/human_to_rename = owner.current - if(istype(human_to_rename)) // Reinforcements get a real name - var/first_name = owner.current.client?.prefs?.read_preference(/datum/preference/name/operative_alias) || pick(GLOB.operative_aliases) - var/chosen_name = "[first_name] [nuke_team.syndicate_name]" - human_to_rename.fully_replace_character_name(human_to_rename.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 += "[nuke_team.tracked_nuke] Code: [nuke_team.memorized_code]
" - owner.add_memory(/datum/memory/key/nuke_code, nuclear_code = nuke_team.memorized_code) - to_chat(owner, "The nuclear authorization code is: [nuke_team.memorized_code]") - else - to_chat(owner, "Unfortunately the syndicate was unable to provide you with nuclear authorization code.") - -/datum/antagonist/nukeop/forge_objectives() - if(nuke_team) - objectives |= nuke_team.objectives - -/// Actually moves our nukie to where they should be -/datum/antagonist/nukeop/proc/move_to_spawnpoint() - // Ensure that the nukiebase is loaded, and wait for it if required - SSmapping.lazy_load_template(LAZY_TEMPLATE_KEY_NUKIEBASE) - var/turf/destination = get_spawnpoint() - owner.current.forceMove(destination) - if(!owner.current.onSyndieBase()) - message_admins("[ADMIN_LOOKUPFLW(owner.current)] is a NUKE OP and move_to_spawnpoint put them somewhere that isn't the syndie base, help please.") - stack_trace("Nuke op move_to_spawnpoint resulted in a location not on the syndicate base. (Was moved to: [destination])") - -/// Gets the position we spawn at -/datum/antagonist/nukeop/proc/get_spawnpoint() - var/team_number = 1 - if(nuke_team) - team_number = nuke_team.members.Find(owner) - - return GLOB.nukeop_start[((team_number - 1) % GLOB.nukeop_start.len) + 1] - -/datum/antagonist/nukeop/leader/get_spawnpoint() - return 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) - stack_trace("Antagonist datum without owner in GLOB.antagonists: [N]") - 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.set_assigned_role(SSjob.GetJobType(/datum/job/nuclear_operative)) - 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 as anything in SSmachines.get_machines_by_type_and_subtypes(/obj/machinery/nuclearbomb)) - if (length(bombue.r_code) <= 5 && bombue.r_code != initial(bombue.r_code)) - code = bombue.r_code - break - if (code) - antag_memory += "Syndicate Nuclear Bomb Code: [code]
" - to_chat(owner.current, "The nuclear authorization code is: [code]") - else - to_chat(admin, span_danger("No valid nuke found!")) - -/datum/antagonist/nukeop/get_preview_icon() - if (!preview_outfit) - return null - - var/icon/final_icon = render_preview_outfit(preview_outfit) - - if (!isnull(preview_outfit_behind)) - var/icon/teammate = render_preview_outfit(preview_outfit_behind) - teammate.Blend(rgb(128, 128, 128, 128), ICON_MULTIPLY) - - final_icon.Blend(teammate, ICON_UNDERLAY, -world.icon_size / 4, 0) - final_icon.Blend(teammate, ICON_UNDERLAY, world.icon_size / 4, 0) - - if (!isnull(nuke_icon_state)) - var/icon/nuke = icon('icons/obj/machines/nuke.dmi', nuke_icon_state) - nuke.Shift(SOUTH, 6) - final_icon.Blend(nuke, ICON_OVERLAY) - - return finish_preview_icon(final_icon) - -/datum/outfit/nuclear_operative - name = "Nuclear Operative (Preview only)" - - back = /obj/item/mod/control/pre_equipped/empty/syndicate - uniform = /obj/item/clothing/under/syndicate - -/datum/outfit/nuclear_operative/post_equip(mob/living/carbon/human/H, visualsOnly) - var/obj/item/mod/module/armor_booster/booster = locate() in H.back - booster.active = TRUE - H.update_worn_back() - -/datum/outfit/nuclear_operative_elite - name = "Nuclear Operative (Elite, Preview only)" - - back = /obj/item/mod/control/pre_equipped/empty/elite - uniform = /obj/item/clothing/under/syndicate - l_hand = /obj/item/modular_computer/pda/nukeops - r_hand = /obj/item/shield/energy - -/datum/outfit/nuclear_operative_elite/post_equip(mob/living/carbon/human/H, visualsOnly) - var/obj/item/mod/module/armor_booster/booster = locate() in H.back - booster.active = TRUE - H.update_worn_back() - var/obj/item/shield/energy/shield = locate() in H.held_items - shield.icon_state = "[shield.base_icon_state]1" - H.update_held_items() - -/datum/antagonist/nukeop/leader - name = "Nuclear Operative Leader" - nukeop_outfit = /datum/outfit/syndicate/leader - always_new_team = TRUE - /// Randomly chosen honorific, for distinction - var/title - /// The nuclear challenge remote we will spawn this player with. - var/challengeitem = /obj/item/nuclear_challenge - -/datum/antagonist/nukeop/leader/memorize_code() - ..() - if(nuke_team?.memorized_code) - var/obj/item/paper/nuke_code_paper = new - nuke_code_paper.add_raw_text("The nuclear authorization code is: [nuke_team.memorized_code]") - nuke_code_paper.name = "nuclear bomb code" - var/mob/living/carbon/human/H = owner.current - if(!istype(H)) - nuke_code_paper.forceMove(get_turf(H)) - else - H.put_in_hands(nuke_code_paper, TRUE) - H.update_icons() - -/datum/antagonist/nukeop/leader/greet() - owner.current.playsound_local(get_turf(owner.current), 'sound/ambience/antag/ops.ogg',100,0, use_reverb = FALSE) - to_chat(owner, "You are the Syndicate [title] for this mission. You are responsible for guiding the team and your ID is the only one who can open the launch bay doors.") - to_chat(owner, "If you feel you are not up to this task, give your ID and radio to another operative.") - if(!CONFIG_GET(flag/disable_warops)) - to_chat(owner, "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.") - owner.announce_objectives() - -/datum/antagonist/nukeop/leader/on_gain() - . = ..() - if(!CONFIG_GET(flag/disable_warops)) - var/mob/living/carbon/human/leader = owner.current - var/obj/item/war_declaration = new challengeitem(leader.drop_location()) - leader.put_in_hands(war_declaration) - nuke_team.war_button_ref = WEAKREF(war_declaration) - 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/human_to_rename = synd_mind.current - if(!istype(human_to_rename)) - continue - var/first_name = human_to_rename.client?.prefs?.read_preference(/datum/preference/name/operative_alias) || pick(GLOB.operative_aliases) - var/chosen_name = "[first_name] [syndicate_name]" - human_to_rename.fully_replace_character_name(human_to_rename.real_name, chosen_name) - -/datum/antagonist/nukeop/leader/proc/ask_name() - var/randomname = pick(GLOB.last_names) - var/newname = tgui_input_text(owner.current, "You are the nuclear operative [title]. Please choose a last name for your family.", "Name change", randomname, MAX_NAME_LEN) - if (!newname) - newname = randomname - else - newname = reject_bad_name(newname) - if(!newname) - newname = randomname - - return capitalize(newname) - -/datum/antagonist/nukeop/lone - name = "Lone Operative" - always_new_team = TRUE - send_to_spawnpoint = FALSE //Handled by event - nukeop_outfit = /datum/outfit/syndicate/full - preview_outfit = /datum/outfit/nuclear_operative - preview_outfit_behind = null - nuke_icon_state = null - -/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 SSmachines.get_machines_by_type(/obj/machinery/nuclearbomb/selfdestruct) - if(nuke) - nuke_team.tracked_nuke = nuke - if(nuke.r_code == NUKE_CODE_UNSET) - 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 - show_in_antagpanel = FALSE - send_to_spawnpoint = FALSE - nukeop_outfit = /datum/outfit/syndicate/reinforcement - -/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 - var/datum/weakref/war_button_ref - -/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/is_disk_rescued() - for(var/obj/item/disk/nuclear/nuke_disk in SSpoints_of_interest.real_nuclear_disks) - //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(nuke_disk)) - return FALSE - //If shuttle escaped check if it's on centcom side - else if(SSshuttle.emergency.mode == SHUTTLE_ENDGAME) - if(!nuke_disk.onCentCom()) - return FALSE - else //Otherwise disk is safe when on station - var/turf/disk_turf = get_turf(nuke_disk) - if(!disk_turf || !is_station_level(disk_turf.z)) - return FALSE - return TRUE - -/datum/team/nuclear/proc/are_all_operatives_dead() - for(var/datum/mind/operative_mind as anything in members) - if(ishuman(operative_mind.current) && (operative_mind.current.stat != DEAD)) - return FALSE - return TRUE - -/datum/team/nuclear/proc/get_result() - var/shuttle_evacuated = EMERGENCY_ESCAPED_OR_ENDGAMED - var/shuttle_landed_base = SSshuttle.emergency.is_hijacked() - var/disk_rescued = is_disk_rescued() - var/syndies_didnt_escape = !is_infiltrator_docked_at_syndiebase() - var/team_is_dead = are_all_operatives_dead() - var/station_was_nuked = GLOB.station_was_nuked - var/station_nuke_source = GLOB.station_nuke_source - - // The nuke detonated on the syndicate base - if(station_nuke_source == DETONATION_HIT_SYNDIE_BASE) - return NUKE_RESULT_FLUKE - - // The station was nuked - if(station_was_nuked) - // The station was nuked and the infiltrator failed to escape - if(syndies_didnt_escape) - return NUKE_RESULT_NOSURVIVORS - // The station was nuked and the infiltrator escaped, and the nuke ops won - else - return NUKE_RESULT_NUKE_WIN - - // The station was not nuked, but something was - else if(station_nuke_source && !disk_rescued) - // The station was not nuked, but something was, and the syndicates didn't escape it - if(syndies_didnt_escape) - return NUKE_RESULT_WRONG_STATION_DEAD - // The station was not nuked, but something was, and the syndicates returned to their base - else - return NUKE_RESULT_WRONG_STATION - - // Nuke didn't blow, but nukies somehow hijacked the emergency shuttle to land at the base anyways. - else if(shuttle_landed_base) - if(disk_rescued) - return NUKE_RESULT_HIJACK_DISK - else - return NUKE_RESULT_HIJACK_NO_DISK - - // No nuke went off, the station rescued the disk - else if(disk_rescued) - // No nuke went off, the shuttle left, and the team is dead - if(shuttle_evacuated && team_is_dead) - return NUKE_RESULT_CREW_WIN_SYNDIES_DEAD - // No nuke went off, but the nuke ops survived - else - return NUKE_RESULT_CREW_WIN - - // No nuke went off, but the disk was left behind - else - // No nuke went off, the disk was left, but all the ops are dead - if(team_is_dead) - return NUKE_RESULT_DISK_LOST - // No nuke went off, the disk was left, there are living ops, but the shuttle left successfully - else if(shuttle_evacuated) - return NUKE_RESULT_DISK_STOLEN - - CRASH("[type] - got an undefined / unexpected result.") - -/datum/team/nuclear/roundend_report() - var/list/parts = list() - parts += "[syndicate_name] Operatives:" - - switch(get_result()) - if(NUKE_RESULT_FLUKE) - parts += "Humiliating Syndicate Defeat" - parts += "The crew of [station_name()] gave [syndicate_name] operatives back their bomb! The syndicate base was destroyed! Next time, don't lose the nuke!" - if(NUKE_RESULT_NUKE_WIN) - parts += "Syndicate Major Victory!" - parts += "[syndicate_name] operatives have destroyed [station_name()]!" - if(NUKE_RESULT_NOSURVIVORS) - parts += "Total Annihilation!" - parts += "[syndicate_name] operatives destroyed [station_name()] but did not leave the area in time and got caught in the explosion. Next time, don't lose the disk!" - if(NUKE_RESULT_WRONG_STATION) - parts += "Crew Minor Victory!" - parts += "[syndicate_name] operatives secured the authentication disk but blew up something that wasn't [station_name()]. Next time, don't do that!" - if(NUKE_RESULT_WRONG_STATION_DEAD) - parts += "[syndicate_name] operatives have earned Darwin Award!" - parts += "[syndicate_name] operatives blew up something that wasn't [station_name()] and got caught in the explosion. Next time, don't do that!" - if(NUKE_RESULT_HIJACK_DISK) - parts += "Syndicate Miniscule Victory!" - parts += "[syndicate_name] operatives failed to destroy [station_name()], but they managed to secure the disk and hijack the emergency shuttle, causing it to land on the syndicate base. Good job?" - if(NUKE_RESULT_HIJACK_NO_DISK) - parts += "Syndicate Insignificant Victory!" - parts += "[syndicate_name] operatives failed to destroy [station_name()] or secure the disk, but they managed to hijack the emergency shuttle, causing it to land on the syndicate base. Good job?" - if(NUKE_RESULT_CREW_WIN_SYNDIES_DEAD) - parts += "Crew Major Victory!" - parts += "The Research Staff has saved the disk and killed the [syndicate_name] Operatives" - if(NUKE_RESULT_CREW_WIN) - parts += "Crew Major Victory!" - parts += "The Research Staff has saved the disk and stopped the [syndicate_name] Operatives!" - if(NUKE_RESULT_DISK_LOST) - parts += "Neutral Victory!" - parts += "The Research Staff failed to secure the authentication disk but did manage to kill most of the [syndicate_name] Operatives!" - if(NUKE_RESULT_DISK_STOLEN) - parts += "Syndicate Minor Victory!" - parts += "[syndicate_name] operatives survived the assault but did not achieve the destruction of [station_name()]. Next time, don't lose the disk!" - else - parts += "Neutral Victory" - parts += "Mission aborted!" - - var/text = "
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 += "
" - text += "(Syndicates used [TC_uses] TC) [purchases]" - if(TC_uses == 0 && GLOB.station_was_nuked && !are_all_operatives_dead()) - text += "[icon2html('icons/ui_icons/antags/badass.dmi', world, "badass")]" - - parts += text - - return "
[parts.Join("
")]
" - -/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 = "Nuclear Disk(s)
" - disk_report += "" - for(var/obj/item/disk/nuclear/N in SSpoints_of_interest.real_nuclear_disks) - disk_report += "" - disk_report += "
[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 [M.real_name] " - 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])FLW
" - - var/post_report - - var/war_declared = FALSE - for(var/obj/item/circuitboard/computer/syndicate_shuttle/board as anything in GLOB.syndicate_shuttle_boards) - if(board.challenge) - war_declared = TRUE - - var/force_war_button = "" - - if(war_declared) - post_report += "War declared." - force_war_button = "\[Force war\]" - else - post_report += "War not declared." - var/obj/item/nuclear_challenge/war_button = war_button_ref?.resolve() - if(war_button) - force_war_button = "\[Force war\]" - else - force_war_button = "\[Cannot declare war, challenge button missing!\]" - - post_report += "\n[force_war_button]" - post_report += "\n\[Send Reinforcement\]" - - var/final_report = ..() - final_report += disk_report - final_report += post_report - return final_report - -#define SPAWN_AT_BASE "Nuke base" -#define SPAWN_AT_INFILTRATOR "Infiltrator" - -/datum/team/nuclear/proc/admin_spawn_reinforcement(mob/admin) - if(!check_rights_for(admin.client, R_ADMIN)) - return - - var/infil_or_nukebase = tgui_alert( - admin, - "Spawn them at the nuke base, or in the Infiltrator?", - "Where to reinforce?", - list(SPAWN_AT_BASE, SPAWN_AT_INFILTRATOR, "Cancel"), - ) - - if(!infil_or_nukebase || infil_or_nukebase == "Cancel") - return - - var/tc_to_spawn = tgui_input_number(admin, "How much TC to spawn with?", "TC", 0, 100) - - var/list/nuke_candidates = SSpolling.poll_ghost_candidates( - "Do you want to play as an emergency syndicate reinforcement?", - check_jobban = ROLE_OPERATIVE, - role = ROLE_OPERATIVE, - poll_time = 30 SECONDS, - ignore_category = POLL_IGNORE_SYNDICATE, - pic_source = /obj/structure/sign/poster/contraband/gorlex_recruitment, - role_name_text = "syndicate reinforcement", - ) - - nuke_candidates -= admin // may be easy to fat-finger say yes. so just don't - - if(!length(nuke_candidates)) - tgui_alert(admin, "No candidates found.", "Recruitment Shortage", list("OK")) - return - - - var/turf/spawn_loc - if(infil_or_nukebase == SPAWN_AT_INFILTRATOR) - var/area/spawn_in - // Prioritize EVA then hallway, if neither can be found default to the first area we can find - for(var/area_type in list(/area/shuttle/syndicate/eva, /area/shuttle/syndicate/hallway, /area/shuttle/syndicate)) - spawn_in = locate(area_type) in GLOB.areas // I'd love to use areas_by_type but the Infiltrator is a unique area - if(spawn_in) - break - - var/list/turf/options = list() - for(var/turf/open/open_turf in spawn_in?.get_turfs_from_all_zlevels()) - if(open_turf.is_blocked_turf()) - continue - options += open_turf - - if(length(options)) - spawn_loc = pick(options) - else - infil_or_nukebase = SPAWN_AT_BASE - - if(infil_or_nukebase == SPAWN_AT_BASE) - spawn_loc = pick(GLOB.nukeop_start) - - var/mob/dead/observer/picked = pick(nuke_candidates) - var/mob/living/carbon/human/nukie = new(spawn_loc) - picked.client.prefs.safe_transfer_prefs_to(nukie, is_antag = TRUE) - nukie.key = picked.key - - var/datum/antagonist/nukeop/antag_datum = new() - antag_datum.send_to_spawnpoint = FALSE - antag_datum.nukeop_outfit = /datum/outfit/syndicate/reinforcement - - nukie.mind.add_antag_datum(antag_datum, src) - - var/datum/component/uplink/uplink = nukie.mind.find_syndicate_uplink() - uplink?.uplink_handler.set_telecrystals(tc_to_spawn) - - // add some pizzazz - do_sparks(4, FALSE, spawn_loc) - new /obj/effect/temp_visual/teleport_abductor/syndi_teleporter(spawn_loc) - playsound(spawn_loc, SFX_SPARKS, 50, TRUE) - playsound(spawn_loc, 'sound/effects/phasein.ogg', 50, TRUE) - - tgui_alert(admin, "Reinforcement spawned at [infil_or_nukebase] with [tc_to_spawn].", "Reinforcements have arrived", list("God speed")) - -#undef SPAWN_AT_BASE -#undef SPAWN_AT_INFILTRATOR - -/// Returns whether or not syndicate operatives escaped. -/proc/is_infiltrator_docked_at_syndiebase() - var/obj/docking_port/mobile/infiltrator/infiltrator_port = SSshuttle.getShuttle("syndicate") - - var/datum/lazy_template/nukie_base/nukie_template = GLOB.lazy_templates[LAZY_TEMPLATE_KEY_NUKIEBASE] - if(!nukie_template) - return FALSE // if its not even loaded, cant be docked - - for(var/datum/turf_reservation/loaded_area as anything in nukie_template.reservations) - var/infiltrator_turf = get_turf(infiltrator_port) - if(infiltrator_turf in loaded_area.reserved_turfs) - return TRUE - return FALSE diff --git a/code/modules/antagonists/nukeop/outfits.dm b/code/modules/antagonists/nukeop/outfits.dm index a3c97a76468..e9a293c3e99 100644 --- a/code/modules/antagonists/nukeop/outfits.dm +++ b/code/modules/antagonists/nukeop/outfits.dm @@ -163,3 +163,30 @@ shoes = /obj/item/clothing/shoes/laceup glasses = /obj/item/clothing/glasses/sunglasses/big faction = "MI13" + +/datum/outfit/nuclear_operative + name = "Nuclear Operative (Preview only)" + + back = /obj/item/mod/control/pre_equipped/empty/syndicate + uniform = /obj/item/clothing/under/syndicate + +/datum/outfit/nuclear_operative/post_equip(mob/living/carbon/human/H, visualsOnly) + var/obj/item/mod/module/armor_booster/booster = locate() in H.back + booster.active = TRUE + H.update_worn_back() + +/datum/outfit/nuclear_operative_elite + name = "Nuclear Operative (Elite, Preview only)" + + back = /obj/item/mod/control/pre_equipped/empty/elite + uniform = /obj/item/clothing/under/syndicate + l_hand = /obj/item/modular_computer/pda/nukeops + r_hand = /obj/item/shield/energy + +/datum/outfit/nuclear_operative_elite/post_equip(mob/living/carbon/human/H, visualsOnly) + var/obj/item/mod/module/armor_booster/booster = locate() in H.back + booster.active = TRUE + H.update_worn_back() + var/obj/item/shield/energy/shield = locate() in H.held_items + shield.icon_state = "[shield.base_icon_state]1" + H.update_held_items() diff --git a/tgstation.dme b/tgstation.dme index 968263500f1..7265ac7350e 100644 --- a/tgstation.dme +++ b/tgstation.dme @@ -3218,8 +3218,12 @@ #include "code\modules\antagonists\ninja\ninja_stars.dm" #include "code\modules\antagonists\ninja\ninjaDrainAct.dm" #include "code\modules\antagonists\ninja\outfit.dm" -#include "code\modules\antagonists\nukeop\nukeop.dm" #include "code\modules\antagonists\nukeop\outfits.dm" +#include "code\modules\antagonists\nukeop\datums\operative.dm" +#include "code\modules\antagonists\nukeop\datums\operative_leader.dm" +#include "code\modules\antagonists\nukeop\datums\operative_lone.dm" +#include "code\modules\antagonists\nukeop\datums\operative_reinforcement.dm" +#include "code\modules\antagonists\nukeop\datums\operative_team.dm" #include "code\modules\antagonists\nukeop\equipment\borgchameleon.dm" #include "code\modules\antagonists\nukeop\equipment\nuclear_authentication_disk.dm" #include "code\modules\antagonists\nukeop\equipment\nuclear_challenge.dm"