Wizardry Inc. (#8899)

Wizard spellbooks can now be stored in the belt slot.
    Necromancers now get 10 spell points, up from 8.
    Smoke now properly layers over mobs, obscuring them.
    Wizard Apprentices and Skeletons are now in the Ghost Spawner menu. The former can be enabled by buying an Apprentice Pebble artifact, a new wizard item which acts as a portable spawnpoint. The latter by casting Raise Dead on a corpse.
    Apprentices are now given additional spells at the bottom of their spellbook, depending on which type of wizard their master is."
    Bought artifacts now appear in your hands, if you have any free.
    The Return to Master spell has received numerous bugfixes and should now work as expected, most of the time.
This commit is contained in:
Geeves
2020-05-25 09:22:31 +02:00
committed by GitHub
parent 9c0055a662
commit e6966e6e2d
19 changed files with 249 additions and 50 deletions

View File

@@ -0,0 +1,24 @@
/datum/ghostspawner/human/skeleton
short_name = "skeleton"
name = "Risen Skeleton"
desc = "Serve your Master. Fight things."
tags = list("Antagonist")
enabled = FALSE
spawn_mob = /mob/living/carbon/human/skeleton
/datum/ghostspawner/human/skeleton/select_spawnpoint(var/use)
return TRUE //We just fake it here, since the spawnpoint is selected if someone is spawned in.
//The proc to actually spawn in the user
/datum/ghostspawner/human/skeleton/spawn_mob(mob/user)
if(!length(spawn_atoms))
to_chat(user, SPAN_DANGER("There are no available skeletons to spawn at!"))
return FALSE
var/mob/living/carbon/human/skeleton/skeleton = pick(spawn_atoms)
if(user && skeleton)
return skeleton.spawn_skeleton(user)
return FALSE

View File

@@ -0,0 +1,24 @@
/datum/ghostspawner/human/apprentice
short_name = "apprentice"
name = "Wizard Apprentice"
desc = "Serve your Master. Cast Spells."
tags = list("Antagonist")
enabled = FALSE
spawn_mob = /mob/living/carbon/human
/datum/ghostspawner/human/apprentice/select_spawnpoint(var/use)
return TRUE //We just fake it here, since the spawnpoint is selected if someone is spawned in.
//The proc to actually spawn in the user
/datum/ghostspawner/human/apprentice/spawn_mob(mob/user)
if(!length(spawn_atoms))
to_chat(user, SPAN_DANGER("There are no available apprentice pebbles to spawn at!"))
return FALSE
var/obj/item/apprentice_pebble/pebble = pick(spawn_atoms)
if(user && pebble)
return pebble.spawn_apprentice(user)
return FALSE

View File

@@ -1,6 +1,17 @@
/mob/living/carbon/human/skeleton/Initialize(mapload)
. = ..(mapload, "Skeleton")
/mob/living/carbon/human/skeleton
var/master
/mob/living/carbon/human/skeleton/proc/spawn_skeleton(var/mob/user)
src.ckey = user.ckey
src.real_name = "[pick(wizard_first)] [pick(wizard_second)]"
src.name = src.real_name
if(master)
to_chat(src, "<B>You are a skeleton minion to [master], they are your master. Obey and protect your master at all costs, you have no free will.</B>")
SSghostroles.remove_spawn_atom("skeleton", src)
/datum/species/skeleton //SPOOKY
name = "Skeleton"
name_plural = "skeletons"
@@ -11,22 +22,22 @@
total_health = 70 //gotta get headshots to kill them, so they're frail
default_language = "Ceti Basic"
language = "Cult"
name_language = "Cult"
default_language = LANGUAGE_TCB
language = LANGUAGE_CULT
name_language = LANGUAGE_CULT
unarmed_types = list(/datum/unarmed_attack/claws/strong, /datum/unarmed_attack/bite/sharp)
darksight = 8
has_organ = list() //skeletons are empty shells for now, maybe we can add something in the future
siemens_coefficient = 0
ethanol_resistance = -1 //no drunk skeletons
taste_sensitivity = TASTE_NUMB
breakcuffs = list(MALE,FEMALE,NEUTER)
breakcuffs = list(MALE, FEMALE, NEUTER)
meat_type = /obj/item/reagent_containers/food/snacks/meat/undead
reagent_tag = IS_UNDEAD
virus_immune = 1
virus_immune = TRUE
rarity_value = 10
blurb = "Skeletons are undead brought back to life through dark wizardry, \

View File

@@ -0,0 +1,47 @@
/obj/item/apprentice_pebble
name = "apprentice pebble"
desc = "A pebble, it feels warm to the touch."
icon = 'icons/obj/wizard.dmi'
icon_state = "pebble"
origin_tech = list(TECH_BLUESPACE = 6, TECH_MATERIAL = 6, TECH_BIO = 6)
w_class = ITEMSIZE_SMALL
var/obj/item/contract/apprentice/contract
/obj/item/apprentice_pebble/Initialize()
. = ..()
contract = new /obj/item/contract/apprentice(src)
SSghostroles.add_spawn_atom("apprentice", src)
var/area/A = get_area(src)
if(A)
say_dead_direct("An artificer pebble has been created in [A.name]! Spawn at it by using the ghost spawner menu in the ghost tab.")
/obj/item/apprentice_pebble/Destroy()
if(contract)
QDEL_NULL(contract)
SSghostroles.remove_spawn_atom("apprentice", src)
return ..()
/obj/item/apprentice_pebble/proc/spawn_apprentice(var/mob/user)
var/mob/living/carbon/human/G = new /mob/living/carbon/human(get_turf(src))
G.ckey = user.ckey
G.real_name = "[pick(wizard_first)] [pick(wizard_second)]"
G.name = G.real_name
G.preEquipOutfit(/datum/outfit/admin/wizard/apprentice, FALSE)
G.equipOutfit(/datum/outfit/admin/wizard/apprentice, FALSE)
G.put_in_hands(contract)
contract = null
var/datum/effect/effect/system/smoke_spread/smoke = new /datum/effect/effect/system/smoke_spread()
smoke.set_up(5, 0, get_turf(src))
smoke.start()
qdel(src)
/obj/item/apprentice_pebble/pickup(mob/living/user)
..()
if(!user.is_wizard())
to_chat(user, SPAN_WARNING("As you pick up \the [src], you feel a wave of power wash over you."))
for(var/obj/machinery/light/P in view(7, user))
P.flicker(1)

View File

@@ -1,7 +1,8 @@
/obj/item/contract/apprentice
name = "apprentice wizarding contract"
desc = "a wizarding school contract for those who want to sign their soul for a piece of the magic pie."
desc = "A wizarding school contract for those who want to sign their soul for a piece of the magic pie."
color = "#993300"
var/list/additional_spells = list()
/obj/item/contract/apprentice/contract_effect(mob/user)
if(user.mind.assigned_role == "Apprentice")
@@ -12,8 +13,10 @@
to_chat(user, SPAN_NOTICE("With the signing of this paper you agree to become \the [contract_master]'s apprentice in the art of wizardry."))
user.faction = "Space Wizard"
wizards.add_antagonist_mind(user.mind, TRUE)
var/obj/item/I = new /obj/item/spellbook/student(get_turf(user))
user.put_in_hands(I)
var/obj/item/spellbook/student/S = new /obj/item/spellbook/student(get_turf(user))
for(var/additional_spell in additional_spells)
S.spellbook.spells[additional_spell] = additional_spells[additional_spell]
user.put_in_hands(S)
user.add_spell(new /spell/noclothes)
if(contract_master)
user.add_spell(new /spell/contract/return_master(contract_master), "const_spell_ready")

View File

@@ -5,6 +5,7 @@ var/list/artefact_feedback = list(/obj/structure/closet/wizard/armor = "HS",
/obj/item/gun/energy/staff/focus = "MF",
/obj/item/monster_manual = "MA",
/obj/item/contract/apprentice = "CP",
/obj/item/apprentice_pebble = "AP",
/obj/structure/closet/wizard/souls = "SS",
/obj/structure/closet/wizard/scrying = "SO",
/obj/item/teleportation_scroll = "TS",
@@ -21,14 +22,15 @@ var/list/artefact_feedback = list(/obj/structure/closet/wizard/armor = "HS",
icon_state = "spellbook"
throw_speed = 1
throw_range = 5
w_class = 2
w_class = ITEMSIZE_SMALL
slot_flags = SLOT_BELT
var/uses = 1
var/temp = null
var/datum/spellbook/spellbook
var/spellbook_type = /datum/spellbook/ //for spawning specific spellbooks.
var/spellbook_type = /datum/spellbook //for spawning specific spellbooks.
/obj/item/spellbook/New()
..()
/obj/item/spellbook/Initialize()
. = ..()
set_spellbook(spellbook_type)
/obj/item/spellbook/proc/set_spellbook(var/type)
@@ -159,8 +161,25 @@ var/list/artefact_feedback = list(/obj/structure/closet/wizard/armor = "HS",
else
if(ispath(path,/spell))
temp = src.add_spell(usr,path)
else if(ispath(path, /obj/item/contract/apprentice))
var/obj/item/contract/apprentice/A = new path(get_turf(usr))
A.contract_master = usr
A.additional_spells = spellbook.apprentice_spells
temp = "You have purchased \a [A]."
spellbook.max_uses -= spellbook.spells[path]
playsound(get_turf(usr),'sound/effects/phasein.ogg',50,1)
usr.put_in_hands(A)
else if(ispath(path, /obj/item/apprentice_pebble))
var/obj/item/apprentice_pebble/A = new path(get_turf(usr))
A.contract.additional_spells = spellbook.apprentice_spells
A.contract.contract_master = usr
temp = "You have purchased \a [A]."
spellbook.max_uses -= spellbook.spells[path]
playsound(get_turf(usr),'sound/effects/phasein.ogg',50,1)
usr.put_in_hands(A)
else
var/obj/O = new path(get_turf(usr))
usr.put_in_hands(O)
temp = "You have purchased \a [O]."
spellbook.max_uses -= spellbook.spells[path]
//finally give it a bit of an oomf
@@ -227,4 +246,5 @@ var/list/artefact_feedback = list(/obj/structure/closet/wizard/armor = "HS",
/datum/spellbook/battlemage = 1,
/datum/spellbook/druid = 1,
/datum/spellbook/necromancer = 1
) //spell's path = cost of spell
) //spell's path = cost of spell
var/list/apprentice_spells = list() // extra spells that apprentices get, based on their master's book

View File

@@ -30,5 +30,14 @@
/obj/item/storage/belt/wands/full = 2,
/obj/item/melee/energy/wizard = 2,
/obj/item/monster_manual = 2,
/obj/item/contract/apprentice = 1
/obj/item/contract/apprentice = 1,
/obj/item/apprentice_pebble = 2
)
apprentice_spells = list(
/spell/targeted/equip_item/shield = 1,
/spell/targeted/torment = 1,
/spell/targeted/heal_target = 2,
/spell/targeted/shapeshift/corrupt_form = 1,
/obj/item/melee/energy/wizard = 2
)

View File

@@ -32,5 +32,14 @@
/obj/item/gun/energy/staff/focus = 2,
/obj/item/storage/belt/wands/full = 2,
/obj/item/poppet = 1,
/obj/item/contract/apprentice = 1
/obj/item/contract/apprentice = 1,
/obj/item/apprentice_pebble = 2
)
apprentice_spells = list(
/spell/targeted/heal_target = 1,
/spell/targeted/heal_target/area = 1,
/spell/targeted/resurrection = 2,
/spell/targeted/genetic/blind = 1,
/spell/radiant_aura = 1
)

View File

@@ -30,5 +30,13 @@
/obj/structure/closet/wizard/souls = 1,
/obj/item/monster_manual = 1,
/obj/item/poppet = 1,
/obj/item/contract/apprentice = 1
/obj/item/contract/apprentice = 1,
/obj/item/apprentice_pebble = 2
)
apprentice_spells = list(
/spell/targeted/heal_target = 1,
/spell/targeted/heal_target/sacrifice = 1,
/spell/aoe_turf/conjure/grove/sanctuary = 1,
/obj/item/poppet = 1
)

