diff --git a/code/game/gamemodes/dynamic/dynamic_rulesets_midround.dm b/code/game/gamemodes/dynamic/dynamic_rulesets_midround.dm
index c14b7b1d0a..cbafe64eb5 100644
--- a/code/game/gamemodes/dynamic/dynamic_rulesets_midround.dm
+++ b/code/game/gamemodes/dynamic/dynamic_rulesets_midround.dm
@@ -15,6 +15,7 @@
var/restrict_ghost_roles = TRUE
/// What mob type the ruleset is restricted to.
var/required_type = /mob/living/carbon/human
+ var/should_use_midround_pref = TRUE
var/list/living_players = list()
var/list/living_antags = list()
var/list/dead_players = list()
@@ -23,6 +24,7 @@
/datum/dynamic_ruleset/midround/from_ghosts
weight = 0
required_type = /mob/dead/observer
+ should_use_midround_pref = FALSE
/// Whether the ruleset should call generate_ruleset_body or not.
var/makeBody = TRUE
/// The rule needs this many applicants to be properly executed.
@@ -43,6 +45,9 @@
if (!M.client) // Are they connected?
trimmed_list.Remove(M)
continue
+ if(should_use_midround_pref && !(M.client.prefs.toggles & MIDROUND_ANTAG))
+ trimmed_list.Remove(M)
+ continue
if(!mode.check_age(M.client, minimum_required_age))
trimmed_list.Remove(M)
continue
@@ -106,10 +111,10 @@
return
message_admins("Polling [possible_volunteers.len] players to apply for the [name] ruleset.")
log_game("DYNAMIC: Polling [possible_volunteers.len] players to apply for the [name] ruleset.")
+ var/flag = antag_flag_override ? antag_flag_override : antag_flag
+ candidates = pollGhostCandidates("The mode is looking for volunteers to become [antag_flag] for [name]", flag, be_special_flag = flag, ignore_category = antag_flag, poll_time = 300)
- candidates = pollGhostCandidates("The mode is looking for volunteers to become [antag_flag] for [name]", antag_flag, be_special_flag = antag_flag_override ? antag_flag_override : antag_flag, poll_time = 300)
-
- if(!candidates || candidates.len <= 0)
+ if(!length(candidates))
mode.dynamic_log("The ruleset [name] received no applications.")
mode.executed_rules -= src
attempt_replacement()
@@ -164,19 +169,10 @@
/datum/dynamic_ruleset/midround/from_ghosts/proc/setup_role(datum/antagonist/new_role)
return
-/// Fired when there are no valid candidates. Will spawn a sleeper agent or latejoin traitor.
+/// Fired when there are no valid candidates. Will try to roll again in a minute.
/datum/dynamic_ruleset/midround/from_ghosts/proc/attempt_replacement()
- var/datum/dynamic_ruleset/midround/autotraitor/sleeper_agent = new
-
- // Otherwise, it has a chance to fail. We don't want that, since this is already pretty unlikely.
- sleeper_agent.has_failure_chance = FALSE
-
- mode.configure_ruleset(sleeper_agent)
-
- if (!mode.picking_specific_rule(sleeper_agent))
- return
-
- mode.picking_specific_rule(/datum/dynamic_ruleset/latejoin/infiltrator)
+ COOLDOWN_START(mode, midround_injection_cooldown, 1 MINUTES)
+ mode.forced_injection = TRUE
//////////////////////////////////////////////
// //
@@ -233,9 +229,8 @@
return ..()
/datum/dynamic_ruleset/midround/autotraitor/execute()
- var/mob/M = pick(living_players)
+ var/mob/M = pick_n_take(living_players)
assigned += M
- living_players -= M
var/datum/antagonist/traitor/newTraitor = new
M.mind.add_antag_datum(newTraitor)
message_admins("[ADMIN_LOOKUPFLW(M)] was selected by the [name] ruleset and has been made into a midround traitor.")
@@ -336,7 +331,7 @@
candidates -= player
continue
- if(player.mind && (player.mind.special_role || player.mind.antag_datums?.len > 0))
+ if(player.mind && (player.mind.special_role || length(player.mind.antag_datums)))
candidates -= player
/datum/dynamic_ruleset/midround/malf/execute()
@@ -355,6 +350,70 @@
M.add_ion_law(generate_ion_law())
return TRUE
+//////////////////////////////////////////////
+// //
+// WIZARD (CREW) //
+// //
+//////////////////////////////////////////////
+
+/datum/dynamic_ruleset/midround/wizard
+ name = "Wizard"
+ antag_datum = /datum/antagonist/wizard
+ antag_flag = "wizard mid crew"
+ antag_flag_override = ROLE_WIZARD
+ protected_roles = list("Prisoner", "Security Officer", "Warden", "Detective", "Head of Security", "Captain", "Chaplain", "Head of Personnel", "Quartermaster", "Chief Engineer", "Chief Medical Officer", "Research Director")
+ restricted_roles = list("AI", "Cyborg")
+ enemy_roles = list("Security Officer","Detective","Head of Security", "Captain")
+ required_enemies = list(0,0,0,0,0,0,0,0,0,0)
+ weight = 0
+ cost = 20
+ requirements = list(101,101,100,60,40,20,20,20,10,10)
+ repeatable = TRUE
+ var/datum/mind/wizard
+
+/datum/dynamic_ruleset/midround/wizard/trim_candidates()
+ ..()
+ candidates = living_players
+ for(var/mob/living/player as anything in candidates)
+ var/turf/player_turf = get_turf(player)
+ if(!player_turf || !is_station_level(player_turf.z))
+ candidates -= player
+ continue
+
+ if(player.mind && (player.mind.special_role || length(player.mind.antag_datums) > 0))
+ candidates -= player
+ candidates = pollCandidates("Do you want to be a wizard?", antag_flag_override, be_special_flag = antag_flag_override, ignore_category = antag_flag_override, poll_time = 300)
+
+/datum/dynamic_ruleset/midround/wizard/ready(forced = FALSE)
+ if(GLOB.wizardstart.len == 0)
+ log_admin("Cannot accept Wizard ruleset. Couldn't find any wizard spawn points.")
+ message_admins("Cannot accept Wizard ruleset. Couldn't find any wizard spawn points.")
+ return FALSE
+ return ..()
+
+/datum/dynamic_ruleset/midround/wizard/execute()
+ var/mob/M = pick_n_take(living_players)
+ assigned += M
+ var/datum/antagonist/wizard/on_station/wiz = new
+ M.mind.add_antag_datum(wiz)
+ wizard = M.mind
+ message_admins("[ADMIN_LOOKUPFLW(M)] was selected by the [name] ruleset and has been made into a midround wizard.")
+ log_game("DYNAMIC: [key_name(M)] was selected by the [name] ruleset and has been made into a midround wizard.")
+ return TRUE
+
+/datum/dynamic_ruleset/midround/wizard/rule_process()
+ if(isliving(wizard.current) && wizard.current.stat!=DEAD)
+ return FALSE
+ for(var/obj/item/phylactery/P in GLOB.poi_list) //TODO : IsProperlyDead()
+ if(P.mind && P.mind.has_antag_datum(/datum/antagonist/wizard))
+ return FALSE
+
+ if(SSevents.wizardmode) //If summon events was active, turn it off
+ SSevents.toggleWizardmode()
+ SSevents.resetFrequency()
+
+ return RULESET_STOP_PROCESSING
+
//////////////////////////////////////////////
// //
// WIZARD (GHOST) //
@@ -459,7 +518,7 @@
antag_flag = "clock mid"
antag_flag_override = ROLE_SERVANT_OF_RATVAR
protected_roles = list("AI", "Cyborg", "Prisoner", "Security Officer", "Warden", "Detective", "Head of Security", "Captain", "Chaplain", "Head of Personnel", "Quartermaster", "Chief Engineer", "Chief Medical Officer", "Research Director")
- restricted_roles = list("AI", "Cyborg", "Prisoner", "Security Officer", "Warden", "Detective", "Head of Security", "Captain", "Chaplain", "Head of Personnel", "Quartermaster", "Chief Engineer", "Chief Medical Officer", "Research Director")
+ restricted_roles = list("AI", "Cyborg")
enemy_roles = list("Security Officer", "Warden", "Detective", "Head of Security", "Captain", "Chaplain", "Head of Personnel", "Quartermaster", "Chief Engineer", "Chief Medical Officer", "Research Director")
required_enemies = list(1,1,1,1,1,1,0,0,0,0)
required_candidates = 2
@@ -536,6 +595,7 @@
name = "Blob Infection"
antag_datum = /datum/antagonist/blob
antag_flag = "blob mid"
+ antag_flag_override = ROLE_BLOB
protected_roles = list("Prisoner", "Security Officer", "Warden", "Detective", "Head of Security", "Captain")
restricted_roles = list("Cyborg", "AI", "Positronic Brain")
enemy_roles = list("Security Officer", "Detective", "Head of Security", "Captain")
@@ -559,11 +619,11 @@
candidates -= player
/datum/dynamic_ruleset/midround/blob_infection/execute()
- if(!candidates || !candidates.len)
+ if(!length(candidates))
return FALSE
var/mob/living/carbon/human/blob_antag = pick_n_take(candidates)
assigned += blob_antag.mind
- blob_antag.mind.special_role = antag_flag
+ blob_antag.mind.special_role = antag_flag_override
return ..()
//////////////////////////////////////////////
diff --git a/code/modules/antagonists/wizard/wizard.dm b/code/modules/antagonists/wizard/wizard.dm
index 63bb2b5b57..5e69bb3847 100644
--- a/code/modules/antagonists/wizard/wizard.dm
+++ b/code/modules/antagonists/wizard/wizard.dm
@@ -1,3 +1,7 @@
+#define WIZARD_DO_NOTHING 0
+#define WIZARD_QDEL_INVENTORY 1
+#define WIZARD_DROP_INVENTORY 2
+
/datum/antagonist/wizard
name = "Space Wizard"
roundend_category = "wizards/witches"
@@ -10,7 +14,8 @@
ui_name = "AntagInfoWizard"
suicide_cry = "FOR THE FEDERATION!!"
var/give_objectives = TRUE
- var/strip = TRUE //strip before equipping
+ var/inventory_mode = WIZARD_QDEL_INVENTORY
+ var/change_species = TRUE
var/allow_rename = TRUE
var/datum/team/wizard/wiz_team //Only created if wizard summons apprentices
var/move_to_lair = TRUE
@@ -87,10 +92,14 @@
var/mob/living/carbon/human/H = owner.current
if(!istype(H))
return
- if(strip)
- H.delete_equipment()
+ switch(inventory_mode)
+ if(WIZARD_QDEL_INVENTORY)
+ H.delete_equipment()
+ if(WIZARD_DROP_INVENTORY)
+ H.unequip_everything()
//Wizards are human by default. Use the mirror if you want something else.
- H.set_species(/datum/species/human)
+ if(change_species)
+ H.set_species(/datum/species/human)
if(H.age < wiz_age)
H.age = wiz_age
H.equipOutfit(outfit_type)
@@ -250,6 +259,17 @@
new_objective.owner = owner
objectives += new_objective
+/datum/antagonist/wizard/on_station
+ inventory_mode = WIZARD_DROP_INVENTORY
+ change_species = FALSE
+
+/datum/antagonist/wizard/on_station/on_gain()
+ var/datum/effect_system/smoke_spread/smoke = new
+ smoke.start()
+ smoke.set_up(2, get_turf(owner))
+ owner.current.visible_message("[owner] suddenly disappears in a puff of smoke, leaving [owner.p_their()] clothes behind!", "You feel yourself being pulled away...")
+ return ..()
+
//Solo wizard report
/datum/antagonist/wizard/roundend_report()
var/list/parts = list()