diff --git a/code/datums/spells/charge.dm b/code/datums/spells/charge.dm new file mode 100644 index 00000000000..342e11049eb --- /dev/null +++ b/code/datums/spells/charge.dm @@ -0,0 +1,82 @@ +/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 + 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 <<"you feel raw magic flowing through you, it feels good!" + else + M <<"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/spellbook/oneuse)) + var/obj/item/weapon/spellbook/oneuse/I = item + if(prob(80)) + user.visible_message("[I] catches fire!") + del(I) + else + I.used = 0 + charged_item = I + 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 << "you feel magical power surging to your hands, but the feeling rapidly fades..." + else if(burnt_out) + user << "[charged_item] doesn't seem to be reacting to the spell..." + else + user << "[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..891a2dbff7c 100644 --- a/code/game/gamemodes/wizard/rightandwrong.dm +++ b/code/game/gamemodes/wizard/rightandwrong.dm @@ -1,11 +1,12 @@ -/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 + if(H.mind) + if(H.mind.special_role == "Wizard" || H.mind.special_role == "apprentice") continue if(prob(25)) ticker.mode.traitors += H.mind H.mind.special_role = "traitor" @@ -18,46 +19,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..36417f0bd36 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,153 @@ 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" + var/used = 0 + 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 <<"You're already far more versed in this spell than this flimsy how-to book can provide." + else + user <<"You've already read this one." + return + if(used) + recoil(user) + else + user.spell_list += S + user <<"you rapidly read through the arcane book. Suddenly you realize you understand [spellname]!" + onlearned(user) + +/obj/item/weapon/spellbook/oneuse/proc/recoil(mob/user as mob) + user.visible_message("[src] glows in a black light!") + +/obj/item/weapon/spellbook/oneuse/proc/onlearned(mob/user as mob) + used = 1 + user.visible_message("[src] glows dark for a second!") + +/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 ="bookfireball" + desc = "This book feels warm to the touch." + +/obj/item/weapon/spellbook/oneuse/fireball/recoil(mob/user as mob) + ..() + explosion(user.loc, -1, 0, 2, 3, 0, flame_range = 2) + del(src) + +/obj/item/weapon/spellbook/oneuse/smoke + spell = /obj/effect/proc_holder/spell/targeted/smoke + spellname = "smoke" + icon_state ="booksmoke" + desc = "This book is overflowing with the dank arts." + +/obj/item/weapon/spellbook/oneuse/smoke/recoil(mob/user as mob) + ..() + user <<"Your stomach rumbles..." + if(user.nutrition) + user.nutrition -= 200 + if(user.nutrition <= 0) + user.nutrition = 0 + +/obj/item/weapon/spellbook/oneuse/blind + spell = /obj/effect/proc_holder/spell/targeted/trigger/blind + spellname = "blind" + icon_state ="bookblind" + desc = "This book looks blurry, no matter how you look at it." + +/obj/item/weapon/spellbook/oneuse/blind/recoil(mob/user as mob) + ..() + user <<"You go blind!" + user.eye_blind = 10 + +/obj/item/weapon/spellbook/oneuse/mindswap + spell = /obj/effect/proc_holder/spell/targeted/mind_transfer + spellname = "mindswap" + icon_state ="bookmindswap" + desc = "This book's cover is pristine, though its pages look ragged and torn." + +/obj/item/weapon/spellbook/oneuse/mindswap/onlearned() + spellname = pick("fireball","smoke","blind","forcewall","knock","horses","charge") + icon_state = "book[spellname]" + name = "spellbook of [spellname]" //Note, desc doesn't change by design + ..() + +/obj/item/weapon/spellbook/oneuse/mindswap/recoil(mob/user as mob) + ..() + user <<"You suddenly don't feel like yourself!" + wabbajack(user) + +/obj/item/weapon/spellbook/oneuse/forcewall + spell = /obj/effect/proc_holder/spell/aoe_turf/conjure/forcewall + spellname = "forcewall" + icon_state ="bookforcewall" + desc = "This book has a dedication to mimes everywhere inside the front cover." + +/obj/item/weapon/spellbook/oneuse/forcewall/recoil(mob/user as mob) + ..() + user <<"You suddenly feel very solid!" + var/obj/structure/closet/statue/S = new /obj/structure/closet/statue(user.loc, user) + S.timer = 30 + user.drop_item() + + +/obj/item/weapon/spellbook/oneuse/knock + spell = /obj/effect/proc_holder/spell/aoe_turf/knock + spellname = "knock" + icon_state ="bookknock" + desc = "This book is hard to hold closed properly." + +/obj/item/weapon/spellbook/oneuse/knock/recoil(mob/user as mob) + ..() + user <<"You're knocked down!" + user.Weaken(20) + +/obj/item/weapon/spellbook/oneuse/horsemask + spell = /obj/effect/proc_holder/spell/targeted/horsemask + spellname = "horses" + icon_state ="bookhorses" + desc = "This book is more horse than your mind has room for." + +/obj/item/weapon/spellbook/oneuse/horsemask/recoil(mob/living/carbon/user as mob) + if(istype(user, /mob/living/carbon/human)) + user <<"HOR-SIE HAS RISEN" + var/obj/item/clothing/mask/horsehead/magichead = new /obj/item/clothing/mask/horsehead + magichead.canremove = 0 //curses! + magichead.flags_inv = null //so you can still see their face + magichead.voicechange = 1 //NEEEEIIGHH + user.drop_from_inventory(user.wear_mask) + user.equip_to_slot_if_possible(magichead, slot_wear_mask, 1, 1) + del(src) + else + user <<"I say thee neigh" + +/obj/item/weapon/spellbook/oneuse/charge + spell = /obj/effect/proc_holder/spell/targeted/charge + spellname = "charging" + icon_state ="bookcharge" + desc = "This book is made of 100% post-consumer wizard." + +/obj/item/weapon/spellbook/oneuse/charge/recoil(mob/user as mob) + ..() + user <<"[src] suddenly feels very warm!" + empulse(src, 1, 1) \ 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/library/lib_items.dm b/code/modules/library/lib_items.dm index e3b03bad0cb..4c04ea6ce13 100644 --- a/code/modules/library/lib_items.dm +++ b/code/modules/library/lib_items.dm @@ -60,7 +60,7 @@ state = 0 if(2) - if(istype(I, /obj/item/weapon/book)) + if(istype(I, /obj/item/weapon/book) || istype(I, /obj/item/weapon/spellbook)) user.drop_item() I.loc = src update_icon() 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..b5146ca47ed --- /dev/null +++ b/code/modules/projectiles/guns/magic.dm @@ -0,0 +1,53 @@ +/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 = "staffofnothing" + item_state = "staff" + 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/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(atom/target as mob, mob/living/user as mob, flag) + ..() + if(charges && !in_chamber && !flag) 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..dd38641e184 --- /dev/null +++ b/code/modules/projectiles/guns/magic/staff.dm @@ -0,0 +1,23 @@ +obj/item/weapon/gun/magic/staff/ + slot_flags = SLOT_BACK + +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" + +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" + +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 = "staffofhealing" + item_state = "staffofhealing" diff --git a/code/modules/projectiles/guns/magic/wand.dm b/code/modules/projectiles/guns/magic/wand.dm new file mode 100644 index 00000000000..1bfc24b7ba2 --- /dev/null +++ b/code/modules/projectiles/guns/magic/wand.dm @@ -0,0 +1,119 @@ +/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 = "wand6" + item_state = "wand" + w_class = 2 + can_charge = 0 + max_charges = 100 //100, 50, 50, 34 (max charge distribution by 25%ths) + var/variable_charges = 1 + +/obj/item/weapon/gun/magic/wand/New() + if(prob(75) && variable_charges) //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(atom/target as mob, mob/living/user as mob) + if(target == user) + return + ..() + +/obj/item/weapon/gun/magic/wand/afterattack(atom/target as mob, mob/living/user as mob) + if(target == user) + if(charges) + zap_self(user) + else + user << "The [name] whizzles quietly." + else + ..() + +/obj/item/weapon/gun/magic/wand/proc/zap_self(mob/living/user as mob) + user.visible_message("[user] zaps \himself with [src]!") + playsound(user, fire_sound, 50, 1) + user.attack_log += "\[[time_stamp()]\] [user]/[user.ckey] zapped \himself with a [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 = "wand4" + max_charges = 3 //3, 2, 2, 1 + +/obj/item/weapon/gun/magic/wand/death/zap_self(mob/living/user as mob) + var/message ="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 = "wand1" + max_charges = 3 //3, 2, 2, 1 + +/obj/item/weapon/gun/magic/wand/resurrection/zap_self(mob/living/user as mob) + user.revive() + user << "You feel great!" + charges-- + ..() + +/obj/item/weapon/gun/magic/wand/polymorph + name = "wand of polymorph" + desc = "This wand is attuned to chaos and will radically alter the victim's form." + projectile_type = "/obj/item/projectile/magic/change" + icon_state = "wand5" + max_charges = 10 //10, 5, 5, 4 + +/obj/item/weapon/gun/magic/wand/polymorph/zap_self(mob/living/user as mob) + ..() //because the user mob ceases to exists by the time wabbajack fully resolves + wabbajack(user) + 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 = "wand3" + max_charges = 10 //10, 5, 5, 4 + +/obj/item/weapon/gun/magic/wand/teleport/zap_self(mob/living/user as mob) + do_teleport(user, user, 10) + var/datum/effect/effect/system/harmless_smoke_spread/smoke = new /datum/effect/effect/system/harmless_smoke_spread() + smoke.set_up(10, 0, user.loc) + smoke.start() + charges-- + ..() + +/obj/item/weapon/gun/magic/wand/door + name = "wand of door creation" + desc = "This particular wand can create doors in any wall for the unscrupulous wizard who shuns teleportation magics." + projectile_type = "/obj/item/projectile/magic/door" + icon_state = "wand0" + max_charges = 20 //20, 10, 10, 7 + +/obj/item/weapon/gun/magic/wand/door/zap_self() + return + +/obj/item/weapon/gun/magic/wand/fireball + name = "wand of fireball" + desc = "This wand shoots scorching balls of fire that explode into destructive flames." + projectile_type = "/obj/item/projectile/magic/fireball" + icon_state = "wand2" + max_charges = 8 //8, 4, 4, 3 + +/obj/item/weapon/gun/magic/wand/fireball/zap_self(mob/living/user as mob) + explosion(user.loc, -1, 0, 2, 3, 0, flame_range = 2) + charges-- + ..() \ No newline at end of file diff --git a/code/modules/projectiles/projectile/magic.dm b/code/modules/projectiles/projectile/magic.dm new file mode 100644 index 00000000000..bec53531f8b --- /dev/null +++ b/code/modules/projectiles/projectile/magic.dm @@ -0,0 +1,223 @@ +/obj/item/projectile/magic + name = "bolt of nothing" + icon_state = "energy" + damage = 0 + damage_type = OXY + nodamage = 1 + flag = "magic" + +/obj/item/projectile/magic/death + name = "bolt of death" + icon_state = "pulse1_bl" + damage = 9001 + damage_type = OXY + nodamage = 0 + flag = "magic" + +/obj/item/projectile/magic/fireball + name = "bolt of fireball" + icon_state = "fireball" + damage = 25 //The spell fireball additionally does 20 burn, so the wand fireball is marginally less painful + damage_type = BRUTE + nodamage = 0 + flag = "magic" + +/obj/item/projectile/magic/fireball/on_hit(var/target) + var/turf/T = get_turf(target) + explosion(T, -1, 0, 2, 3, 0, flame_range = 2) + +/obj/item/projectile/magic/resurrection + name = "bolt of resurrection" + icon_state = "ion" + damage = 0 + damage_type = OXY + nodamage = 1 + flag = "magic" + +/obj/item/projectile/magic/resurrection/on_hit(var/mob/living/carbon/target) + + if(istype(target,/mob)) + var/old_stat = target.stat + target.revive() + target.suiciding = 0 + if(!target.ckey) + for(var/mob/dead/observer/ghost in player_list) + if(target.real_name == ghost.real_name) + ghost.reenter_corpse() + break + if(old_stat != DEAD) + target << "You 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) + var/teleammount = 0 + var/teleloc = target + if(!isturf(target)) + teleloc = target.loc + for(var/atom/movable/stuff in teleloc) + if(!stuff.anchored && stuff.loc) + teleammount++ + do_teleport(stuff, stuff, 10) + var/datum/effect/effect/system/harmless_smoke_spread/smoke = new /datum/effect/effect/system/harmless_smoke_spread() + smoke.set_up(max(round(10 - teleammount),1), 0, stuff.loc) //Smoke drops off if a lot of stuff is moved for the sake of sanity + smoke.start() + +/obj/item/projectile/magic/door + name = "bolt of door creation" + icon_state = "energy" + damage = 0 + damage_type = OXY + nodamage = 1 + flag = "magic" + +/obj/item/projectile/magic/door/on_hit(var/atom/target) + var/atom/T = target.loc + if(isturf(target)) + if(target.density) + new /obj/structure/mineral_door/wood(target) + target:ChangeTurf(/turf/simulated/floor/plating) + else if (isturf(T)) + if(T.density) + new /obj/structure/mineral_door/wood(T) + T:ChangeTurf(/turf/simulated/floor/plating) + +/obj/item/projectile/magic/change + name = "bolt of change" + icon_state = "ice_1" + damage = 0 + damage_type = BURN + nodamage = 1 + flag = "magic" + +/obj/item/projectile/magic/change/on_hit(var/atom/change) + wabbajack(change) + +proc/wabbajack(mob/living/M) + if(istype(M)) + if(istype(M, /mob/living) && M.stat != DEAD) + if(M.monkeyizing) return + M.monkeyizing = 1 + M.canmove = 0 + M.icon = null + M.overlays.Cut() + M.invisibility = 101 + + if(istype(M, /mob/living/silicon/robot)) + var/mob/living/silicon/robot/Robot = M + if(Robot.mmi) del(Robot.mmi) + else + for(var/obj/item/W in M) + 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 = M.loc + W.dropped(M) + + 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(M.loc) + new_mob.universal_speak = 1 + if("robot") + new_mob = new /mob/living/silicon/robot(M.loc) + new_mob.gender = M.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(M) //Does not transfer key/client. + if("slime") + if(prob(50)) new_mob = new /mob/living/carbon/slime/adult(M.loc) + else new_mob = new /mob/living/carbon/slime(M.loc) + new_mob.universal_speak = 1 + if("xeno") + if(prob(50)) + new_mob = new /mob/living/carbon/alien/humanoid/hunter(M.loc) + else + new_mob = new /mob/living/carbon/alien/humanoid/sentinel(M.loc) + new_mob.universal_speak = 1 + + /*var/alien_caste = pick("Hunter","Sentinel","Drone","Larva") + switch(alien_caste) + if("Hunter") new_mob = new /mob/living/carbon/alien/humanoid/hunter(M.loc) + if("Sentinel") new_mob = new /mob/living/carbon/alien/humanoid/sentinel(M.loc) + if("Drone") new_mob = new /mob/living/carbon/alien/humanoid/drone(M.loc) + else new_mob = new /mob/living/carbon/alien/larva(M.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(M.loc) + if("corgi") new_mob = new /mob/living/simple_animal/corgi(M.loc) + if("crab") new_mob = new /mob/living/simple_animal/crab(M.loc) + if("pug") new_mob = new /mob/living/simple_animal/pug(M.loc) + if("cat") new_mob = new /mob/living/simple_animal/cat(M.loc) + if("carp") new_mob = new /mob/living/simple_animal/hostile/carp(M.loc) + if("bear") new_mob = new /mob/living/simple_animal/hostile/bear(M.loc) + if("mushroom") new_mob = new /mob/living/simple_animal/mushroom(M.loc) + if("tomato") new_mob = new /mob/living/simple_animal/tomato(M.loc) + if("mouse") new_mob = new /mob/living/simple_animal/mouse(M.loc) + if("chicken") new_mob = new /mob/living/simple_animal/chicken(M.loc) + if("cow") new_mob = new /mob/living/simple_animal/cow(M.loc) + if("lizard") new_mob = new /mob/living/simple_animal/lizard(M.loc) + else new_mob = new /mob/living/simple_animal/chick(M.loc) + new_mob.universal_speak = 1 + if("human") + new_mob = new /mob/living/carbon/human(M.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 M.spell_list) + new_mob.spell_list += new S.type + + new_mob.a_intent = "harm" + if(M.mind) + M.mind.transfer_to(new_mob) + else + new_mob.key = M.key + + new_mob << "Your 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/icons/mob/back.dmi b/icons/mob/back.dmi index f48b9281daa..32bfa869468 100644 Binary files a/icons/mob/back.dmi and b/icons/mob/back.dmi differ diff --git a/icons/mob/items_lefthand.dmi b/icons/mob/items_lefthand.dmi index 0e3993dfd06..8489d84c792 100644 Binary files a/icons/mob/items_lefthand.dmi and b/icons/mob/items_lefthand.dmi differ diff --git a/icons/mob/items_righthand.dmi b/icons/mob/items_righthand.dmi index 97a9cff6b32..cbb4183793f 100644 Binary files a/icons/mob/items_righthand.dmi and b/icons/mob/items_righthand.dmi differ diff --git a/icons/obj/gun.dmi b/icons/obj/gun.dmi index 53237188526..98283e0ee84 100644 Binary files a/icons/obj/gun.dmi and b/icons/obj/gun.dmi differ diff --git a/icons/obj/library.dmi b/icons/obj/library.dmi index c59263e514b..e5f084762af 100644 Binary files a/icons/obj/library.dmi and b/icons/obj/library.dmi differ diff --git a/tgstation.dme b/tgstation.dme index e37f31b61a0..cbbb0dab917 100644 --- a/tgstation.dme +++ b/tgstation.dme @@ -174,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" @@ -1080,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" @@ -1087,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"