View File

@@ -10,7 +10,7 @@
title = "The Art of Necromancy"
title_desc = "Buy spells using your available spell slots. Artefacts may also be bought however their cost is permanent."
book_flags = CAN_MAKE_CONTRACTS
max_uses = 8
max_uses = 10
spells = list(/spell/targeted/projectile/dumbfire/fireball = 1,
/spell/targeted/torment = 1,
@@ -26,5 +26,13 @@
/obj/structure/closet/wizard/armor = 1,
/obj/structure/closet/wizard/scrying = 2,
/obj/structure/closet/wizard/souls = 1,
/obj/item/contract/apprentice = 1
/obj/item/contract/apprentice = 1,
/obj/item/apprentice_pebble = 2
)
apprentice_spells = list(
/spell/aoe_turf/conjure/summon/bats = 1,
/spell/targeted/shapeshift/corrupt_form = 1,
/spell/targeted/raise_dead = 2,
/obj/structure/closet/wizard/souls = 1
)

View File

@@ -25,5 +25,6 @@
/obj/structure/closet/wizard/scrying = 2,
/obj/item/storage/belt/wands/full = 4,
/obj/item/teleportation_scroll = 1,
/obj/item/contract/apprentice = 1
/obj/item/contract/apprentice = 1,
/obj/item/apprentice_pebble = 2
)

