diff --git a/code/datums/mind.dm b/code/datums/mind.dm
index 7a581b816c1..c630c1714f7 100644
--- a/code/datums/mind.dm
+++ b/code/datums/mind.dm
@@ -342,11 +342,9 @@
/datum/mind/proc/memory_edit_wizard(mob/living/carbon/human/H)
. = _memory_edit_header("wizard")
- if(src in SSticker.mode.wizards)
+ if(has_antag_datum(/datum/antagonist/wizard))
. += "WIZARD|no"
. += "
To lair, undress, dress up, let choose name."
- if(!objective_holder.has_objectives())
- . += "
Objectives are empty! Randomize!"
else
. += "wizard|NO"
@@ -927,24 +925,18 @@
switch(href_list["wizard"])
if("clear")
- if(src in SSticker.mode.wizards)
- SSticker.mode.wizards -= src
- special_role = null
- current.spellremove(current)
- current.faction = list("Station")
- SSticker.mode.update_wiz_icons_removed(src)
- to_chat(current, "You have been brainwashed! You are no longer a wizard!")
+ if(has_antag_datum(/datum/antagonist/wizard))
+ remove_antag_datum(/datum/antagonist/wizard)
+
log_admin("[key_name(usr)] has de-wizarded [key_name(current)]")
message_admins("[key_name_admin(usr)] has de-wizarded [key_name_admin(current)]")
if("wizard")
- if(!(src in SSticker.mode.wizards))
- SSticker.mode.wizards += src
- special_role = SPECIAL_ROLE_WIZARD
- //ticker.mode.learn_basic_spells(current)
- SSticker.mode.update_wiz_icons_added(src)
- SEND_SOUND(current, sound('sound/ambience/antag/ragesmages.ogg'))
- to_chat(current, "You are a Space Wizard!")
- current.faction = list("wizard")
+ if(!has_antag_datum(/datum/antagonist/wizard))
+ var/datum/antagonist/wizard/wizard = new /datum/antagonist/wizard()
+ wizard.should_equip_wizard = FALSE
+ wizard.should_name_pick = FALSE
+ add_antag_datum(wizard)
+
log_admin("[key_name(usr)] has wizarded [key_name(current)]")
message_admins("[key_name_admin(usr)] has wizarded [key_name_admin(current)]")
current.create_log(MISC_LOG, "[current] was made into a wizard by [key_name_admin(usr)]")
@@ -953,18 +945,18 @@
log_admin("[key_name(usr)] has moved [key_name(current)] to the wizard's lair")
message_admins("[key_name_admin(usr)] has moved [key_name_admin(current)] to the wizard's lair")
if("dressup")
- SSticker.mode.equip_wizard(current)
+ var/datum/antagonist/wizard/wizard = has_antag_datum(/datum/antagonist/wizard)
+ var/list/text_result = wizard.equip_wizard()
+ to_chat(current, chat_box_red(text_result.Join("
")))
log_admin("[key_name(usr)] has equipped [key_name(current)] as a wizard")
message_admins("[key_name_admin(usr)] has equipped [key_name_admin(current)] as a wizard")
if("name")
- INVOKE_ASYNC(SSticker.mode, TYPE_PROC_REF(/datum/game_mode/wizard, name_wizard), current)
+ var/datum/antagonist/wizard/wizard = has_antag_datum(/datum/antagonist/wizard)
+ if(!istype(wizard))
+ return
+ wizard.name_wizard()
log_admin("[key_name(usr)] has allowed wizard [key_name(current)] to name themselves")
message_admins("[key_name_admin(usr)] has allowed wizard [key_name_admin(current)] to name themselves")
- if("autoobjectives")
- SSticker.mode.forge_wizard_objectives(src)
- to_chat(usr, "The objectives for wizard [key] have been generated. You can edit them and announce manually.")
- log_admin("[key_name(usr)] has automatically forged wizard objectives for [key_name(current)]")
- message_admins("[key_name_admin(usr)] has automatically forged wizard objectives for [key_name_admin(current)]")
else if(href_list["changeling"])
@@ -1637,26 +1629,6 @@
SSticker.mode.blob_overminds += src
special_role = SPECIAL_ROLE_BLOB_OVERMIND
-/datum/mind/proc/make_Wizard()
- if(!(src in SSticker.mode.wizards))
- SSticker.mode.wizards += src
- special_role = SPECIAL_ROLE_WIZARD
- assigned_role = SPECIAL_ROLE_WIZARD
- //ticker.mode.learn_basic_spells(current)
- if(!GLOB.wizardstart.len)
- current.loc = pick(GLOB.latejoin)
- to_chat(current, "HOT INSERTION, GO GO GO")
- else
- current.loc = pick(GLOB.wizardstart)
-
- SSticker.mode.equip_wizard(current)
- for(var/obj/item/spellbook/S in current.contents)
- S.op = 0
- INVOKE_ASYNC(SSticker.mode, TYPE_PROC_REF(/datum/game_mode/wizard, name_wizard), current)
- SSticker.mode.forge_wizard_objectives(src)
- SSticker.mode.greet_wizard(src)
- SSticker.mode.update_wiz_icons_added(src)
-
/datum/mind/proc/make_Abductor()
var/role = alert("Abductor Role?", "Role", "Agent", "Scientist")
var/team = input("Abductor Team?", "Team?") in list(1,2,3,4)
diff --git a/code/game/gamemodes/wizard/artefact.dm b/code/game/gamemodes/wizard/artefact.dm
index a5d2c841b5f..3074242b50a 100644
--- a/code/game/gamemodes/wizard/artefact.dm
+++ b/code/game/gamemodes/wizard/artefact.dm
@@ -24,52 +24,40 @@
data["used"] = used
return data
-/obj/item/contract/ui_act(action, params)
+/obj/item/contract/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state)
if(..())
return
- var/mob/living/carbon/human/H = usr
-
if(used)
return
+ INVOKE_ASYNC(src, PROC_REF(async_find_apprentice), action, ui.user)
+ SStgui.close_uis(src)
+/obj/item/contract/proc/async_find_apprentice(action, user)
+ if(!ishuman(user))
+ return
+ var/mob/living/carbon/human/H = user
used = TRUE
var/image/source = image('icons/obj/cardboard_cutout.dmi', "cutout_wizard")
var/list/candidates = SSghost_spawns.poll_candidates("Do you want to play as the wizard apprentice of [H.real_name]?", ROLE_WIZARD, TRUE, source = source)
- if(length(candidates))
- var/mob/C = pick(candidates)
- new /obj/effect/particle_effect/smoke(H.loc)
- var/mob/living/carbon/human/M = new/mob/living/carbon/human(H.loc)
- M.key = C.key
- to_chat(M, "You are [H.real_name]'s apprentice! You are bound by magic contract to follow [H.p_their()] orders and help [H.p_them()] in accomplishing [H.p_their()] goals.")
- equip_apprentice(action, M, H)
- var/wizard_name_first = pick(GLOB.wizard_first)
- var/wizard_name_second = pick(GLOB.wizard_second)
- var/randomname = "[wizard_name_first] [wizard_name_second]"
- var/newname = sanitize(copytext_char(input(M, "You are the wizard's apprentice. Would you like to change your name to something else?", "Name change", randomname) as null|text, 1, MAX_NAME_LEN))
-
- if(!newname)
- newname = randomname
- M.mind.name = newname
- M.real_name = newname
- M.name = newname
-
- var/datum/objective/protect/new_objective = new /datum/objective/protect
- new_objective.target = H.mind
- new_objective.explanation_text = "Protect and obey [H.real_name], your teacher."
- M.mind.add_mind_objective(new_objective)
-
- SSticker.mode.apprentices += M.mind
- M.mind.special_role = SPECIAL_ROLE_WIZARD_APPRENTICE
- SSticker.mode.update_wiz_icons_added(M.mind)
- dust_if_respawnable(C)
- M.faction = list("wizard")
- SStgui.close_uis(src)
- else
+ if(!length(candidates))
used = FALSE
to_chat(H, "Unable to reach your apprentice! You can either attack the spellbook with the contract to refund your points, or wait and try again later.")
+ return
+ new /obj/effect/particle_effect/smoke(get_turf(H))
+
+ var/mob/C = pick(candidates)
+ var/mob/living/carbon/human/M = new /mob/living/carbon/human(get_turf(H))
+ M.key = C.key
+
+ var/datum/antagonist/wizard/apprentice/apprentice = new /datum/antagonist/wizard/apprentice()
+ apprentice.my_teacher = H
+ apprentice.class_type = action
+ M.mind.add_antag_datum(apprentice)
+
+ dust_if_respawnable(C)
/obj/item/contract/attack_self(mob/user as mob)
if(..())
@@ -81,67 +69,6 @@
ui_interact(user)
-/obj/item/contract/proc/equip_apprentice(action, mob/living/carbon/human/M, mob/living/carbon/human/H)
- M.equip_to_slot_or_del(new /obj/item/radio/headset(M), SLOT_HUD_LEFT_EAR)
- if(action == "stealth")
- M.equip_to_slot_or_del(new /obj/item/clothing/under/color/grey(M), SLOT_HUD_JUMPSUIT)
- else
- M.equip_to_slot_or_del(new /obj/item/clothing/under/color/lightpurple(M), SLOT_HUD_JUMPSUIT)
- M.equip_to_slot_or_del(new /obj/item/storage/backpack(M), SLOT_HUD_BACK)
- M.equip_to_slot_or_del(new /obj/item/storage/box(M), SLOT_HUD_IN_BACKPACK)
- M.equip_to_slot_or_del(new /obj/item/teleportation_scroll/apprentice(M), SLOT_HUD_RIGHT_STORE)
- switch(action)
- if("fire")
- M.mind.AddSpell(new /obj/effect/proc_holder/spell/fireball/apprentice(null))
- M.mind.AddSpell(new /obj/effect/proc_holder/spell/sacred_flame(null))
- ADD_TRAIT(M, TRAIT_RESISTHEAT, MAGIC_TRAIT)
- ADD_TRAIT(M, TRAIT_RESISTHIGHPRESSURE, MAGIC_TRAIT)
- M.mind.AddSpell(new /obj/effect/proc_holder/spell/ethereal_jaunt(null))
- M.equip_to_slot_or_del(new /obj/item/clothing/shoes/sandal(M), SLOT_HUD_SHOES)
- M.equip_to_slot_or_del(new /obj/item/clothing/suit/wizrobe/red(M), SLOT_HUD_OUTER_SUIT)
- M.equip_to_slot_or_del(new /obj/item/clothing/head/wizard/red(M), SLOT_HUD_HEAD)
- to_chat(M, "Your service has not gone unrewarded. Under the tutelage of [H.real_name], you've acquired proficiency in the fundamentals of Firebending, enabling you to cast spells like Fireball, Sacred Flame, and Ethereal Jaunt.")
- to_chat(M, "You are immune to fire, but you are NOT immune to the explosions caused by your fireballs. Neither is your teacher, for that matter. Be careful!")
- if("translocation")
- M.mind.AddSpell(new /obj/effect/proc_holder/spell/area_teleport/teleport(null))
- M.mind.AddSpell(new /obj/effect/proc_holder/spell/turf_teleport/blink(null))
- M.mind.AddSpell(new /obj/effect/proc_holder/spell/ethereal_jaunt(null))
- M.equip_to_slot_or_del(new /obj/item/clothing/shoes/sandal(M), SLOT_HUD_SHOES)
- M.equip_to_slot_or_del(new /obj/item/clothing/suit/wizrobe(M), SLOT_HUD_OUTER_SUIT)
- M.equip_to_slot_or_del(new /obj/item/clothing/head/wizard(M), SLOT_HUD_HEAD)
- to_chat(M, "Your service has not gone unrewarded. While studying under [H.real_name], you mastered reality-bending mobility spells, allowing you to cast Teleport, Blink, and Ethereal Jaunt.")
- if("restoration")
- M.mind.AddSpell(new /obj/effect/proc_holder/spell/charge(null))
- M.mind.AddSpell(new /obj/effect/proc_holder/spell/aoe/knock(null))
- var/obj/effect/proc_holder/spell/return_to_teacher/S = new /obj/effect/proc_holder/spell/return_to_teacher(null)
- S.teacher = H.mind
- M.mind.AddSpell(S)
- M.equip_to_slot_or_del(new /obj/item/gun/magic/staff/healing(M), SLOT_HUD_RIGHT_HAND)
- M.equip_to_slot_or_del(new /obj/item/clothing/shoes/sandal/marisa(M), SLOT_HUD_SHOES)
- M.equip_to_slot_or_del(new /obj/item/clothing/suit/wizrobe/marisa(M), SLOT_HUD_OUTER_SUIT)
- M.equip_to_slot_or_del(new /obj/item/clothing/head/wizard/marisa(M), SLOT_HUD_HEAD)
- to_chat(M, "Your service has not gone unrewarded. Under the guidance of [H.real_name], you've acquired life-saving survival spells. You can now cast Charge and Knock, and possess the ability to teleport back to your mentor.")
- to_chat(M, "Your Charge spell can be used to recharge your Staff of Healing or reduce the cooldowns of your teacher, if you are grabbing them with empty hands.")
- if("stealth")
- M.mind.AddSpell(new /obj/effect/proc_holder/spell/mind_transfer(null))
- M.mind.AddSpell(new /obj/effect/proc_holder/spell/aoe/knock(null))
- M.mind.AddSpell(new /obj/effect/proc_holder/spell/fireball/toolbox(null))
- M.mind.AddSpell(new /obj/effect/proc_holder/spell/disguise_self(null))
- M.equip_to_slot_or_del(new /obj/item/clothing/shoes/black(M), SLOT_HUD_SHOES)
- M.equip_to_slot_or_del(new /obj/item/clothing/mask/gas(M), SLOT_HUD_WEAR_MASK)
- M.equip_to_slot_or_del(new /obj/item/clothing/gloves/color/yellow(M), SLOT_HUD_GLOVES)
- M.equip_to_slot_or_del(new /obj/item/storage/belt/utility/full(M), SLOT_HUD_BELT)
- to_chat(M, "Your service has not gone unrewarded. Under the mentorship of [H.real_name], you've mastered stealthy, robeless spells. You can now cast Mindswap, Knock, Homing Toolbox, and Disguise Self without the need for wizard robes.")
- if("honk")
- M.mind.AddSpell(new /obj/effect/proc_holder/spell/touch/banana/apprentice(null))
- M.mind.AddSpell(new /obj/effect/proc_holder/spell/ethereal_jaunt(null))
- M.mind.AddSpell(new /obj/effect/proc_holder/spell/summonitem(null))
- M.equip_to_slot_or_del(new /obj/item/gun/magic/staff/slipping(M), SLOT_HUD_RIGHT_HAND)
- M.equip_to_slot_or_del(new /obj/item/clothing/shoes/clown_shoes/magical/nodrop(M), SLOT_HUD_SHOES)
- M.equip_to_slot_or_del(new /obj/item/clothing/suit/wizrobe/clown(M), SLOT_HUD_OUTER_SUIT)
- M.equip_to_slot_or_del(new /obj/item/clothing/head/wizard/clown(M), SLOT_HUD_HEAD)
- M.equip_to_slot_or_del(new /obj/item/clothing/mask/gas/clownwiz(M), SLOT_HUD_WEAR_MASK)
- to_chat(M, "Your dedication pays off! Under [H.real_name]'s guidance, you've mastered magical honkings, seamlessly casting spells like Banana Touch, Ethereal Jaunt, and Instant Summons, while skillfully wielding a Staff of Slipping. Honk!")
///////////////////////////Veil Render//////////////////////
diff --git a/code/game/gamemodes/wizard/raginmages.dm b/code/game/gamemodes/wizard/raginmages.dm
index e710e024147..a524a17e5bf 100644
--- a/code/game/gamemodes/wizard/raginmages.dm
+++ b/code/game/gamemodes/wizard/raginmages.dm
@@ -2,7 +2,6 @@
name = "ragin' mages"
config_tag = "raginmages"
required_players = 20
- use_huds = TRUE
but_wait_theres_more = TRUE
var/max_mages = 0
var/making_mage = FALSE
@@ -18,17 +17,6 @@
to_chat(world, "The current game mode is - Ragin' Mages!")
to_chat(world, "The Space Wizard Federation is pissed, crew must help defeat all the Space Wizards invading the station!")
-/datum/game_mode/wizard/raginmages/greet_wizard(datum/mind/wizard, you_are=1)
- var/list/messages = list()
- if(you_are)
- messages.Add("You are the Space Wizard!")
- messages.Add("The Space Wizards Federation has given you the following tasks:")
-
- messages.Add("Supreme Objective: Make sure the station pays for its actions against our diplomats. We might send more Wizards to the station if the situation is not developing in our favour.")
- messages.Add(wizard.prepare_announce_objectives(title = FALSE))
- to_chat(wizard.current, chat_box_red(messages.Join("
")))
- wizard.current.create_log(MISC_LOG, "[wizard.current] was made into a wizard")
-
/datum/game_mode/wizard/raginmages/check_finished()
var/wizards_alive = 0
var/wizard_cap = CEILING((num_players_started() / players_per_mage), 1)
@@ -37,14 +25,14 @@
if(isnull(wizard.current))
continue
if(wizard.current.stat == DEAD || isbrain(wizard.current) || !iscarbon(wizard.current))
- squabble_helper(wizard)
- continue
- if(wizard.current.stat == UNCONSCIOUS)
- if(wizard.current.health < HEALTH_THRESHOLD_DEAD) //Lets make this not get funny rng crit involved
+ if(squabble_helper(wizard))
+ continue
+ if(wizard.current.stat != CONSCIOUS)
+ if(wizard.current.health < HEALTH_THRESHOLD_DEAD || wizard.current.stat == DEAD) //Lets make this not get funny rng crit involved
if(!squabble_helper(wizard))
to_chat(wizard.current, "The Space Wizard Federation is upset with your performance and have terminated your employment.")
wizard.current.dust() // *REAL* ACTION!! *REAL* DRAMA!! *REAL* BLOODSHED!!
- continue
+ continue
if(!wizard.current.client)
continue // Could just be a bad connection, so SSD wiz's shouldn't be gibbed over it, but they're not "alive" either
@@ -126,7 +114,10 @@
making_mage = FALSE
if(harry)
var/mob/living/carbon/human/new_character = makeBody(harry)
- new_character.mind.make_Wizard() // This puts them at the wizard spawn, worry not
+ var/datum/antagonist/wizard/wizard = new /datum/antagonist/wizard()
+ wizard.additional_text = "Make sure the station pays for its actions against our diplomats. We might send more Wizards to the station if the situation is not developing in our favour."
+ new_character.mind.add_antag_datum(wizard)
+ new_character.forceMove(pick(GLOB.wizardstart))
new_character.equip_to_slot_or_del(new /obj/item/reagent_containers/drinks/mugwort(harry), SLOT_HUD_IN_BACKPACK)
// The first wiznerd can get their mugwort from the wizard's den, new ones will also need mugwort!
mages_made++
diff --git a/code/game/gamemodes/wizard/soulstone.dm b/code/game/gamemodes/wizard/soulstone.dm
index c13da60ffc9..713904da0d1 100644
--- a/code/game/gamemodes/wizard/soulstone.dm
+++ b/code/game/gamemodes/wizard/soulstone.dm
@@ -451,8 +451,9 @@
if(user)
S.faction |= "\ref[user]" //Add the master as a faction, allowing inter-mob cooperation
if(iswizard(user))
- SSticker.mode.update_wiz_icons_added(S.mind)
- S.mind.special_role = SPECIAL_ROLE_WIZARD_APPRENTICE
+ var/datum/antagonist/wizard/construct/construct = new /datum/antagonist/wizard/construct()
+ construct.my_creator = user
+ S.mind.add_antag_datum(construct)
if(IS_CULTIST(user))
S.mind.add_antag_datum(/datum/antagonist/cultist)
to_chat(S, "Your soul has been captured! You are now bound to the cult's will. Help them succeed in their goals at all costs.")
diff --git a/code/game/gamemodes/wizard/wizard.dm b/code/game/gamemodes/wizard/wizard.dm
index 66e13e9fb79..6c20df34f16 100644
--- a/code/game/gamemodes/wizard/wizard.dm
+++ b/code/game/gamemodes/wizard/wizard.dm
@@ -10,238 +10,116 @@
required_enemies = 1
recommended_enemies = 1
single_antag_positions = list()
- var/use_huds = TRUE
var/finished = FALSE
var/but_wait_theres_more = FALSE
+ var/list/pre_wizards = list()
/datum/game_mode/wizard/announce()
to_chat(world, "The current game mode is - Wizard!")
to_chat(world, "There is a SPACE WIZARD on the station. You can't let him achieve his objective!")
-/datum/game_mode/wizard/can_start()//This could be better, will likely have to recode it later
- if(!..())
- return 0
+/datum/game_mode/wizard/pre_setup()
var/list/datum/mind/possible_wizards = get_players_for_role(ROLE_WIZARD)
- if(possible_wizards.len==0)
- return 0
+ if(!length(possible_wizards))
+ return FALSE
var/datum/mind/wizard = pick(possible_wizards)
- wizards += wizard
+ pre_wizards += wizard
wizard.assigned_role = SPECIAL_ROLE_WIZARD //So they aren't chosen for other jobs.
wizard.special_role = SPECIAL_ROLE_WIZARD
- wizard.set_original_mob(wizard.current)
- if(GLOB.wizardstart.len == 0)
+ if(!length(GLOB.wizardstart))
to_chat(wizard.current, "A starting location for you could not be found, please report this bug!")
- return 0
- return 1
-
-/datum/game_mode/wizard/pre_setup()
- for(var/datum/mind/wiz in wizards)
- wiz.current.loc = pick(GLOB.wizardstart)
- ..()
- return 1
+ return FALSE
+ return TRUE
/datum/game_mode/wizard/post_setup()
- for(var/datum/mind/wizard in wizards)
- log_game("[key_name(wizard)] has been selected as a Wizard")
- forge_wizard_objectives(wizard)
- equip_wizard(wizard.current)
- INVOKE_ASYNC(src, PROC_REF(name_wizard), wizard.current)
- greet_wizard(wizard)
- if(use_huds)
- update_wiz_icons_added(wizard)
-
+ for(var/datum/mind/wiz in pre_wizards)
+ wiz.add_antag_datum(/datum/antagonist/wizard)
+ wiz.current.forceMove(pick(GLOB.wizardstart))
+ pre_wizards.Cut()
..()
-/datum/game_mode/proc/remove_wizard(datum/mind/wizard_mind)
- if(wizard_mind in wizards)
- SSticker.mode.wizards -= wizard_mind
- wizard_mind.special_role = null
- wizard_mind.current.create_attack_log("De-wizarded")
- wizard_mind.current.create_log(CONVERSION_LOG, "De-wizarded")
- wizard_mind.current.spellremove(wizard_mind.current)
- wizard_mind.current.faction = list("Station")
- if(issilicon(wizard_mind.current))
- to_chat(wizard_mind.current, "You have been turned into a robot! You can feel your magical powers fading away...")
- else
- to_chat(wizard_mind.current, "You have been brainwashed! You are no longer a wizard.")
- SSticker.mode.update_wiz_icons_removed(wizard_mind)
-
-/datum/game_mode/proc/update_wiz_icons_added(datum/mind/wiz_mind)
- var/datum/atom_hud/antag/wizhud = GLOB.huds[ANTAG_HUD_WIZ]
- wizhud.join_hud(wiz_mind.current)
- set_antag_hud(wiz_mind.current, ((wiz_mind in wizards) ? "hudwizard" : "apprentice"))
-
-/datum/game_mode/proc/update_wiz_icons_removed(datum/mind/wiz_mind)
- var/datum/atom_hud/antag/wizhud = GLOB.huds[ANTAG_HUD_WIZ]
- wizhud.leave_hud(wiz_mind.current)
- set_antag_hud(wiz_mind.current, null)
-
-/datum/game_mode/proc/forge_wizard_objectives(datum/mind/wizard)
- wizard.add_mind_objective(/datum/objective/wizchaos)
-
-/datum/game_mode/proc/name_wizard(mob/living/carbon/human/wizard_mob)
- //Allows the wizard to choose a custom name or go with a random one. Spawn 0 so it does not lag the round starting.
- var/wizard_name_first = pick(GLOB.wizard_first)
- var/wizard_name_second = pick(GLOB.wizard_second)
- var/randomname = "[wizard_name_first] [wizard_name_second]"
- var/newname = sanitize(copytext_char(input(wizard_mob, "You are the Space Wizard. Would you like to change your name to something else?", "Name change", randomname) as null|text, 1, MAX_NAME_LEN))
-
- if(!newname)
- newname = randomname
-
- wizard_mob.real_name = newname
- wizard_mob.name = newname
- if(wizard_mob.mind)
- wizard_mob.mind.name = newname
-
-/datum/game_mode/proc/greet_wizard(datum/mind/wizard, you_are=1)
- addtimer(CALLBACK(wizard.current, TYPE_PROC_REF(/mob, playsound_local), null, 'sound/ambience/antag/ragesmages.ogg', 100, 0), 30)
- var/list/messages = list()
- if(you_are)
- messages.Add("You are the Space Wizard!")
- messages.Add("The Space Wizards Federation has given you the following tasks:")
-
- messages.Add(wizard.prepare_announce_objectives(title = FALSE))
- messages.Add("For more information, check the wiki page: ([GLOB.configuration.url.wiki_url]/index.php/Wizard)")
- to_chat(wizard.current, chat_box_red(messages.Join("
")))
- wizard.current.create_log(MISC_LOG, "[wizard.current] was made into a wizard")
-
-/datum/game_mode/proc/equip_wizard(mob/living/carbon/human/wizard_mob)
- if(!istype(wizard_mob))
- return
-
- //So zards properly get their items when they are admin-made.
- qdel(wizard_mob.wear_suit)
- qdel(wizard_mob.head)
- qdel(wizard_mob.shoes)
- qdel(wizard_mob.r_hand)
- qdel(wizard_mob.r_store)
- qdel(wizard_mob.l_store)
-
- if(isplasmaman(wizard_mob))
- wizard_mob.equipOutfit(new /datum/outfit/plasmaman/wizard)
- wizard_mob.internal = wizard_mob.r_hand
- wizard_mob.update_action_buttons_icon()
- else
- wizard_mob.equip_to_slot_or_del(new /obj/item/clothing/under/color/lightpurple(wizard_mob), SLOT_HUD_JUMPSUIT)
- wizard_mob.equip_to_slot_or_del(new /obj/item/clothing/head/wizard(wizard_mob), SLOT_HUD_HEAD)
- wizard_mob.dna.species.after_equip_job(null, wizard_mob)
- wizard_mob.rejuvenate() //fix any damage taken by naked vox/plasmamen/etc while round setups
- wizard_mob.equip_to_slot_or_del(new /obj/item/radio/headset(wizard_mob), SLOT_HUD_LEFT_EAR)
- wizard_mob.equip_to_slot_or_del(new /obj/item/clothing/shoes/sandal(wizard_mob), SLOT_HUD_SHOES)
- wizard_mob.equip_to_slot_or_del(new /obj/item/clothing/suit/wizrobe(wizard_mob), SLOT_HUD_OUTER_SUIT)
- wizard_mob.equip_to_slot_or_del(new /obj/item/storage/backpack/satchel(wizard_mob), SLOT_HUD_BACK)
- if(wizard_mob.dna.species.speciesbox)
- wizard_mob.equip_to_slot_or_del(new wizard_mob.dna.species.speciesbox(wizard_mob), SLOT_HUD_IN_BACKPACK)
- else
- wizard_mob.equip_to_slot_or_del(new /obj/item/storage/box/survival(wizard_mob), SLOT_HUD_IN_BACKPACK)
- wizard_mob.equip_to_slot_or_del(new /obj/item/teleportation_scroll(wizard_mob), SLOT_HUD_RIGHT_STORE)
- var/obj/item/spellbook/spellbook = new /obj/item/spellbook(wizard_mob)
- spellbook.owner = wizard_mob
- wizard_mob.equip_to_slot_or_del(spellbook, SLOT_HUD_LEFT_HAND)
-
- wizard_mob.faction = list("wizard")
- wizard_mob.mind.offstation_role = TRUE
-
-
-
- to_chat(wizard_mob, "You will find a list of available spells in your spell book. Choose your magic arsenal carefully.")
- to_chat(wizard_mob, "The spellbook is bound to you, and others cannot use it.")
- to_chat(wizard_mob, "In your pockets you will find a teleport scroll. Use it as needed.")
- wizard_mob.mind.store_memory("Remember: do not forget to prepare your spells.")
- wizard_mob.update_icons()
- wizard_mob.gene_stability += DEFAULT_GENE_STABILITY //magic
- return TRUE
-
// Checks if the game should end due to all wizards and apprentices being dead, or MMI'd/Borged
/datum/game_mode/wizard/check_finished()
- var/wizards_alive = 0
- var/apprentices_alive = 0
+ if(but_wait_theres_more)
+ return ..()
// Wizards
for(var/datum/mind/wizard in wizards)
if(!iscarbon(wizard.current) || wizard.current.stat == DEAD) // wizard is in an MMI, don't count them as alive
continue
- wizards_alive++
+ return ..()
// Apprentices
- if(!wizards_alive)
- for(var/datum/mind/apprentice in apprentices)
- if(!iscarbon(apprentice.current))
- continue
- if(apprentice.current.stat==DEAD)
- continue
- if(istype(apprentice.current, /obj/item/mmi)) // apprentice is in an MMI, don't count them as alive
- continue
- apprentices_alive++
-
- if(wizards_alive || apprentices_alive || but_wait_theres_more)
+ for(var/datum/mind/apprentice in apprentices)
+ if(!iscarbon(apprentice.current))
+ continue
+ if(apprentice.current.stat == DEAD)
+ continue
+ if(istype(apprentice.current, /obj/item/mmi)) // apprentice is in an MMI, don't count them as alive
+ continue
return ..()
- else
- finished = TRUE
- return 1
+
+ finished = TRUE
+ return TRUE
/datum/game_mode/wizard/declare_completion(ragin = 0)
if(finished && !ragin)
SSticker.mode_result = "wizard loss - wizard killed"
to_chat(world, " The wizard[(wizards.len>1)?"s":""] has been killed by the crew! The Space Wizards Federation has been taught a lesson they will not soon forget!")
..()
- return 1
+ return TRUE
/datum/game_mode/proc/auto_declare_completion_wizard()
- if(length(wizards))
- var/list/text = list("
the wizards/witches were:")
+ if(!length(wizards))
+ return
+ var/list/text = list("
the wizards/witches were:")
- for(var/datum/mind/wizard in wizards)
+ for(var/datum/mind/wizard in wizards)
- text += "
[wizard.get_display_key()] was [wizard.name] ("
- if(wizard.current)
- if(wizard.current.stat == DEAD)
- text += "died"
- else
- text += "survived"
- if(wizard.current.real_name != wizard.name)
- text += " as [wizard.current.real_name]"
+ text += "
[wizard.get_display_key()] was [wizard.name] ("
+ if(wizard.current)
+ if(wizard.current.stat == DEAD)
+ text += "died"
else
- text += "body destroyed"
- text += ")"
+ text += "survived"
+ if(wizard.current.real_name != wizard.name)
+ text += " as [wizard.current.real_name]"
+ else
+ text += "body destroyed"
+ text += ")"
- var/count = 1
- var/wizardwin = 1
- for(var/datum/objective/objective in wizard.get_all_objectives(include_team = FALSE))
- if(objective.check_completion())
- text += "
Objective #[count]: [objective.explanation_text] Success!"
- SSblackbox.record_feedback("nested tally", "wizard_objective", 1, list("[objective.type]", "SUCCESS"))
- else
- text += "
Objective #[count]: [objective.explanation_text] Fail."
- SSblackbox.record_feedback("nested tally", "wizard_objective", 1, list("[objective.type]", "FAIL"))
- wizardwin = 0
- count++
-
- if(wizard.current && wizard.current.stat!=DEAD && wizardwin)
- text += "
The wizard was successful!"
- SSblackbox.record_feedback("tally", "wizard_success", 1, "SUCCESS")
+ var/count = 1
+ var/wizardwin = 1
+ for(var/datum/objective/objective in wizard.get_all_objectives(include_team = FALSE))
+ if(objective.check_completion())
+ text += "
Objective #[count]: [objective.explanation_text] Success!"
+ SSblackbox.record_feedback("nested tally", "wizard_objective", 1, list("[objective.type]", "SUCCESS"))
else
- text += "
The wizard has failed!"
- SSblackbox.record_feedback("tally", "wizard_success", 1, "FAIL")
- if(wizard.spell_list)
- text += "
[wizard.name] used the following spells: "
- var/i = 1
- for(var/obj/effect/proc_holder/spell/S in wizard.spell_list)
- text += "[S.name]"
- if(wizard.spell_list.len > i)
- text += ", "
- i++
- text += "
"
+ text += "
Objective #[count]: [objective.explanation_text] Fail."
+ SSblackbox.record_feedback("nested tally", "wizard_objective", 1, list("[objective.type]", "FAIL"))
+ wizardwin = 0
+ count++
- return text.Join("")
+ if(wizard.current && wizard.current.stat != DEAD && wizardwin)
+ text += "
The wizard was successful!"
+ SSblackbox.record_feedback("tally", "wizard_success", 1, "SUCCESS")
+ else
+ text += "
The wizard has failed!"
+ SSblackbox.record_feedback("tally", "wizard_success", 1, "FAIL")
+ if(wizard.spell_list)
+ text += "
[wizard.name] used the following spells: "
+ text += english_list(wizard.spell_list)
+
+ text += "
"
+
+ return text.Join("")
//OTHER PROCS
//To batch-remove wizard spells. Linked to mind.dm
-/mob/proc/spellremove(mob/M)
+/mob/proc/spellremove()
if(!mind)
return
for(var/obj/effect/proc_holder/spell/spell_to_remove in mind.spell_list)
@@ -249,26 +127,10 @@
mind.spell_list -= spell_to_remove
//To batch-remove mob spells.
-/mob/proc/mobspellremove(mob/M)
+/mob/proc/mobspellremove()
for(var/obj/effect/proc_holder/spell/spell_to_remove in mob_spell_list)
qdel(spell_to_remove)
mob_spell_list -= spell_to_remove
-/*Checks if the wizard can cast spells.
-Made a proc so this is not repeated 14 (or more) times.*/
-/mob/proc/casting()
-//Removed the stat check because not all spells require clothing now.
- if(!istype(usr:wear_suit, /obj/item/clothing/suit/wizrobe))
- to_chat(usr, "I don't feel strong enough without my robe.")
- return 0
- if(!istype(usr:shoes, /obj/item/clothing/shoes/sandal))
- to_chat(usr, "I don't feel strong enough without my sandals.")
- return 0
- if(!istype(usr:head, /obj/item/clothing/head/wizard))
- to_chat(usr, "I don't feel strong enough without my hat.")
- return 0
- else
- return 1
-
-/proc/iswizard(mob/living/M as mob)
- return istype(M) && M.mind && SSticker && SSticker.mode && ((M.mind in SSticker.mode.wizards) || (M.mind in SSticker.mode.apprentices))
+/proc/iswizard(mob/living/M)
+ return istype(M) && M.mind?.has_antag_datum(/datum/antagonist/wizard)
diff --git a/code/game/objects/items/weapons/dice.dm b/code/game/objects/items/weapons/dice.dm
index a7f4fc10780..d3495458b8f 100644
--- a/code/game/objects/items/weapons/dice.dm
+++ b/code/game/objects/items/weapons/dice.dm
@@ -150,7 +150,7 @@
/obj/item/dice/d20/fate/diceroll(mob/user)
. = ..()
if(!used)
- if(!ishuman(user) || !user.mind || (user.mind in SSticker.mode.wizards))
+ if(!ishuman(user) || !user.mind || iswizard(user))
to_chat(user, "You feel the magic of the dice is restricted to ordinary humans!")
return
@@ -163,7 +163,7 @@
addtimer(CALLBACK(src, PROC_REF(effect), user, .), 1 SECONDS)
/obj/item/dice/d20/fate/equipped(mob/user, slot)
- if(!ishuman(user) || !user.mind || (user.mind in SSticker.mode.wizards))
+ if(!ishuman(user) || !user.mind || iswizard(user))
to_chat(user, "You feel the magic of the dice is restricted to ordinary humans! You should leave it alone.")
user.unEquip(src)
diff --git a/code/game/objects/items/weapons/staff.dm b/code/game/objects/items/weapons/staff.dm
index 8a749cd4179..255b2d4cfe1 100644
--- a/code/game/objects/items/weapons/staff.dm
+++ b/code/game/objects/items/weapons/staff.dm
@@ -58,7 +58,7 @@
..()
/obj/item/staff/broom/dropped(mob/user)
- if((user.mind in SSticker.mode.wizards) && user.flying)
+ if(iswizard(user) && user.flying)
user.flying = FALSE
..()
diff --git a/code/modules/admin/misc_admin_procs.dm b/code/modules/admin/misc_admin_procs.dm
index 81de0ed78b3..35b1a6c8121 100644
--- a/code/modules/admin/misc_admin_procs.dm
+++ b/code/modules/admin/misc_admin_procs.dm
@@ -647,9 +647,9 @@ GLOBAL_VAR_INIT(nologevent, 0)
antag_list += "Cultist"
if(M.mind in SSticker.mode.syndicates)
antag_list += "Nuclear Operative"
- if(M.mind in SSticker.mode.wizards)
+ if(iswizard(M))
antag_list += "Wizard"
- if(M.mind in SSticker.mode.changelings)
+ if(ischangeling(M))
antag_list += "Changeling"
if(M.mind in SSticker.mode.abductors)
antag_list += "Abductor"
diff --git a/code/modules/admin/verbs/one_click_antag.dm b/code/modules/admin/verbs/one_click_antag.dm
index af3031c6805..e9801ac73f9 100644
--- a/code/modules/admin/verbs/one_click_antag.dm
+++ b/code/modules/admin/verbs/one_click_antag.dm
@@ -147,10 +147,11 @@
candidates -= selected
var/mob/living/carbon/human/new_character = makeBody(selected)
- new_character.mind.make_Wizard()
+ new_character.mind.add_antag_datum(/datum/antagonist/wizard)
+ new_character.forceMove(pick(GLOB.wizardstart))
dust_if_respawnable(selected)
- return 1
- return 0
+ return TRUE
+ return FALSE
/datum/admins/proc/makeCult()
diff --git a/code/modules/admin/verbs/randomverbs.dm b/code/modules/admin/verbs/randomverbs.dm
index beb312f2dc4..335b6bd6ea2 100644
--- a/code/modules/admin/verbs/randomverbs.dm
+++ b/code/modules/admin/verbs/randomverbs.dm
@@ -455,9 +455,11 @@ Traitors and the like can also be revived with the previous role mostly intact.
else
new_character.mind.add_antag_datum(/datum/antagonist/traitor)
if("Wizard")
- new_character.loc = pick(GLOB.wizardstart)
+ new_character.forceMove(pick(GLOB.wizardstart))
//ticker.mode.learn_basic_spells(new_character)
- SSticker.mode.equip_wizard(new_character)
+ var/datum/antagonist/wizard/wizard = new_character.mind.has_antag_datum(/datum/antagonist/wizard)
+ if(istype(wizard))
+ wizard.equip_wizard()
if("Syndicate")
var/obj/effect/landmark/synd_spawn = locate("landmark*Syndicate-Spawn")
if(synd_spawn)
diff --git a/code/modules/antagonists/wizard/datum_apprentice.dm b/code/modules/antagonists/wizard/datum_apprentice.dm
new file mode 100644
index 00000000000..a638a34c2da
--- /dev/null
+++ b/code/modules/antagonists/wizard/datum_apprentice.dm
@@ -0,0 +1,102 @@
+/datum/antagonist/wizard/apprentice
+ name = "Wizard Apprentice"
+ special_role = SPECIAL_ROLE_WIZARD_APPRENTICE
+ antag_hud_name = "apprentice"
+ antag_datum_blacklist = list(/datum/antagonist/wizard/construct)
+
+ /// Temporary reference to a mob for purposes of objectives, and general text for the apprentice.
+ var/mob/living/my_teacher
+ /// The class type of this apprentice,
+ var/class_type
+
+/datum/antagonist/wizard/apprentice/greet()
+ . = ..()
+ . += "You are [my_teacher.real_name]'s apprentice! You are bound by magic contract to follow [my_teacher.p_their()] orders and help [my_teacher.p_them()] in accomplishing [my_teacher.p_their()] goals."
+
+/datum/antagonist/wizard/apprentice/give_objectives()
+ var/datum/objective/protect/new_objective = new /datum/objective/protect
+ new_objective.target = my_teacher.mind
+ new_objective.explanation_text = "Protect and obey [my_teacher.real_name], your teacher."
+ add_antag_objective(new_objective)
+
+/datum/antagonist/wizard/apprentice/on_gain()
+ . = ..()
+ my_teacher = null // all uses of my_teacher come before this, so lets clean up the reference.
+
+/datum/antagonist/wizard/apprentice/add_owner_to_gamemode()
+ SSticker.mode.apprentices |= owner
+
+/datum/antagonist/wizard/apprentice/remove_owner_from_gamemode()
+ SSticker.mode.apprentices -= owner
+
+/datum/antagonist/wizard/apprentice/equip_wizard()
+ if(!class_type)
+ CRASH("/datum/antagonist/wizard/apprentice was never assigned a class_type")
+ var/mob/living/carbon/human/new_wiz = owner.current
+ new_wiz.equip_to_slot_or_del(new /obj/item/radio/headset(new_wiz), SLOT_HUD_LEFT_EAR)
+ if(class_type == "stealth")
+ new_wiz.equip_to_slot_or_del(new /obj/item/clothing/under/color/grey(new_wiz), SLOT_HUD_JUMPSUIT)
+ else
+ new_wiz.equip_to_slot_or_del(new /obj/item/clothing/under/color/lightpurple(new_wiz), SLOT_HUD_JUMPSUIT)
+ new_wiz.equip_to_slot_or_del(new /obj/item/storage/backpack(new_wiz), SLOT_HUD_BACK)
+ new_wiz.equip_to_slot_or_del(new /obj/item/storage/box(new_wiz), SLOT_HUD_IN_BACKPACK)
+ new_wiz.equip_to_slot_or_del(new /obj/item/teleportation_scroll/apprentice(new_wiz), SLOT_HUD_RIGHT_STORE)
+
+ var/list/messages = list()
+ switch(class_type)
+ if("fire")
+ new_wiz.mind.AddSpell(new /obj/effect/proc_holder/spell/fireball/apprentice(null))
+ new_wiz.mind.AddSpell(new /obj/effect/proc_holder/spell/sacred_flame(null))
+ ADD_TRAIT(new_wiz, TRAIT_RESISTHEAT, MAGIC_TRAIT)
+ ADD_TRAIT(new_wiz, TRAIT_RESISTHIGHPRESSURE, MAGIC_TRAIT)
+ new_wiz.mind.AddSpell(new /obj/effect/proc_holder/spell/ethereal_jaunt(null))
+ new_wiz.equip_to_slot_or_del(new /obj/item/clothing/shoes/sandal(new_wiz), SLOT_HUD_SHOES)
+ new_wiz.equip_to_slot_or_del(new /obj/item/clothing/suit/wizrobe/red(new_wiz), SLOT_HUD_OUTER_SUIT)
+ new_wiz.equip_to_slot_or_del(new /obj/item/clothing/head/wizard/red(new_wiz), SLOT_HUD_HEAD)
+ messages += "Your service has not gone unrewarded. Under the tutelage of [my_teacher.real_name], you've acquired proficiency in the fundamentals of Firebending, enabling you to cast spells like Fireball, Sacred Flame, and Ethereal Jaunt."
+ messages += "You are immune to fire, but you are NOT immune to the explosions caused by your fireballs. Neither is your teacher, for that matter. Be careful!"
+ if("translocation")
+ new_wiz.mind.AddSpell(new /obj/effect/proc_holder/spell/area_teleport/teleport(null))
+ new_wiz.mind.AddSpell(new /obj/effect/proc_holder/spell/turf_teleport/blink(null))
+ new_wiz.mind.AddSpell(new /obj/effect/proc_holder/spell/ethereal_jaunt(null))
+ new_wiz.equip_to_slot_or_del(new /obj/item/clothing/shoes/sandal(new_wiz), SLOT_HUD_SHOES)
+ new_wiz.equip_to_slot_or_del(new /obj/item/clothing/suit/wizrobe(new_wiz), SLOT_HUD_OUTER_SUIT)
+ new_wiz.equip_to_slot_or_del(new /obj/item/clothing/head/wizard(new_wiz), SLOT_HUD_HEAD)
+ messages += "Your service has not gone unrewarded. While studying under [my_teacher.real_name], you mastered reality-bending mobility spells, allowing you to cast Teleport, Blink, and Ethereal Jaunt."
+ if("restoration")
+ new_wiz.mind.AddSpell(new /obj/effect/proc_holder/spell/charge(null))
+ new_wiz.mind.AddSpell(new /obj/effect/proc_holder/spell/aoe/knock(null))
+ var/obj/effect/proc_holder/spell/return_to_teacher/S = new /obj/effect/proc_holder/spell/return_to_teacher(null)
+ S.teacher = my_teacher.mind
+ new_wiz.mind.AddSpell(S)
+ new_wiz.equip_to_slot_or_del(new /obj/item/gun/magic/staff/healing(new_wiz), SLOT_HUD_RIGHT_HAND)
+ new_wiz.equip_to_slot_or_del(new /obj/item/clothing/shoes/sandal/marisa(new_wiz), SLOT_HUD_SHOES)
+ new_wiz.equip_to_slot_or_del(new /obj/item/clothing/suit/wizrobe/marisa(new_wiz), SLOT_HUD_OUTER_SUIT)
+ new_wiz.equip_to_slot_or_del(new /obj/item/clothing/head/wizard/marisa(new_wiz), SLOT_HUD_HEAD)
+ messages += "Your service has not gone unrewarded. Under the guidance of [my_teacher.real_name], you've acquired life-saving survival spells. You can now cast Charge and Knock, and possess the ability to teleport back to your mentor."
+ messages += "Your Charge spell can be used to recharge your Staff of Healing or reduce the cooldowns of your teacher, if you are grabbing them with empty hands."
+ if("stealth")
+ new_wiz.mind.AddSpell(new /obj/effect/proc_holder/spell/mind_transfer(null))
+ new_wiz.mind.AddSpell(new /obj/effect/proc_holder/spell/aoe/knock(null))
+ new_wiz.mind.AddSpell(new /obj/effect/proc_holder/spell/fireball/toolbox(null))
+ new_wiz.mind.AddSpell(new /obj/effect/proc_holder/spell/disguise_self(null))
+ new_wiz.equip_to_slot_or_del(new /obj/item/clothing/shoes/black(new_wiz), SLOT_HUD_SHOES)
+ new_wiz.equip_to_slot_or_del(new /obj/item/clothing/mask/gas(new_wiz), SLOT_HUD_WEAR_MASK)
+ new_wiz.equip_to_slot_or_del(new /obj/item/clothing/gloves/color/yellow(new_wiz), SLOT_HUD_GLOVES)
+ new_wiz.equip_to_slot_or_del(new /obj/item/storage/belt/utility/full(new_wiz), SLOT_HUD_BELT)
+ messages += "Your service has not gone unrewarded. Under the mentorship of [my_teacher.real_name], you've mastered stealthy, robeless spells. You can now cast Mindswap, Knock, Homing Toolbox, and Disguise Self without the need for wizard robes."
+ if("honk")
+ new_wiz.mind.AddSpell(new /obj/effect/proc_holder/spell/touch/banana/apprentice(null))
+ new_wiz.mind.AddSpell(new /obj/effect/proc_holder/spell/ethereal_jaunt(null))
+ new_wiz.mind.AddSpell(new /obj/effect/proc_holder/spell/summonitem(null))
+ new_wiz.equip_to_slot_or_del(new /obj/item/gun/magic/staff/slipping(new_wiz), SLOT_HUD_RIGHT_HAND)
+ new_wiz.equip_to_slot_or_del(new /obj/item/clothing/shoes/clown_shoes/magical/nodrop(new_wiz), SLOT_HUD_SHOES)
+ new_wiz.equip_to_slot_or_del(new /obj/item/clothing/suit/wizrobe/clown(new_wiz), SLOT_HUD_OUTER_SUIT)
+ new_wiz.equip_to_slot_or_del(new /obj/item/clothing/head/wizard/clown(new_wiz), SLOT_HUD_HEAD)
+ new_wiz.equip_to_slot_or_del(new /obj/item/clothing/mask/gas/clownwiz(new_wiz), SLOT_HUD_WEAR_MASK)
+ messages += "Your dedication pays off! Under [my_teacher.real_name]'s guidance, you've mastered magical honkings, seamlessly casting spells like Banana Touch, Ethereal Jaunt, and Instant Summons, while skillfully wielding a Staff of Slipping. Honk!"
+
+ return messages
+
+/datum/antagonist/wizard/apprentice/full_on_wizard()
+ return FALSE
diff --git a/code/modules/antagonists/wizard/datum_wiz_construct.dm b/code/modules/antagonists/wizard/datum_wiz_construct.dm
new file mode 100644
index 00000000000..d678a0fc209
--- /dev/null
+++ b/code/modules/antagonists/wizard/datum_wiz_construct.dm
@@ -0,0 +1,36 @@
+/datum/antagonist/wizard/construct
+ name = "Magical Construct"
+ special_role = SPECIAL_ROLE_WIZARD_APPRENTICE
+ antag_hud_name = "apprentice"
+ antag_datum_blacklist = list(/datum/antagonist/wizard/apprentice)
+
+ should_equip_wizard = FALSE
+ should_name_pick = FALSE
+ /// Temporary reference to a mob for purposes of objectives, and general text for the apprentice.
+ var/mob/living/my_creator
+
+/datum/antagonist/wizard/construct/greet()
+ . = ..()
+ . += "You are [my_creator.real_name]'s construct! You are bound by magic to follow [my_creator.p_their()] orders and help [my_creator.p_them()] in accomplishing [my_creator.p_their()] goals."
+
+/datum/antagonist/wizard/construct/give_objectives()
+ var/datum/objective/protect/new_objective = new /datum/objective/protect
+ new_objective.target = my_creator.mind
+ new_objective.explanation_text = "Protect and obey [my_creator.real_name], your creator."
+ add_antag_objective(new_objective)
+
+/datum/antagonist/wizard/construct/on_gain()
+ . = ..()
+ my_creator = null // all uses of my_creator come before this, so lets clean up the reference.
+
+/datum/antagonist/wizard/construct/add_owner_to_gamemode()
+ SSticker.mode.apprentices |= owner
+
+/datum/antagonist/wizard/construct/remove_owner_from_gamemode()
+ SSticker.mode.apprentices -= owner
+
+/datum/antagonist/wizard/construct/equip_wizard()
+ return
+
+/datum/antagonist/wizard/construct/full_on_wizard()
+ return FALSE
diff --git a/code/modules/antagonists/wizard/datum_wizard.dm b/code/modules/antagonists/wizard/datum_wizard.dm
new file mode 100644
index 00000000000..90a5fb17e85
--- /dev/null
+++ b/code/modules/antagonists/wizard/datum_wizard.dm
@@ -0,0 +1,118 @@
+//Greetings from the Wizard Federation!!
+/datum/antagonist/wizard
+ name = "Wizard"
+ roundend_category = "wizards"
+ job_rank = ROLE_WIZARD
+ special_role = SPECIAL_ROLE_WIZARD
+ give_objectives = TRUE
+ antag_hud_name = "hudwizard"
+ antag_hud_type = ANTAG_HUD_WIZ
+ clown_gain_text = "Your new magical powers has allowed you to overcome your clownish nature, allowing you to wield weapons without harming yourself."
+ clown_removal_text = "You lose your magical powers and return to your own clumsy, clownish self."
+ wiki_page_name = "Wizard"
+ var/should_equip_wizard = TRUE
+ var/should_name_pick = TRUE
+ var/additional_text
+
+/datum/antagonist/wizard/on_gain()
+ . = ..()
+ owner.current.faction -= "neutral"
+ owner.current.faction |= "wizard"
+ owner.offstation_role = TRUE
+ if(should_name_pick)
+ name_wizard()
+ SEND_SOUND(owner.current, 'sound/ambience/antag/ragesmages.ogg')
+
+/datum/antagonist/wizard/greet()
+ . = ..()
+ if(additional_text)
+ . += additional_text
+
+/datum/antagonist/wizard/finalize_antag()
+ var/list/messages = list()
+ if(should_equip_wizard)
+ messages = equip_wizard()
+ if(full_on_wizard())
+ messages += "Remember to bring your magical Mugwort Tea, it will slowly heal you when you drink it."
+ return messages
+
+/datum/antagonist/wizard/detach_from_owner()
+ owner.current.faction |= "neutral"
+ owner.current.faction -= "wizard"
+ owner.offstation_role = FALSE
+ owner.current.spellremove()
+ return ..()
+
+/datum/antagonist/wizard/farewell()
+ if(owner?.current)
+ to_chat(owner.current, "You have been brainwashed! You are no longer a [name]!")
+
+/datum/antagonist/wizard/add_owner_to_gamemode()
+ SSticker.mode.wizards |= owner
+
+/datum/antagonist/wizard/remove_owner_from_gamemode()
+ SSticker.mode.wizards -= owner
+
+/datum/antagonist/wizard/give_objectives()
+ add_antag_objective(/datum/objective/wizchaos)
+
+/datum/antagonist/wizard/proc/name_wizard()
+ INVOKE_ASYNC(src, PROC_REF(_name_wizard))
+
+/datum/antagonist/wizard/proc/_name_wizard()
+ PRIVATE_PROC(TRUE)
+ var/wizard_name_first = pick(GLOB.wizard_first)
+ var/wizard_name_second = pick(GLOB.wizard_second)
+ var/randomname = "[wizard_name_first] [wizard_name_second]"
+ var/newname = sanitize(copytext(input(owner.current, "You are the Space Wizard. Would you like to change your name to something else?", "Name change", randomname) as null|text,1,MAX_NAME_LEN))
+
+ if(!newname)
+ newname = randomname
+ owner.current.rename_character(owner.current.real_name, newname)
+
+/datum/antagonist/wizard/proc/equip_wizard()
+ if(!ishuman(owner.current))
+ return
+ var/mob/living/carbon/human/new_wiz = owner.current
+
+ //So zards properly get their items when they are admin-made.
+ qdel(new_wiz.wear_suit)
+ qdel(new_wiz.head)
+ qdel(new_wiz.shoes)
+ qdel(new_wiz.r_hand)
+ qdel(new_wiz.r_store)
+ qdel(new_wiz.l_store)
+
+ if(isplasmaman(new_wiz))
+ new_wiz.equipOutfit(new /datum/outfit/plasmaman/wizard)
+ new_wiz.internal = new_wiz.r_hand
+ new_wiz.update_action_buttons_icon()
+ else
+ new_wiz.equip_to_slot_or_del(new /obj/item/clothing/under/color/lightpurple(new_wiz), SLOT_HUD_JUMPSUIT)
+ new_wiz.equip_to_slot_or_del(new /obj/item/clothing/head/wizard(new_wiz), SLOT_HUD_HEAD)
+ new_wiz.dna.species.after_equip_job(null, new_wiz)
+ new_wiz.rejuvenate() //fix any damage taken by naked vox/plasmamen/etc while round setups
+ new_wiz.equip_to_slot_or_del(new /obj/item/radio/headset(new_wiz), SLOT_HUD_LEFT_EAR)
+ new_wiz.equip_to_slot_or_del(new /obj/item/clothing/shoes/sandal(new_wiz), SLOT_HUD_SHOES)
+ new_wiz.equip_to_slot_or_del(new /obj/item/clothing/suit/wizrobe(new_wiz), SLOT_HUD_OUTER_SUIT)
+ new_wiz.equip_to_slot_or_del(new /obj/item/storage/backpack/satchel(new_wiz), SLOT_HUD_BACK)
+ if(new_wiz.dna.species.speciesbox)
+ new_wiz.equip_to_slot_or_del(new new_wiz.dna.species.speciesbox(new_wiz), SLOT_HUD_IN_BACKPACK)
+ else
+ new_wiz.equip_to_slot_or_del(new /obj/item/storage/box/survival(new_wiz), SLOT_HUD_IN_BACKPACK)
+ new_wiz.equip_to_slot_or_del(new /obj/item/teleportation_scroll(new_wiz), SLOT_HUD_RIGHT_STORE)
+ var/obj/item/spellbook/spellbook = new /obj/item/spellbook(new_wiz)
+ spellbook.owner = new_wiz
+ new_wiz.equip_to_slot_or_del(spellbook, SLOT_HUD_LEFT_HAND)
+
+ var/list/reading = list()
+ reading += "You will find a list of available spells in your spell book. Choose your magic arsenal carefully."
+ reading += "The spellbook is bound to you, and others cannot use it."
+ reading += "In your pockets you will find a teleport scroll. Use it as needed."
+ new_wiz.mind.store_memory("Remember: do not forget to prepare your spells.")
+ new_wiz.update_icons()
+ new_wiz.gene_stability += DEFAULT_GENE_STABILITY //magic
+ return reading
+
+/datum/antagonist/wizard/proc/full_on_wizard()
+ return TRUE
diff --git a/code/modules/clothing/shoes/magboots.dm b/code/modules/clothing/shoes/magboots.dm
index 25f49a27a8b..fb1bce27ee5 100644
--- a/code/modules/clothing/shoes/magboots.dm
+++ b/code/modules/clothing/shoes/magboots.dm
@@ -155,15 +155,16 @@
magical = TRUE
/obj/item/clothing/shoes/magboots/wizard/attack_self(mob/user)
- if(user)
- if(user.mind in SSticker.mode.wizards)
- if(magpulse) //faint blue light when shoes are turned on gives a reason to turn them off when not needed in maint
- set_light(0)
- else
- set_light(2, 1, LIGHT_COLOR_LIGHTBLUE)
- ..()
- else
- to_chat(user, "You poke the gem on [src]. Nothing happens.")
+ if(!user)
+ return
+ if(!iswizard(user))
+ to_chat(user, "You poke the gem on [src]. Nothing happens.")
+ return
+ if(magpulse) //faint blue light when shoes are turned on gives a reason to turn them off when not needed in maint
+ set_light(0)
+ else
+ set_light(2, 1, LIGHT_COLOR_LIGHTBLUE)
+ ..()
/obj/item/clothing/shoes/magboots/gravity
diff --git a/code/modules/mob/dead/observer/orbit.dm b/code/modules/mob/dead/observer/orbit.dm
index 715f18cccc5..bd621a2f4cf 100644
--- a/code/modules/mob/dead/observer/orbit.dm
+++ b/code/modules/mob/dead/observer/orbit.dm
@@ -111,8 +111,6 @@
if(SSticker && SSticker.mode)
other_antags += list(
"Blob" = (mind.special_role == SPECIAL_ROLE_BLOB),
- "Wizard" = (mind in SSticker.mode.wizards),
- "Wizard's Apprentice" = (mind in SSticker.mode.apprentices),
"Nuclear Operative" = (mind in SSticker.mode.syndicates),
"Abductor" = (mind in SSticker.mode.abductors)
)
diff --git a/code/modules/mob/living/carbon/human/species/grey.dm b/code/modules/mob/living/carbon/human/species/grey.dm
index 9902aaf0c1b..21de51a0324 100644
--- a/code/modules/mob/living/carbon/human/species/grey.dm
+++ b/code/modules/mob/living/carbon/human/species/grey.dm
@@ -66,17 +66,18 @@
/datum/species/grey/after_equip_job(datum/job/J, mob/living/carbon/human/H)
var/translator_pref = H.client.prefs.active_character.speciesprefs
- if(translator_pref || ((ismindshielded(H) || J.job_department_flags & DEP_FLAG_COMMAND) && HAS_TRAIT(H, TRAIT_WINGDINGS)))
- if(J.title == "Mime")
- return
- if(J.title == "Clown")
- var/obj/item/organ/internal/cyberimp/brain/speech_translator/clown/implant = new
- implant.insert(H)
- else
- var/obj/item/organ/internal/cyberimp/brain/speech_translator/implant = new
- implant.insert(H)
- if(!translator_pref)
- to_chat(H, "A speech translator implant has been installed due to your role on the station.")
+ if(translator_pref || ((ismindshielded(H) || J?.job_department_flags & DEP_FLAG_COMMAND) && HAS_TRAIT(H, TRAIT_WINGDINGS)))
+ if(istype(J))
+ if(J.title == "Mime")
+ return
+ if(J.title == "Clown")
+ var/obj/item/organ/internal/cyberimp/brain/speech_translator/clown/implant = new
+ implant.insert(H)
+ return
+ var/obj/item/organ/internal/cyberimp/brain/speech_translator/implant = new
+ implant.insert(H)
+ if(!translator_pref && istype(J))
+ to_chat(H, "A speech translator implant has been installed due to your role on the station.")
/datum/species/grey/handle_reagents(mob/living/carbon/human/H, datum/reagent/R)
if(R.id == "sacid" || R.id == "facid")
diff --git a/code/modules/mob/living/silicon/silicon_login.dm b/code/modules/mob/living/silicon/silicon_login.dm
index 6592a4d6a33..3786144abc6 100644
--- a/code/modules/mob/living/silicon/silicon_login.dm
+++ b/code/modules/mob/living/silicon/silicon_login.dm
@@ -3,7 +3,7 @@
if(mind && SSticker && SSticker.mode)
SSticker.mode.remove_revolutionary(mind, 1)
mind.remove_antag_datum(/datum/antagonist/cultist)
- SSticker.mode.remove_wizard(mind)
+ mind.remove_antag_datum(/datum/antagonist/wizard)
mind.remove_antag_datum(/datum/antagonist/changeling)
mind.remove_antag_datum(/datum/antagonist/vampire)
SSticker.mode.remove_abductor(mind)
diff --git a/code/modules/mob/living/simple_animal/constructs.dm b/code/modules/mob/living/simple_animal/constructs.dm
index 0889c60fb81..b02d0a309f7 100644
--- a/code/modules/mob/living/simple_animal/constructs.dm
+++ b/code/modules/mob/living/simple_animal/constructs.dm
@@ -48,11 +48,13 @@
/mob/living/simple_animal/hostile/construct/Destroy()
mind?.remove_antag_datum(/datum/antagonist/cultist, silent_removal = TRUE)
+ mind?.remove_antag_datum(/datum/antagonist/wizard/construct, silent_removal = TRUE)
remove_held_body()
return ..()
/mob/living/simple_animal/hostile/construct/death(gibbed)
mind?.remove_antag_datum(/datum/antagonist/cultist, silent_removal = TRUE)
+ mind?.remove_antag_datum(/datum/antagonist/wizard/construct, silent_removal = TRUE)
if(held_body) // Null check for empty bodies
held_body.forceMove(get_turf(src))
SSticker.mode?.cult_team?.add_cult_immunity(held_body)
diff --git a/code/modules/mob/living/simple_animal/shade.dm b/code/modules/mob/living/simple_animal/shade.dm
index 17e52b478a8..ca63f9a1217 100644
--- a/code/modules/mob/living/simple_animal/shade.dm
+++ b/code/modules/mob/living/simple_animal/shade.dm
@@ -36,6 +36,7 @@
/mob/living/simple_animal/shade/Destroy()
mind?.remove_antag_datum(/datum/antagonist/cultist, silent_removal = TRUE)
+ mind?.remove_antag_datum(/datum/antagonist/wizard/construct, silent_removal = TRUE)
return ..()
/mob/living/simple_animal/shade/attackby(obj/item/O, mob/user) //Marker -Agouri
diff --git a/code/modules/mob/mob.dm b/code/modules/mob/mob.dm
index 20014d64459..b2b39500d14 100644
--- a/code/modules/mob/mob.dm
+++ b/code/modules/mob/mob.dm
@@ -7,8 +7,8 @@
s_active.close(src)
QDEL_NULL(hud_used)
if(mind && mind.current == src)
- spellremove(src)
- mobspellremove(src)
+ spellremove()
+ mobspellremove()
QDEL_LIST_CONTENTS(viruses)
QDEL_LIST_CONTENTS(actions)
for(var/alert in alerts)
diff --git a/paradise.dme b/paradise.dme
index 0fe422233ef..9109a7e1c8d 100644
--- a/paradise.dme
+++ b/paradise.dme
@@ -1468,6 +1468,9 @@
#include "code\modules\antagonists\vampire\vampire_powers\hemomancer_powers.dm"
#include "code\modules\antagonists\vampire\vampire_powers\umbrae_powers.dm"
#include "code\modules\antagonists\vampire\vampire_powers\vampire_powers.dm"
+#include "code\modules\antagonists\wizard\datum_apprentice.dm"
+#include "code\modules\antagonists\wizard\datum_wiz_construct.dm"
+#include "code\modules\antagonists\wizard\datum_wizard.dm"
#include "code\modules\arcade\arcade_base.dm"
#include "code\modules\arcade\arcade_prize.dm"
#include "code\modules\arcade\claw_game.dm"