diff --git a/code/__DEFINES/vv.dm b/code/__DEFINES/vv.dm
index d3fde025cb8..5423bf92410 100644
--- a/code/__DEFINES/vv.dm
+++ b/code/__DEFINES/vv.dm
@@ -133,3 +133,21 @@
// paintings
#define VV_HK_REMOVE_PAINTING "remove_painting"
+
+// /obj/effect/proc_holder/spell
+/// Require casting_clothes to cast spell.
+#define VV_HK_SPELL_SET_ROBELESS "spell_set_robeless"
+/// Require cult armor to cast spell.
+#define VV_HK_SPELL_SET_CULT "spell_set_cult"
+/// Require the mob to be ishuman() to cast spell.
+#define VV_HK_SPELL_SET_HUMANONLY "spell_set_humanonly"
+/// Require mob to not be a brain or pAI to cast spell.
+#define VV_HK_SPELL_SET_NONABSTRACT "spell_set_nonabstract"
+/// Spell can now be cast without casting_clothes.
+#define VV_HK_SPELL_UNSET_ROBELESS "spell_unset_robeless"
+/// Spell can now be cast without cult armour.
+#define VV_HK_SPELL_UNSET_CULT "spell_unset_cult"
+/// Any /mob can cast this spell.
+#define VV_HK_SPELL_UNSET_HUMANONLY "spell_unset_humanonly"
+/// Abstract mobs such as brains or pAIs can cast this spell.
+#define VV_HK_SPELL_UNSET_NONABSTRACT "spell_unset_nonabstract"
diff --git a/code/modules/admin/admin_verbs.dm b/code/modules/admin/admin_verbs.dm
index 9c63b48dd20..30abdbc24d7 100644
--- a/code/modules/admin/admin_verbs.dm
+++ b/code/modules/admin/admin_verbs.dm
@@ -620,42 +620,58 @@ GLOBAL_PROTECT(admin_verbs_hideable)
set category = "Debug"
printAllCards()
-/client/proc/give_spell(mob/T in GLOB.mob_list)
+/client/proc/give_spell(mob/spell_recipient in GLOB.mob_list)
set category = "Admin.Fun"
set name = "Give Spell"
set desc = "Gives a spell to a mob."
var/list/spell_list = list()
var/type_length = length_char("/obj/effect/proc_holder/spell") + 2
- for(var/A in GLOB.spells)
- spell_list[copytext_char("[A]", type_length)] = A
- var/obj/effect/proc_holder/spell/S = input("Choose the spell to give to that guy", "ABRAKADABRA") as null|anything in sortList(spell_list)
- if(!S)
+ for(var/spell in GLOB.spells)
+ spell_list[copytext_char("[spell]", type_length)] = spell
+ var/spell_desc = input("Choose the spell to give to that guy", "ABRAKADABRA") as null|anything in sortList(spell_list)
+ if(!spell_desc)
+ return
+
+ var/robeless = (alert(usr, "Would you like to force this spell to be robeless?", "Robeless Casting?", "Force Robeless", "Use Spell Setting") == "Force Robeless")
+
+ if(QDELETED(spell_recipient))
+ to_chat(usr, "The intended spell recipient no longer exists.")
return
SSblackbox.record_feedback("tally", "admin_verb", 1, "Give Spell") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
- log_admin("[key_name(usr)] gave [key_name(T)] the spell [S].")
- message_admins("[key_name_admin(usr)] gave [key_name_admin(T)] the spell [S].")
+ log_admin("[key_name(usr)] gave [key_name(spell_recipient)] the spell [spell_desc][robeless ? " (Forced robeless)" : ""].")
+ message_admins("[key_name_admin(usr)] gave [key_name_admin(spell_recipient)] the spell [spell_desc][spell_desc][robeless ? " (Forced robeless)" : ""].")
- S = spell_list[S]
- if(T.mind)
- T.mind.AddSpell(new S)
+ var/spell_path = spell_list[spell_desc]
+ var/obj/effect/proc_holder/spell/new_spell = new spell_path()
+
+ if(robeless)
+ new_spell.clothes_req = FALSE
+ new_spell.cult_req = FALSE
+
+ if(spell_recipient.mind)
+ spell_recipient.mind.AddSpell(new_spell)
else
- T.AddSpell(new S)
+ spell_recipient.AddSpell(new_spell)
message_admins("Spells given to mindless mobs will not be transferred in mindswap or cloning!")
-/client/proc/remove_spell(mob/T in GLOB.mob_list)
+/client/proc/remove_spell(mob/removal_target in GLOB.mob_list)
set category = "Admin.Fun"
set name = "Remove Spell"
set desc = "Remove a spell from the selected mob."
- if(T?.mind)
- var/obj/effect/proc_holder/spell/S = input("Choose the spell to remove", "NO ABRAKADABRA") as null|anything in sortList(T.mind.spell_list)
- if(S)
- T.mind.RemoveSpell(S)
- log_admin("[key_name(usr)] removed the spell [S] from [key_name(T)].")
- message_admins("[key_name_admin(usr)] removed the spell [S] from [key_name_admin(T)].")
- SSblackbox.record_feedback("tally", "admin_verb", 1, "Remove Spell") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
+ var/target_spell_list = length(removal_target?.mind?.spell_list) ? removal_target.mind.spell_list : removal_target.mob_spell_list
+
+ if(!length(target_spell_list))
+ return
+
+ var/obj/effect/proc_holder/spell/removed_spell = input("Choose the spell to remove", "NO ABRAKADABRA") as null|anything in sortList(target_spell_list)
+ if(removed_spell)
+ removal_target.mind.RemoveSpell(removed_spell)
+ log_admin("[key_name(usr)] removed the spell [removed_spell] from [key_name(removal_target)].")
+ message_admins("[key_name_admin(usr)] removed the spell [removed_spell] from [key_name_admin(removal_target)].")
+ SSblackbox.record_feedback("tally", "admin_verb", 1, "Remove Spell") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
/client/proc/give_disease(mob/living/T in GLOB.mob_living_list)
set category = "Admin.Fun"
diff --git a/code/modules/spells/spell.dm b/code/modules/spells/spell.dm
index 3b79c9eaf65..1571c03756a 100644
--- a/code/modules/spells/spell.dm
+++ b/code/modules/spells/spell.dm
@@ -569,3 +569,53 @@ GLOBAL_LIST_INIT(spells, typesof(/obj/effect/proc_holder/spell)) //needed for th
user.visible_message("A wreath of gentle light passes over [user]!", "You wreath yourself in healing light!")
user.adjustBruteLoss(-10)
user.adjustFireLoss(-10)
+
+/obj/effect/proc_holder/spell/vv_get_dropdown()
+ . = ..()
+ VV_DROPDOWN_OPTION("", "---------")
+ if(clothes_req)
+ VV_DROPDOWN_OPTION(VV_HK_SPELL_SET_ROBELESS, "Set Robeless")
+ else
+ VV_DROPDOWN_OPTION(VV_HK_SPELL_UNSET_ROBELESS, "Unset Robeless")
+
+ if(cult_req)
+ VV_DROPDOWN_OPTION(VV_HK_SPELL_SET_CULT, "Set Cult Robeless")
+ else
+ VV_DROPDOWN_OPTION(VV_HK_SPELL_UNSET_CULT, "Unset Cult Robeless")
+
+ if(human_req)
+ VV_DROPDOWN_OPTION(VV_HK_SPELL_UNSET_HUMANONLY, "Unset Require Humanoid Mob")
+ else
+ VV_DROPDOWN_OPTION(VV_HK_SPELL_SET_HUMANONLY, "Set Require Humanoid Mob")
+
+ if(nonabstract_req)
+ VV_DROPDOWN_OPTION(VV_HK_SPELL_UNSET_NONABSTRACT, "Unset Require Body")
+ else
+ VV_DROPDOWN_OPTION(VV_HK_SPELL_SET_NONABSTRACT, "Set Require Body")
+
+/obj/effect/proc_holder/spell/vv_do_topic(list/href_list)
+ . = ..()
+ if(href_list[VV_HK_SPELL_SET_ROBELESS])
+ clothes_req = FALSE
+ return
+ if(href_list[VV_HK_SPELL_UNSET_ROBELESS])
+ clothes_req = TRUE
+ return
+ if(href_list[VV_HK_SPELL_SET_CULT])
+ cult_req = FALSE
+ return
+ if(href_list[VV_HK_SPELL_UNSET_CULT])
+ cult_req = TRUE
+ return
+ if(href_list[VV_HK_SPELL_UNSET_HUMANONLY])
+ human_req = FALSE
+ return
+ if(href_list[VV_HK_SPELL_SET_HUMANONLY])
+ human_req = TRUE
+ return
+ if(href_list[VV_HK_SPELL_UNSET_NONABSTRACT])
+ nonabstract_req = FALSE
+ return
+ if(href_list[VV_HK_SPELL_SET_NONABSTRACT])
+ nonabstract_req = TRUE
+ return