View File

@@ -28,5 +28,13 @@
/obj/item/gun/energy/staff/animate = 1,
/obj/structure/closet/wizard/scrying = 1,
/obj/item/monster_manual = 2,
/obj/item/contract/apprentice = 1
/obj/item/contract/apprentice = 1,
/obj/item/apprentice_pebble = 2
)
apprentice_spells = list(
/spell/targeted/projectile/dumbfire/fireball = 1,
/spell/aoe_turf/smoke = 1,
/spell/targeted/mindcontrol = 2,
/obj/structure/closet/wizard/scrying = 1
)

View File

@@ -18,42 +18,34 @@
..()
for(var/mob/living/target in targets)
if(!(target.stat == DEAD))
to_chat(user, "This spell can't affect the living.")
return 0
if(target.stat != DEAD)
to_chat(user, SPAN_WARNING("This spell can't affect the living."))
return FALSE
if(isundead(target))
to_chat(user, "This spell can't affect the undead.")
return 0
to_chat(user, SPAN_WARNING("This spell can't affect the undead."))
return FALSE
if(islesserform(target))
to_chat(user, "This spell can't affect this lesser creature.")
return 0
to_chat(user, SPAN_WARNING("This spell can't affect this lesser creature."))
return FALSE
if(isipc(target))
to_chat(user, "This spell can't affect non-organics.")
return 0
to_chat(user, SPAN_WARNING("This spell can't affect non-organics."))
return FALSE
var/mob/living/carbon/human/skeleton/F = new(get_turf(target))
var/mob/living/carbon/human/skeleton/F = new /mob/living/carbon/human/skeleton(get_turf(target))
SSghostroles.add_spawn_atom("skeleton", F)
var/area/A = get_area(F)
if(A)
say_dead_direct("A skeleton has been created in [A.name]! Spawn in as it by using the ghost spawner menu in the ghost tab.")
target.visible_message("<span class='cult'>\The [target] explodes in a shower of gore, a skeleton emerges from the remains!</span>")
target.gib()
var/datum/ghosttrap/ghost = get_ghost_trap("skeleton minion")
ghost.request_player(F,"A wizard is requesting a skeleton minion.", 60 SECONDS)
spawn(600)
if(F)
if(!F.ckey || !F.client)
F.visible_message("With no soul to keep \the [F] linked to this plane, it turns into dust.")
F.dust()
F.master = user
F.faction = user.faction
else
to_chat(F, "<B>You are a skeleton minion to [usr], they are your master. Obey and protect your master at all costs, you have no free will.</B>")
F.faction = usr.faction
F.preEquipOutfit(/datum/outfit/admin/wizard/skeleton, FALSE)
F.equipOutfit(/datum/outfit/admin/wizard/skeleton, FALSE)
//equips the skeleton war gear
F.equip_to_slot_or_del(new /obj/item/clothing/under/gladiator(F), slot_w_uniform)
F.equip_to_slot_or_del(new /obj/item/clothing/shoes/sandal(F), slot_shoes)
F.equip_to_slot_or_del(new /obj/item/material/twohanded/spear/bone(F), slot_back)
F.equip_to_slot_or_del(new /obj/item/clothing/head/helmet/bone(F), slot_head)
F.equip_to_slot_or_del(new /obj/item/clothing/suit/armor/bone(F), slot_wear_suit)
return 1
return TRUE

View File

@@ -20,9 +20,9 @@
if(!target)
return
to_chat(user, SPAN_WARNING("\The [user] teleported to you!"))
to_chat(target, FONT_LARGE(SPAN_WARNING("\The [user] teleported to you!")))
user.forceMove(get_turf(target))
user.visible_message(SPAN_WARNING("\The [user] appears out of thin air!"))
user.visible_message(SPAN_WARNING("\The [user] appears out of thin air!"), SPAN_NOTICE("You successfully teleport to \the [target]."))
var/datum/effect/effect/system/smoke_spread/smoke = new /datum/effect/effect/system/smoke_spread
smoke.set_up(5, 0, get_turf(user))
smoke.attach(user)