diff --git a/code/_onclick/click.dm b/code/_onclick/click.dm
index 272b3157b88..cad5657fc37 100644
--- a/code/_onclick/click.dm
+++ b/code/_onclick/click.dm
@@ -38,7 +38,7 @@
return
next_click = world.time + 1
- if(client.buildmode)
+ if(client && client.buildmode)
build_click(src, client.buildmode, params, A)
return
@@ -411,7 +411,7 @@
/* if(buckled && buckled.movable)
buckled.dir = direction
buckled.handle_rotation()*/
-
+
/obj/screen/click_catcher
icon = 'icons/mob/screen1_full.dmi'
icon_state = "passage0"
diff --git a/code/datums/uplink_item.dm b/code/datums/uplink_item.dm
index c287c00975d..acea0966db9 100644
--- a/code/datums/uplink_item.dm
+++ b/code/datums/uplink_item.dm
@@ -147,6 +147,16 @@ var/list/uplink_items = list()
cost = 2
job = list("Chef")
+//Chaplain
+
+/datum/uplink_item/jobspecific/voodoo
+ name = "Voodoo Doll"
+ desc = "A doll created by Syndicate Witch Doctors. Ingredients: Something of the Thread, Something of the Head, Something of the Body, Something of the Dead, Secret Voodoo herbs, and Monosodium glutamate."
+ reference = "VD"
+ item = /obj/item/voodoo
+ cost = 13
+ job = list("Chaplain")
+
//Janitor
/datum/uplink_item/jobspecific/cautionsign
diff --git a/code/game/asteroid.dm b/code/game/asteroid.dm
index 3753c888912..6f6cdd18a2f 100644
--- a/code/game/asteroid.dm
+++ b/code/game/asteroid.dm
@@ -80,7 +80,7 @@ var/global/max_secret_rooms = 6
walltypes = list(/turf/simulated/wall/mineral/plasma=3,/turf/simulated/mineral/random/high_chance=1)
floortypes = list(/turf/simulated/floor/wood)
treasureitems = list(/obj/item/weapon/veilrender/vealrender=2, /obj/item/weapon/spellbook/oneuse/blind=1,/obj/item/clothing/head/wizard/red=2,
- /obj/item/weapon/spellbook/oneuse/forcewall=1, /obj/item/weapon/spellbook/oneuse/smoke=1, /obj/structure/constructshell = 1, /obj/item/toy/katana=3)
+ /obj/item/weapon/spellbook/oneuse/forcewall=1, /obj/item/weapon/spellbook/oneuse/smoke=1, /obj/structure/constructshell = 1, /obj/item/toy/katana=3,/obj/item/voodoo=3)
fluffitems = list(/obj/structure/safe/floor=1,/obj/structure/dresser=1,/obj/item/weapon/storage/belt/soulstone=1,/obj/item/trash/candle=3,
/obj/item/weapon/dice=3,/obj/item/weapon/twohanded/staff=2,/obj/effect/decal/cleanable/dirt=3,/obj/item/weapon/coin/mythril=3)
diff --git a/code/game/gamemodes/wizard/artefact.dm b/code/game/gamemodes/wizard/artefact.dm
index 3008d2db0c7..63de49edb1b 100644
--- a/code/game/gamemodes/wizard/artefact.dm
+++ b/code/game/gamemodes/wizard/artefact.dm
@@ -597,3 +597,239 @@ var/global/list/multiverse = list()
probability_evil = 100
duplicate_self = 1
sword_type = /obj/item/weapon/multisword/pike
+
+
+/////////////////////////////////////////Necromantic Stone///////////////////
+
+/obj/item/device/necromantic_stone
+ name = "necromantic stone"
+ desc = "A shard capable of resurrecting humans as skeleton thralls."
+ icon = 'icons/obj/wizard.dmi'
+ icon_state = "necrostone"
+ item_state = "electronic"
+ origin_tech = "bluespace=4;materials=4"
+ w_class = 1
+ var/list/spooky_scaries = list()
+ var/unlimited = 0
+ var/heresy = 0
+
+/obj/item/device/necromantic_stone/unlimited
+ unlimited = 1
+
+/obj/item/device/necromantic_stone/attack(mob/living/carbon/human/M as mob, mob/living/carbon/human/user as mob)
+
+ if(!istype(M))
+ return ..()
+
+ if(!istype(user))
+ return
+
+ if(M.stat != DEAD)
+ user << "This artifact can only affect the dead!"
+ return
+
+ if(!M.mind || !M.client)
+ user << "There is no soul connected to this body..."
+ return
+
+ check_spooky()//clean out/refresh the list
+
+ if(spooky_scaries.len >= 3 && !unlimited)
+ user << "This artifact can only affect three undead at a time!"
+ return
+ M.makeSkeleton()
+ M.visible_message(" A massive amount of flesh sloughs off [M] and a skeleton rises up!")
+ M.revive()
+ spooky_scaries |= M
+ M << "You have been revived by [user.real_name]!"
+ M << "They are your master now, assist them even if it costs you your new life!"
+ equip_skeleton(M)
+ desc = "A shard capable of resurrecting humans as skeleton thralls[unlimited ? "." : ", [spooky_scaries.len]/3 active thralls."]"
+
+/obj/item/device/necromantic_stone/proc/check_spooky()
+ if(unlimited) //no point, the list isn't used.
+ return
+ for(var/X in spooky_scaries)
+ if(!istype(X, /mob/living/carbon/human))
+ spooky_scaries.Remove(X)
+ continue
+ var/mob/living/carbon/human/H = X
+ if(H.stat == DEAD)
+ spooky_scaries.Remove(X)
+ continue
+ listclearnulls(spooky_scaries)
+
+//Funny gimmick, skeletons always seem to wear roman/ancient armour
+//Voodoo Zombie Pirates added for paradise
+/obj/item/device/necromantic_stone/proc/equip_skeleton(mob/living/carbon/human/H as mob)
+ for(var/obj/item/I in H)
+ H.unEquip(I)
+ var/randomSpooky = "roman"//defualt
+ if(heresy)
+ randomSpooky = "yand"
+ else
+ randomSpooky = pick("roman","pirate","yand","clown")
+
+ switch(randomSpooky)
+ if("roman")
+ var/hat = pick(/obj/item/clothing/head/helmet/roman, /obj/item/clothing/head/helmet/roman/legionaire)
+ H.equip_to_slot_or_del(new hat(H), slot_head)
+ H.equip_to_slot_or_del(new /obj/item/clothing/under/roman(H), slot_w_uniform)
+ H.equip_to_slot_or_del(new /obj/item/clothing/shoes/roman(H), slot_shoes)
+ H.equip_to_slot_or_del(new /obj/item/weapon/shield/riot/roman(H), slot_l_hand)
+ H.equip_to_slot_or_del(new /obj/item/weapon/claymore(H), slot_r_hand)
+ H.equip_to_slot_or_del(new /obj/item/weapon/twohanded/spear(H), slot_back)
+ if("pirate")
+ H.equip_to_slot_or_del(new /obj/item/clothing/under/pirate(H), slot_w_uniform)
+ H.equip_to_slot_or_del(new /obj/item/clothing/suit/pirate_brown(H), slot_wear_suit)
+ H.equip_to_slot_or_del(new /obj/item/clothing/head/bandana(H), slot_head)
+ H.equip_to_slot_or_del(new /obj/item/clothing/shoes/sandal(H), slot_shoes)
+ H.equip_to_slot_or_del(new /obj/item/clothing/glasses/eyepatch(H), slot_glasses)
+ H.equip_to_slot_or_del(new /obj/item/weapon/claymore(H), slot_r_hand)
+ H.equip_to_slot_or_del(new /obj/item/weapon/twohanded/spear(H), slot_back)
+ H.equip_to_slot_or_del(new /obj/item/weapon/shield/riot/roman(H), slot_l_hand)
+ if("yand")//mine is an evil laugh
+ H.equip_to_slot_or_del(new /obj/item/clothing/shoes/sandal(H), slot_shoes)
+ H.equip_to_slot_or_del(new /obj/item/clothing/head/kitty(H), slot_head)
+ H.equip_to_slot_or_del(new /obj/item/clothing/under/schoolgirl(H), slot_w_uniform)
+ H.equip_to_slot_or_del(new /obj/item/clothing/suit/armor/vest(H), slot_wear_suit)
+ H.equip_to_slot_or_del(new /obj/item/weapon/katana(H), slot_r_hand)
+ H.equip_to_slot_or_del(new /obj/item/weapon/shield/riot/roman(H), slot_l_hand)
+ H.equip_to_slot_or_del(new /obj/item/weapon/twohanded/spear(H), slot_back)
+ if("clown")
+ H.equip_to_slot_or_del(new /obj/item/clothing/under/rank/clown(H), slot_w_uniform)
+ H.equip_to_slot_or_del(new /obj/item/clothing/shoes/clown_shoes(H), slot_shoes)
+ H.equip_to_slot_or_del(new /obj/item/clothing/mask/gas/clown_hat(H), slot_wear_mask)
+ H.equip_to_slot_or_del(new /obj/item/clothing/head/stalhelm(H), slot_head)
+ H.equip_to_slot_or_del(new /obj/item/weapon/bikehorn(H), slot_l_store)
+ H.equip_to_slot_or_del(new /obj/item/weapon/claymore(H), slot_r_hand)
+ H.equip_to_slot_or_del(new /obj/item/weapon/shield/riot/roman(H), slot_l_hand)
+ H.equip_to_slot_or_del(new /obj/item/weapon/twohanded/spear(H), slot_back)
+
+
+/obj/item/device/necromantic_stone/nya
+ name = "nya-cromantic stone"
+ desc = "A shard capable of resurrecting humans as creatures of Vile Heresy. Even the Wizard Federation fears it.."
+ icon = 'icons/obj/wizard.dmi'
+ icon_state = "nyacrostone"
+ item_state = "electronic"
+ origin_tech = "bluespace=4;materials=4"
+ w_class = 1
+ heresy = 1
+ unlimited = 1
+
+/////////////////////////////////////////Voodoo///////////////////
+
+
+/obj/item/voodoo
+ name = "wicker doll"
+ desc = "Something creepy about it."
+ icon = 'icons/obj/wizard.dmi'
+ icon_state = "voodoo"
+ item_state = "electronic"
+ var/mob/living/carbon/human/target = null
+ var/list/mob/living/carbon/human/possible = list()
+ var/obj/item/link = null
+ var/cooldown_time = 30 //3s
+ var/cooldown = 0
+
+
+
+/obj/item/voodoo/attackby(obj/item/I as obj, mob/user as mob, params)
+ if(target && cooldown < world.time)
+ if(is_hot(I))
+ target << "You suddenly feel very hot"
+ target.bodytemperature += 50
+ GiveHint(target)
+ else if(can_puncture(I))
+ target << "You feel a stabbing pain in [parse_zone(user.zone_sel.selecting)]!"
+ target.Weaken(2)
+ GiveHint(target)
+ else if(istype(I,/obj/item/weapon/bikehorn))
+ target << "HONK"
+ target << 'sound/items/AirHorn.ogg'
+ target.ear_damage += rand(0,3)
+ GiveHint(target)
+ cooldown = world.time +cooldown_time
+ return
+ if(!link)
+ if(I.loc == user && istype(I) && I.w_class <= 2)
+ user.drop_item()
+ I.loc = src
+ link = I
+ user << "You attach [I] to the doll."
+ update_targets()
+ ..()
+/obj/item/voodoo/check_eye(mob/user as mob)
+ return src.loc == user
+
+/obj/item/voodoo/attack_self(mob/user as mob)
+ if(!target && possible.len)
+ target = input(user, "Select your victim!", "Voodoo") as null|anything in possible
+ return
+ if(user.zone_sel.selecting == "chest")
+ if(link)
+ target = null
+ link.loc = get_turf(src)
+ user << "You remove the [link] from the doll."
+ link = null
+ update_targets()
+ return
+ if(target && cooldown < world.time)
+ switch(user.zone_sel.selecting)
+ if("mouth")
+ var/wgw = sanitize(input(user, "What would you like the victim to say", "Voodoo", null) as text)
+ target.say(wgw)
+ log_game("[user][user.key] made [target][target.key] say [wgw] with a voodoo doll.")
+ if("eyes")
+ user.set_machine(src)
+ if(user.client)
+ user.client.eye = target
+ user.client.perspective = EYE_PERSPECTIVE
+ spawn(100)
+ user.reset_view()
+ user.unset_machine()
+ if("r_leg","l_leg")
+ user << "You move the doll's legs around."
+ var/turf/T = get_step(target,pick(cardinal))
+ target.Move(T)
+ if("r_arm","l_arm")
+ //use active hand on random nearby mob
+ var/list/nearby_mobs = list()
+ for(var/mob/living/L in range(1,target))
+ if(L!=target)
+ nearby_mobs |= L
+ if(nearby_mobs.len)
+ var/mob/living/T = pick(nearby_mobs)
+ log_game("[user][user.key] made [target][target.key] click on [T] with a voodoo doll.")
+ target.ClickOn(T)
+ GiveHint(target)
+ if("head")
+ user << "You smack the doll's head with your hand."
+ target.Dizzy(10)
+ target << "You suddenly feel as if your head was hit with a hammer!"
+ GiveHint(target,user)
+ cooldown = world.time + cooldown_time
+
+/obj/item/voodoo/proc/update_targets()
+ possible = list()
+ if(!link)
+ return
+ for(var/mob/living/carbon/human/H in living_mob_list)
+ if(md5(H.dna.uni_identity) in link.fingerprints)
+ possible |= H
+
+/obj/item/voodoo/proc/GiveHint(mob/victim,force=0)
+ if(prob(50) || force)
+ var/way = dir2text(get_dir(victim,get_turf(src)))
+ victim << "You feel a dark presence from [way]"
+ if(prob(20) || force)
+ var/area/A = get_area(src)
+ victim << "You feel a dark presence from [A.name]"
+
+/obj/item/voodoo/fire_act()
+ if(target)
+ target.adjust_fire_stacks(20)
+ target.IgniteMob()
+ GiveHint(target,1)
+ return ..()
\ No newline at end of file
diff --git a/code/game/gamemodes/wizard/rightandwrong.dm b/code/game/gamemodes/wizard/rightandwrong.dm
index e98517688d8..a417c839a7e 100644
--- a/code/game/gamemodes/wizard/rightandwrong.dm
+++ b/code/game/gamemodes/wizard/rightandwrong.dm
@@ -2,8 +2,8 @@
/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","boltaction","arg")
- 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")
+ 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","voodoo")
+ var/list/magicspeciallist = list("staffchange","staffanimation", "wandbelt", "contract", "staffchaos","necromantic")
usr << "You summoned [summon_type ? "magic" : "guns"]!"
message_admins("[key_name_admin(usr)] summoned [summon_type ? "magic" : "guns"]!")
for(var/mob/living/carbon/human/H in player_list)
@@ -110,6 +110,9 @@
H.see_invisible = SEE_INVISIBLE_LEVEL_TWO
H << "The walls suddenly disappear."
+ if("voodoo")
+ new /obj/item/voodoo(get_turf(H))
+
if("special")
magiclist -= "special" //only one super OP item per summoning max
switch (randomizemagicspecial)
@@ -123,4 +126,6 @@
new /obj/item/weapon/contract(get_turf(H))
if("staffchaos")
new /obj/item/weapon/gun/magic/staff/chaos(get_turf(H))
+ if("necromantic")
+ new /obj/item/device/necromantic_stone(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 acf20832ba8..54426761a02 100644
--- a/code/game/gamemodes/wizard/spellbook.dm
+++ b/code/game/gamemodes/wizard/spellbook.dm
@@ -281,6 +281,12 @@
user.mind.AddSpell(new /obj/effect/proc_holder/spell/aoe_turf/conjure/construct(null))
return .
+/datum/spellbook_entry/item/necrostone
+ name = "A Necromantic Stone"
+ desc = "A Necromantic stone is able to resurrect three dead individuals as skeletal thralls for you to command."
+ item_path = /obj/item/device/necromantic_stone
+ log_name = "NS"
+
/datum/spellbook_entry/item/wands
name = "Wand Assortment"
desc = "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."
diff --git a/icons/obj/wizard.dmi b/icons/obj/wizard.dmi
index 273eeab0921..c35817db609 100644
Binary files a/icons/obj/wizard.dmi and b/icons/obj/wizard.dmi differ