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