diff --git a/code/modules/antagonists/roguetown/villain/peasantrebel.dm b/code/modules/antagonists/roguetown/villain/peasantrebel.dm
index c6d1962bc..3636902ef 100644
--- a/code/modules/antagonists/roguetown/villain/peasantrebel.dm
+++ b/code/modules/antagonists/roguetown/villain/peasantrebel.dm
@@ -111,21 +111,6 @@
return FALSE
return TRUE
-/obj/effect/proc_holder/spell/self/rebelconvert
- name = "RECRUIT REBELS"
- desc = "!"
- antimagic_allowed = TRUE
- charge_max = 150
-
-/obj/effect/proc_holder/spell/self/rebelconvert/cast(list/targets,mob/user = usr)
- ..()
- var/inputty = input("Make a speech!", "ROGUETOWN") as text|null
- if(inputty)
- user.say(inputty, forced = "spell")
- var/datum/antagonist/prebel/PR = user.mind.has_antag_datum(/datum/antagonist/prebel)
- for(var/mob/living/carbon/human/L in get_hearers_in_view(6, get_turf(user)))
- addtimer(CALLBACK(L,TYPE_PROC_REF(/mob/living/carbon/human, rev_ask), user,PR,inputty),1)
-
/mob/living/carbon/human/proc/rev_ask(mob/living/carbon/human/guy,datum/antagonist/prebel/mind_datum,offer)
if(!guy || !mind_datum || !offer)
return
diff --git a/code/modules/antagonists/roguetown/villain/werewolf/werewolf_spells.dm b/code/modules/antagonists/roguetown/villain/werewolf/werewolf_spells.dm
index 9bfba3928..e904fe0de 100644
--- a/code/modules/antagonists/roguetown/villain/werewolf/werewolf_spells.dm
+++ b/code/modules/antagonists/roguetown/villain/werewolf/werewolf_spells.dm
@@ -32,6 +32,7 @@
message_admins("WEREWOLF: [werewolf_player.wolfname] howls: [message]")
+//Old version, ugly and no feedback with the new icons
/obj/effect/proc_holder/spell/self/claws
name = "Lupine Claws"
desc = "!"
@@ -62,4 +63,32 @@
user.put_in_hands(r, TRUE, FALSE, TRUE)
//user.visible_message("Your claws extend.", "You feel your claws extending.", "You hear a sound of claws extending.")
extended = TRUE
-
\ No newline at end of file
+
+//New version (to work nicely with the new icons)
+/obj/effect/proc_holder/spell/invoked/claws
+ name = "Lupine Claws"
+ desc = "!"
+ overlay_state = "claws"
+ antimagic_allowed = TRUE
+ charge_max = 20 //2 seconds
+ var/extended = FALSE
+ var/obj/item/rogueweapon/werewolf_claw/left/l
+ var/obj/item/rogueweapon/werewolf_claw/right/r
+
+/obj/effect/proc_holder/spell/invoked/claws/on_activation(mob/user = usr)
+ l = new(user,1)
+ r = new(user,2)
+ user.put_in_hands(l, TRUE, FALSE, TRUE)
+ user.put_in_hands(r, TRUE, FALSE, TRUE)
+ //user.visible_message("Your claws extend.", "You feel your claws extending.", "You hear a sound of claws extending.")
+ extended = TRUE
+
+/obj/effect/proc_holder/spell/invoked/claws/on_deactivation(mob/user = usr)
+ l = user.get_active_held_item()
+ r = user.get_inactive_held_item()
+ user.dropItemToGround(l, TRUE)
+ user.dropItemToGround(r, TRUE)
+ qdel(l)
+ qdel(r)
+ //user.visible_message("Your claws retract.", "You feel your claws retracting.", "You hear a sound of claws retracting.")
+ extended = FALSE
diff --git a/code/modules/antagonists/roguetown/villain/werewolf/werewolf_transformation.dm b/code/modules/antagonists/roguetown/villain/werewolf/werewolf_transformation.dm
index 96ff16cb8..433c645bd 100644
--- a/code/modules/antagonists/roguetown/villain/werewolf/werewolf_transformation.dm
+++ b/code/modules/antagonists/roguetown/villain/werewolf/werewolf_transformation.dm
@@ -116,7 +116,7 @@
W.mind.adjust_skillrank(/datum/skill/misc/climbing, 6, TRUE)
W.AddSpell(new /obj/effect/proc_holder/spell/self/howl)
- W.AddSpell(new /obj/effect/proc_holder/spell/self/claws)
+ W.AddSpell(new /obj/effect/proc_holder/spell/invoked/claws)
ADD_TRAIT(src, TRAIT_NOSLEEP, TRAIT_GENERIC)
@@ -171,7 +171,7 @@
W.mind.skill_experience = WA.stored_experience.Copy()
W.RemoveSpell(new /obj/effect/proc_holder/spell/self/howl)
- W.RemoveSpell(new /obj/effect/proc_holder/spell/self/claws)
+ W.RemoveSpell(new /obj/effect/proc_holder/spell/invoked/claws)
W.regenerate_icons()
diff --git a/code/modules/jobs/job_types/roguetown/adventurer/types/combat/mage.dm b/code/modules/jobs/job_types/roguetown/adventurer/types/combat/mage.dm
index 68f5a5e90..aa9e0c46f 100644
--- a/code/modules/jobs/job_types/roguetown/adventurer/types/combat/mage.dm
+++ b/code/modules/jobs/job_types/roguetown/adventurer/types/combat/mage.dm
@@ -56,6 +56,20 @@
H.change_stat("intelligence", 3)
H.change_stat("constitution", 1)
H.change_stat("endurance", -1)
- H.mind.AddSpell(new /obj/effect/proc_holder/spell/invoked/projectile/fireball)
- H.mind.AddSpell(new /obj/effect/proc_holder/spell/invoked/projectile/lightningbolt)
- H.mind.AddSpell(new /obj/effect/proc_holder/spell/invoked/projectile/fetch)
+ var/list/possible_spells = list(
+ "/obj/effect/proc_holder/spell/arcane/telepathy",
+ "/obj/effect/proc_holder/spell/arcane/ignite",
+ "/obj/effect/proc_holder/spell/arcane/blink",
+ "/obj/effect/proc_holder/spell/arcane/swap",
+ "/obj/effect/proc_holder/spell/arcane/smokescreen",
+ "/obj/effect/proc_holder/spell/arcane/blindness",
+ "/obj/effect/proc_holder/spell/arcane/invisibility",
+ "/obj/effect/proc_holder/spell/arcane/projectile/fetch"
+ )
+ H.mind.AddSpell(pick(new /obj/effect/proc_holder/spell/arcane/projectile/fireball,new /obj/effect/proc_holder/spell/arcane/projectile/lightningbolt))
+ for(var/i=2,i>0,i--)
+ var/random_item = pick(possible_spells)
+ var typepath = text2path(random_item)
+ H.mind.AddSpell(new typepath)
+ possible_spells.Remove(random_item)
+ possible_spells = null
diff --git a/code/modules/jobs/job_types/roguetown/adventurer/types/combat/sorceress.dm b/code/modules/jobs/job_types/roguetown/adventurer/types/combat/sorceress.dm
index c389c526d..ed967e742 100644
--- a/code/modules/jobs/job_types/roguetown/adventurer/types/combat/sorceress.dm
+++ b/code/modules/jobs/job_types/roguetown/adventurer/types/combat/sorceress.dm
@@ -27,7 +27,7 @@
backl = /obj/item/storage/backpack/rogue/satchel
beltr = /obj/item/reagent_containers/glass/bottle/rogue/manapot
beltl = /obj/item/rogueweapon/huntingknife
- neck = /obj/item/storage/belt/rogue/pouch/coins/poor
+ neck = /obj/item/storage/belt/rogue/pouch/coins/poor
r_hand = /obj/item/rogueweapon/woodstaff
if(H.mind)
H.mind.adjust_skillrank(/datum/skill/combat/polearms, 1, TRUE)
@@ -47,6 +47,20 @@
H.change_stat("strength", -1)
H.change_stat("intelligence", 4)
H.change_stat("speed", 1)
- H.mind.AddSpell(new /obj/effect/proc_holder/spell/invoked/projectile/fireball)
- H.mind.AddSpell(new /obj/effect/proc_holder/spell/invoked/projectile/lightningbolt)
- H.mind.AddSpell(new /obj/effect/proc_holder/spell/invoked/projectile/fetch)
+ var/list/possible_spells = list(
+ "/obj/effect/proc_holder/spell/arcane/telepathy",
+ "/obj/effect/proc_holder/spell/arcane/ignite",
+ "/obj/effect/proc_holder/spell/arcane/blink",
+ "/obj/effect/proc_holder/spell/arcane/swap",
+ "/obj/effect/proc_holder/spell/arcane/smokescreen",
+ "/obj/effect/proc_holder/spell/arcane/blindness",
+ "/obj/effect/proc_holder/spell/arcane/invisibility",
+ "/obj/effect/proc_holder/spell/arcane/projectile/fetch"
+ )
+ H.mind.AddSpell(pick(new /obj/effect/proc_holder/spell/arcane/projectile/fireball,new /obj/effect/proc_holder/spell/arcane/projectile/lightningbolt))
+ for(var/i=2,i>0,i--)
+ var/random_item = pick(possible_spells)
+ var typepath = text2path(random_item)
+ H.mind.AddSpell(new typepath)
+ possible_spells.Remove(random_item)
+ possible_spells = null
diff --git a/code/modules/jobs/job_types/roguetown/church/priest.dm b/code/modules/jobs/job_types/roguetown/church/priest.dm
index 71f321eb7..d2d1d1c85 100644
--- a/code/modules/jobs/job_types/roguetown/church/priest.dm
+++ b/code/modules/jobs/job_types/roguetown/church/priest.dm
@@ -154,19 +154,3 @@
to_chat(src, span_warning("I need to do this from the chapel."))
return FALSE
priority_announce("[inputty]", title = "The Priest Speaks", sound = 'sound/misc/bell.ogg')
-
-/obj/effect/proc_holder/spell/self/convertrole/templar
- name = "Recruit Templar"
- new_role = "Templar"
- recruitment_faction = "Templars"
- recruitment_message = "Serve the nine, %RECRUIT!"
- accept_message = "FOR THE NINE!"
- refuse_message = "I refuse."
-
-/obj/effect/proc_holder/spell/self/convertrole/monk
- name = "Recruit Acolyte"
- new_role = "Acolyte"
- recruitment_faction = "Church"
- recruitment_message = "Serve the nine, %RECRUIT!"
- accept_message = "FOR THE NINE!"
- refuse_message = "I refuse."
diff --git a/code/modules/jobs/job_types/roguetown/courtier/magician.dm b/code/modules/jobs/job_types/roguetown/courtier/magician.dm
index 514193072..dd5aa0d50 100644
--- a/code/modules/jobs/job_types/roguetown/courtier/magician.dm
+++ b/code/modules/jobs/job_types/roguetown/courtier/magician.dm
@@ -13,7 +13,6 @@
"Half-Elf",
"Aasimar",
)
- spells = list(/obj/effect/proc_holder/spell/invoked/projectile/fireball/greater, /obj/effect/proc_holder/spell/invoked/projectile/fireball, /obj/effect/proc_holder/spell/invoked/projectile/lightningbolt, /obj/effect/proc_holder/spell/invoked/projectile/fetch)
display_order = JDO_MAGICIAN
tutorial = "Your creed is one dedicated to the conquering of the arcane arts and the constant thrill of knowledge. \
You owe your life to the Lord, for it was his coin that allowed you to continue your studies in these dark times. \
@@ -70,3 +69,24 @@
head = /obj/item/clothing/head/roguetown/wizhat
armor = /obj/item/clothing/suit/roguetown/shirt/robe/wizard
H.dna.species.soundpack_m = new /datum/voicepack/male/wizard()
+
+ var/list/possible_spells = list(
+ "/obj/effect/proc_holder/spell/arcane/telepathy",
+ "/obj/effect/proc_holder/spell/arcane/ignite",
+ "/obj/effect/proc_holder/spell/arcane/blink",
+ "/obj/effect/proc_holder/spell/arcane/swap",
+ "/obj/effect/proc_holder/spell/arcane/smokescreen",
+ "/obj/effect/proc_holder/spell/arcane/projectile/lightningbolt",
+ "/obj/effect/proc_holder/spell/arcane/projectile/fireball",
+ "/obj/effect/proc_holder/spell/arcane/blindness",
+ "/obj/effect/proc_holder/spell/arcane/invisibility",
+ "/obj/effect/proc_holder/spell/arcane/projectile/fetch"
+ )
+ H.mind.AddSpell(new /obj/effect/proc_holder/spell/arcane/projectile/fireball/greater)
+ for(var/i=3,i>0,i--)
+ var/random_item = pick(possible_spells)
+ var typepath = text2path(random_item)
+ H.mind.AddSpell(new typepath)
+ possible_spells.Remove(random_item)
+ possible_spells = null
+
diff --git a/code/modules/jobs/job_types/roguetown/garrison/bogmaster.dm b/code/modules/jobs/job_types/roguetown/garrison/bogmaster.dm
index 59c344183..1a42c946e 100644
--- a/code/modules/jobs/job_types/roguetown/garrison/bogmaster.dm
+++ b/code/modules/jobs/job_types/roguetown/garrison/bogmaster.dm
@@ -86,18 +86,3 @@
ADD_TRAIT(H, TRAIT_HEAVYARMOR, TRAIT_GENERIC)
ADD_TRAIT(H, TRAIT_MEDIUMARMOR, TRAIT_GENERIC)
ADD_TRAIT(H, TRAIT_STEELHEARTED, TRAIT_GENERIC)
-
-/obj/effect/proc_holder/spell/self/convertrole/bog
- name = "Recruit Bogmen"
- new_role = "Bog Guard"
- recruitment_faction = "Bog Guard"
- recruitment_message = "Serve the bog, %RECRUIT!"
- accept_message = "FOR THE BOG!"
- refuse_message = "I refuse."
-
-/obj/effect/proc_holder/spell/self/convertrole/bog/convert(mob/living/carbon/human/recruit, mob/living/carbon/human/recruiter)
- . = ..()
- if(!.)
- return
- recruit.verbs |= /mob/proc/haltyell
-
diff --git a/code/modules/jobs/job_types/roguetown/nobility/lady.dm b/code/modules/jobs/job_types/roguetown/nobility/lady.dm
index ee34bb202..ff3b07b63 100644
--- a/code/modules/jobs/job_types/roguetown/nobility/lady.dm
+++ b/code/modules/jobs/job_types/roguetown/nobility/lady.dm
@@ -71,12 +71,3 @@
H.change_stat("speed", 2)
H.change_stat("perception", 2)
H.change_stat("fortune", 5)
-
-/obj/effect/proc_holder/spell/self/convertrole/servant
- name = "Recruit Servant"
- new_role = "Servant"
- recruitment_faction = "Servants"
- recruitment_message = "Serve the crown, %RECRUIT!"
- accept_message = "FOR THE CROWN!"
- refuse_message = "I refuse."
- charge_max = 100
diff --git a/code/modules/jobs/job_types/roguetown/nobility/lord.dm b/code/modules/jobs/job_types/roguetown/nobility/lord.dm
index 7f1c70288..fda6ad66f 100644
--- a/code/modules/jobs/job_types/roguetown/nobility/lord.dm
+++ b/code/modules/jobs/job_types/roguetown/nobility/lord.dm
@@ -65,12 +65,12 @@ GLOBAL_LIST_EMPTY(lord_titles)
belt = /obj/item/storage/belt/rogue/leather/plaquegold
l_hand = /obj/item/rogueweapon/lordscepter
backpack_contents = list(/obj/item/rogueweapon/huntingknife/idagger/steel/special = 1)
- id = /obj/item/clothing/ring/active/nomag
+ id = /obj/item/clothing/ring/active/nomag
if(H.gender == MALE)
pants = /obj/item/clothing/under/roguetown/tights/black
shirt = /obj/item/clothing/suit/roguetown/shirt/undershirt/black
armor = /obj/item/clothing/suit/roguetown/armor/leather/vest/black
- shoes = /obj/item/clothing/shoes/roguetown/boots
+ shoes = /obj/item/clothing/shoes/roguetown/boots
if(H.mind)
H.mind.adjust_skillrank(/datum/skill/combat/polearms, 2, TRUE)
H.mind.adjust_skillrank(/datum/skill/combat/maces, 2, TRUE)
@@ -140,61 +140,3 @@ GLOBAL_LIST_EMPTY(lord_titles)
else
family_guy.fully_replace_character_name(family_guy.real_name, family_guy.real_name + " " + GLOB.lordsurname)
return family_guy.real_name
-
-/obj/effect/proc_holder/spell/self/grant_title
- name = "Grant Title"
- desc = "Grant someone a title of honor... Or shame."
- antimagic_allowed = TRUE
- charge_max = 100
- /// Maximum range for title granting
- var/title_range = 3
- /// Maximum length for the title
- var/title_length = 42
-
-/obj/effect/proc_holder/spell/self/grant_title/cast(list/targets, mob/user = usr)
- . = ..()
- var/granted_title = input(user, "What title do you wish to grant?", "[name]") as null|text
- granted_title = reject_bad_text(granted_title, title_length)
- if(!granted_title)
- return
- var/list/recruitment = list()
- for(var/mob/living/carbon/human/village_idiot in (get_hearers_in_view(title_range, user) - user))
- //not allowed
- if(!can_title(village_idiot))
- continue
- recruitment[village_idiot.name] = village_idiot
- if(!length(recruitment))
- to_chat(user, span_warning("There are no potential honoraries in range."))
- return
- var/inputty = input(user, "Select an honorary!", "[name]") as anything in recruitment
- if(inputty)
- var/mob/living/carbon/human/recruit = recruitment[inputty]
- if(!QDELETED(recruit) && (recruit in get_hearers_in_view(title_range, user)))
- INVOKE_ASYNC(src, PROC_REF(village_idiotify), recruit, user, granted_title)
- else
- to_chat(user, span_warning("Honorific failed!"))
- else
- to_chat(user, span_warning("Honorific cancelled."))
-
-/obj/effect/proc_holder/spell/self/grant_title/proc/can_title(mob/living/carbon/human/recruit)
- //wtf
- if(QDELETED(recruit))
- return FALSE
- //need a mind
- if(!recruit.mind)
- return FALSE
- //need to see their damn face
- if(!recruit.get_face_name(null))
- return FALSE
- return TRUE
-
-/obj/effect/proc_holder/spell/self/grant_title/proc/village_idiotify(mob/living/carbon/human/recruit, mob/living/carbon/human/recruiter, granted_title)
- if(QDELETED(recruit) || QDELETED(recruiter) || !granted_title)
- return FALSE
- if(GLOB.lord_titles[recruit.real_name])
- recruiter.say("I HEREBY STRIP YOU, [uppertext(recruit.name)], OF THE TITLE OF [uppertext(GLOB.lord_titles[recruit.real_name])]!")
- GLOB.lord_titles -= recruit.real_name
- return FALSE
- recruiter.say("I HEREBY GRANT YOU, [uppertext(recruit.name)], THE TITLE OF [uppertext(granted_title)]!")
- GLOB.lord_titles[recruit.real_name] = granted_title
- return TRUE
diff --git a/code/modules/jobs/job_types/roguetown/nobility/sheriff.dm b/code/modules/jobs/job_types/roguetown/nobility/sheriff.dm
index ab2d70635..0ecad3d07 100644
--- a/code/modules/jobs/job_types/roguetown/nobility/sheriff.dm
+++ b/code/modules/jobs/job_types/roguetown/nobility/sheriff.dm
@@ -91,91 +91,3 @@
ADD_TRAIT(H, TRAIT_MEDIUMARMOR, TRAIT_GENERIC)
ADD_TRAIT(H, TRAIT_STEELHEARTED, TRAIT_GENERIC)
H.verbs |= /mob/proc/haltyell
-
-/obj/effect/proc_holder/spell/self/convertrole
- name = "Recruit Beggar"
- desc = "Recruit someone to your cause."
- antimagic_allowed = TRUE
- charge_max = 100
- /// Role given if recruitment is accepted
- var/new_role = "Beggar"
- /// Faction shown to the user in the recruitment prompt
- var/recruitment_faction = "Beggars"
- /// Message the recruiter gives
- var/recruitment_message = "Serve the beggars, %RECRUIT!"
- /// Range to search for potential recruits
- var/recruitment_range = 3
- /// Say message when the recruit accepts
- var/accept_message = "I will serve!"
- /// Say message when the recruit refuses
- var/refuse_message = "I refuse."
-
-/obj/effect/proc_holder/spell/self/convertrole/cast(list/targets,mob/user = usr)
- . = ..()
- var/list/recruitment = list()
- for(var/mob/living/carbon/human/recruit in (get_hearers_in_view(recruitment_range, user) - user))
- //not allowed
- if(!can_convert(recruit))
- continue
- recruitment[recruit.name] = recruit
- if(!length(recruitment))
- to_chat(user, span_warning("There are no potential recruits in range."))
- return
- var/inputty = input(user, "Select a potential recruit!", "[name]") as anything in recruitment
- if(inputty)
- var/mob/living/carbon/human/recruit = recruitment[inputty]
- if(!QDELETED(recruit) && (recruit in get_hearers_in_view(recruitment_range, user)))
- INVOKE_ASYNC(src, PROC_REF(convert), recruit, user)
- else
- to_chat(user, span_warning("Recruitment failed!"))
- else
- to_chat(user, span_warning("Recruitment cancelled."))
-
-/obj/effect/proc_holder/spell/self/convertrole/proc/can_convert(mob/living/carbon/human/recruit)
- //wtf
- if(QDELETED(recruit))
- return FALSE
- //need a mind
- if(!recruit.mind)
- return FALSE
- //only migrants and peasants
- if(!(recruit.job in GLOB.peasant_positions) && \
- !(recruit.job in GLOB.yeoman_positions) && \
- !(recruit.job in GLOB.allmig_positions) && \
- !(recruit.job in GLOB.mercenary_positions))
- return FALSE
- //need to see their damn face
- if(!recruit.get_face_name(null))
- return FALSE
- return TRUE
-
-/obj/effect/proc_holder/spell/self/convertrole/proc/convert(mob/living/carbon/human/recruit, mob/living/carbon/human/recruiter)
- if(QDELETED(recruit) || QDELETED(recruiter))
- return FALSE
- recruiter.say(replacetext(recruitment_message, "%RECRUIT", "[recruit]"), forced = "[name]")
- var/prompt = alert(recruit, "Do you wish to become a [new_role]?", "[recruitment_faction] Recruitment", "Yes", "No")
- if(QDELETED(recruit) || QDELETED(recruiter) || !(recruiter in get_hearers_in_view(recruitment_range, recruit)))
- return FALSE
- if(prompt != "Yes")
- if(refuse_message)
- recruit.say(refuse_message, forced = "[name]")
- return FALSE
- if(accept_message)
- recruit.say(accept_message, forced = "[name]")
- if(new_role)
- recruit.job = new_role
- return TRUE
-
-/obj/effect/proc_holder/spell/self/convertrole/guard
- name = "Recruit Guardsmen"
- new_role = "Watchman"
- recruitment_faction = "Watchman"
- recruitment_message = "Serve the town guard, %RECRUIT!"
- accept_message = "FOR THE KING!"
- refuse_message = "I refuse."
-
-/obj/effect/proc_holder/spell/self/convertrole/guard/convert(mob/living/carbon/human/recruit, mob/living/carbon/human/recruiter)
- . = ..()
- if(!.)
- return
- recruit.verbs |= /mob/proc/haltyell
diff --git a/code/modules/jobs/job_types/roguetown/yeomen/archivist.dm b/code/modules/jobs/job_types/roguetown/yeomen/archivist.dm
index a21f10a64..547a0a70c 100644
--- a/code/modules/jobs/job_types/roguetown/yeomen/archivist.dm
+++ b/code/modules/jobs/job_types/roguetown/yeomen/archivist.dm
@@ -6,7 +6,7 @@
faction = "Station"
total_positions = 1
spawn_positions = 1
- spells = list(/obj/effect/proc_holder/spell/invoked/projectile/fetch)
+ spells = list(/obj/effect/proc_holder/spell/arcane/projectile/fetch)
allowed_races = list(
"Humen",
"Elf",
@@ -46,9 +46,8 @@
H.mind.adjust_skillrank(/datum/skill/misc/alchemy, 6, TRUE)
H.mind.adjust_skillrank(/datum/skill/misc/medicine, 3, TRUE)
H.mind.adjust_skillrank(/datum/skill/misc/riding, 2, TRUE)
+ H.mind.adjust_skillrank(/datum/skill/magic/arcane, 1, TRUE)
H.change_stat("strength", -2)
H.change_stat("intelligence", 8)
H.change_stat("constitution", -2)
H.change_stat("speed", -2)
-
-
diff --git a/code/modules/spells/roguetown/_roguetown.dm b/code/modules/spells/roguetown/_roguetown.dm
index 1e8983ed6..23f6af13f 100644
--- a/code/modules/spells/roguetown/_roguetown.dm
+++ b/code/modules/spells/roguetown/_roguetown.dm
@@ -11,12 +11,29 @@
invocation_type = "shout"
var/active_sound
+//Old update icon
+///obj/effect/proc_holder/spell/update_icon()
+// if(!action)
+// return
+// action.button_icon_state = "[base_icon_state][active]"
+// if(overlay_state)
+// action.overlay_state = overlay_state
+// action.name = name
+// action.UpdateButtonIcon()
+
+//That is a ugly way of checking it the spell is a mmb cast or not and I know it...
+//But it's what worked better so far for some reason.
/obj/effect/proc_holder/spell/update_icon()
if(!action)
return
- action.button_icon_state = "[base_icon_state][active]"
- if(overlay_state)
- action.overlay_state = overlay_state
+ action.button_icon_state = base_icon_state
+ if (selection_type == "view")
+ if(overlay_state)
+ action.overlay_state = "[overlay_state]1"
+ else
+ action.button_icon_state = "[base_icon_state][active]"
+ if(overlay_state)
+ action.overlay_state = "[overlay_state][active]"
action.name = name
action.UpdateButtonIcon()
diff --git a/code/modules/spells/roguetown/arcane.dm b/code/modules/spells/roguetown/arcane.dm
new file mode 100644
index 000000000..3d569679c
--- /dev/null
+++ b/code/modules/spells/roguetown/arcane.dm
@@ -0,0 +1,193 @@
+//This is basically a pseudo spell/Invoked clone
+//Might as well do this if we end having both arcane and divine versions some spells
+//That will also help organizing future lists and shit (specially if we are adding spell books later)
+
+/obj/effect/proc_holder/spell/arcane
+ name = "arcane spell"
+ range = -1
+ selection_type = "range"
+ no_early_release = TRUE
+ charge_max = 30
+ charge_type = "recharge"
+ invocation_type = "shout"
+ var/active_sound
+ clothes_req = FALSE
+ warnie = "spellwarning"
+ no_early_release = TRUE
+ chargedloop = /datum/looping_sound/invokegen
+ associated_skill = /datum/skill/magic/arcane
+ charging_slowdown = 1
+
+/obj/effect/proc_holder/spell/arcane/Click()
+ var/mob/living/user = usr
+ if(!istype(user))
+ return
+ if(!can_cast(user))
+ start_recharge()
+ deactivate(user)
+ return
+ if(active)
+ deactivate(user)
+ else
+ if(active_sound)
+ user.playsound_local(user,active_sound,100,vary = FALSE)
+ active = TRUE
+ add_ranged_ability(user, null, TRUE)
+ on_activation(user)
+ update_icon()
+ start_recharge()
+
+/obj/effect/proc_holder/spell/arcane/deactivate(mob/living/user)
+ ..()
+ active = FALSE
+ remove_ranged_ability(null)
+ on_deactivation(user)
+
+/obj/effect/proc_holder/spell/arcane/proc/on_activation(mob/user)
+ return
+
+/obj/effect/proc_holder/spell/arcane/proc/on_deactivation(mob/user)
+ return
+
+/obj/effect/proc_holder/spell/arcane/InterceptClickOn(mob/living/caller, params, atom/target)
+ . = ..()
+ if(.)
+ return FALSE
+ if(!can_cast(caller) || !cast_check(FALSE, ranged_ability_user))
+ return FALSE
+ if(perform(list(target), TRUE, user = ranged_ability_user))
+ caller.mind.adjust_experience(associated_skill, (caller.STAINT*0.3))//Arcane Skill exp gain - Delete/Edit if on your leisure
+ return TRUE
+
+/obj/effect/proc_holder/spell/arcane/projectile
+ var/projectile_type = /obj/projectile/magic/teleport
+ var/list/projectile_var_overrides = list()
+ var/projectile_amount = 1 //Projectiles per cast.
+ var/current_amount = 0 //How many projectiles left.
+ var/projectiles_per_fire = 1 //Projectiles per fire. Probably not a good thing to use unless you override ready_projectile().
+
+/obj/effect/proc_holder/spell/arcane/projectile/proc/ready_projectile(obj/projectile/P, atom/target, mob/user, iteration)
+ return
+
+/obj/effect/proc_holder/spell/arcane/projectile/cast(list/targets, mob/living/user)
+ . = ..()
+ var/target = targets[1]
+ var/turf/T = user.loc
+ var/turf/U = get_step(user, user.dir) // Get the tile infront of the move, based on their direction
+ if(!isturf(U) || !isturf(T))
+ return FALSE
+ fire_projectile(user, target)
+ user.newtonian_move(get_dir(U, T))
+ update_icon()
+ start_recharge()
+ return TRUE
+
+/obj/effect/proc_holder/spell/arcane/projectile/proc/fire_projectile(mob/living/user, atom/target)
+ current_amount--
+ for(var/i in 1 to projectiles_per_fire)
+ var/obj/projectile/P = new projectile_type(user.loc)
+ if(istype(P, /obj/projectile/magic/bloodsteal))
+ var/obj/projectile/magic/bloodsteal/B = P
+ B.sender = user
+ P.firer = user
+ P.preparePixelProjectile(target, user)
+ for(var/V in projectile_var_overrides)
+ if(P.vars[V])
+ P.vv_edit_var(V, projectile_var_overrides[V])
+ ready_projectile(P, target, user, i)
+ P.fire()
+ return TRUE
+
+/obj/effect/proc_holder/spell/arcane/targeted //can mean aoe for mobs (limited/unlimited number) or one target mob
+ var/max_targets = 1 //leave 0 for unlimited targets in range, 1 for one selectable target in range, more for limited number of casts (can all target one guy, depends on target_ignore_prev) in range
+ var/target_ignore_prev = 1 //only important if max_targets > 1, affects if the spell can be cast multiple times at one person from one cast
+ var/include_user = 0 //if it includes usr in the target list
+ var/random_target = 0 // chooses random viable target instead of asking the caster
+ var/random_target_priority = TARGET_CLOSEST // if random_target is enabled how it will pick the target
+
+
+/obj/effect/proc_holder/spell/arcane/aoe_turf //affects all turfs in view or range (depends)
+ var/inner_radius = -1 //for all your ring spell needs
+
+/obj/effect/proc_holder/spell/arcane/targeted/choose_targets(mob/user = usr)
+ var/list/targets = list()
+
+ switch(max_targets)
+ if(0) //unlimited
+ for(var/mob/living/target in view_or_range(range, user, selection_type))
+ if(!can_target(target))
+ continue
+ targets += target
+ if(1) //single target can be picked
+ if(range < 0)
+ targets += user
+ else
+ var/possible_targets = list()
+
+ for(var/mob/living/M in view_or_range(range, user, selection_type))
+ if(!include_user && user == M)
+ continue
+ if(!can_target(M))
+ continue
+ possible_targets += M
+
+ //targets += input("Choose the target for the spell.", "Targeting") as mob in possible_targets
+ //Adds a safety check post-input to make sure those targets are actually in range.
+ var/mob/M
+ if(!random_target)
+ M = input("Choose the target for the spell.", "Targeting") as null|mob in sortNames(possible_targets)
+ else
+ switch(random_target_priority)
+ if(TARGET_RANDOM)
+ M = pick(possible_targets)
+ if(TARGET_CLOSEST)
+ for(var/mob/living/L in possible_targets)
+ if(M)
+ if(get_dist(user,L) < get_dist(user,M))
+ if(los_check(user,L))
+ M = L
+ else
+ if(los_check(user,L))
+ M = L
+ if(M in view_or_range(range, user, selection_type))
+ targets += M
+
+ else
+ var/list/possible_targets = list()
+ for(var/mob/living/target in view_or_range(range, user, selection_type))
+ if(!can_target(target))
+ continue
+ possible_targets += target
+ for(var/i=1,i<=max_targets,i++)
+ if(!possible_targets.len)
+ break
+ if(target_ignore_prev)
+ var/target = pick(possible_targets)
+ possible_targets -= target
+ targets += target
+ else
+ targets += pick(possible_targets)
+
+ if(!include_user && (user in targets))
+ targets -= user
+
+ if(!targets.len && !cast_without_targets) //doesn't waste the spell
+ revert_cast(user)
+ return
+
+ perform(targets,user=user)
+
+/obj/effect/proc_holder/spell/arcane/aoe_turf/choose_targets(mob/user = usr)
+ var/list/targets = list()
+
+ for(var/turf/target in view_or_range(range,user,selection_type))
+ if(!can_target(target))
+ continue
+ if(!(target in view_or_range(inner_radius,user,selection_type)))
+ targets += target
+
+ if(!targets.len) //doesn't waste the spell
+ revert_cast()
+ return
+
+ perform(targets,user=user)
diff --git a/code/modules/spells/roguetown/arcane/blindness.dm b/code/modules/spells/roguetown/arcane/blindness.dm
new file mode 100644
index 000000000..dbce6704c
--- /dev/null
+++ b/code/modules/spells/roguetown/arcane/blindness.dm
@@ -0,0 +1,23 @@
+// BLINDNESS--------------
+
+/obj/effect/proc_holder/spell/arcane/blindness
+ name = "Blindness"
+ desc = ""
+ overlay_state = "blindness"
+ releasedrain = 40
+ chargedrain = 0
+ chargetime = 0
+ charge_max = 10 SECONDS
+ range = 7
+ movement_interrupt = FALSE
+ sound = 'sound/magic/churn.ogg'
+ antimagic_allowed = TRUE
+
+/obj/effect/proc_holder/spell/arcane/blindness/cast(list/targets, mob/user = usr)
+ if(isliving(targets[1]))
+ var/mob/living/target = targets[1]
+ if(target.anti_magic_check(TRUE, TRUE))
+ return FALSE
+ target.visible_message(span_warning("[user] points at [target]'s eyes!"),span_warning("My eyes are covered in darkness!"))
+ target.blind_eyes(2)
+ return TRUE
\ No newline at end of file
diff --git a/code/modules/spells/roguetown/arcane/blink.dm b/code/modules/spells/roguetown/arcane/blink.dm
new file mode 100644
index 000000000..93446d3e4
--- /dev/null
+++ b/code/modules/spells/roguetown/arcane/blink.dm
@@ -0,0 +1,30 @@
+//BLINK-----------------
+
+/obj/effect/proc_holder/spell/arcane/blink
+ name = "Blink"
+ desc = ""
+ overlay_state = "blink"
+ sound = 'sound/magic/magic_nulled.ogg'
+ range = 8
+ releasedrain = 50
+ chargedrain = 0
+ chargetime = 0
+ charge_max = 15 SECONDS
+ var/include_space = FALSE //whether it includes space tiles in possible teleport locations
+ var/include_dense = FALSE //whether it includes dense tiles in possible teleport locations
+
+/obj/effect/temp_visual/blink
+ icon_state = "anom"
+ layer = ABOVE_MOB_LAYER
+ plane = GAME_PLANE_UPPER
+
+/obj/effect/proc_holder/spell/arcane/blink/cast(list/targets,mob/user = usr)
+ . = ..()
+ if(isopenturf(targets[1]))
+ var/atom/location = get_turf(targets[1])
+ if(location in oview(range,user))
+ new /obj/effect/temp_visual/swap(get_turf(user))
+ new /obj/effect/temp_visual/swap(get_turf(location))
+ do_teleport(user, location, forceMove = TRUE, channel = TELEPORT_CHANNEL_MAGIC)
+ return TRUE
+ return FALSE
diff --git a/code/modules/spells/roguetown/arcane/fetch.dm b/code/modules/spells/roguetown/arcane/fetch.dm
new file mode 100644
index 000000000..f17f4a070
--- /dev/null
+++ b/code/modules/spells/roguetown/arcane/fetch.dm
@@ -0,0 +1,26 @@
+//FETCH-------------------------
+
+/obj/effect/proc_holder/spell/arcane/projectile/fetch
+ name = "Fetch"
+ desc = ""
+ range = 15
+ projectile_type = /obj/projectile/magic/fetch
+ overlay_state = "fetch"
+ sound = list('sound/magic/magnet.ogg')
+ releasedrain = 5
+ chargedrain = 0
+ chargetime = 0
+ charge_max = 5 SECONDS
+ warnie = "spellwarning"
+ no_early_release = TRUE
+ charging_slowdown = 1
+
+/obj/projectile/magic/fetch/on_hit(target)
+ . = ..()
+ if(ismob(target))
+ var/mob/M = target
+ if(M.anti_magic_check())
+ visible_message(span_warning("[target] repells the fetch!"))
+ playsound(get_turf(target), 'sound/magic/magic_nulled.ogg', 100)
+ qdel(src)
+ return BULLET_ACT_BLOCK
\ No newline at end of file
diff --git a/code/modules/spells/roguetown/arcane/fireball.dm b/code/modules/spells/roguetown/arcane/fireball.dm
new file mode 100644
index 000000000..b7037c025
--- /dev/null
+++ b/code/modules/spells/roguetown/arcane/fireball.dm
@@ -0,0 +1,72 @@
+//FIREBALL-------------------------
+
+/obj/effect/proc_holder/spell/arcane/projectile/fireball
+ name = "Fireball"
+ desc = ""
+ clothes_req = FALSE
+ range = 8
+ projectile_type = /obj/projectile/magic/aoe/fireball/rogue
+ overlay_state = "fireball"
+ sound = list('sound/magic/fireball.ogg')
+ active = FALSE
+ releasedrain = 30
+ chargedrain = 1
+ chargetime = 15
+ charge_max = 10 SECONDS
+ warnie = "spellwarning"
+ no_early_release = TRUE
+ movement_interrupt = FALSE
+ charging_slowdown = 3
+
+/obj/effect/proc_holder/spell/arcane/projectile/fireball/fire_projectile(list/targets, mob/living/user)
+ projectile_var_overrides = list("range" = 8)
+ return ..()
+
+/obj/projectile/magic/aoe/fireball/rogue
+ name = "fireball"
+ exp_heavy = 0
+ exp_light = 0
+ exp_flash = 0
+ exp_fire = 1
+ damage = 10
+ damage_type = BURN
+ nodamage = FALSE
+ flag = "magic"
+ hitsound = 'sound/blank.ogg'
+
+/obj/projectile/magic/aoe/fireball/rogue/on_hit(target)
+ . = ..()
+ if(ismob(target))
+ var/mob/M = target
+ if(M.anti_magic_check())
+ visible_message(span_warning("[src] fizzles on contact with [target]!"))
+ playsound(get_turf(target), 'sound/magic/magic_nulled.ogg', 100)
+ qdel(src)
+ return BULLET_ACT_BLOCK
+
+//GREATER FIREBALL-------------------------
+
+/obj/effect/proc_holder/spell/arcane/projectile/fireball/greater
+ name = "Greater Fireball"
+ desc = ""
+ clothes_req = FALSE
+ range = 8
+ projectile_type = /obj/projectile/magic/aoe/fireball/rogue/great
+ overlay_state = "greaterfireball"
+ sound = list('sound/magic/fireball.ogg')
+ releasedrain = 50
+ chargedrain = 1
+ chargetime = 15
+ charge_max = 10 SECONDS
+ warnie = "spellwarning"
+ no_early_release = TRUE
+ movement_interrupt = TRUE
+ chargedloop = /datum/looping_sound/invokegen
+
+/obj/projectile/magic/aoe/fireball/rogue/great
+ name = "fireball"
+ exp_heavy = 0
+ exp_light = 1
+ exp_flash = 2
+ exp_fire = 2
+ flag = "magic"
\ No newline at end of file
diff --git a/code/modules/spells/roguetown/arcane/ignite.dm b/code/modules/spells/roguetown/arcane/ignite.dm
new file mode 100644
index 000000000..6c08ccda2
--- /dev/null
+++ b/code/modules/spells/roguetown/arcane/ignite.dm
@@ -0,0 +1,35 @@
+//IGNITE------------------
+
+/obj/effect/proc_holder/spell/arcane/ignite
+ name = "Ignite"
+ desc = ""
+ overlay_state = "flame"
+ sound = 'sound/items/firelight.ogg'
+ range = 4
+ releasedrain = 30
+ chargedrain = 0
+ chargetime = 0
+ charge_max = 10 SECONDS
+
+/obj/effect/proc_holder/spell/arcane/ignite/cast(list/targets, mob/user = usr)
+ . = ..()
+ if(isliving(targets[1]))
+ var/mob/living/L = targets[1]
+ user.visible_message("[user] points at [L]!")
+ if(L.anti_magic_check(TRUE, TRUE))
+ return FALSE
+ L.adjust_fire_stacks(5)
+ L.IgniteMob()
+ addtimer(CALLBACK(L, TYPE_PROC_REF(/mob/living, ExtinguishMob)), 5 SECONDS)
+ return TRUE
+
+ // Spell interaction with ignitable objects (burn wooden things, light torches up)
+ else if(isobj(targets[1]))
+ var/obj/O = targets[1]
+ if(O.fire_act())
+ user.visible_message("[user] points at [O], igniting it in flames!")
+ return TRUE
+ else
+ to_chat(user, span_warning("You point at [O], but it fails to catch fire."))
+ return FALSE
+ return FALSE
\ No newline at end of file
diff --git a/code/modules/spells/roguetown/arcane/invisibility.dm b/code/modules/spells/roguetown/arcane/invisibility.dm
new file mode 100644
index 000000000..6d1579936
--- /dev/null
+++ b/code/modules/spells/roguetown/arcane/invisibility.dm
@@ -0,0 +1,26 @@
+// INVISIBILITY--------------
+
+/obj/effect/proc_holder/spell/arcane/invisibility
+ name = "Invisibility"
+ desc = ""
+ overlay_state = "invisibility"
+ releasedrain = 50
+ chargedrain = 0
+ chargetime = 0
+ charge_max = 30 SECONDS
+ range = 3
+ movement_interrupt = FALSE
+ sound = 'sound/misc/area.ogg' //This sound doesnt play for some reason. Fix me.
+ antimagic_allowed = TRUE
+
+/obj/effect/proc_holder/spell/arcane/invisibility/cast(list/targets, mob/living/user)
+ if(isliving(targets[1]))
+ var/mob/living/target = targets[1]
+ if(target.anti_magic_check(TRUE, TRUE))
+ return FALSE
+ target.visible_message(span_warning("[target] starts to fade into thin air!"), span_notice("You start to become invisible!"))
+ animate(target, alpha = 0, time = 1 SECONDS, easing = EASE_IN)
+ target.mob_timers[MT_INVISIBILITY] = world.time + 15 SECONDS
+ addtimer(CALLBACK(target, TYPE_PROC_REF(/mob/living, update_sneak_invis), TRUE), 15 SECONDS)
+ addtimer(CALLBACK(target, TYPE_PROC_REF(/atom/movable, visible_message), span_warning("[target] fades back into view."), span_notice("You become visible again.")), 15 SECONDS)
+ return FALSE
\ No newline at end of file
diff --git a/code/modules/spells/roguetown/arcane/lightning.dm b/code/modules/spells/roguetown/arcane/lightning.dm
new file mode 100644
index 000000000..1476cdfc2
--- /dev/null
+++ b/code/modules/spells/roguetown/arcane/lightning.dm
@@ -0,0 +1,48 @@
+//LIGHTNING---------------
+
+/obj/effect/proc_holder/spell/arcane/projectile/lightningbolt
+ name = "Bolt of Lightning"
+ desc = ""
+ overlay_state = "lightning"
+ sound = 'sound/magic/lightning.ogg'
+ range = 8
+ projectile_type = /obj/projectile/magic/lightning
+ releasedrain = 30
+ chargedrain = 1
+ chargetime = 15
+ charge_max = 10 SECONDS
+ movement_interrupt = FALSE
+ charging_slowdown = 3
+
+/obj/projectile/magic/lightning
+ name = "bolt of lightning"
+ tracer_type = /obj/effect/projectile/tracer/stun
+ muzzle_type = null
+ impact_type = null
+ hitscan = TRUE
+ movement_type = UNSTOPPABLE
+ light_color = LIGHT_COLOR_WHITE
+ damage = 15
+ damage_type = BURN
+ nodamage = FALSE
+ speed = 0.3
+ flag = "magic"
+ light_color = "#ffffff"
+ light_range = 7
+
+/obj/projectile/magic/lightning/on_hit(target)
+ . = ..()
+ if(ismob(target))
+ var/mob/M = target
+ if(M.anti_magic_check())
+ visible_message(span_warning("[src] fizzles on contact with [target]!"))
+ playsound(get_turf(target), 'sound/magic/magic_nulled.ogg', 100)
+ qdel(src)
+ return BULLET_ACT_BLOCK
+ if(isliving(target))
+ var/mob/living/L = target
+// for(var/obj/item/I in L.get_equipped_items()) //Maybe add 5 damage for each metal gear in the target?
+// if(I.smeltresult == /obj/item/ingot/iron) //More damage if the target is on water tuff too?
+// damage += 5 //(dont know it that code work tho)
+ L.electrocute_act(1, src)
+ qdel(src)
\ No newline at end of file
diff --git a/code/modules/spells/roguetown/arcane/smokescreen.dm b/code/modules/spells/roguetown/arcane/smokescreen.dm
new file mode 100644
index 000000000..d1b30d5ae
--- /dev/null
+++ b/code/modules/spells/roguetown/arcane/smokescreen.dm
@@ -0,0 +1,68 @@
+//SMOKESCREEN-----------------
+
+/obj/effect/proc_holder/spell/arcane/smokescreen
+ name = "Smokescreen"
+ desc = ""
+ overlay_state = "smoke"
+ sound = 'sound/items/firesnuff.ogg'
+ range = 8
+ releasedrain = 30
+ chargedrain = 0
+ chargetime = 0
+ charge_max = 10 SECONDS
+ smoke_spread = 1 //Just Smoke
+ smoke_amt = 2
+
+/obj/effect/proc_holder/spell/arcane/smokescreen/cast(list/targets,mob/user = usr)
+ . = ..()
+ if(isliving(targets[1]))
+ return TRUE
+ else if(isopenturf(targets[1]))
+ return TRUE
+ return FALSE
+
+//DENSE SMOKE-------------------
+
+/obj/effect/proc_holder/spell/arcane/densesmoke
+ name = "Dense Smoke"
+ desc = ""
+ overlay_state = "smoke"
+ sound = 'sound/items/firesnuff.ogg'
+ range = 8
+ releasedrain = 40
+ chargedrain = 1
+ chargetime = 10
+ charge_max = 15 SECONDS
+ smoke_spread = 2 //Now it makes the target cough and drop items in hand
+ smoke_amt = 1
+
+/obj/effect/proc_holder/spell/arcane/densesmoke/cast(list/targets,mob/user = usr)
+ . = ..()
+ if(isliving(targets[1]))
+ return TRUE
+ else if(isopenturf(targets[1]))
+ return TRUE
+ return FALSE
+
+//SLEEPING GAS-------------------
+
+/obj/effect/proc_holder/spell/arcane/sleepgas
+ name = "Sleeping Gas"
+ desc = ""
+ overlay_state = "smoke"
+ sound = 'sound/items/firesnuff.ogg'
+ range = 8
+ releasedrain = 60
+ chargedrain = 1
+ chargetime = 30
+ charge_max = 30 SECONDS
+ smoke_spread = 3 //Now this will make the target to fall asleep
+ smoke_amt = 2
+
+/obj/effect/proc_holder/spell/arcane/sleepgas/cast(list/targets,mob/user = usr)
+ . = ..()
+ if(isliving(targets[1]))
+ return TRUE
+ else if(isopenturf(targets[1]))
+ return TRUE
+ return FALSE
\ No newline at end of file
diff --git a/code/modules/spells/roguetown/arcane/swap.dm b/code/modules/spells/roguetown/arcane/swap.dm
new file mode 100644
index 000000000..2ef5e107e
--- /dev/null
+++ b/code/modules/spells/roguetown/arcane/swap.dm
@@ -0,0 +1,35 @@
+//SWAP PLACES-----------------
+
+/obj/effect/proc_holder/spell/arcane/swap
+ name = "Location Swap"
+ desc = ""
+ overlay_state = "swap"
+ sound = 'sound/magic/magic_nulled.ogg'
+ range = 8
+ releasedrain = 50
+ chargedrain = 1
+ chargetime = 15
+ charge_max = 20 SECONDS
+ charging_slowdown = 3
+ var/include_space = FALSE //whether it includes space tiles in possible teleport locations
+ var/include_dense = FALSE //whether it includes dense tiles in possible teleport locations
+
+/obj/effect/temp_visual/swap
+ icon_state = "anom"
+ layer = ABOVE_MOB_LAYER
+ plane = GAME_PLANE_UPPER
+
+/obj/effect/proc_holder/spell/arcane/swap/cast(list/targets, mob/living/user)
+ if(isliving(targets[1]))
+ var/mob/living/target = targets[1]
+ if(target.anti_magic_check(TRUE, TRUE))
+ return FALSE
+ new /obj/effect/temp_visual/swap(get_turf(user))
+ new /obj/effect/temp_visual/swap(get_turf(target))
+ var/atom/targl = get_turf(target)
+ if(do_teleport(target, user, forceMove = TRUE, channel = TELEPORT_CHANNEL_MAGIC))
+ do_teleport(user, targl, forceMove = TRUE, channel = TELEPORT_CHANNEL_MAGIC)
+ if(ismob(target))
+ var/mob/M = target
+ to_chat(M, span_warning("You find myself somewhere else..."))
+ return TRUE
\ No newline at end of file
diff --git a/code/modules/spells/roguetown/arcane/telepathy.dm b/code/modules/spells/roguetown/arcane/telepathy.dm
new file mode 100644
index 000000000..ed70c87cf
--- /dev/null
+++ b/code/modules/spells/roguetown/arcane/telepathy.dm
@@ -0,0 +1,28 @@
+//TELEPATHY---------------------------
+
+/obj/effect/proc_holder/spell/arcane/telepathy
+ name = "telepathy"
+ desc = ""
+ range = 15
+ overlay_state = "psy"
+ sound = list('sound/magic/magnet.ogg')
+ releasedrain = 20
+ chargedrain = 0
+ chargetime = 0
+ charge_max = 15 SECONDS
+ warnie = "spellwarning"
+ no_early_release = TRUE
+ charging_slowdown = 1
+
+/obj/effect/proc_holder/spell/arcane/telepathy/cast(list/targets,mob/user = usr)
+ . = ..()
+ if(isliving(targets[1]))
+ var/mob/living/target = targets[1]
+ if(target.anti_magic_check(TRUE, TRUE))
+ return FALSE
+ var/input = stripped_input(user, "What message are you sending?", null, "")
+ if(!input)
+ return FALSE
+ to_chat(user, span_warning("I transmit to [target]: " + "[input]"))
+ to_chat(target, span_warning("You hear a voice in your head saying: ") + span_boldwarning("[input]"))
+ return TRUE
\ No newline at end of file
diff --git a/code/modules/spells/roguetown/other/grant_title.dm b/code/modules/spells/roguetown/other/grant_title.dm
new file mode 100644
index 000000000..03bd7da94
--- /dev/null
+++ b/code/modules/spells/roguetown/other/grant_title.dm
@@ -0,0 +1,60 @@
+//Grant Title---------------------
+
+/obj/effect/proc_holder/spell/self/grant_title
+ name = "Grant Title"
+ desc = "Grant someone a title of honor... Or shame."
+ overlay_state = "recruit"
+ antimagic_allowed = TRUE
+ charge_max = 100
+ /// Maximum range for title granting
+ var/title_range = 3
+ /// Maximum length for the title
+ var/title_length = 42
+
+/obj/effect/proc_holder/spell/self/grant_title/cast(list/targets, mob/user = usr)
+ . = ..()
+ var/granted_title = input(user, "What title do you wish to grant?", "[name]") as null|text
+ granted_title = reject_bad_text(granted_title, title_length)
+ if(!granted_title)
+ return
+ var/list/recruitment = list()
+ for(var/mob/living/carbon/human/village_idiot in (get_hearers_in_view(title_range, user) - user))
+ //not allowed
+ if(!can_title(village_idiot))
+ continue
+ recruitment[village_idiot.name] = village_idiot
+ if(!length(recruitment))
+ to_chat(user, span_warning("There are no potential honoraries in range."))
+ return
+ var/inputty = input(user, "Select an honorary!", "[name]") as anything in recruitment
+ if(inputty)
+ var/mob/living/carbon/human/recruit = recruitment[inputty]
+ if(!QDELETED(recruit) && (recruit in get_hearers_in_view(title_range, user)))
+ INVOKE_ASYNC(src, PROC_REF(village_idiotify), recruit, user, granted_title)
+ else
+ to_chat(user, span_warning("Honorific failed!"))
+ else
+ to_chat(user, span_warning("Honorific cancelled."))
+
+/obj/effect/proc_holder/spell/self/grant_title/proc/can_title(mob/living/carbon/human/recruit)
+ //wtf
+ if(QDELETED(recruit))
+ return FALSE
+ //need a mind
+ if(!recruit.mind)
+ return FALSE
+ //need to see their damn face
+ if(!recruit.get_face_name(null))
+ return FALSE
+ return TRUE
+
+/obj/effect/proc_holder/spell/self/grant_title/proc/village_idiotify(mob/living/carbon/human/recruit, mob/living/carbon/human/recruiter, granted_title)
+ if(QDELETED(recruit) || QDELETED(recruiter) || !granted_title)
+ return FALSE
+ if(GLOB.lord_titles[recruit.real_name])
+ recruiter.say("I HEREBY STRIP YOU, [uppertext(recruit.name)], OF THE TITLE OF [uppertext(GLOB.lord_titles[recruit.real_name])]!")
+ GLOB.lord_titles -= recruit.real_name
+ return FALSE
+ recruiter.say("I HEREBY GRANT YOU, [uppertext(recruit.name)], THE TITLE OF [uppertext(granted_title)]!")
+ GLOB.lord_titles[recruit.real_name] = granted_title
+ return TRUE
\ No newline at end of file
diff --git a/code/modules/spells/roguetown/jester.dm b/code/modules/spells/roguetown/other/jester.dm
similarity index 100%
rename from code/modules/spells/roguetown/jester.dm
rename to code/modules/spells/roguetown/other/jester.dm
diff --git a/code/modules/spells/roguetown/other/recruiting.dm b/code/modules/spells/roguetown/other/recruiting.dm
new file mode 100644
index 000000000..1f9369f6b
--- /dev/null
+++ b/code/modules/spells/roguetown/other/recruiting.dm
@@ -0,0 +1,155 @@
+/obj/effect/proc_holder/spell/self/convertrole
+ name = "Recruit Beggar"
+ desc = "Recruit someone to your cause."
+ overlay_state = "recruit"
+ antimagic_allowed = TRUE
+ charge_max = 100
+ /// Role given if recruitment is accepted
+ var/new_role = "Beggar"
+ /// Faction shown to the user in the recruitment prompt
+ var/recruitment_faction = "Beggars"
+ /// Message the recruiter gives
+ var/recruitment_message = "Serve the beggars, %RECRUIT!"
+ /// Range to search for potential recruits
+ var/recruitment_range = 3
+ /// Say message when the recruit accepts
+ var/accept_message = "I will serve!"
+ /// Say message when the recruit refuses
+ var/refuse_message = "I refuse."
+
+/obj/effect/proc_holder/spell/self/convertrole/cast(list/targets,mob/user = usr)
+ . = ..()
+ var/list/recruitment = list()
+ for(var/mob/living/carbon/human/recruit in (get_hearers_in_view(recruitment_range, user) - user))
+ //not allowed
+ if(!can_convert(recruit))
+ continue
+ recruitment[recruit.name] = recruit
+ if(!length(recruitment))
+ to_chat(user, span_warning("There are no potential recruits in range."))
+ return
+ var/inputty = input(user, "Select a potential recruit!", "[name]") as anything in recruitment
+ if(inputty)
+ var/mob/living/carbon/human/recruit = recruitment[inputty]
+ if(!QDELETED(recruit) && (recruit in get_hearers_in_view(recruitment_range, user)))
+ INVOKE_ASYNC(src, PROC_REF(convert), recruit, user)
+ else
+ to_chat(user, span_warning("Recruitment failed!"))
+ else
+ to_chat(user, span_warning("Recruitment cancelled."))
+
+/obj/effect/proc_holder/spell/self/convertrole/proc/can_convert(mob/living/carbon/human/recruit)
+ //wtf
+ if(QDELETED(recruit))
+ return FALSE
+ //need a mind
+ if(!recruit.mind)
+ return FALSE
+ //only migrants and peasants
+ if(!(recruit.job in GLOB.peasant_positions) && \
+ !(recruit.job in GLOB.yeoman_positions) && \
+ !(recruit.job in GLOB.allmig_positions) && \
+ !(recruit.job in GLOB.mercenary_positions))
+ return FALSE
+ //need to see their damn face
+ if(!recruit.get_face_name(null))
+ return FALSE
+ return TRUE
+
+/obj/effect/proc_holder/spell/self/convertrole/proc/convert(mob/living/carbon/human/recruit, mob/living/carbon/human/recruiter)
+ if(QDELETED(recruit) || QDELETED(recruiter))
+ return FALSE
+ recruiter.say(replacetext(recruitment_message, "%RECRUIT", "[recruit]"), forced = "[name]")
+ var/prompt = alert(recruit, "Do you wish to become a [new_role]?", "[recruitment_faction] Recruitment", "Yes", "No")
+ if(QDELETED(recruit) || QDELETED(recruiter) || !(recruiter in get_hearers_in_view(recruitment_range, recruit)))
+ return FALSE
+ if(prompt != "Yes")
+ if(refuse_message)
+ recruit.say(refuse_message, forced = "[name]")
+ return FALSE
+ if(accept_message)
+ recruit.say(accept_message, forced = "[name]")
+ if(new_role)
+ recruit.job = new_role
+ return TRUE
+
+//GUARD--------------------------------------
+
+/obj/effect/proc_holder/spell/self/convertrole/guard
+ name = "Recruit Guardsmen"
+ new_role = "Watchman"
+ recruitment_faction = "Watchman"
+ recruitment_message = "Serve the town guard, %RECRUIT!"
+ accept_message = "FOR THE KING!"
+ refuse_message = "I refuse."
+
+/obj/effect/proc_holder/spell/self/convertrole/guard/convert(mob/living/carbon/human/recruit, mob/living/carbon/human/recruiter)
+ . = ..()
+ if(!.)
+ return
+ recruit.verbs |= /mob/proc/haltyell
+
+//BOG GUARD--------------------------------------
+
+/obj/effect/proc_holder/spell/self/convertrole/bog
+ name = "Recruit Bogmen"
+ new_role = "Bog Guard"
+ recruitment_faction = "Bog Guard"
+ recruitment_message = "Serve the bog, %RECRUIT!"
+ accept_message = "FOR THE BOG!"
+ refuse_message = "I refuse."
+
+/obj/effect/proc_holder/spell/self/convertrole/bog/convert(mob/living/carbon/human/recruit, mob/living/carbon/human/recruiter)
+ . = ..()
+ if(!.)
+ return
+ recruit.verbs |= /mob/proc/haltyell
+
+//SERVANT--------------------------------------
+
+/obj/effect/proc_holder/spell/self/convertrole/servant
+ name = "Recruit Servant"
+ new_role = "Servant"
+ recruitment_faction = "Servants"
+ recruitment_message = "Serve the crown, %RECRUIT!"
+ accept_message = "FOR THE CROWN!"
+ refuse_message = "I refuse."
+ charge_max = 100
+
+//TEMPLAR--------------------------------------
+
+/obj/effect/proc_holder/spell/self/convertrole/templar
+ name = "Recruit Templar"
+ new_role = "Templar"
+ recruitment_faction = "Templars"
+ recruitment_message = "Serve the nine, %RECRUIT!"
+ accept_message = "FOR THE NINE!"
+ refuse_message = "I refuse."
+
+//ACOLYTE--------------------------------------
+
+/obj/effect/proc_holder/spell/self/convertrole/monk
+ name = "Recruit Acolyte"
+ new_role = "Acolyte"
+ recruitment_faction = "Church"
+ recruitment_message = "Serve the nine, %RECRUIT!"
+ accept_message = "FOR THE NINE!"
+ refuse_message = "I refuse."
+
+//REBEL--------------------------------------
+
+/obj/effect/proc_holder/spell/self/rebelconvert
+ name = "RECRUIT REBELS"
+ desc = "!"
+ overlay_state = "recruit"
+ antimagic_allowed = TRUE
+ charge_max = 150
+
+/obj/effect/proc_holder/spell/self/rebelconvert/cast(list/targets,mob/user = usr)
+ ..()
+ var/inputty = input("Make a speech!", "ROGUETOWN") as text|null
+ if(inputty)
+ user.say(inputty, forced = "spell")
+ var/datum/antagonist/prebel/PR = user.mind.has_antag_datum(/datum/antagonist/prebel)
+ for(var/mob/living/carbon/human/L in get_hearers_in_view(6, get_turf(user)))
+ addtimer(CALLBACK(L,TYPE_PROC_REF(/mob/living/carbon/human, rev_ask), user,PR,inputty),1)
diff --git a/icons/mob/actions/roguespells.dmi b/icons/mob/actions/roguespells.dmi
index 62263e41e..ddc68f3a6 100644
Binary files a/icons/mob/actions/roguespells.dmi and b/icons/mob/actions/roguespells.dmi differ
diff --git a/icons/mob/actions/roguespellsbackup.dmi b/icons/mob/actions/roguespellsbackup.dmi
new file mode 100644
index 000000000..62263e41e
Binary files /dev/null and b/icons/mob/actions/roguespellsbackup.dmi differ
diff --git a/roguetown.dme b/roguetown.dme
index 6948c28ae..40cdb514c 100644
--- a/roguetown.dme
+++ b/roguetown.dme
@@ -3257,8 +3257,8 @@
#include "code\modules\shuttle\white_ship.dm"
#include "code\modules\spells\spell.dm"
#include "code\modules\spells\roguetown\_roguetown.dm"
+#include "code\modules\spells\roguetown\arcane.dm"
#include "code\modules\spells\roguetown\confessor.dm"
-#include "code\modules\spells\roguetown\jester.dm"
#include "code\modules\spells\roguetown\monk.dm"
#include "code\modules\spells\roguetown\necromancer.dm"
#include "code\modules\spells\roguetown\priest.dm"
@@ -3270,6 +3270,19 @@
#include "code\modules\spells\roguetown\acolyte\necra.dm"
#include "code\modules\spells\roguetown\acolyte\noc.dm"
#include "code\modules\spells\roguetown\acolyte\pestra.dm"
+#include "code\modules\spells\roguetown\arcane\blindness.dm"
+#include "code\modules\spells\roguetown\arcane\blink.dm"
+#include "code\modules\spells\roguetown\arcane\fetch.dm"
+#include "code\modules\spells\roguetown\arcane\fireball.dm"
+#include "code\modules\spells\roguetown\arcane\ignite.dm"
+#include "code\modules\spells\roguetown\arcane\invisibility.dm"
+#include "code\modules\spells\roguetown\arcane\lightning.dm"
+#include "code\modules\spells\roguetown\arcane\smokescreen.dm"
+#include "code\modules\spells\roguetown\arcane\swap.dm"
+#include "code\modules\spells\roguetown\arcane\telepathy.dm"
+#include "code\modules\spells\roguetown\other\grant_title.dm"
+#include "code\modules\spells\roguetown\other\jester.dm"
+#include "code\modules\spells\roguetown\other\recruiting.dm"
#include "code\modules\spells\spell_types\aimed.dm"
#include "code\modules\spells\spell_types\area_teleport.dm"
#include "code\modules\spells\spell_types\barnyard.dm"