diff --git a/code/datums/spells/charge.dm b/code/datums/spells/charge.dm
new file mode 100644
index 00000000000..0ace8c7d9cd
--- /dev/null
+++ b/code/datums/spells/charge.dm
@@ -0,0 +1,74 @@
+/obj/effect/proc_holder/spell/targeted/charge
+ name = "Charge"
+ desc = "This spell can be used to charge up spent magical artifacts, among other things."
+
+ school = "transmutation"
+ charge_max = 600
+ clothes_req = 0
+ invocation = "DIRI CEL"
+ invocation_type = "whisper"
+ range = -1
+ cooldown_min = 400 //50 deciseconds reduction per rank
+ include_user = 1
+
+
+/obj/effect/proc_holder/spell/targeted/charge/cast(list/targets)
+ for(var/mob/living/user in targets)
+ var/list/hand_items = list(user.get_active_hand(),user.get_inactive_hand())
+ var/charged_item = null
+ var/burnt_out = 0
+ world << "[user.l_hand] and [user.r_hand]"
+ for(var/obj/item in hand_items)
+ if(istype(item, /obj/item/weapon/grab))
+ var/obj/item/weapon/grab/G = item
+ if(G.affecting)
+ var/mob/M = G.affecting
+ if(M.spell_list.len != 0)
+ for(var/obj/effect/proc_holder/spell/S in M.spell_list)
+ S.charge_counter = S.charge_max
+ M <<"\blue you feel raw magic flowing through you, it feels good!"
+ else
+ M <<"\blue you feel very strange for a moment, but then it passes."
+ burnt_out = 1
+ charged_item = M
+ break
+ else if(istype(item, /obj/item/weapon/gun/magic))
+ var/obj/item/weapon/gun/magic/I = item
+ if(prob(80))
+ I.max_charges--
+ if(I.max_charges <= 0)
+ I.max_charges = 0
+ burnt_out = 1
+ I.charges = I.max_charges
+ charged_item = I
+ break
+ else if(istype(item, /obj/item/weapon/cell/))
+ var/obj/item/weapon/cell/C = item
+ if(prob(80))
+ C.maxcharge -= 200
+ if(C.maxcharge <= 1) //Div by 0 protection
+ C.maxcharge = 1
+ burnt_out = 1
+ C.charge = C.maxcharge
+ charged_item = C
+ break
+ else if(item.contents)
+ var/obj/I = null
+ for(I in item.contents)
+ if(istype(I, /obj/item/weapon/cell/))
+ var/obj/item/weapon/cell/C = I
+ if(prob(80))
+ C.maxcharge -= 200
+ if(C.maxcharge <= 1) //Div by 0 protection
+ C.maxcharge = 1
+ burnt_out = 1
+ C.charge = C.maxcharge
+ item.update_icon()
+ charged_item = item
+ break
+ if(!charged_item)
+ user << "\blue you feel magical power surging to your hands, but the feeling rapidly fades..."
+ else if(burnt_out)
+ user << "\red [charged_item] doesn't seem to be reacting to the spell..."
+ else
+ user << "\blue [charged_item] suddenly feels very warm!"
diff --git a/code/game/gamemodes/wizard/artefact.dm b/code/game/gamemodes/wizard/artefact.dm
index 5bad56a6135..3d404dfc846 100644
--- a/code/game/gamemodes/wizard/artefact.dm
+++ b/code/game/gamemodes/wizard/artefact.dm
@@ -27,6 +27,8 @@
dat += "Your apprentice is skilled in offensive magic. They know Magic Missile and Fireball.
"
dat += "Bluespace Manipulation
"
dat += "Your apprentice is able to defy physics, melting through solid objects and travelling great distances in the blink of an eye. They know Teleport and Ethereal Jaunt.
"
+ dat += "Healing
"
+ dat += "Your apprentice is training to cast spells that will aid your survival. They know Forcewall and Charge and come with a Staff of Healing.
"
dat += "Robeless
"
dat += "Your apprentice is training to cast spells without their robes. They know Knock and Mindswap.
"
user << browse(dat, "window=radio")
@@ -66,6 +68,11 @@
M.spell_list += new /obj/effect/proc_holder/spell/targeted/area_teleport/teleport(M)
M.spell_list += new /obj/effect/proc_holder/spell/targeted/ethereal_jaunt(M)
M << "Your service has not gone unrewarded, however. Studying under [H.real_name], you have learned reality bending mobility spells. You are able to cast teleport and ethereal jaunt."
+ if("healing")
+ M.spell_list += new /obj/effect/proc_holder/spell/targeted/charge(M)
+ M.spell_list += new /obj/effect/proc_holder/spell/aoe_turf/conjure/forcewall(M)
+ M.equip_to_slot_or_del(new /obj/item/weapon/gun/magic/staff/healing(M), slot_r_hand)
+ M << "Your service has not gone unrewarded, however. Studying under [H.real_name], you have learned livesaving survival spells. You are able to cast charge and forcewall."
if("robeless")
M.spell_list += new /obj/effect/proc_holder/spell/aoe_turf/knock(M)
M.spell_list += new /obj/effect/proc_holder/spell/targeted/mind_transfer(M)
diff --git a/code/game/gamemodes/wizard/rightandwrong.dm b/code/game/gamemodes/wizard/rightandwrong.dm
index c18732cdb01..4b0d7633e82 100644
--- a/code/game/gamemodes/wizard/rightandwrong.dm
+++ b/code/game/gamemodes/wizard/rightandwrong.dm
@@ -1,8 +1,8 @@
-/mob/proc/rightandwrong()
- usr << "You summoned guns!"
- message_admins("[key_name_admin(usr, 1)] summoned guns!")
+/mob/proc/rightandwrong(var/summon_type) //0 = Summon Guns, 1 = Summon Magic
+ usr << "You summoned [summon_type ? "magic" : "guns"]!"
+ message_admins("[key_name_admin(usr, 1)] summoned [summon_type ? "magic" : "guns"]!")
for(var/mob/living/carbon/human/H in player_list)
if(H.stat == 2 || !(H.client)) continue
if(is_special_character(H)) continue
@@ -18,46 +18,95 @@
for(var/datum/objective/OBJ in H.mind.objectives)
H << "Objective #[obj_count]: [OBJ.explanation_text]"
obj_count++
- var/randomize = pick("taser","egun","laser","revolver","detective","smg","nuclear","deagle","gyrojet","pulse","silenced","cannon","doublebarrel","shotgun","combatshotgun","mateba","smg","uzi","crossbow","saw")
- switch (randomize)
- if("taser")
- new /obj/item/weapon/gun/energy/taser(get_turf(H))
- if("egun")
- new /obj/item/weapon/gun/energy/gun(get_turf(H))
- if("laser")
- new /obj/item/weapon/gun/energy/laser(get_turf(H))
- if("revolver")
- new /obj/item/weapon/gun/projectile/revolver(get_turf(H))
- if("detective")
- new /obj/item/weapon/gun/projectile/revolver/detective(get_turf(H))
- if("smg")
- new /obj/item/weapon/gun/projectile/automatic/c20r(get_turf(H))
- if("nuclear")
- new /obj/item/weapon/gun/energy/gun/nuclear(get_turf(H))
- if("deagle")
- new /obj/item/weapon/gun/projectile/automatic/deagle/camo(get_turf(H))
- if("gyrojet")
- new /obj/item/weapon/gun/projectile/automatic/gyropistol(get_turf(H))
- if("pulse")
- new /obj/item/weapon/gun/energy/pulse_rifle(get_turf(H))
- if("silenced")
- new /obj/item/weapon/gun/projectile/automatic/pistol(get_turf(H))
- new /obj/item/weapon/silencer(get_turf(H))
- if("cannon")
- new /obj/item/weapon/gun/energy/lasercannon(get_turf(H))
- if("doublebarrel")
- new /obj/item/weapon/gun/projectile/revolver/doublebarrel(get_turf(H))
- if("shotgun")
- new /obj/item/weapon/gun/projectile/shotgun/(get_turf(H))
- if("combatshotgun")
- new /obj/item/weapon/gun/projectile/shotgun/combat(get_turf(H))
- if("mateba")
- new /obj/item/weapon/gun/projectile/revolver/mateba(get_turf(H))
- if("smg")
- new /obj/item/weapon/gun/projectile/automatic(get_turf(H))
- if("uzi")
- new /obj/item/weapon/gun/projectile/automatic/mini_uzi(get_turf(H))
- if("crossbow")
- new /obj/item/weapon/gun/energy/crossbow(get_turf(H))
- if("saw")
- new /obj/item/weapon/gun/projectile/automatic/l6_saw(get_turf(H))
\ No newline at end of file
+ var/randomizeguns = pick("taser","egun","laser","revolver","detective","smg","nuclear","deagle","gyrojet","pulse","silenced","cannon","doublebarrel","shotgun","combatshotgun","mateba","smg","uzi","crossbow","saw")
+ var/randomizemagic = pick("fireball","smoke","blind","mindswap","forcewall","knock","horsemask","charge","wandnothing", "wanddeath", "wandresurrection", "wandpolymorph", "wandteleport", "wanddoor", "wandfireball", "staffchange", "staffanimation", "staffhealing", "armor", "scrying")
+ if(!summon_type)
+ switch (randomizeguns)
+ if("taser")
+ new /obj/item/weapon/gun/energy/taser(get_turf(H))
+ if("egun")
+ new /obj/item/weapon/gun/energy/gun(get_turf(H))
+ if("laser")
+ new /obj/item/weapon/gun/energy/laser(get_turf(H))
+ if("revolver")
+ new /obj/item/weapon/gun/projectile/revolver(get_turf(H))
+ if("detective")
+ new /obj/item/weapon/gun/projectile/revolver/detective(get_turf(H))
+ if("smg")
+ new /obj/item/weapon/gun/projectile/automatic/c20r(get_turf(H))
+ if("nuclear")
+ new /obj/item/weapon/gun/energy/gun/nuclear(get_turf(H))
+ if("deagle")
+ new /obj/item/weapon/gun/projectile/automatic/deagle/camo(get_turf(H))
+ if("gyrojet")
+ new /obj/item/weapon/gun/projectile/automatic/gyropistol(get_turf(H))
+ if("pulse")
+ new /obj/item/weapon/gun/energy/pulse_rifle(get_turf(H))
+ if("silenced")
+ new /obj/item/weapon/gun/projectile/automatic/pistol(get_turf(H))
+ new /obj/item/weapon/silencer(get_turf(H))
+ if("cannon")
+ new /obj/item/weapon/gun/energy/lasercannon(get_turf(H))
+ if("doublebarrel")
+ new /obj/item/weapon/gun/projectile/revolver/doublebarrel(get_turf(H))
+ if("shotgun")
+ new /obj/item/weapon/gun/projectile/shotgun/(get_turf(H))
+ if("combatshotgun")
+ new /obj/item/weapon/gun/projectile/shotgun/combat(get_turf(H))
+ if("mateba")
+ new /obj/item/weapon/gun/projectile/revolver/mateba(get_turf(H))
+ if("smg")
+ new /obj/item/weapon/gun/projectile/automatic(get_turf(H))
+ if("uzi")
+ new /obj/item/weapon/gun/projectile/automatic/mini_uzi(get_turf(H))
+ if("crossbow")
+ new /obj/item/weapon/gun/energy/crossbow(get_turf(H))
+ if("saw")
+ new /obj/item/weapon/gun/projectile/automatic/l6_saw(get_turf(H))
+ else
+ switch (randomizemagic)
+ if("fireball")
+ new /obj/item/weapon/spellbook/oneuse/fireball(get_turf(H))
+ if("smoke")
+ new /obj/item/weapon/spellbook/oneuse/smoke(get_turf(H))
+ if("blind")
+ new /obj/item/weapon/spellbook/oneuse/blind(get_turf(H))
+ if("mindswap")
+ new /obj/item/weapon/spellbook/oneuse/mindswap(get_turf(H))
+ if("forcewall")
+ new /obj/item/weapon/spellbook/oneuse/forcewall(get_turf(H))
+ if("knock")
+ new /obj/item/weapon/spellbook/oneuse/knock(get_turf(H))
+ if("horsemask")
+ new /obj/item/weapon/spellbook/oneuse/horsemask(get_turf(H))
+ if("charge")
+ new /obj/item/weapon/spellbook/oneuse/charge(get_turf(H))
+ if("wandnothing")
+ new /obj/item/weapon/gun/magic/wand(get_turf(H))
+ if("wanddeath")
+ new /obj/item/weapon/gun/magic/wand/death(get_turf(H))
+ if("wandresurrection")
+ new /obj/item/weapon/gun/magic/wand/resurrection(get_turf(H))
+ if("wandpolymorph")
+ new /obj/item/weapon/gun/magic/wand/polymorph(get_turf(H))
+ if("wandteleport")
+ new /obj/item/weapon/gun/magic/wand/teleport(get_turf(H))
+ if("wanddoor")
+ new /obj/item/weapon/gun/magic/wand/door(get_turf(H))
+ if("staffchange")
+ new /obj/item/weapon/gun/magic/staff/change(get_turf(H))
+ if("staffanimation")
+ new /obj/item/weapon/gun/magic/staff/animate(get_turf(H))
+ if("staffhealing")
+ new /obj/item/weapon/gun/magic/staff/healing(get_turf(H))
+ if("armor")
+ new /obj/item/clothing/suit/space/rig/wizard(get_turf(H))
+ new /obj/item/clothing/head/helmet/space/rig/wizard(get_turf(H))
+ if("scrying")
+ new /obj/item/weapon/scrying(get_turf(H))
+ if (!(XRAY in H.mutations))
+ H.mutations.Add(XRAY)
+ H.sight |= (SEE_MOBS|SEE_OBJS|SEE_TURFS)
+ H.see_in_dark = 8
+ H.see_invisible = SEE_INVISIBLE_LEVEL_TWO
+ H << "\blue The walls suddenly disappear."
diff --git a/code/game/gamemodes/wizard/spellbook.dm b/code/game/gamemodes/wizard/spellbook.dm
index 156554d486d..055e887981f 100644
--- a/code/game/gamemodes/wizard/spellbook.dm
+++ b/code/game/gamemodes/wizard/spellbook.dm
@@ -86,6 +86,9 @@
dat += "Summon Guns (One time use, global spell)
"
dat += "Nothing could possibly go wrong with arming a crew of lunatics just itching for an excuse to kill eachother. Just be careful not to get hit in the crossfire!
"
+ dat += "Summon Magic (One time use, global spell)
"
+ dat += "Share the wonders of magic with the crew and show them why they aren't to be trusted with it at the same time.
"
+
dat += "
"
dat += "Artefacts:
"
dat += "Powerful items imbued with eldritch magics. Summoning one will count towards your maximum number of spells.
"
@@ -150,7 +153,7 @@
uses--
/*
*/
- var/list/available_spells = list(magicmissile = "Magic Missile", fireball = "Fireball", disintegrate = "Disintegrate", disabletech = "Disable Tech", smoke = "Smoke", blind = "Blind", mindswap = "Mind Transfer", forcewall = "Forcewall", blink = "Blink", teleport = "Teleport", mutate = "Mutate", etherealjaunt = "Ethereal Jaunt", knock = "Knock", horseman = "Curse of the Horseman", fleshtostone = "Flesh to Stone", summonguns = "Summon Guns", staffchange = "Staff of Change", soulstone = "Six Soul Stone Shards and the spell Artificer", armor = "Mastercrafted Armor Set", staffanimate = "Staff of Animation")
+ var/list/available_spells = list(magicmissile = "Magic Missile", fireball = "Fireball", disintegrate = "Disintegrate", disabletech = "Disable Tech", smoke = "Smoke", blind = "Blind", mindswap = "Mind Transfer", forcewall = "Forcewall", blink = "Blink", teleport = "Teleport", mutate = "Mutate", etherealjaunt = "Ethereal Jaunt", knock = "Knock", horseman = "Curse of the Horseman", fleshtostone = "Flesh to Stone", summonguns = "Summon Guns", summonmagic = "Summon Magic", staffchange = "Staff of Change", soulstone = "Six Soul Stone Shards and the spell Artificer", armor = "Mastercrafted Armor Set", staffanimate = "Staff of Animation")
var/already_knows = 0
for(var/obj/effect/proc_holder/spell/aspell in H.spell_list)
if(available_spells[href_list["spell_choice"]] == initial(aspell.name))
@@ -246,12 +249,17 @@
temp = "You have learned flesh to stone."
if("summonguns")
feedback_add_details("wizard_spell_learned","SG") //please do not change the abbreviation to keep data processing consistent. Add a unique id to any new spells
- H.rightandwrong()
+ H.rightandwrong(0)
max_uses--
temp = "You have cast summon guns."
+ if("summonmagic")
+ feedback_add_details("wizard_spell_learned","SM") //please do not change the abbreviation to keep data processing consistent. Add a unique id to any new spells
+ H.rightandwrong(1)
+ max_uses--
+ temp = "You have cast summon magic."
if("staffchange")
feedback_add_details("wizard_spell_learned","ST") //please do not change the abbreviation to keep data processing consistent. Add a unique id to any new spells
- new /obj/item/weapon/gun/energy/staff(get_turf(H))
+ new /obj/item/weapon/gun/magic/staff/change(get_turf(H))
temp = "You have purchased a staff of change."
max_uses--
if("soulstone")
@@ -270,7 +278,7 @@
max_uses--
if("staffanimation")
feedback_add_details("wizard_spell_learned","SA") //please do not change the abbreviation to keep data processing consistent. Add a unique id to any new spells
- new /obj/item/weapon/gun/energy/staff/animate(get_turf(H))
+ new /obj/item/weapon/gun/magic/staff/animate(get_turf(H))
temp = "You have purchased a staff of animation."
max_uses--
if("contract")
@@ -295,3 +303,82 @@
attack_self(H)
return
+
+//Single Use Spellbooks//
+
+/obj/item/weapon/spellbook/oneuse
+ var/spell = /obj/effect/proc_holder/spell/targeted/projectile/magic_missile //just a placeholder to avoid runtimes if someone spawned the generic
+ var/spellname = "sandbox"
+ name = "spellbook of "
+ uses = 1
+ max_uses = 1
+ desc = "This template spellbook was never meant for the eyes of man..."
+
+/obj/item/weapon/spellbook/oneuse/New()
+ ..()
+ name += spellname
+
+/obj/item/weapon/spellbook/oneuse/attack_self(mob/user as mob)
+ var/obj/effect/proc_holder/spell/S = new spell
+ for(var/obj/effect/proc_holder/spell/knownspell in user.spell_list)
+ if(knownspell.type == S.type)
+ if(user.mind)
+ if(user.mind.special_role == "apprentice" || user.mind.special_role == "wizard")
+ user <<"\blue You're already far more versed in this spell than this flimsy how-to book can provide."
+ else
+ user <<"\blue You've already read this one."
+ return
+ user.spell_list += S
+ user <<"\blue you rapidly read through the arcane book. Suddenly it vanishes and you realize you understand [spellname]!"
+ del (src)
+
+/obj/item/weapon/spellbook/oneuse/attackby()
+ return
+
+/obj/item/weapon/spellbook/oneuse/fireball
+ spell = /obj/effect/proc_holder/spell/dumbfire/fireball
+ spellname = "fireball"
+ icon_state ="book2"
+ desc = "This book feels warm to the touch."
+
+/obj/item/weapon/spellbook/oneuse/smoke
+ spell = /obj/effect/proc_holder/spell/targeted/smoke
+ spellname = "smoke"
+ icon_state ="book5"
+ desc = "This book is overflowing with the dank arts."
+
+/obj/item/weapon/spellbook/oneuse/blind
+ spell = /obj/effect/proc_holder/spell/targeted/trigger/blind
+ spellname = "blind"
+ icon_state ="book1"
+ desc = "This book looks blurry, no matter how you look at it."
+
+/obj/item/weapon/spellbook/oneuse/mindswap
+ spell = /obj/effect/proc_holder/spell/targeted/mind_transfer
+ spellname = "mindswap"
+ icon_state ="book6"
+ desc = "This book's cover is pristine, though its pages look ragged and torn."
+
+/obj/item/weapon/spellbook/oneuse/forcewall
+ spell = /obj/effect/proc_holder/spell/aoe_turf/conjure/forcewall
+ spellname = "forcewall"
+ icon_state ="book4"
+ desc = "This book has a dedication to mimes everywhere inside the front cover."
+
+/obj/item/weapon/spellbook/oneuse/knock
+ spell = /obj/effect/proc_holder/spell/aoe_turf/knock
+ spellname = "knock"
+ icon_state ="book7"
+ desc = "This book is hard to hold closed properly."
+
+/obj/item/weapon/spellbook/oneuse/horsemask
+ spell = /obj/effect/proc_holder/spell/targeted/horsemask
+ spellname = "horses"
+ icon_state ="book3"
+ desc = "This book is more horse than your mind has room for."
+
+/obj/item/weapon/spellbook/oneuse/charge
+ spell = /obj/effect/proc_holder/spell/targeted/charge
+ spellname = "charging"
+ icon_state ="bookInfections"
+ desc = "This book is made of 100% post-consumer wizard."
\ No newline at end of file
diff --git a/code/game/machinery/recharger.dm b/code/game/machinery/recharger.dm
index 4968f427ea2..11668d874c5 100644
--- a/code/game/machinery/recharger.dm
+++ b/code/game/machinery/recharger.dm
@@ -25,8 +25,6 @@
if (istype(G, /obj/item/weapon/gun/energy/gun/nuclear) || istype(G, /obj/item/weapon/gun/energy/crossbow))
user << "Your gun's recharge port was removed to make room for a miniaturized reactor."
return
- if (istype(G, /obj/item/weapon/gun/energy/staff))
- return
user.drop_item()
G.loc = src
charging = G
diff --git a/code/game/machinery/turrets.dm b/code/game/machinery/turrets.dm
index 39da02b0e1d..2316f12f45a 100644
--- a/code/game/machinery/turrets.dm
+++ b/code/game/machinery/turrets.dm
@@ -219,7 +219,7 @@
if(3)
A = new /obj/item/projectile/beam/pulse( loc )
if(4)
- A = new /obj/item/projectile/change( loc )
+ A = new /obj/item/projectile/magic/change( loc )
if(5)
A = new /obj/item/projectile/bluetag( loc )
if(6)
diff --git a/code/modules/projectiles/guns/energy/special.dm b/code/modules/projectiles/guns/energy/special.dm
index 6b0d70beece..c1ed4531c26 100644
--- a/code/modules/projectiles/guns/energy/special.dm
+++ b/code/modules/projectiles/guns/energy/special.dm
@@ -26,55 +26,6 @@
charge_cost = 100
projectile_type = "/obj/item/projectile/energy/declone"
-obj/item/weapon/gun/energy/staff
- name = "staff of change"
- desc = "An artefact that spits bolts of coruscating energy which cause the target's very form to reshape itself"
- icon = 'icons/obj/gun.dmi'
- icon_state = "staffofchange"
- item_state = "staffofchange"
- fire_sound = 'sound/weapons/emitter.ogg'
- flags = FPRINT | TABLEPASS | CONDUCT
- slot_flags = SLOT_BACK
- w_class = 5
- charge_cost = 200
- projectile_type = "/obj/item/projectile/change"
- origin_tech = null
- clumsy_check = 0
- var/charge_tick = 0
-
-
- New()
- ..()
- processing_objects.Add(src)
-
-
- Del()
- processing_objects.Remove(src)
- ..()
-
-
- process()
- charge_tick++
- if(charge_tick < 4) return 0
- charge_tick = 0
- if(!power_supply) return 0
- power_supply.give(200)
- return 1
-
- update_icon()
- return
-
- shoot_with_empty_chamber(mob/living/user as mob|obj)
- user << "The [name] whizzles quietly."
- return
-
-/obj/item/weapon/gun/energy/staff/animate
- name = "staff of animation"
- desc = "An artefact that spits bolts of life-force which causes objects which are hit by it to animate and come to life! This magic doesn't affect machines."
- projectile_type = "/obj/item/projectile/animate"
- icon_state = "staffofanimation"
- item_state = "staffofanimation"
-
/obj/item/weapon/gun/energy/floragun
name = "floral somatoray"
desc = "A tool that discharges controlled radiation which induces mutation in plant cells."
diff --git a/code/modules/projectiles/guns/magic.dm b/code/modules/projectiles/guns/magic.dm
new file mode 100644
index 00000000000..c719bd4f663
--- /dev/null
+++ b/code/modules/projectiles/guns/magic.dm
@@ -0,0 +1,56 @@
+/obj/item/weapon/gun/magic
+ name = "staff of nothing"
+ desc = "This staff is boring to watch because even though it came first you've seen everything it can do in other staves for years."
+ icon = 'icons/obj/gun.dmi'
+ icon_state = "staffofchange"
+ item_state = "staffofchange"
+ fire_sound = 'sound/weapons/emitter.ogg'
+ flags = FPRINT | TABLEPASS | CONDUCT
+ w_class = 5
+ var/projectile_type = "/obj/item/projectile/magic"
+ var/max_charges = 6
+ var/charges = 0
+ var/recharge_rate = 4
+ var/charge_tick = 0
+ var/can_charge = 1
+ origin_tech = null
+ clumsy_check = 0
+
+/obj/item/weapon/gun/magic/emp_act(severity)
+ return
+
+/obj/item/weapon/gun/magic/process_chambered()
+ if(in_chamber) return 1
+ if(!charges) return 0
+ if(!projectile_type) return 0
+ in_chamber = new projectile_type(src)
+ return 1
+
+/obj/item/weapon/gun/magic/afterattack()
+ ..()
+ if(charges ) charges--
+
+/obj/item/weapon/gun/magic/New()
+ ..()
+ charges = max_charges
+ if(can_charge) processing_objects.Add(src)
+
+
+/obj/item/weapon/gun/magic/Del()
+ if(can_charge) processing_objects.Remove(src)
+ ..()
+
+
+/obj/item/weapon/gun/magic/process()
+ charge_tick++
+ if(charge_tick < recharge_rate || charges >= max_charges) return 0
+ charge_tick = 0
+ charges++
+ return 1
+
+/obj/item/weapon/gun/magic/update_icon()
+ return
+
+/obj/item/weapon/gun/magic/shoot_with_empty_chamber(mob/living/user as mob|obj)
+ user << "The [name] whizzles quietly."
+ return
\ No newline at end of file
diff --git a/code/modules/projectiles/guns/magic/staff.dm b/code/modules/projectiles/guns/magic/staff.dm
new file mode 100644
index 00000000000..cff5d6e603d
--- /dev/null
+++ b/code/modules/projectiles/guns/magic/staff.dm
@@ -0,0 +1,23 @@
+obj/item/weapon/gun/magic/staff/change
+ name = "staff of change"
+ desc = "An artefact that spits bolts of coruscating energy which cause the target's very form to reshape itself"
+ projectile_type = "/obj/item/projectile/magic/change"
+ icon_state = "staffofchange"
+ item_state = "staffofchange"
+ slot_flags = SLOT_BACK
+
+obj/item/weapon/gun/magic/staff/animate
+ name = "staff of animation"
+ desc = "An artefact that spits bolts of life-force which causes objects which are hit by it to animate and come to life! This magic doesn't affect machines."
+ projectile_type = "/obj/item/projectile/magic/animate"
+ icon_state = "staffofanimation"
+ item_state = "staffofanimation"
+ slot_flags = SLOT_BACK
+
+obj/item/weapon/gun/magic/staff/healing
+ name = "staff of healing"
+ desc = "An artefact that spits bolts of restoring magic which can remove ailments of all kinds and even raise the dead."
+ projectile_type = "/obj/item/projectile/magic/resurrection"
+ icon_state = "staffofanimation"
+ item_state = "staffofanimation"
+ slot_flags = SLOT_BACK
\ No newline at end of file
diff --git a/code/modules/projectiles/guns/magic/wand.dm b/code/modules/projectiles/guns/magic/wand.dm
new file mode 100644
index 00000000000..479e1fda0c7
--- /dev/null
+++ b/code/modules/projectiles/guns/magic/wand.dm
@@ -0,0 +1,227 @@
+/obj/item/weapon/gun/magic/wand/
+ name = "wand of nothing"
+ desc = "It's not just a stick, it's a MAGIC stick!"
+ projectile_type = "/obj/item/projectile/magic"
+ icon_state = "staffofanimation"
+ item_state = "staffofanimation"
+ w_class = 2
+ can_charge = 0
+ max_charges = 100 //100, 50, 50, 34 (max charge distribution by 25%ths)
+ w_class = 2
+
+/obj/item/weapon/gun/magic/wand/New()
+ if(prob(75)) //25% chance of listed max charges, 50% chance of 1/2 max charges, 25% chance of 1/3 max charges
+ if(prob(33))
+ max_charges = Ceiling(max_charges / 3)
+ else
+ max_charges = Ceiling(max_charges / 2)
+ ..()
+
+/obj/item/weapon/gun/magic/wand/examine()
+ ..()
+ usr << "Has [charges] charge\s remaining."
+ return
+
+/obj/item/weapon/gun/magic/wand/attack_self(mob/living/user as mob)
+ if(charges)
+ zap_self(user)
+ else
+ user << "The [name] whizzles quietly."
+ ..()
+
+/obj/item/weapon/gun/magic/wand/proc/zap_self(mob/living/user as mob)
+ user.visible_message("\blue [user] zaps \himself with [src]!")
+
+/obj/item/weapon/gun/magic/wand/death
+ name = "wand of death"
+ desc = "This deadly wand overwhelms the victim's body with pure energy, slaying them without fail."
+ projectile_type = "/obj/item/projectile/magic/death"
+ icon_state = "staffofanimation"
+ item_state = "staffofanimation"
+ max_charges = 3 //3, 2, 2, 1
+
+/obj/item/weapon/gun/magic/wand/death/zap_self(mob/living/user as mob)
+ if(alert(user, "You really want to zap yourself with the wand of death?",, "Yes", "No") == "Yes" && charges && user.get_active_hand() == src && isliving(user))
+ var/message ="\red You irradiate yourself with pure energy! "
+ message += pick("Do not pass go. Do not collect 200 zorkmids.","You feel more confident in your spell casting skills.","You Die...","Do you want your possessions identified?")
+ user << message
+ user.adjustOxyLoss(500)
+ charges--
+ ..()
+
+/obj/item/weapon/gun/magic/wand/resurrection
+ name = "wand of resurrection"
+ desc = "This wand uses healing magics to heal and revive. They are rarely utilized within the Wizard Federation for some reason."
+ projectile_type = "/obj/item/projectile/magic/resurrection"
+ icon_state = "staffofanimation"
+ item_state = "staffofanimation"
+ max_charges = 3 //3, 2, 2, 1
+
+/obj/item/weapon/gun/magic/wand/resurrection/zap_self(mob/living/user as mob)
+ user.setToxLoss(0)
+ user.setOxyLoss(0)
+ user.setCloneLoss(0)
+ user.SetParalysis(0)
+ user.SetStunned(0)
+ user.SetWeakened(0)
+ user.radiation = 0
+ user.heal_overall_damage(user.getBruteLoss(), user.getFireLoss())
+ user.reagents.clear_reagents()
+ user << "You feel great!"
+ charges--
+ ..()
+
+/obj/item/weapon/gun/magic/wand/polymorph
+ name = "wand of polymorph"
+ desc = "This wand inflicts is attuned to chaos and will radically alter the victim's form."
+ projectile_type = "/obj/item/projectile/magic/change"
+ icon_state = "staffofanimation"
+ item_state = "staffofanimation"
+ max_charges = 10 //10, 5, 5, 4
+
+/obj/item/weapon/gun/magic/wand/polymorph/zap_self(mob/living/user as mob)
+ if(alert(user, "Your new form might not have arms to zap with... Continue?",, "Yes", "No") == "Yes" && charges && user.get_active_hand() == src && isliving(user))
+ if(user.monkeyizing) return
+ user.monkeyizing = 1
+ user.canmove = 0
+ user.icon = null
+ user.overlays.Cut()
+ user.invisibility = 101
+ for(var/obj/item/W in user)
+ if(istype(W, /obj/item/weapon/implant)) //TODO: Carn. give implants a dropped() or something
+ del(W)
+ continue
+ W.layer = initial(W.layer)
+ W.loc = user.loc
+ W.dropped(user)
+
+ var/mob/living/new_mob
+
+ var/randomize = pick("monkey","robot","slime","xeno","human","animal")
+ switch(randomize)
+ if("monkey")
+ new_mob = new /mob/living/carbon/monkey(user.loc)
+ new_mob.universal_speak = 1
+ if("robot")
+ new_mob = new /mob/living/silicon/robot(user.loc)
+ new_mob.gender = user.gender
+ new_mob.invisibility = 0
+ new_mob.job = "Cyborg"
+ var/mob/living/silicon/robot/Robot = new_mob
+ Robot.mmi = new /obj/item/device/mmi(new_mob)
+ Robot.mmi.transfer_identity(user) //Does not transfer key/client.
+ if("slime")
+ if(prob(50)) new_mob = new /mob/living/carbon/slime/adult(user.loc)
+ else new_mob = new /mob/living/carbon/slime(user.loc)
+ new_mob.universal_speak = 1
+ if("xeno")
+ if(prob(50))
+ new_mob = new /mob/living/carbon/alien/humanoid/hunter(user.loc)
+ else
+ new_mob = new /mob/living/carbon/alien/humanoid/sentinel(user.loc)
+ new_mob.universal_speak = 1
+ if("animal")
+ var/animal = pick("parrot","corgi","crab","pug","cat","carp","bear","mushroom","tomato","mouse","chicken","cow","lizard","chick")
+ switch(animal)
+ if("parrot") new_mob = new /mob/living/simple_animal/parrot(user.loc)
+ if("corgi") new_mob = new /mob/living/simple_animal/corgi(user.loc)
+ if("crab") new_mob = new /mob/living/simple_animal/crab(user.loc)
+ if("pug") new_mob = new /mob/living/simple_animal/pug(user.loc)
+ if("cat") new_mob = new /mob/living/simple_animal/cat(user.loc)
+ if("carp") new_mob = new /mob/living/simple_animal/hostile/carp(user.loc)
+ if("bear") new_mob = new /mob/living/simple_animal/hostile/bear(user.loc)
+ if("mushroom") new_mob = new /mob/living/simple_animal/mushroom(user.loc)
+ if("tomato") new_mob = new /mob/living/simple_animal/tomato(user.loc)
+ if("mouse") new_mob = new /mob/living/simple_animal/mouse(user.loc)
+ if("chicken") new_mob = new /mob/living/simple_animal/chicken(user.loc)
+ if("cow") new_mob = new /mob/living/simple_animal/cow(user.loc)
+ if("lizard") new_mob = new /mob/living/simple_animal/lizard(user.loc)
+ else new_mob = new /mob/living/simple_animal/chick(user.loc)
+ new_mob.universal_speak = 1
+ if("human")
+ new_mob = new /mob/living/carbon/human(user.loc)
+
+ var/datum/preferences/A = new() //Randomize appearance for the human
+ A.copy_to(new_mob)
+
+ var/mob/living/carbon/human/H = new_mob
+ ready_dna(H)
+ if(H.dna)
+ H.dna.mutantrace = pick("lizard","golem","slime","plant","fly","shadow","adamantine","skeleton",8;"")
+ H.update_body()
+ else
+ return
+
+ for (var/obj/effect/proc_holder/spell/S in user.spell_list)
+ new_mob.spell_list += new S.type
+
+ new_mob.a_intent = "harm"
+ if(user.mind)
+ user.mind.transfer_to(new_mob)
+ else
+ new_mob.key = user.key
+
+ new_mob << "Your form morphs into that of a [randomize]."
+
+ del(user)
+ return new_mob
+ charges--
+ ..()
+
+/obj/item/weapon/gun/magic/wand/teleport
+ name = "wand of teleportation"
+ desc = "This wand will wrench targets through space and time to move them somewhere else."
+ projectile_type = "/obj/item/projectile/magic/teleport"
+ icon_state = "staffofanimation"
+ item_state = "staffofanimation"
+ max_charges = 10 //10, 5, 5, 4
+
+/obj/item/weapon/gun/magic/wand/teleport/zap_self(mob/living/user as mob)
+ var/list/turfs = new/list()
+ var/inner_tele_radius = 0
+ var/outer_tele_radius = 6
+ for(var/turf/T in range(user,outer_tele_radius))
+ if(T in range(user,inner_tele_radius)) continue
+ if(T.x>world.maxx-outer_tele_radius || T.xworld.maxy-outer_tele_radius || T.yYou feel great!"
+ else
+ target << "You rise with a start, you're alive!!!"
+
+/obj/item/projectile/magic/teleport
+ name = "bolt of teleportation"
+ icon_state = "bluespace"
+ damage = 0
+ damage_type = OXY
+ nodamage = 1
+ flag = "magic"
+ var/inner_tele_radius = 0
+ var/outer_tele_radius = 6
+
+/obj/item/projectile/magic/teleport/on_hit(var/mob/target)
+ if(isturf(target))
+ return
+
+ var/list/turfs = new/list()
+ for(var/turf/T in range(target,outer_tele_radius))
+ if(T in range(target,inner_tele_radius)) continue
+ if(T.x>world.maxx-outer_tele_radius || T.xworld.maxy-outer_tele_radius || T.yYour form morphs into that of a [randomize]."
+
+ del(M)
+ return new_mob
+
+/obj/item/projectile/magic/animate
+ name = "bolt of animation"
+ icon_state = "red_1"
+ damage = 0
+ damage_type = BURN
+ nodamage = 1
+ flag = "magic"
+
+/obj/item/projectile/magic/animate/Bump(var/atom/change)
+ . = ..()
+ if(istype(change, /obj/item) || istype(change, /obj/structure) && !is_type_in_list(change, protected_objects))
+ var/obj/O = change
+ new /mob/living/simple_animal/hostile/mimic/copy(O.loc, O, firer)
+ else if(istype(change, /mob/living/simple_animal/hostile/mimic/copy))
+ // Change our allegiance!
+ var/mob/living/simple_animal/hostile/mimic/copy/C = change
+ C.ChangeOwner(firer)
\ No newline at end of file
diff --git a/tgstation.dme b/tgstation.dme
index 5bd8184b7dd..cbbb0dab917 100644
--- a/tgstation.dme
+++ b/tgstation.dme
@@ -6,48 +6,6 @@
// BEGIN_FILE_DIR
#define FILE_DIR .
-#define FILE_DIR "html"
-#define FILE_DIR "icons"
-#define FILE_DIR "icons/ass"
-#define FILE_DIR "icons/effects"
-#define FILE_DIR "icons/mecha"
-#define FILE_DIR "icons/misc"
-#define FILE_DIR "icons/mob"
-#define FILE_DIR "icons/obj"
-#define FILE_DIR "icons/obj/assemblies"
-#define FILE_DIR "icons/obj/atmospherics"
-#define FILE_DIR "icons/obj/clothing"
-#define FILE_DIR "icons/obj/doors"
-#define FILE_DIR "icons/obj/flora"
-#define FILE_DIR "icons/obj/machines"
-#define FILE_DIR "icons/obj/pipes"
-#define FILE_DIR "icons/obj/power_cond"
-#define FILE_DIR "icons/pda_icons"
-#define FILE_DIR "icons/spideros_icons"
-#define FILE_DIR "icons/stamp_icons"
-#define FILE_DIR "icons/Testing"
-#define FILE_DIR "icons/turf"
-#define FILE_DIR "icons/vending_icons"
-#define FILE_DIR "nano"
-#define FILE_DIR "nano/images"
-#define FILE_DIR "sound"
-#define FILE_DIR "sound/AI"
-#define FILE_DIR "sound/ambience"
-#define FILE_DIR "sound/effects"
-#define FILE_DIR "sound/hallucinations"
-#define FILE_DIR "sound/items"
-#define FILE_DIR "sound/machines"
-#define FILE_DIR "sound/mecha"
-#define FILE_DIR "sound/misc"
-#define FILE_DIR "sound/piano"
-#define FILE_DIR "sound/violin"
-#define FILE_DIR "sound/voice"
-#define FILE_DIR "sound/voice/complionator"
-#define FILE_DIR "sound/vox_fem"
-#define FILE_DIR "sound/weapons"
-#define FILE_DIR "tools"
-#define FILE_DIR "tools/AddToChangelog"
-#define FILE_DIR "tools/AddToChangelog/AddToChangelog"
// END_FILE_DIR
// BEGIN_PREFERENCES
@@ -216,6 +174,7 @@
#include "code\datums\helper_datums\teleport.dm"
#include "code\datums\helper_datums\topic_input.dm"
#include "code\datums\spells\area_teleport.dm"
+#include "code\datums\spells\charge.dm"
#include "code\datums\spells\conjure.dm"
#include "code\datums\spells\construct_spells.dm"
#include "code\datums\spells\dumbfire.dm"
@@ -1122,6 +1081,7 @@
#include "code\modules\projectiles\ammunition\bullets.dm"
#include "code\modules\projectiles\ammunition\magazines.dm"
#include "code\modules\projectiles\guns\energy.dm"
+#include "code\modules\projectiles\guns\magic.dm"
#include "code\modules\projectiles\guns\projectile.dm"
#include "code\modules\projectiles\guns\energy\laser.dm"
#include "code\modules\projectiles\guns\energy\nuclear.dm"
@@ -1129,15 +1089,16 @@
#include "code\modules\projectiles\guns\energy\special.dm"
#include "code\modules\projectiles\guns\energy\stun.dm"
#include "code\modules\projectiles\guns\energy\temperature.dm"
+#include "code\modules\projectiles\guns\magic\staff.dm"
+#include "code\modules\projectiles\guns\magic\wand.dm"
#include "code\modules\projectiles\guns\projectile\automatic.dm"
#include "code\modules\projectiles\guns\projectile\pistol.dm"
#include "code\modules\projectiles\guns\projectile\revolver.dm"
#include "code\modules\projectiles\guns\projectile\shotgun.dm"
-#include "code\modules\projectiles\projectile\animate.dm"
#include "code\modules\projectiles\projectile\beams.dm"
#include "code\modules\projectiles\projectile\bullets.dm"
-#include "code\modules\projectiles\projectile\change.dm"
#include "code\modules\projectiles\projectile\energy.dm"
+#include "code\modules\projectiles\projectile\magic.dm"
#include "code\modules\projectiles\projectile\special.dm"
#include "code\modules\reagents\Chemistry-Colours.dm"
#include "code\modules\reagents\Chemistry-Holder.dm"