From 4e8691b6be66368c31c1961a211b54f11f278bcd Mon Sep 17 00:00:00 2001
From: SkyratBot <59378654+SkyratBot@users.noreply.github.com>
Date: Fri, 29 Jul 2022 19:55:08 +0200
Subject: [PATCH] [MIRROR] Nuke Ops Leader update [MDB IGNORE] (#15275)
* Nuke Ops Leader update (#68830)
makes the nuke op player with the most nuke ops playtime the leader
makes the leader start with loud mode on on their radio
idea for that second one from BeeStation/BeeStation-Hornet#6631
making the most playtime nuke op the leader prevents 1st time players from rolling it, they will generally be more competent, and able to be entrusted, just like you can trust a head of staff more. a player with more competency will also probably be better at actually leading and not just clicking a button to open the ship, if they try.
the radio is a tiny change to make the leader matter more, and able to give better leadership, because im pretty sure most people dont even realize the leader has access to loud mode
* Nuke Ops Leader update
Co-authored-by: Fikou <23585223+Fikou@users.noreply.github.com>
---
.../dynamic/dynamic_rulesets_midround.dm | 30 ++++++++++++-------
.../dynamic/dynamic_rulesets_roundstart.dm | 15 ++++++----
.../antagonists/_common/antag_helpers.dm | 28 +++++++++++++++++
code/modules/antagonists/nukeop/nukeop.dm | 17 ++++-------
code/modules/antagonists/nukeop/outfits.dm | 27 +++++++++--------
code/modules/mob/mob_helpers.dm | 12 ++++++++
6 files changed, 89 insertions(+), 40 deletions(-)
diff --git a/code/game/gamemodes/dynamic/dynamic_rulesets_midround.dm b/code/game/gamemodes/dynamic/dynamic_rulesets_midround.dm
index 0eaf01665be..2a9aa501730 100644
--- a/code/game/gamemodes/dynamic/dynamic_rulesets_midround.dm
+++ b/code/game/gamemodes/dynamic/dynamic_rulesets_midround.dm
@@ -157,18 +157,22 @@
else // Not dead? Disregard them, pick a new applicant
i--
continue
-
if(!applicant)
i--
continue
-
- var/mob/new_character = applicant
-
- if (makeBody)
- new_character = generate_ruleset_body(applicant)
-
- finish_setup(new_character, i)
assigned += applicant
+ finish_applications()
+
+/// Here the accepted applications get generated bodies and their setup is finished.
+/// Called by review_applications()
+/datum/dynamic_ruleset/midround/from_ghosts/proc/finish_applications()
+ var/i = 0
+ for(var/mob/applicant as anything in assigned)
+ i++
+ var/mob/new_character = applicant
+ if(makeBody)
+ new_character = generate_ruleset_body(applicant)
+ finish_setup(new_character, i)
notify_ghosts("[applicant.name] has been picked for the ruleset [name]!", source = new_character, action = NOTIFY_ORBIT, header="Something Interesting!")
/datum/dynamic_ruleset/midround/from_ghosts/proc/generate_ruleset_body(mob/applicant)
@@ -382,6 +386,7 @@
requirements = REQUIREMENTS_VERY_HIGH_THREAT_NEEDED
var/list/operative_cap = list(2,2,3,3,4,5,5,5,5,5)
var/datum/team/nuclear/nuke_team
+ var/mob/leader
flags = HIGH_IMPACT_RULESET
/datum/dynamic_ruleset/midround/from_ghosts/nuclear/acceptable(population=0, threat=0)
@@ -396,11 +401,16 @@
return FALSE
return ..()
+/datum/dynamic_ruleset/midround/from_ghosts/nuclear/finish_applications()
+ leader = get_most_experienced(assigned, ROLE_NUCLEAR_OPERATIVE)
+ return ..()
+
/datum/dynamic_ruleset/midround/from_ghosts/nuclear/finish_setup(mob/new_character, index)
new_character.mind.set_assigned_role(SSjob.GetJobType(/datum/job/nuclear_operative))
new_character.mind.special_role = ROLE_NUCLEAR_OPERATIVE
- if (index == 1) // Our first guy is the leader
- var/datum/antagonist/nukeop/leader/new_role = new
+ if(new_character.mind == leader)
+ leader = null
+ var/datum/antagonist/nukeop/leader/new_role = new()
nuke_team = new_role.nuke_team
new_character.mind.add_antag_datum(new_role)
else
diff --git a/code/game/gamemodes/dynamic/dynamic_rulesets_roundstart.dm b/code/game/gamemodes/dynamic/dynamic_rulesets_roundstart.dm
index 3e47a2f2083..fcf61b0be2f 100644
--- a/code/game/gamemodes/dynamic/dynamic_rulesets_roundstart.dm
+++ b/code/game/gamemodes/dynamic/dynamic_rulesets_roundstart.dm
@@ -390,6 +390,7 @@
requirements = list(90,90,90,80,60,40,30,20,10,10)
flags = HIGH_IMPACT_RULESET
antag_cap = list("denominator" = 18, "offset" = 1)
+ var/required_role = ROLE_NUCLEAR_OPERATIVE
var/datum/team/nuclear/nuke_team
/datum/dynamic_ruleset/roundstart/nuclear/ready(population, forced = FALSE)
@@ -410,15 +411,16 @@
return TRUE
/datum/dynamic_ruleset/roundstart/nuclear/execute()
- var/leader = TRUE
- for(var/datum/mind/M in assigned)
- if (leader)
- leader = FALSE
- var/datum/antagonist/nukeop/leader/new_op = M.add_antag_datum(antag_leader_datum)
+ var/most_experienced = get_most_experienced(assigned, required_role)
+ if(!most_experienced)
+ most_experienced = assigned[1]
+ for(var/datum/mind/assigned_player in assigned)
+ if(assigned_player == most_experienced)
+ var/datum/antagonist/nukeop/leader/new_op = assigned_player.add_antag_datum(antag_leader_datum)
nuke_team = new_op.nuke_team
else
var/datum/antagonist/nukeop/new_op = new antag_datum()
- M.add_antag_datum(new_op)
+ assigned_player.add_antag_datum(new_op)
return TRUE
/datum/dynamic_ruleset/roundstart/nuclear/round_result()
@@ -595,6 +597,7 @@
antag_flag_override = ROLE_OPERATIVE
antag_leader_datum = /datum/antagonist/nukeop/leader/clownop
requirements = list(101,101,101,101,101,101,101,101,101,101)
+ required_role = ROLE_CLOWN_OPERATIVE
/datum/dynamic_ruleset/roundstart/nuclear/clown_ops/pre_execute()
. = ..()
diff --git a/code/modules/antagonists/_common/antag_helpers.dm b/code/modules/antagonists/_common/antag_helpers.dm
index e939e1f78cc..19dc4cbb7db 100644
--- a/code/modules/antagonists/_common/antag_helpers.dm
+++ b/code/modules/antagonists/_common/antag_helpers.dm
@@ -7,3 +7,31 @@
continue
if(!antag_type || !specific && istype(A,antag_type) || specific && A.type == antag_type)
. += A.owner
+
+/// From a list of players (minds, mobs or clients), finds the one with the highest playtime (either from a specific role or overall living) and returns it.
+/proc/get_most_experienced(list/players, specific_role)
+ if(!CONFIG_GET(flag/use_exp_tracking)) //woops
+ return
+ var/most_experienced
+ for(var/client/player as anything in players)
+ if(!most_experienced)
+ most_experienced = player
+ continue
+ player = get_player_client(player)
+ if(!player?.prefs || !length(player.prefs.exp))
+ continue
+ var/client/most_played = get_player_client(most_experienced)
+ if(!most_played?.prefs || !length(most_played.prefs.exp))
+ most_experienced = player
+ continue
+ var/player_playtime
+ var/most_playtime
+ if(specific_role)
+ player_playtime = player.prefs.exp[specific_role] ? text2num(player.prefs.exp[specific_role]) : 0
+ most_playtime = most_played.prefs.exp[specific_role] ? text2num(most_played.prefs.exp[specific_role]) : 0
+ else
+ player_playtime = player.get_exp_living(TRUE)
+ most_playtime = most_played.get_exp_living(TRUE)
+ if(player_playtime > most_playtime)
+ most_experienced = player
+ return most_experienced
diff --git a/code/modules/antagonists/nukeop/nukeop.dm b/code/modules/antagonists/nukeop/nukeop.dm
index b7400ff2f2c..bd3eddc22e1 100644
--- a/code/modules/antagonists/nukeop/nukeop.dm
+++ b/code/modules/antagonists/nukeop/nukeop.dm
@@ -244,24 +244,19 @@
/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 the distribution of telecrystals 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 to another operative.")
+ 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/obj/item/dukinuki = new challengeitem
- var/mob/living/carbon/human/H = owner.current
- if(!istype(H))
- dukinuki.forceMove(H.drop_location())
- else
- H.put_in_hands(dukinuki, TRUE)
- nuke_team.war_button_ref = WEAKREF(dukinuki)
-
+ 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/nuketeam_name_assign), 1)
/datum/antagonist/nukeop/leader/proc/nuketeam_name_assign()
diff --git a/code/modules/antagonists/nukeop/outfits.dm b/code/modules/antagonists/nukeop/outfits.dm
index c4b9fd3dbb3..1fec618a12d 100644
--- a/code/modules/antagonists/nukeop/outfits.dm
+++ b/code/modules/antagonists/nukeop/outfits.dm
@@ -25,25 +25,26 @@
id_trim = /datum/id_trim/chameleon/operative/nuke_leader
-/datum/outfit/syndicate/post_equip(mob/living/carbon/human/H, visualsOnly = FALSE)
+/datum/outfit/syndicate/post_equip(mob/living/carbon/human/nukie, visualsOnly = FALSE)
if(visualsOnly)
return
- var/obj/item/radio/R = H.ears
- R.set_frequency(FREQ_SYNDICATE)
- R.freqlock = TRUE
+ var/obj/item/radio/radio = nukie.ears
+ radio.set_frequency(FREQ_SYNDICATE)
+ radio.freqlock = TRUE
if(command_radio)
- R.command = TRUE
+ radio.command = TRUE
+ radio.use_command = TRUE
if(ispath(uplink_type, /obj/item/uplink/nuclear) || tc) // /obj/item/uplink/nuclear understands 0 tc
- var/obj/item/U = new uplink_type(H, H.key, tc)
- H.equip_to_slot_or_del(U, ITEM_SLOT_BACKPACK)
+ var/obj/item/uplink = new uplink_type(nukie, nukie.key, tc)
+ nukie.equip_to_slot_or_del(uplink, ITEM_SLOT_BACKPACK)
- var/obj/item/implant/weapons_auth/W = new/obj/item/implant/weapons_auth(H)
- W.implant(H)
- var/obj/item/implant/explosive/E = new/obj/item/implant/explosive(H)
- E.implant(H)
- H.faction |= ROLE_SYNDICATE
- H.update_icons()
+ var/obj/item/implant/weapons_auth/weapons_implant = new/obj/item/implant/weapons_auth(nukie)
+ weapons_implant.implant(nukie)
+ var/obj/item/implant/explosive/explosive_implant = new/obj/item/implant/explosive(nukie)
+ explosive_implant.implant(nukie)
+ nukie.faction |= ROLE_SYNDICATE
+ nukie.update_icons()
/datum/outfit/syndicate/full
name = "Syndicate Operative - Full Kit"
diff --git a/code/modules/mob/mob_helpers.dm b/code/modules/mob/mob_helpers.dm
index faf7e5078eb..0281765d141 100644
--- a/code/modules/mob/mob_helpers.dm
+++ b/code/modules/mob/mob_helpers.dm
@@ -422,3 +422,15 @@
if(ITEM_SLOT_SUITSTORE)
return /obj/item
return null
+
+/// Returns a client from a mob, mind or client
+/proc/get_player_client(player)
+ if(ismob(player))
+ var/mob/player_mob = player
+ player = player_mob.client
+ else if(istype(player, /datum/mind))
+ var/datum/mind/player_mind = player
+ player = player_mind.current.client
+ if(!istype(player, /client))
+ return
+ return player