diff --git a/code/datums/spells/charge.dm b/code/datums/spells/charge.dm index 6594ead232f..b4603f5e6b1 100644 --- a/code/datums/spells/charge.dm +++ b/code/datums/spells/charge.dm @@ -42,7 +42,7 @@ break else if(istype(item, /obj/item/weapon/gun/magic)) var/obj/item/weapon/gun/magic/I = item - if(prob(80)) + if(prob(80) && !I.can_charge) I.max_charges-- if(I.max_charges <= 0) I.max_charges = 0 diff --git a/code/datums/spells/horsemask.dm b/code/datums/spells/horsemask.dm index 9766d356232..b04969d2d98 100644 --- a/code/datums/spells/horsemask.dm +++ b/code/datums/spells/horsemask.dm @@ -22,11 +22,11 @@ return var/mob/living/carbon/target = targets[1] - + if(!target) return - if(!(target.type in compatible_mobs)) + if(target.type in compatible_mobs || ishuman(target)) user << "It'd be stupid to curse [target] with a horse's head!" return diff --git a/code/datums/spells/mind_transfer.dm b/code/datums/spells/mind_transfer.dm index c905bf88a97..389091da2c8 100644 --- a/code/datums/spells/mind_transfer.dm +++ b/code/datums/spells/mind_transfer.dm @@ -10,10 +10,6 @@ range = 1 cooldown_min = 200 //100 deciseconds reduction per rank var/list/protected_roles = list("Wizard","Changeling","Cultist") //which roles are immune to the spell - var/base_spell_loss_chance = 20 //base probability of the wizard losing a spell in the process - var/spell_loss_chance_modifier = 7 //amount of probability of losing a spell added per spell (mind_transfer included) - var/spell_loss_amount = 1 //the maximum amount of spells possible to lose during a single transfer - var/msg_wait = 500 //how long in deciseconds it waits before telling that body doesn't feel right or mind swap robbed of a spell var/paralysis_amount_caster = 20 //how much the caster is paralysed for after the spell var/paralysis_amount_victim = 20 //how much the victim is paralysed for after the spell icon_power_button = "spell_mind" @@ -53,27 +49,6 @@ Also, you never added distance checking after target is selected. I've went ahea var/mob/living/victim = target//The target of the spell whos body will be transferred to. var/mob/caster = user//The wizard/whomever doing the body transferring. - //SPELL LOSS BEGIN - //NOTE: The caster must ALWAYS keep mind transfer, even when other spells are lost. - var/obj/effect/proc_holder/spell/wizard/targeted/mind_transfer/m_transfer = locate() in user.spell_list//Find mind transfer directly. - var/list/checked_spells = user.spell_list - checked_spells -= m_transfer //Remove Mind Transfer from the list. - - if(caster.spell_list.len)//If they have any spells left over after mind transfer is taken out. If they don't, we don't need this. - for(var/i=spell_loss_amount,(i>0&&checked_spells.len),i--)//While spell loss amount is greater than zero and checked_spells has spells in it, run this proc. - for(var/j=checked_spells.len,(j>0&&checked_spells.len),j--)//While the spell list to check is greater than zero and has spells in it, run this proc. - if(prob(base_spell_loss_chance)) - checked_spells -= pick(checked_spells)//Pick a random spell to remove. - spawn(msg_wait) - victim << "The mind transfer has robbed you of a spell." - break//Spell lost. Break loop, going back to the previous for() statement. - else//Or keep checking, adding spell chance modifier to increase chance of losing a spell. - base_spell_loss_chance += spell_loss_chance_modifier - - checked_spells += m_transfer//Add back Mind Transfer. - user.spell_list = checked_spells//Set user spell list to whatever the new list is. - //SPELL LOSS END - //MIND TRANSFER BEGIN if(caster.mind.special_verbs.len)//If the caster had any special verbs, remove them from the mob verb list. for(var/V in caster.mind.special_verbs)//Since the caster is using an object spell system, this is mostly moot. @@ -105,7 +80,3 @@ Also, you never added distance checking after target is selected. I've went ahea //Here we paralyze both mobs and knock them out for a time. caster.Paralyse(paralysis_amount_caster) victim.Paralyse(paralysis_amount_victim) - - //After a certain amount of time the victim gets a message about being in a different body. - spawn(msg_wait) - caster << "\red You feel woozy and lightheaded. Your body doesn't seem like your own." diff --git a/code/game/gamemodes/wizard/rightandwrong.dm b/code/game/gamemodes/wizard/rightandwrong.dm index e1b0c7a65f3..b87d0de8b50 100644 --- a/code/game/gamemodes/wizard/rightandwrong.dm +++ b/code/game/gamemodes/wizard/rightandwrong.dm @@ -1,6 +1,9 @@ /mob/proc/rightandwrong(var/summon_type) //0 = Summon Guns, 1 = Summon Magic + var/list/gunslist = list("taser","egun","laser","revolver","detective","c20r","nuclear","deagle","gyrojet","pulse","silenced","cannon","doublebarrel","shotgun","combatshotgun","bulldog","mateba","sabr","crossbow","saw","car") + var/list/magiclist = list("fireball","smoke","blind","mindswap","forcewall","knock","horsemask","charge", "summonitem", "wandnothing", "wanddeath", "wandresurrection", "wandpolymorph", "wandteleport", "wanddoor", "wandfireball", "staffhealing", "armor", "scrying", "staffdoor", "special") + var/list/magicspeciallist = list("staffchange","staffanimation", "wandbelt", "contract", "staffchaos") 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) @@ -19,8 +22,9 @@ for(var/datum/objective/OBJ in H.mind.objectives) H << "Objective #[obj_count]: [OBJ.explanation_text]" obj_count++ - var/randomizeguns = pick("taser","egun","laser","revolver","detective","c20r","nuclear","deagle","gyrojet","pulse","silenced","cannon","doublebarrel","shotgun","combatshotgun","bulldog","mateba","sabr","crossbow","saw","car") - var/randomizemagic = pick("fireball","smoke","blind","mindswap","forcewall","knock","horsemask","charge","wandnothing", "wanddeath", "wandresurrection", "wandpolymorph", "wandteleport", "wanddoor", "wandfireball", "staffchange", "staffhealing", "armor", "scrying") + var/randomizeguns = pick(gunslist) + var/randomizemagic = pick(magiclist) + var/randomizemagicspecial = pick(magicspeciallist) if(!summon_type) switch (randomizeguns) if("taser") @@ -96,10 +100,12 @@ 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("wandfireball") + new /obj/item/weapon/gun/magic/wand/fireball(get_turf(H)) if("staffhealing") new /obj/item/weapon/gun/magic/staff/healing(get_turf(H)) + if("staffdoor") + new /obj/item/weapon/gun/magic/staff/door(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)) @@ -110,4 +116,19 @@ 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." + H << "The walls suddenly disappear." + + if("special") + magiclist -= "special" //only one super OP item per summoning max + switch (randomizemagicspecial) + 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("wandbelt") + new /obj/item/weapon/storage/belt/wands/full(get_turf(H)) + if("contract") + new /obj/item/weapon/contract(get_turf(H)) + if("staffchaos") + new /obj/item/weapon/gun/magic/staff/chaos(get_turf(H)) + H << "You suddenly feel lucky." diff --git a/code/game/gamemodes/wizard/spellbook.dm b/code/game/gamemodes/wizard/spellbook.dm index efb7538cdb0..7cbb4f22a1c 100644 --- a/code/game/gamemodes/wizard/spellbook.dm +++ b/code/game/gamemodes/wizard/spellbook.dm @@ -11,6 +11,7 @@ var/temp = null var/max_uses = 5 var/op = 1 + var/activepage /obj/item/weapon/spellbook/attackby(obj/item/O as obj, mob/user as mob) if(istype(O, /obj/item/weapon/contract)) @@ -31,12 +32,22 @@ var/dat if(temp) dat = "[temp]

Clear" - else - dat = "The Book of Spells:
" - dat += "Spells left to memorize: [uses]
" + else if(!activepage || activepage == "return") + dat = "The Book of Magic:
" + dat += "Uses remaining: [uses]
" + dat += "
" + dat += "Learn and Improve Magical Abilities
" + dat += "Summon Magical Tools and Weapons
" + dat += "Cast Powerful One Time Spells
" + + dat += "
" + dat += "Re-memorize Spells
" + else if (activepage == "spells") + dat += "Spells:
" + dat += "Spells that can be reused endlessly. Unless stated otherwise all spells require full wizard garb as a focus.
" + dat += "The number after the spell name is the cooldown time. You can reduce this number by spending more points on the spell.
" + dat += "
" - dat += "Memorize which spell:
" - dat += "The number after the spell name is the cooldown time.
" dat += "Remove Clothes Requirement" dat += "Warning: this takes away 2 spell choices.
" @@ -86,6 +97,20 @@ dat += "Flesh to Stone (60)
" dat += "This spell will curse a person to immediately turn into an unmoving statue. The effect will eventually wear off if the statue is not destroyed.
" + dat += "Instant Summons (10)
" + dat += "This spell can be used to bind a valuable item to you, bringing it to your hand at will. Using this spell while holding the bound item will allow you to unbind it. It does not require wizard garb.
" + + dat += "
" + + dat += "Return
" + + else if (activepage == "oneuse") + dat += "One Time Spells:
" + dat += "These potent spells can only be used once and will be used automatically upon purchase.
" + dat += "The effects are global and irreversable, these spells cannot be unlearned, but they can be bought multiple times.
" + + dat += "
" + 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!
" @@ -93,9 +118,14 @@ 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 += "Return
" + + else if (activepage == "artifacts") + dat += "Artefacts:
" - dat += "Powerful items imbued with eldritch magics. Summoning one will count towards your maximum number of spells.
" - dat += "It is recommended that only experienced wizards attempt to wield such artefacts.
" + dat += "Powerful items imbued with eldritch magics. Summoning one will count towards your maximum number of uses.
" + dat += "These items are not bound to you and can be stolen. Additionaly they cannot typically be returned once purchased.
" dat += "
" dat += "Staff of Change
" @@ -106,14 +136,26 @@ dat += "Soul Stone Shards are ancient tools capable of capturing and harnessing the spirits of the dead and dying. The spell Artificer allows you to create arcane machines for the captured souls to pilot.
" dat += "
" - dat += "Mastercrafted Armor Set
" - dat += "An artefact suit of armor that allows you to cast spells while providing more protection against attacks and the void of space.
" - dat += "
" - dat += "Staff of Animation
" dat += "An arcane staff capable of shooting bolts of eldritch energy which cause inanimate objects to come to life. This magic doesn't affect machines.
" dat += "
" + dat += "Staff of Door Creation
" + dat += "A particular staff that can mold solid metal into ornate wooden doors. Useful for getting around in the absence of other transportation. Does not work on glass.
" + dat += "
" + + dat += "Staff of Chaos
" + dat += "A caprious tool that can fire all sorts of magic without any rhyme or reason. Using it on people you care about is not recommended.
" + dat += "
" + + dat += "Wand Assortment
" + dat += "A collection of wands that allow for a wide variety of utility. Wands do not recharge, so be conservative in use. Comes in a handy belt.
" + dat += "
" + + dat += "Mastercrafted Armor Set
" + dat += "An artefact suit of armor that allows you to cast spells while providing more protection against attacks and the void of space.
" + dat += "
" + dat += "Contract of Apprenticeship
" dat += "A magical contract binding an apprentice wizard to your service, using it will summon them to your side.
" dat += "
" @@ -122,7 +164,7 @@ dat += "An incandescent orb of crackling energy, using it will allow you to ghost while alive, allowing you to spy upon the station with ease. In addition, buying it will permanently grant you x-ray vision.
" dat += "
" - dat += "Re-memorize Spells
" + dat += "Return
" user << browse(dat, "window=radio") onclose(user, "radio") return @@ -152,11 +194,13 @@ feedback_add_details("wizard_spell_learned","UM") //please do not change the abbreviation to keep data processing consistent. Add a unique id to any new spells else temp = "You may only re-memorize spells whilst located inside the wizard sanctuary." + else if(href_list["spell_choice"] == "spells" || href_list["spell_choice"] == "artifacts" || href_list["spell_choice"] == "oneuse" || href_list["spell_choice"] == "return") + activepage = href_list["spell_choice"] else if(uses >= 1 && max_uses >=1) 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", 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/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", summonitem = "Instant Summons", 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", staffchaos = "Staff of Chaos", staffdoor = "Staff of Door Creation", wands = "Wand Assortment") var/already_knows = 0 for(var/obj/effect/proc_holder/spell/wizard/aspell in H.spell_list) if(available_spells[href_list["spell_choice"]] == initial(aspell.name)) @@ -255,24 +299,20 @@ feedback_add_details("wizard_spell_learned","FS") //please do not change the abbreviation to keep data processing consistent. Add a unique id to any new spells H.spell_list += new /obj/effect/proc_holder/spell/wizard/targeted/inflict_handler/flesh_to_stone(H) temp = "You have learned flesh to stone." + if("summonitem") + feedback_add_details("wizard_spell_learned","IS") //please do not change the abbreviation to keep data processing consistent. Add a unique id to any new spells + H.spell_list += new /obj/effect/proc_holder/spell/wizard/targeted/summonitem(null) + temp = "You have learned instant summons." if("summonguns") - if(max_uses < 5) - temp = "You need 5 slots for this spell" - return - else - 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(0) - max_uses-=5 - temp = "You have cast summon guns." + 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(0) + max_uses-- + temp = "You have cast summon guns." if("summonmagic") - if(max_uses < 5) - temp = "You need 5 slots for this spell" - return - else - 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-=5 - temp = "You have cast summon magic." + 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/magic/staff/change(get_turf(H)) @@ -297,6 +337,21 @@ new /obj/item/weapon/gun/magic/staff/animate(get_turf(H)) temp = "You have purchased a staff of animation." max_uses-- + if("staffchaos") + feedback_add_details("wizard_spell_learned","SC") //please do not change the abbreviation to keep data processing consistent. Add a unique id to any new spells + new /obj/item/weapon/gun/magic/staff/chaos(get_turf(H)) + temp = "You have purchased a staff of chaos." + max_uses-- + if("staffdoor") + feedback_add_details("wizard_spell_learned","SD") //please do not change the abbreviation to keep data processing consistent. Add a unique id to any new spells + new /obj/item/weapon/gun/magic/staff/door(get_turf(H)) + temp = "You have purchased a staff of door creation." + max_uses-- + if("wands") + feedback_add_details("wizard_spell_learned","WA") //please do not change the abbreviation to keep data processing consistent. Add a unique id to any new spells + new /obj/item/weapon/storage/belt/wands/full(get_turf(H)) + temp = "You have purchased an assortment of wands." + max_uses-- if("contract") feedback_add_details("wizard_spell_learned","CT") //please do not change the abbreviation to keep data processing consistent. Add a unique id to any new spells new /obj/item/weapon/contract(get_turf(H)) @@ -317,6 +372,7 @@ else if(href_list["temp"]) temp = null + activepage = null attack_self(H) return @@ -510,4 +566,15 @@ /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 + empulse(src, 1, 1) + +/obj/item/weapon/spellbook/oneuse/summonitem + spell = /obj/effect/proc_holder/spell/wizard/targeted/summonitem + spellname = "instant summons" + icon_state ="booksummons" + desc = "This book is bright and garish, very hard to miss." + +/obj/item/weapon/spellbook/oneuse/summonitem/recoil(mob/user as mob) + ..() + user <<"[src] suddenly vanishes!" + qdel(src) diff --git a/code/game/gamemodes/wizard/summonitem.dm b/code/game/gamemodes/wizard/summonitem.dm new file mode 100644 index 00000000000..cca82c3c0c0 --- /dev/null +++ b/code/game/gamemodes/wizard/summonitem.dm @@ -0,0 +1,107 @@ +/obj/effect/proc_holder/spell/wizard/targeted/summonitem + name = "Instant Summons" + desc = "This spell can be used to recall a previously marked item to your hand from anywhere in the universe." + school = "transmutation" + charge_max = 100 + clothes_req = 0 + invocation = "GAR YOK" + invocation_type = "whisper" + range = -1 + level_max = 1 //cannot be improved + cooldown_min = 100 + include_user = 1 + + var/obj/marked_item + +/obj/effect/proc_holder/spell/wizard/targeted/summonitem/cast(list/targets) + for(var/mob/living/user in targets) + var/list/hand_items = list(user.get_active_hand(),user.get_inactive_hand()) + var/butterfingers = 0 + var/message + + if(!marked_item) //linking item to the spell + message = "" + for(var/obj/item in hand_items) + if(istype(item, /obj/item/brain)) //Yeah, sadly this doesn't work due to the organ system. + break + marked_item = item + message += "You mark [item] for recall." + name = "Recall [item]" + break + + if(!marked_item) + if(hand_items) + message = "You aren't holding anything that can be marked for recall." + else + message = "You must hold the desired item in your hands to mark it for recall." + else if(marked_item && marked_item in hand_items) //unlinking item to the spell + message = "You remove the mark on [marked_item] to use elsewhere." + name = "Instant Summons" + marked_item = null + + else if(marked_item && !marked_item.loc) //the item was destroyed at some point + message = "You sense your marked item has been destroyed!" + name = "Instant Summons" + marked_item = null + + else //Getting previously marked item + var/obj/item_to_retrive = marked_item + var/infinite_recursion = 0 //I don't want to know how someone could put something inside itself but these are wizards so let's be safe + + while(!isturf(item_to_retrive.loc) && infinite_recursion < 10) //if it's in something you get the whole thing. + if(ismob(item_to_retrive.loc)) //If its on someone, properly drop it + var/mob/M = item_to_retrive.loc + + if(issilicon(M)) //Items in silicons warp the whole silicon + M.loc.visible_message("[M] suddenly disappears!") + M.loc = user.loc + M.loc.visible_message("[M] suddenly appears!") + item_to_retrive = null + break + + M.u_equip(item_to_retrive) + + if(ishuman(M)) //Edge case housekeeping + var/mob/living/carbon/human/C = M + /*if(C.internal_organs_by_name && item_to_retrive in C.internal_organs_by_name ) //This won't work, as we use organ datums instead of objects. --DZD + C.internal_organs_by_name -= item_to_retrive + if(istype(marked_item, /obj/item/brain)) //If this code ever runs I will be happy + var/obj/item/brain/B = new /obj/item/brain(user.loc) + B.transfer_identity(C) + C.death() + add_logs(user, C, "magically debrained", addition="INTENT: [uppertext(user.a_intent)]")*/ + if(C.stomach_contents && item_to_retrive in C.stomach_contents) + C.stomach_contents -= item_to_retrive + + else + if(istype(item_to_retrive.loc,/obj/machinery/portable_atmospherics/)) //Edge cases for moved machinery + var/obj/machinery/portable_atmospherics/P = item_to_retrive.loc + P.disconnect() + P.update_icon() + + item_to_retrive = item_to_retrive.loc + + infinite_recursion += 1 + + if(!item_to_retrive) + return + + item_to_retrive.loc.visible_message("The [item_to_retrive.name] suddenly disappears!") + + + if(user.hand) //left active hand + if(!user.equip_to_slot_if_possible(item_to_retrive, slot_l_hand, 0, 1, 1)) + if(!user.equip_to_slot_if_possible(item_to_retrive, slot_r_hand, 0, 1, 1)) + butterfingers = 1 + else //right active hand + if(!user.equip_to_slot_if_possible(item_to_retrive, slot_r_hand, 0, 1, 1)) + if(!user.equip_to_slot_if_possible(item_to_retrive, slot_l_hand, 0, 1, 1)) + butterfingers = 1 + if(butterfingers) + item_to_retrive.loc = user.loc + item_to_retrive.loc.visible_message("The [item_to_retrive.name] suddenly appears!") + else + item_to_retrive.loc.visible_message("The [item_to_retrive.name] suddenly appears in [user]'s hand!") + + if(message) + user << message diff --git a/code/game/objects/items/weapons/storage/belt.dm b/code/game/objects/items/weapons/storage/belt.dm index cb93c71d9d7..4c88b7b2b46 100644 --- a/code/game/objects/items/weapons/storage/belt.dm +++ b/code/game/objects/items/weapons/storage/belt.dm @@ -197,3 +197,26 @@ new /obj/item/ammo_casing/shotgun/beanbag(src) new /obj/item/ammo_casing/shotgun/beanbag(src) new /obj/item/ammo_casing/shotgun/beanbag(src) + +/obj/item/weapon/storage/belt/wands + name = "wand belt" + desc = "A belt designed to hold various rods of power. A veritable fanny pack of exotic magic." + icon_state = "soulstonebelt" + item_state = "soulstonebelt" + storage_slots = 6 + can_hold = list( + "/obj/item/weapon/gun/magic/wand" + ) + +/obj/item/weapon/storage/belt/wands/full/New() + ..() + new /obj/item/weapon/gun/magic/wand/death(src) + new /obj/item/weapon/gun/magic/wand/resurrection(src) + new /obj/item/weapon/gun/magic/wand/polymorph(src) + new /obj/item/weapon/gun/magic/wand/teleport(src) + new /obj/item/weapon/gun/magic/wand/door(src) + new /obj/item/weapon/gun/magic/wand/fireball(src) + + for(var/obj/item/weapon/gun/magic/wand/W in contents) //All wands in this pack come in the best possible condition + W.max_charges = initial(W.max_charges) + W.charges = W.max_charges diff --git a/code/game/objects/structures/crates_lockers/closets/statue.dm b/code/game/objects/structures/crates_lockers/closets/statue.dm index c9ff9a4e110..e089c4448f0 100644 --- a/code/game/objects/structures/crates_lockers/closets/statue.dm +++ b/code/game/objects/structures/crates_lockers/closets/statue.dm @@ -62,6 +62,17 @@ /obj/structure/closet/statue/dump_contents() + if(istype(src.loc, /mob/living/simple_animal/hostile/statue)) + var/mob/living/simple_animal/hostile/statue/S = src.loc + src.loc = S.loc + if(S.mind) + for(var/mob/M in contents) + S.mind.transfer_to(M) + M << "As the animating magic wears off you feel yourself coming back to your senses. You are yourself again!" + break + qdel(S) + + for(var/obj/O in src) O.loc = src.loc @@ -74,7 +85,6 @@ M.client.perspective = MOB_PERSPECTIVE - /obj/structure/closet/statue/open() return diff --git a/code/modules/mob/living/simple_animal/hostile/statue.dm b/code/modules/mob/living/simple_animal/hostile/statue.dm index 5cc2d33eee1..30115ec7957 100644 --- a/code/modules/mob/living/simple_animal/hostile/statue.dm +++ b/code/modules/mob/living/simple_animal/hostile/statue.dm @@ -48,11 +48,12 @@ sight = SEE_SELF|SEE_MOBS|SEE_OBJS|SEE_TURFS anchored = 1 // status_flags = GODMODE // Cannot push also + var/mob/living/creator = null // No movement while seen code. -/mob/living/simple_animal/hostile/statue/New() +/mob/living/simple_animal/hostile/statue/New(loc, var/mob/living/creator) ..() // Give spells spell_list += new /obj/effect/proc_holder/spell/wizard/aoe_turf/flicker_lights(src) @@ -62,6 +63,10 @@ // Give nightvision see_invisible = SEE_INVISIBLE_OBSERVER_NOLIGHTING + // Set creator + if(creator) + src.creator = creator + /mob/living/simple_animal/hostile/statue/Move(var/turf/NewLoc) if(can_be_seen(NewLoc)) icon_state = "angelseen" @@ -173,12 +178,17 @@ // Stop attacking clientless mobs /mob/living/simple_animal/hostile/statue/CanAttack(var/atom/the_target) + if(mind && mind.key && !ckey) + return 0 if(isliving(the_target)) var/mob/living/L = the_target if(!L.client && !L.ckey) return 0 return ..() +/mob/living/simple_animal/hostile/statue/ListTargets() + . = ..() + return . - creator // Statue powers diff --git a/code/modules/projectiles/guns/magic.dm b/code/modules/projectiles/guns/magic.dm index 41e72bebd95..9401783c54a 100644 --- a/code/modules/projectiles/guns/magic.dm +++ b/code/modules/projectiles/guns/magic.dm @@ -13,6 +13,7 @@ var/recharge_rate = 4 var/charge_tick = 0 var/can_charge = 1 + var/no_den_usage origin_tech = null clumsy_check = 0 @@ -27,6 +28,13 @@ return 1 /obj/item/weapon/gun/magic/afterattack(atom/target as mob, mob/living/user as mob, flag) + if(no_den_usage) + var/area/A = get_area(user) + if(istype(A, /area/wizard_station)) + user << "You know better than to violate the security of The Den, best wait until you leave to use [src]." + return + else + no_den_usage = 0 ..() if(charges && !in_chamber && !flag) charges-- diff --git a/code/modules/projectiles/guns/magic/staff.dm b/code/modules/projectiles/guns/magic/staff.dm index ad0671867fc..c9d7ec064f0 100644 --- a/code/modules/projectiles/guns/magic/staff.dm +++ b/code/modules/projectiles/guns/magic/staff.dm @@ -1,15 +1,5 @@ obj/item/weapon/gun/magic/staff/ slot_flags = SLOT_BACK - max_charges = 100 //100, 50, 50, 34 (max charge distribution by 25%ths) - var/variable_charges = 1 - -/obj/item/weapon/gun/magic/staff/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/staff/change name = "staff of change" @@ -17,7 +7,6 @@ obj/item/weapon/gun/magic/staff/change projectile_type = "/obj/item/projectile/magic/change" icon_state = "staffofchange" item_state = "staffofchange" - max_charges = 8 //8, 4, 4, 3 obj/item/weapon/gun/magic/staff/animate name = "staff of animation" @@ -25,7 +14,6 @@ obj/item/weapon/gun/magic/staff/animate projectile_type = "/obj/item/projectile/magic/animate" icon_state = "staffofanimation" item_state = "staffofanimation" - max_charges = 8 //8, 4, 4, 3 obj/item/weapon/gun/magic/staff/healing name = "staff of healing" @@ -33,4 +21,34 @@ obj/item/weapon/gun/magic/staff/healing projectile_type = "/obj/item/projectile/magic/resurrection" icon_state = "staffofhealing" item_state = "staffofhealing" - max_charges = 8 //8, 4, 4, 3 + +obj/item/weapon/gun/magic/staff/chaos + name = "staff of chaos" + desc = "An artefact that spits bolts of chaotic magic that can potentially do anything." + projectile_type = "/obj/item/projectile/magic" + icon_state = "staffofchaos" + item_state = "staffofchaos" + icon_override = 'icons/mob/in-hand/staff.dmi' + max_charges = 10 + recharge_rate = 2 + + no_den_usage = 1 + +/obj/item/weapon/gun/magic/staff/chaos/process_chambered() //Snowflake proc, because this uses projectile_type instead of ammo_casing for whatever reason. + projectile_type = pick(typesof(/obj/item/projectile/magic)) + if(in_chamber) return 1 + if(!charges) return 0 + in_chamber = new projectile_type(src) + return 1 + +obj/item/weapon/gun/magic/staff/door + name = "staff of door creation" + desc = "An artefact that spits bolts of transformative magic that can create doors in walls." + projectile_type = "/obj/item/projectile/magic/door" + icon_state = "staffofdoor" + item_state = "staffofdoor" + icon_override = 'icons/mob/in-hand/staff.dmi' + max_charges = 10 + recharge_rate = 2 + + no_den_usage = 1 \ No newline at end of file diff --git a/code/modules/projectiles/guns/magic/wand.dm b/code/modules/projectiles/guns/magic/wand.dm index d0841fff5e4..10dcf66ee00 100644 --- a/code/modules/projectiles/guns/magic/wand.dm +++ b/code/modules/projectiles/guns/magic/wand.dm @@ -8,6 +8,14 @@ can_charge = 0 max_charges = 100 //100, 50, 50, 34 (max charge distribution by 25%ths) var/variable_charges = 1 + var/drained = 0 + +/obj/item/projectile/magic/fireball/Range() + var/mob/living/L = locate(/mob/living) in (range(src, 1) - firer) + if(L && L.stat != DEAD) + Bump(L) //Magic Bullet #teachthecontroversy + return + ..() /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 @@ -35,11 +43,19 @@ ..() /obj/item/weapon/gun/magic/wand/afterattack(atom/target as mob, mob/living/user as mob) - if(!charges) + if(!charges && !drained) user << "The [name] whizzles quietly." icon_state = "[icon_state]-drained" + drained = 1 return if(target == user) + if(no_den_usage) + var/area/A = get_area(user) + if(istype(A, /area/wizard_station)) + user << "You know better than to violate the security of The Den, best wait until you leave to use [src]." + return + else + no_den_usage = 0 zap_self(user) else ..() @@ -103,6 +119,7 @@ projectile_type = "/obj/item/projectile/magic/teleport" icon_state = "telewand" max_charges = 10 //10, 5, 5, 4 + no_den_usage = 1 /obj/item/weapon/gun/magic/wand/teleport/zap_self(mob/living/user as mob) do_teleport(user, user, 10) diff --git a/code/modules/projectiles/projectile/magic.dm b/code/modules/projectiles/projectile/magic.dm index da7ec9a02d3..28bdf2961e2 100644 --- a/code/modules/projectiles/projectile/magic.dm +++ b/code/modules/projectiles/projectile/magic.dm @@ -17,7 +17,7 @@ /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 = 10 damage_type = BRUTE nodamage = 0 flag = "magic" @@ -25,6 +25,9 @@ /obj/item/projectile/magic/fireball/on_hit(var/target) var/turf/T = get_turf(target) explosion(T, -1, 0, 2, 3, 0) + if(ismob(target)) //multiple flavors of pain + var/mob/living/M = target + M.take_overall_damage(0,10) //between this 10 burn, the 10 brute, the explosion brute, and the onfire burn, your at about 65 damage if you stop drop and roll immediately /obj/item/projectile/magic/resurrection name = "bolt of resurrection" @@ -151,7 +154,10 @@ proc/wabbajack(mob/living/M) 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) + if(prob(30)) + new_mob = new /mob/living/silicon/robot/syndicate(M.loc) + else + new_mob = new /mob/living/silicon/robot(M.loc) new_mob.gender = M.gender new_mob.invisibility = 0 new_mob.job = "Cyborg" @@ -179,12 +185,14 @@ proc/wabbajack(mob/living/M) new_mob.universal_speak = 1*/ if("animal") if(prob(50)) - var/beast = pick("carp","bear","mushroom","statue") + var/beast = pick("carp","bear","mushroom","statue", "bat", "goat") switch(beast) 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/hostile/mushroom(M.loc) if("statue") new_mob = new /mob/living/simple_animal/hostile/statue(M.loc) + if("bat") new_mob = new /mob/living/simple_animal/hostile/scarybat(M.loc) + if("goat") new_mob = new /mob/living/simple_animal/hostile/retaliate/goat(M.loc) else var/animal = pick("parrot","corgi","crab","pug","cat","tomato","mouse","chicken","cow","lizard","chick","fox") switch(animal) @@ -217,6 +225,9 @@ proc/wabbajack(mob/living/M) for (var/obj/effect/proc_holder/spell/wizard/S in M.spell_list) new_mob.spell_list += new S.type + new_mob.attack_log = M.attack_log + M.attack_log += text("\[[time_stamp()]\] [M.real_name] ([M.ckey]) became [new_mob.real_name].") + new_mob.a_intent = "harm" if(M.mind) M.mind.transfer_to(new_mob) @@ -241,15 +252,16 @@ proc/wabbajack(mob/living/M) if(istype(change, /obj/item) || istype(change, /obj/structure) && !is_type_in_list(change, protected_objects)) if(istype(change, /obj/structure/closet/statue)) for(var/mob/living/carbon/human/H in change.contents) - var/mob/living/simple_animal/hostile/statue/S = new /mob/living/simple_animal/hostile/statue(change.loc) + var/mob/living/simple_animal/hostile/statue/S = new /mob/living/simple_animal/hostile/statue(change.loc, firer) S.name = "statue of [H.name]" S.faction = list("\ref[firer]") S.icon = change.icon if(H.mind) H.mind.transfer_to(S) - S << "You are an animate statue. You cannot move when monitored, but are nearly invincible and deadly when unobserved! Do not harm [firer.name], your creator." - del(H) - del(change) + S << "You are an animated statue. You cannot move when monitored, but are nearly invincible and deadly when unobserved! Do not harm [firer.name], your creator." + H = change + H.loc = S + del(src) else var/obj/O = change new /mob/living/simple_animal/hostile/mimic/copy(O.loc, O, firer) diff --git a/icons/mob/in-hand/staff.dmi b/icons/mob/in-hand/staff.dmi new file mode 100644 index 00000000000..3a8f1ebee4f Binary files /dev/null and b/icons/mob/in-hand/staff.dmi differ diff --git a/icons/obj/gun.dmi b/icons/obj/gun.dmi index a105ed232af..273552a5f6c 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 1c405908b43..3cfdd226e92 100644 Binary files a/icons/obj/library.dmi and b/icons/obj/library.dmi differ diff --git a/paradise.dme b/paradise.dme index ad02ece0581..947a94145a4 100644 --- a/paradise.dme +++ b/paradise.dme @@ -164,7 +164,6 @@ #include "code\ATMOSPHERICS\components\unary\vent_pump.dm" #include "code\ATMOSPHERICS\components\unary\vent_scrubber.dm" #include "code\controllers\_DynamicAreaLighting_TG.dm" -#include "code\controllers\communications.dm" #include "code\controllers\configuration.dm" #include "code\controllers\emergency_shuttle_controller.dm" #include "code\controllers\failsafe.dm" @@ -245,6 +244,7 @@ #include "code\game\asteroid.dm" #include "code\game\atoms.dm" #include "code\game\atoms_movable.dm" +#include "code\game\communications.dm" #include "code\game\response_team.dm" #include "code\game\shuttle_engines.dm" #include "code\game\skincmd.dm" @@ -353,6 +353,7 @@ #include "code\game\gamemodes\wizard\rightandwrong.dm" #include "code\game\gamemodes\wizard\soulstone.dm" #include "code\game\gamemodes\wizard\spellbook.dm" +#include "code\game\gamemodes\wizard\summonitem.dm" #include "code\game\gamemodes\wizard\wizard.dm" #include "code\game\gamemodes\xenos\xenos.dm" #include "code\game\jobs\access.dm" @@ -863,7 +864,6 @@ #include "code\modules\admin\verbs\randomverbs.dm" #include "code\modules\admin\verbs\striketeam.dm" #include "code\modules\admin\verbs\striketeam_syndicate.dm" -#include "code\modules\admin\verbs\ticklag.dm" #include "code\modules\admin\verbs\tripAI.dm" #include "code\modules\admin\verbs\vox_raiders.dm" #include "code\modules\assembly\assembly.dm"