Ports /vg/'s spell system for the sake of cult porting.

Does offer a much more pleasant basis to work with in the future, if someone wishes to add more spell-like abilities.
This commit is contained in:
PsiOmega
2015-04-09 14:36:46 +02:00
parent e6f83f8fa2
commit 990530d118
85 changed files with 3135 additions and 1924 deletions

View File

@@ -0,0 +1,25 @@
/*
Aoe turf spells target a ring of tiles around the user
This ring has an outer radius (range) and an inner radius (inner_radius)
Aoe turf spells have two useful flags: IGNOREDENSE and IGNORESPACE. These are explained in setup.dm
*/
/spell/aoe_turf //affects all turfs in view or range (depends)
spell_flags = IGNOREDENSE
var/inner_radius = -1 //for all your ring spell needs
/spell/aoe_turf/choose_targets(mob/user = usr)
var/list/targets = list()
for(var/turf/target in view_or_range(range,user,selection_type))
if(!(target in view_or_range(inner_radius,user,selection_type)))
if(target.density && (spell_flags & IGNOREDENSE))
continue
if(istype(target, /turf/space) && (spell_flags & IGNORESPACE))
continue
targets += target
if(!targets.len) //doesn't waste the spell
return
return targets

View File

@@ -0,0 +1,34 @@
/spell/aoe_turf/blink
name = "Blink"
desc = "This spell randomly teleports you a short distance."
school = "abjuration"
charge_max = 20
spell_flags = Z2NOCAST | IGNOREDENSE | IGNORESPACE
invocation = "none"
invocation_type = SpI_NONE
range = 7
inner_radius = 1
cooldown_min = 5 //4 deciseconds reduction per rank
hud_state = "wiz_blink"
/spell/aoe_turf/blink/cast(var/list/targets, mob/user)
if(!targets.len)
return
var/turf/T = pick(targets)
var/turf/starting = get_turf(user)
if(T)
if(user.buckled)
user.buckled = null
user.forceMove(T)
var/datum/effect/effect/system/smoke_spread/smoke = new /datum/effect/effect/system/smoke_spread()
smoke.set_up(3, 0, starting)
smoke.start()
smoke = new()
smoke.set_up(3, 0, T)
smoke.start()
return

View File

@@ -0,0 +1,69 @@
/spell/aoe_turf/charge
name = "Charge"
desc = "This spell can be used to charge up spent magical artifacts, among other things."
school = "transmutation"
charge_max = 600
spell_flags = 0
invocation = "DIRI CEL"
invocation_type = SpI_WHISPER
range = 0
cooldown_min = 400 //50 deciseconds reduction per rank
hud_state = "wiz_charge"
/spell/aoe_turf/charge/cast(var/list/targets, mob/user)
for(var/turf/T in targets)
depth_cast(T)
/spell/aoe_turf/charge/proc/depth_cast(var/list/targets)
for(var/atom/A in targets)
if(A.contents.len)
depth_cast(A.contents)
cast_charge(A)
/spell/aoe_turf/charge/proc/mob_charge(var/mob/living/M)
if(M.spell_list.len != 0)
for(var/spell/S in M.spell_list)
if(!istype(S, /spell/aoe_turf/charge))
S.charge_counter = S.charge_max
M <<"<span class='notice'>You feel raw magic flowing through you, it feels good!</span>"
else
M <<"<span class='notice'>You feel very strange for a moment, but then it passes.</span>"
return M
/spell/aoe_turf/charge/proc/cast_charge(var/atom/target)
var/atom/charged_item
if(istype(target, /mob/living))
charged_item = mob_charge(target)
if(istype(target, /obj/item/weapon/grab))
var/obj/item/weapon/grab/G = target
if(G.affecting)
var/mob/M = G.affecting
charged_item = mob_charge(M)
if(istype(target, /obj/item/weapon/spellbook/oneuse))
var/obj/item/weapon/spellbook/oneuse/I = target
if(prob(50))
I.visible_message("<span class='warning'>[I] catches fire!</span>")
del(I)
else
I.used = 0
charged_item = I
if(istype(target, /obj/item/weapon/cell/))
var/obj/item/weapon/cell/C = target
if(prob(80))
C.maxcharge -= 200
if(C.maxcharge <= 1) //Div by 0 protection
C.maxcharge = 1
C.charge = C.maxcharge
charged_item = C
if(!charged_item)
return 0
else
charged_item.visible_message("<span class='notice'>[charged_item] suddenly sparks with energy!</span>")
return 1

View File

@@ -0,0 +1,74 @@
/*
Conjure spells spawn things (mobs, objs, turfs) in their summon_type
How they spawn stuff is decided by behaviour vars, which are explained below
*/
/spell/aoe_turf/conjure
name = "Conjure"
desc = "This spell conjures objs of the specified types in range."
school = "conjuration" //funny, that
var/list/summon_type = list() //determines what exactly will be summoned
//should be text, like list("/obj/machinery/bot/ed209")
range = 0 //default values: only spawn on the player tile
selection_type = "view"
duration = 0 // 0=permanent, any other time in deciseconds - how long the summoned objects last for
var/summon_amt = 1 //amount of objects summoned
var/summon_exclusive = 0 //spawn one of everything, instead of random things
var/list/newVars = list() //vars of the summoned objects will be replaced with those where they meet
//should have format of list("emagged" = 1,"name" = "Wizard's Justicebot"), for example
cast_sound = 'sound/items/welder.ogg'
/spell/aoe_turf/conjure/cast(list/targets, mob/user)
playsound(get_turf(user), cast_sound, 50, 1)
for(var/i=1,i <= summon_amt,i++)
if(!targets.len)
break
var/summoned_object_type
if(summon_exclusive)
if(!summon_type.len)
break
summoned_object_type = summon_type[1]
summon_type -= summoned_object_type
else
summoned_object_type = pick(summon_type)
var/turf/spawn_place = pick(targets)
if(spell_flags & IGNOREPREV)
targets -= spawn_place
var/atom/summoned_object
if(ispath(summoned_object_type,/turf))
if(istype(get_turf(user),/turf/simulated/shuttle) || istype(spawn_place, /turf/simulated/shuttle))
user << "<span class='warning>You can't build things on shuttles!</span>"
continue
spawn_place.ChangeTurf(summoned_object_type)
summoned_object = spawn_place
else
summoned_object = new summoned_object_type(spawn_place)
var/atom/movable/overlay/animation = new /atom/movable/overlay(spawn_place)
animation.name = "conjure"
animation.density = 0
animation.anchored = 1
animation.icon = 'icons/effects/effects.dmi'
animation.layer = 3
animation.master = summoned_object
for(var/varName in newVars)
if(varName in summoned_object.vars)
summoned_object.vars[varName] = newVars[varName]
if(duration)
spawn(duration)
if(summoned_object && !istype(summoned_object, /turf))
qdel(summoned_object)
conjure_animation(animation, spawn_place)
return
/spell/aoe_turf/conjure/proc/conjure_animation(var/atom/movable/overlay/animation, var/turf/target)
del(animation)

View File

@@ -0,0 +1,137 @@
//////////////////////////////Construct Spells/////////////////////////
/spell/aoe_turf/conjure/construct
name = "Artificer"
desc = "This spell conjures a construct which may be controlled by Shades"
school = "conjuration"
charge_max = 600
spell_flags = 0
invocation = "none"
invocation_type = SpI_NONE
range = 0
summon_type = list(/obj/structure/constructshell)
hud_state = "artificer"
/spell/aoe_turf/conjure/construct/lesser
charge_max = 1800
summon_type = list(/obj/structure/constructshell/cult)
hud_state = "const_shell"
override_base = "const"
/spell/aoe_turf/conjure/floor
name = "Floor Construction"
desc = "This spell constructs a cult floor"
charge_max = 20
spell_flags = Z2NOCAST | CONSTRUCT_CHECK
invocation = "none"
invocation_type = SpI_NONE
range = 0
summon_type = list(/turf/simulated/floor/engine/cult)
hud_state = "const_floor"
/spell/aoe_turf/conjure/floor/conjure_animation(var/atom/movable/overlay/animation, var/turf/target)
animation.icon_state = "cultfloor"
flick("cultfloor",animation)
spawn(10)
del(animation)
/spell/aoe_turf/conjure/wall
name = "Lesser Construction"
desc = "This spell constructs a cult wall"
charge_max = 100
spell_flags = Z2NOCAST | CONSTRUCT_CHECK
invocation = "none"
invocation_type = SpI_NONE
range = 0
summon_type = list(/turf/simulated/wall/cult)
hud_state = "const_wall"
/spell/aoe_turf/conjure/wall/conjure_animation(var/atom/movable/overlay/animation, var/turf/target)
animation.icon_state = "cultwall"
flick("cultwall",animation)
spawn(10)
del(animation)
/spell/aoe_turf/conjure/wall/reinforced
name = "Greater Construction"
desc = "This spell constructs a reinforced metal wall"
charge_max = 300
spell_flags = Z2NOCAST
invocation = "none"
invocation_type = SpI_NONE
range = 0
cast_delay = 50
summon_type = list(/turf/simulated/wall/r_wall)
/spell/aoe_turf/conjure/soulstone
name = "Summon Soulstone"
desc = "This spell reaches into Nar-Sie's realm, summoning one of the legendary fragments across time and space"
charge_max = 3000
spell_flags = 0
invocation = "none"
invocation_type = SpI_NONE
range = 0
summon_type = list(/obj/item/device/soulstone)
hud_state = "const_stone"
override_base = "const"
/spell/aoe_turf/conjure/pylon
name = "Red Pylon"
desc = "This spell conjures a fragile crystal from Nar-Sie's realm. Makes for a convenient light source."
charge_max = 200
spell_flags = CONSTRUCT_CHECK
invocation = "none"
invocation_type = SpI_NONE
range = 0
summon_type = list(/obj/structure/cult/pylon)
hud_state = "const_pylon"
/spell/aoe_turf/conjure/pylon/cast(list/targets)
..()
var/turf/spawn_place = pick(targets)
for(var/obj/structure/cult/pylon/P in spawn_place.contents)
if(P.isbroken)
P.repair(usr)
continue
return
/spell/aoe_turf/conjure/forcewall/lesser
name = "Shield"
desc = "Allows you to pull up a shield to protect yourself and allies from incoming threats"
charge_max = 300
spell_flags = 0
invocation = "none"
invocation_type = SpI_NONE
range = 0
summon_type = list(/obj/effect/forcefield/cult)
duration = 200
hud_state = "const_juggwall"
//Code for the Juggernaut construct's forcefield, that seemed like a good place to put it.
/obj/effect/forcefield/cult
desc = "That eerie looking obstacle seems to have been pulled from another dimension through sheer force"
name = "Juggerwall"
icon = 'icons/effects/effects.dmi'
icon_state = "m_shield_cult"
l_color = "#B40000"
luminosity = 2
/obj/effect/forcefield/cult/cultify()
return

View File

@@ -0,0 +1,52 @@
/spell/aoe_turf/conjure/forcewall
name = "Forcewall"
desc = "Create a wall of pure energy at your location."
summon_type = list(/obj/effect/forcefield)
duration = 300
charge_max = 100
spell_flags = 0
range = 0
cast_sound = null
hud_state = "wiz_shield"
/spell/aoe_turf/conjure/forcewall/mime
name = "Invisible wall"
desc = "Create an invisible wall on your location."
school = "mime"
panel = "Mime"
summon_type = list(/obj/effect/forcefield/mime)
invocation_type = SpI_EMOTE
invocation = "mimes placing their hands on a flat surfacing, and pushing against it."
charge_max = 300
cast_sound = null
override_base = "grey"
hud_state = "mime_wall"
/obj/effect/forcefield
desc = "A space wizard's magic wall."
name = "FORCEWALL"
icon = 'icons/effects/effects.dmi'
icon_state = "m_shield"
anchored = 1.0
opacity = 0
density = 1
unacidable = 1
/obj/effect/forcefield/bullet_act(var/obj/item/projectile/Proj, var/def_zone)
var/turf/T = get_turf(src.loc)
if(T)
for(var/mob/M in T)
Proj.on_hit(M,M.bullet_act(Proj, def_zone))
return
/obj/effect/forcefield/mime
icon_state = "empty"
name = "invisible wall"
desc = "You have a bad feeling about this."
/obj/effect/forcefield/cultify()
new /obj/effect/forcefield/cult(get_turf(src))
qdel(src)
return

View File

@@ -0,0 +1,23 @@
/spell/aoe_turf/disable_tech
name = "Disable Tech"
desc = "This spell disables all weapons, cameras and most other technology in range."
charge_max = 400
spell_flags = NEEDSCLOTHES
invocation = "NEC CANTIO"
invocation_type = SpI_SHOUT
selection_type = "range"
range = 0
inner_radius = -1
cooldown_min = 200 //50 deciseconds reduction per rank
var/emp_heavy = 6
var/emp_light = 10
hud_state = "wiz_tech"
/spell/aoe_turf/disable_tech/cast(list/targets)
for(var/turf/target in targets)
empulse(get_turf(target), emp_heavy, emp_light)
return

View File

@@ -0,0 +1,44 @@
/spell/aoe_turf/knock
name = "Knock"
desc = "This spell opens nearby doors and does not require wizard garb."
school = "transmutation"
charge_max = 100
spell_flags = 0
invocation = "AULIE OXIN FIERA"
invocation_type = SpI_WHISPER
range = 3
cooldown_min = 20 //20 deciseconds reduction per rank
hud_state = "wiz_knock"
/spell/aoe_turf/knock/cast(list/targets)
for(var/turf/T in targets)
for(var/obj/machinery/door/door in T.contents)
spawn(1)
if(istype(door,/obj/machinery/door/airlock))
var/obj/machinery/door/airlock/AL = door //casting is important
AL.locked = 0
door.open()
return
//Construct version
/spell/aoe_turf/knock/harvester
name = "Disintegrate Doors"
desc = "No door shall stop you."
spell_flags = CONSTRUCT_CHECK
charge_max = 100
invocation = ""
invocation_type = "silent"
range = 5
hud_state = "const_knock"
/spell/aoe_turf/knock/harvester/cast(list/targets)
for(var/turf/T in targets)
for(var/obj/machinery/door/door in T.contents)
spawn door.cultify()
return

View File

@@ -0,0 +1,17 @@
/spell/aoe_turf/smoke
name = "Smoke"
desc = "This spell spawns a cloud of choking smoke at your location and does not require wizard garb."
school = "conjuration"
charge_max = 120
spell_flags = 0
invocation = "none"
invocation_type = SpI_NONE
range = 1
inner_radius = -1
cooldown_min = 20 //25 deciseconds reduction per rank
smoke_spread = 2
smoke_amt = 5
hud_state = "wiz_smoke"

View File

@@ -0,0 +1,41 @@
/spell/aoe_turf/conjure/summonEdSwarm //test purposes
name = "Dispense Wizard Justice"
desc = "This spell dispenses wizard justice."
summon_type = list(/obj/machinery/bot/secbot/ed209)
summon_amt = 10
range = 3
newVars = list("emagged" = 1,"name" = "Wizard's Justicebot")
hud_state = "wiz_ed"
/spell/aoe_turf/conjure/carp
name = "Summon Carp"
desc = "This spell conjures a simple carp."
school = "conjuration"
charge_max = 1200
spell_flags = NEEDSCLOTHES
invocation = "NOUK FHUNMM SACP RISSKA"
invocation_type = SpI_SHOUT
range = 1
summon_type = list(/mob/living/simple_animal/hostile/carp)
hud_state = "wiz_carp"
/spell/aoe_turf/conjure/creature
name = "Summon Creature Swarm"
desc = "This spell tears the fabric of reality, allowing horrific daemons to spill forth"
school = "conjuration"
charge_max = 1200
spell_flags = 0
invocation = "IA IA"
invocation_type = SpI_SHOUT
summon_amt = 10
range = 3
summon_type = list(/mob/living/simple_animal/hostile/creature)
hud_state = "wiz_creature"

View File

@@ -1,82 +0,0 @@
/obj/effect/proc_holder/spell/targeted/area_teleport
name = "Area teleport"
desc = "This spell teleports you to a type of area of your selection."
var/randomise_selection = 0 //if it lets the usr choose the teleport loc or picks it from the list
var/invocation_area = 1 //if the invocation appends the selected area
/obj/effect/proc_holder/spell/targeted/area_teleport/perform(list/targets, recharge = 1)
var/thearea = before_cast(targets)
if(!thearea || !cast_check(1))
revert_cast()
return
invocation(thearea)
spawn(0)
if(charge_type == "recharge" && recharge)
start_recharge()
cast(targets,thearea)
after_cast(targets)
/obj/effect/proc_holder/spell/targeted/area_teleport/before_cast(list/targets)
var/A = null
if(!randomise_selection)
A = input("Area to teleport to", "Teleport", A) in teleportlocs
else
A = pick(teleportlocs)
var/area/thearea = teleportlocs[A]
return thearea
/obj/effect/proc_holder/spell/targeted/area_teleport/cast(list/targets,area/thearea)
for(var/mob/living/target in targets)
var/list/L = list()
for(var/turf/T in get_area_turfs(thearea.type))
if(!T.density)
var/clear = 1
for(var/obj/O in T)
if(O.density)
clear = 0
break
if(clear)
L+=T
if(!L.len)
usr <<"The spell matrix was unable to locate a suitable teleport destination for an unknown reason. Sorry."
return
if(target && target.buckled)
target.buckled.unbuckle_mob()
var/list/tempL = L
var/attempt = null
var/success = 0
while(tempL.len)
attempt = pick(tempL)
success = target.Move(attempt)
if(!success)
tempL.Remove(attempt)
else
break
if(!success)
target.loc = pick(L)
return
/obj/effect/proc_holder/spell/targeted/area_teleport/invocation(area/chosenarea = null)
if(!invocation_area || !chosenarea)
..()
else
switch(invocation_type)
if("shout")
usr.say("[invocation] [uppertext(chosenarea.name)]")
if(usr.gender==MALE)
playsound(usr.loc, pick('sound/misc/null.ogg','sound/misc/null.ogg'), 100, 1)
else
playsound(usr.loc, pick('sound/misc/null.ogg','sound/misc/null.ogg'), 100, 1)
if("whisper")
usr.whisper("[invocation] [uppertext(chosenarea.name)]")
return

View File

@@ -0,0 +1,19 @@
//////////////////////Scrying orb//////////////////////
/obj/item/weapon/scrying
name = "scrying orb"
desc = "An incandescent orb of otherworldly energy, staring into it gives you vision beyond mortal means."
icon = 'icons/obj/projectiles.dmi'
icon_state = "bluespace"
throw_speed = 3
throw_range = 7
throwforce = 10
damtype = BURN
force = 10
hitsound = 'sound/items/welder2.ogg'
/obj/item/weapon/scrying/attack_self(mob/user as mob)
user << "<span class='info'>You can see... everything!</span>"
visible_message("<span class='danger'>[usr] stares into [src], their eyes glazing over.</span>")
announce_ghost_joinleave(user.ghostize(1), 1, "You feel that they used a powerful artifact to [pick("invade","disturb","disrupt","infest","taint","spoil","blight")] this place with their presence.")
return

View File

@@ -1,87 +0,0 @@
/obj/effect/proc_holder/spell/aoe_turf/conjure
name = "Conjure"
desc = "This spell conjures objs of the specified types in range."
var/list/summon_type = list() //determines what exactly will be summoned
//should be text, like list("/obj/machinery/bot/ed209")
var/summon_lifespan = 0 // 0=permanent, any other time in deciseconds
var/summon_amt = 1 //amount of objects summoned
var/summon_ignore_density = 0 //if set to 1, adds dense tiles to possible spawn places
var/summon_ignore_prev_spawn_points = 0 //if set to 1, each new object is summoned on a new spawn point
var/list/newVars = list() //vars of the summoned objects will be replaced with those where they meet
//should have format of list("emagged" = 1,"name" = "Wizard's Justicebot"), for example
var/delay = 1//Go Go Gadget Inheritance
/obj/effect/proc_holder/spell/aoe_turf/conjure/cast(list/targets)
for(var/turf/T in targets)
if(T.density && !summon_ignore_density)
targets -= T
playsound(src.loc, 'sound/items/welder.ogg', 50, 1)
if(do_after(usr,delay))
for(var/i=0,i<summon_amt,i++)
if(!targets.len)
break
var/summoned_object_type = pick(summon_type)
var/spawn_place = pick(targets)
if(summon_ignore_prev_spawn_points)
targets -= spawn_place
if(ispath(summoned_object_type,/turf))
var/turf/O = spawn_place
var/turf/N = summoned_object_type
O.ChangeTurf(N)
else
var/atom/summoned_object = new summoned_object_type(spawn_place)
for(var/varName in newVars)
if(varName in summoned_object.vars)
summoned_object.vars[varName] = newVars[varName]
if(summon_lifespan)
spawn(summon_lifespan)
if(summoned_object)
del(summoned_object)
else
switch(charge_type)
if("recharge")
charge_counter = charge_max - 5//So you don't lose charge for a failed spell(Also prevents most over-fill)
if("charges")
charge_counter++//Ditto, just for different spell types
return
/obj/effect/proc_holder/spell/aoe_turf/conjure/summonEdSwarm //test purposes
name = "Dispense Wizard Justice"
desc = "This spell dispenses wizard justice."
summon_type = list(/obj/item/weapon/secbot_assembly/ed209_assembly)
summon_amt = 10
range = 3
newVars = list("emagged" = 1,"name" = "Wizard's Justicebot")
//This was previously left in the old wizard code, not being included.
//Wasn't sure if I should transfer it here, or to code/datums/spells.dm
//But I decided because it is a conjuration related object it would fit better here
//Feel free to change this, I don't know.
/obj/effect/forcefield
desc = "A space wizard's magic wall."
name = "FORCEWALL"
icon = 'icons/effects/effects.dmi'
icon_state = "m_shield"
anchored = 1.0
opacity = 0
density = 1
unacidable = 1
bullet_act(var/obj/item/projectile/Proj, var/def_zone)
var/turf/T = get_turf(src.loc)
if(T)
for(var/mob/M in T)
Proj.on_hit(M,M.bullet_act(Proj, def_zone))
return

View File

@@ -0,0 +1,12 @@
//////////////////////////////Construct Spells/////////////////////////
proc/findNullRod(var/atom/target)
if(istype(target,/obj/item/weapon/nullrod))
var/turf/T = get_turf(target)
T.turf_animation('icons/effects/96x96.dmi',"nullding",-32,-32,MOB_LAYER+1,'sound/piano/Ab7.ogg')
return 1
else if(target.contents)
for(var/atom/A in target.contents)
if(findNullRod(A))
return 1
return 0

View File

@@ -1,86 +0,0 @@
/obj/effect/proc_holder/spell/dumbfire
var/projectile_type = ""
var/activate_on_collision = 1
var/proj_icon = 'icons/obj/projectiles.dmi'
var/proj_icon_state = "spell"
var/proj_name = "a spell projectile"
var/proj_trail = 0 //if it leaves a trail
var/proj_trail_lifespan = 0 //deciseconds
var/proj_trail_icon = 'icons/obj/wizard.dmi'
var/proj_trail_icon_state = "trail"
var/proj_type = "/obj/effect/proc_holder/spell" //IMPORTANT use only subtypes of this
var/proj_insubstantial = 0 //if it can pass through dense objects or not
var/proj_trigger_range = 1 //the range from target at which the projectile triggers cast(target)
var/proj_lifespan = 100 //in deciseconds * proj_step_delay
var/proj_step_delay = 1 //lower = faster
/obj/effect/proc_holder/spell/dumbfire/choose_targets(mob/user = usr)
var/turf/T = get_turf(usr)
for(var/i = 1; i < range; i++)
var/turf/new_turf = get_step(T, usr.dir)
if(new_turf.density)
break
T = new_turf
perform(list(T))
/obj/effect/proc_holder/spell/dumbfire/cast(list/targets, mob/user = usr)
for(var/turf/target in targets)
spawn(0)
var/obj/effect/proc_holder/spell/targeted/projectile
if(istext(proj_type))
var/projectile_type = text2path(proj_type)
projectile = new projectile_type(user)
if(istype(proj_type,/obj/effect/proc_holder/spell))
projectile = new /obj/effect/proc_holder/spell/targeted/trigger(user)
projectile:linked_spells += proj_type
projectile.icon = proj_icon
projectile.icon_state = proj_icon_state
projectile.set_dir(get_dir(projectile, target))
projectile.name = proj_name
var/current_loc = usr.loc
projectile.loc = current_loc
for(var/i = 0,i < proj_lifespan,i++)
if(!projectile)
break
if(proj_insubstantial)
projectile.loc = get_step(projectile, projectile.dir)
else
step(projectile, projectile.dir)
if(projectile.loc == current_loc || i == proj_lifespan)
projectile.cast(current_loc)
break
var/mob/living/L = locate(/mob/living) in range(projectile, proj_trigger_range) - usr
if(L)
projectile.cast(L.loc)
break
if(proj_trail && projectile)
spawn(0)
if(projectile)
var/obj/effect/overlay/trail = new /obj/effect/overlay(projectile.loc)
trail.icon = proj_trail_icon
trail.icon_state = proj_trail_icon_state
trail.density = 0
spawn(proj_trail_lifespan)
del(trail)
current_loc = projectile.loc
sleep(proj_step_delay)
if(projectile)
del(projectile)

View File

@@ -1,13 +0,0 @@
/obj/effect/proc_holder/spell/targeted/emplosion
name = "Emplosion"
desc = "This spell emplodes an area."
var/emp_heavy = 2
var/emp_light = 3
/obj/effect/proc_holder/spell/targeted/emplosion/cast(list/targets)
for(var/mob/living/target in targets)
empulse(target.loc, emp_heavy, emp_light)
return

View File

@@ -1,106 +0,0 @@
/obj/effect/proc_holder/spell/targeted/ethereal_jaunt
name = "Ethereal Jaunt"
desc = "This spell creates your ethereal form, temporarily making you invisible and able to pass through walls."
school = "transmutation"
charge_max = 300
clothes_req = 1
invocation = "none"
invocation_type = "none"
range = -1
include_user = 1
centcomm_cancast = 0 //Prevent people from getting to centcomm
var phaseshift = 0
var/jaunt_duration = 50 //in deciseconds
/obj/effect/proc_holder/spell/targeted/ethereal_jaunt/cast(list/targets) //magnets, so mostly hardcoded
for(var/mob/living/target in targets)
spawn(0)
if(target.buckled)
var/obj/structure/bed/buckled_to = target.buckled.
buckled_to.unbuckle_mob()
var/mobloc = get_turf(target.loc)
var/obj/effect/dummy/spell_jaunt/holder = new /obj/effect/dummy/spell_jaunt( mobloc )
var/atom/movable/overlay/animation = new /atom/movable/overlay( mobloc )
animation.name = "water"
animation.density = 0
animation.anchored = 1
animation.icon = 'icons/mob/mob.dmi'
animation.icon_state = "liquify"
animation.layer = 5
animation.master = holder
if(phaseshift == 1)
animation.dir = target.dir
flick("phase_shift",animation)
target.loc = holder
target.client.eye = holder
sleep(jaunt_duration)
mobloc = get_turf(target.loc)
animation.loc = mobloc
target.canmove = 0
sleep(20)
animation.dir = target.dir
flick("phase_shift2",animation)
sleep(5)
if(!target.Move(mobloc))
for(var/direction in list(1,2,4,8,5,6,9,10))
var/turf/T = get_step(mobloc, direction)
if(T)
if(target.Move(T))
break
target.canmove = 1
target.client.eye = target
del(animation)
del(holder)
else
flick("liquify",animation)
target.loc = holder
target.client.eye = holder
var/datum/effect/effect/system/steam_spread/steam = new /datum/effect/effect/system/steam_spread()
steam.set_up(10, 0, mobloc)
steam.start()
sleep(jaunt_duration)
mobloc = get_turf(target.loc)
animation.loc = mobloc
steam.location = mobloc
steam.start()
target.canmove = 0
sleep(20)
flick("reappear",animation)
sleep(5)
if(!target.Move(mobloc))
for(var/direction in list(1,2,4,8,5,6,9,10))
var/turf/T = get_step(mobloc, direction)
if(T)
if(target.Move(T))
break
target.canmove = 1
target.client.eye = target
del(animation)
del(holder)
/obj/effect/dummy/spell_jaunt
name = "water"
icon = 'icons/effects/effects.dmi'
icon_state = "nothing"
var/canmove = 1
density = 0
anchored = 1
/obj/effect/dummy/spell_jaunt/relaymove(var/mob/user, direction)
if (!src.canmove) return
var/turf/newLoc = get_step(src,direction)
if(!(newLoc.flags & NOJAUNT))
loc = newLoc
else
user << "<span class='warning'>Some strange aura is blocking the way!</span>"
src.canmove = 0
spawn(2) src.canmove = 1
/obj/effect/dummy/spell_jaunt/ex_act(blah)
return
/obj/effect/dummy/spell_jaunt/bullet_act(blah)
return

View File

@@ -1,15 +0,0 @@
/obj/effect/proc_holder/spell/targeted/explosion
name = "Explosion"
desc = "This spell explodes an area."
var/ex_severe = 1
var/ex_heavy = 2
var/ex_light = 3
var/ex_flash = 4
/obj/effect/proc_holder/spell/targeted/explosion/cast(list/targets)
for(var/mob/living/target in targets)
explosion(target.loc,ex_severe,ex_heavy,ex_light,ex_flash)
return

View File

@@ -0,0 +1,85 @@
/spell/area_teleport
name = "Teleport"
desc = "This spell teleports you to a type of area of your selection."
school = "abjuration"
charge_max = 600
spell_flags = NEEDSCLOTHES
invocation = "SCYAR NILA"
invocation_type = SpI_SHOUT
cooldown_min = 200 //100 deciseconds reduction per rank
smoke_spread = 1
smoke_amt = 5
var/randomise_selection = 0 //if it lets the usr choose the teleport loc or picks it from the list
var/invocation_area = 1 //if the invocation appends the selected area
cast_sound = 'sound/effects/teleport.ogg'
hud_state = "wiz_tele"
/spell/area_teleport/before_cast()
return
/spell/area_teleport/choose_targets()
var/A = null
if(!randomise_selection)
A = input("Area to teleport to", "Teleport", A) in teleportlocs
else
A = pick(teleportlocs)
var/area/thearea = teleportlocs[A]
return list(thearea)
/spell/area_teleport/cast(area/thearea, mob/user)
if(!istype(thearea))
if(istype(thearea, /list))
thearea = thearea[1]
var/list/L = list()
for(var/turf/T in get_area_turfs(thearea.type))
if(!T.density)
var/clear = 1
for(var/obj/O in T)
if(O.density)
clear = 0
break
if(clear)
L+=T
if(!L.len)
user <<"The spell matrix was unable to locate a suitable teleport destination for an unknown reason. Sorry."
return
if(user && user.buckled)
user.buckled = null
var/attempt = null
var/success = 0
while(L.len)
attempt = pick(L)
success = user.Move(attempt)
if(!success)
L.Remove(attempt)
else
break
if(!success)
user.loc = pick(L)
return
/spell/area_teleport/after_cast()
return
/spell/area_teleport/invocation(mob/user, area/chosenarea)
if(!istype(chosenarea))
return //can't have that, can we
if(!invocation_area || !chosenarea)
..()
else
invocation += "[uppertext(chosenarea.name)]"
..()
return

View File

@@ -0,0 +1,175 @@
/spell/rune_write
name = "Scribe a Rune"
desc = "Let's you instantly manifest a working rune."
school = "evocation"
charge_max = 100
charge_type = Sp_RECHARGE
invocation_type = SpI_NONE
spell_flags = CONSTRUCT_CHECK
hud_state = "const_rune"
smoke_amt = 1
/spell/rune_write/choose_targets(mob/user = usr)
return list(user)
/spell/rune_write/cast(null, mob/user = usr)
if(!cultwords["travel"])
runerandom()
var/list/runes = list("Teleport", "Teleport Other", "Spawn a Tome", "Change Construct Type", "Convert", "EMP", "Drain Blood", "See Invisible", "Resurrect", "Hide Runes", "Reveal Runes", "Astral Journey", "Manifest a Ghost", "Imbue Talisman", "Sacrifice", "Wall", "Free Cultist", "Summon Cultist", "Deafen", "Blind", "BloodBoil", "Communicate", "Stun")
var/r = input(user, "Choose a rune to scribe", "Rune Scribing") in runes //not cancellable.
var/obj/effect/rune/R = new /obj/effect/rune(user.loc)
if(istype(user.loc,/turf))
var/area/A = get_area(user)
log_and_message_admins("created \an [r] rune at \the [A.name] - [user.loc.x]-[user.loc.y]-[user.loc.z].", user)
switch(r)
if("Teleport")
if(cast_check(1))
var/beacon
if(user)
beacon = input(user, "Select the last rune", "Rune Scribing") in rnwords
R.word1=cultwords["travel"]
R.word2=cultwords["self"]
R.word3=beacon
R.check_icon()
if("Teleport Other")
if(cast_check(1))
var/beacon
if(user)
beacon = input(user, "Select the last rune", "Rune Scribing") in rnwords
R.word1=cultwords["travel"]
R.word2=cultwords["other"]
R.word3=beacon
R.check_icon()
if("Spawn a Tome")
if(cast_check(1))
R.word1=cultwords["see"]
R.word2=cultwords["blood"]
R.word3=cultwords["hell"]
R.check_icon()
if("Change Construct Type")
if(cast_check(1))
R.word1=cultwords["hell"]
R.word2=cultwords["destroy"]
R.word3=cultwords["other"]
R.check_icon()
if("Convert")
if(cast_check(1))
R.word1=cultwords["join"]
R.word2=cultwords["blood"]
R.word3=cultwords["self"]
R.check_icon()
if("EMP")
if(cast_check(1))
R.word1=cultwords["destroy"]
R.word2=cultwords["see"]
R.word3=cultwords["technology"]
R.check_icon()
if("Drain Blood")
if(cast_check(1))
R.word1=cultwords["travel"]
R.word2=cultwords["blood"]
R.word3=cultwords["self"]
R.check_icon()
if("See Invisible")
if(cast_check(1))
R.word1=cultwords["see"]
R.word2=cultwords["hell"]
R.word3=cultwords["join"]
R.check_icon()
if("Resurrect")
if(cast_check(1))
R.word1=cultwords["blood"]
R.word2=cultwords["join"]
R.word3=cultwords["hell"]
R.check_icon()
if("Hide Runes")
if(cast_check(1))
R.word1=cultwords["hide"]
R.word2=cultwords["see"]
R.word3=cultwords["blood"]
R.check_icon()
if("Astral Journey")
if(cast_check(1))
R.word1=cultwords["hell"]
R.word2=cultwords["travel"]
R.word3=cultwords["self"]
R.check_icon()
if("Manifest a Ghost")
if(cast_check(1))
R.word1=cultwords["blood"]
R.word2=cultwords["see"]
R.word3=cultwords["travel"]
R.check_icon()
if("Imbue Talisman")
if(cast_check(1))
R.word1=cultwords["hell"]
R.word2=cultwords["technology"]
R.word3=cultwords["join"]
R.check_icon()
if("Sacrifice")
if(cast_check(1))
R.word1=cultwords["hell"]
R.word2=cultwords["blood"]
R.word3=cultwords["join"]
R.check_icon()
if("Reveal Runes")
if(cast_check(1))
R.word1=cultwords["blood"]
R.word2=cultwords["see"]
R.word3=cultwords["hide"]
R.check_icon()
if("Wall")
if(cast_check(1))
R.word1=cultwords["destroy"]
R.word2=cultwords["travel"]
R.word3=cultwords["self"]
R.check_icon()
if("Freedom")
if(cast_check(1))
R.word1=cultwords["travel"]
R.word2=cultwords["technology"]
R.word3=cultwords["other"]
R.check_icon()
if("Cultsummon")
if(cast_check(1))
R.word1=cultwords["join"]
R.word2=cultwords["other"]
R.word3=cultwords["self"]
R.check_icon()
if("Deafen")
if(cast_check(1))
R.word1=cultwords["hide"]
R.word2=cultwords["other"]
R.word3=cultwords["see"]
R.check_icon()
if("Blind")
if(cast_check(1))
R.word1=cultwords["destroy"]
R.word2=cultwords["see"]
R.word3=cultwords["other"]
R.check_icon()
if("BloodBoil")
if(cast_check(1))
R.word1=cultwords["destroy"]
R.word2=cultwords["see"]
R.word3=cultwords["blood"]
R.check_icon()
if("Communicate")
if(cast_check(1))
R.word1=cultwords["self"]
R.word2=cultwords["other"]
R.word3=cultwords["technology"]
R.check_icon()
if("Stun")
if(cast_check(1))
R.word1=cultwords["join"]
R.word2=cultwords["hide"]
R.word3=cultwords["technology"]
R.check_icon()
else
user << "<span class='warning'> You do not have enough space to write a proper rune.</span>"
return

View File

@@ -1,31 +0,0 @@
/obj/effect/proc_holder/spell/targeted/genetic
name = "Genetic"
desc = "This spell inflicts a set of mutations and disabilities upon the target."
var/disabilities = 0 //bits
var/list/mutations = list() //mutation strings
var/duration = 100 //deciseconds
/*
Disabilities
1st bit - ?
2nd bit - ?
3rd bit - ?
4th bit - ?
5th bit - ?
6th bit - ?
*/
/obj/effect/proc_holder/spell/targeted/genetic/cast(list/targets)
for(var/mob/living/target in targets)
for(var/x in mutations)
target.mutations.Add(x)
target.disabilities |= disabilities
target.update_mutations() //update target's mutation overlays
spawn(duration)
for(var/x in mutations)
target.mutations.Remove(x)
target.disabilities &= ~disabilities
target.update_mutations()
return

View File

@@ -1,50 +0,0 @@
/obj/effect/proc_holder/spell/targeted/horsemask
name = "Curse of the Horseman"
desc = "This spell triggers a curse on a target, causing them to wield an unremovable horse head mask. They will speak like a horse! Any masks they are wearing will be disintegrated. This spell does not require robes."
school = "transmutation"
charge_type = "recharge"
charge_max = 150
charge_counter = 0
clothes_req = 0
stat_allowed = 0
invocation = "KN'A FTAGHU, PUCK 'BTHNK!"
invocation_type = "shout"
range = 7
selection_type = "range"
var/list/compatible_mobs = list(/mob/living/carbon/human)
/obj/effect/proc_holder/spell/targeted/horsemask/cast(list/targets, mob/user = usr)
if(!targets.len)
user << "<span class='notice'>No target found in range.</span>"
return
var/mob/living/carbon/target = targets[1]
if(!(target.type in compatible_mobs))
user << "<span class='notice'>It'd be stupid to curse [target] with a horse's head!</span>"
return
if(!(target in oview(range)))//If they are not in overview after selection.
user << "<span class='notice'>They are too far away!</span>"
return
var/obj/item/clothing/mask/horsehead/magic/magichead = new /obj/item/clothing/mask/horsehead/magic
target.visible_message( "<span class='danger'>[target]'s face lights up in fire, and after the event a horse's head takes its place!</span>", \
"<span class='danger'>Your face burns up, and shortly after the fire you realise you have the face of a horse!</span>")
target.equip_to_slot(magichead, slot_wear_mask)
flick("e_flash", target.flash)
//item used by the horsehead spell
/obj/item/clothing/mask/horsehead/magic
//flags_inv = null //so you can still see their face... no. How can you recognize someone when their face is completely different?
voicechange = 1 //NEEEEIIGHH
dropped(mob/user as mob)
canremove = 1
..()
equipped(var/mob/user, var/slot)
if (slot == slot_wear_mask)
canremove = 0 //curses!
..()

View File

@@ -1,59 +0,0 @@
/obj/effect/proc_holder/spell/targeted/inflict_handler
name = "Inflict Handler"
desc = "This spell blinds and/or destroys/damages/heals and/or weakens/stuns the target."
var/amt_weakened = 0
var/amt_paralysis = 0
var/amt_stunned = 0
//set to negatives for healing
var/amt_dam_fire = 0
var/amt_dam_brute = 0
var/amt_dam_oxy = 0
var/amt_dam_tox = 0
var/amt_eye_blind = 0
var/amt_eye_blurry = 0
var/destroys = "none" //can be "none", "gib" or "disintegrate"
/obj/effect/proc_holder/spell/targeted/inflict_handler/cast(list/targets)
for(var/mob/living/target in targets)
switch(destroys)
if("gib")
target.gib()
if("gib_brain")
if(ishuman(target) || issmall(target))
var/mob/living/carbon/C = target
if(!C.has_brain()) // Their brain is already taken out
var/obj/item/organ/brain/B = new(C.loc)
B.transfer_identity(C)
target.gib()
if("disintegrate")
target.dust()
if(!target)
continue
//damage
if(amt_dam_brute > 0)
if(amt_dam_fire >= 0)
target.take_overall_damage(amt_dam_brute,amt_dam_fire)
else if (amt_dam_fire < 0)
target.take_overall_damage(amt_dam_brute,0)
target.heal_overall_damage(0,amt_dam_fire)
else if(amt_dam_brute < 0)
if(amt_dam_fire > 0)
target.take_overall_damage(0,amt_dam_fire)
target.heal_overall_damage(amt_dam_brute,0)
else if (amt_dam_fire <= 0)
target.heal_overall_damage(amt_dam_brute,amt_dam_fire)
target.adjustToxLoss(amt_dam_tox)
target.oxyloss += amt_dam_oxy
//disabling
target.Weaken(amt_weakened)
target.Paralyse(amt_paralysis)
target.Stun(amt_stunned)
target.eye_blind += amt_eye_blind
target.eye_blurry += amt_eye_blurry

View File

@@ -1,20 +0,0 @@
/obj/effect/proc_holder/spell/aoe_turf/knock
name = "Knock"
desc = "This spell opens nearby doors and does not require wizard garb."
school = "transmutation"
charge_max = 100
clothes_req = 0
invocation = "AULIE OXIN FIERA"
invocation_type = "whisper"
range = 3
/obj/effect/proc_holder/spell/aoe_turf/knock/cast(list/targets)
for(var/turf/T in targets)
for(var/obj/machinery/door/door in T.contents)
spawn(1)
if(istype(door,/obj/machinery/door/airlock))
var/obj/machinery/door/airlock/A = door
A.unlock(1) //forced because it's magic!
door.open()
return

View File

@@ -1,116 +0,0 @@
/obj/effect/proc_holder/spell/targeted/mind_transfer
name = "Mind Transfer"
desc = "This spell allows the user to switch bodies with a target."
school = "transmutation"
charge_max = 600
clothes_req = 0
invocation = "GIN'YU CAPAN"
invocation_type = "whisper"
range = 1
var/list/protected_roles = list("Wizard","Changeling","Cultist") //which roles are immune to the spell
var/list/compatible_mobs = list(/mob/living/carbon/human) //which types of mobs are affected by the spell. NOTE: change at your own risk
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
/*
Urist: I don't feel like figuring out how you store object spells so I'm leaving this for you to do.
Make sure spells that are removed from spell_list are actually removed and deleted when mind transfering.
Also, you never added distance checking after target is selected. I've went ahead and did that.
*/
/obj/effect/proc_holder/spell/targeted/mind_transfer/cast(list/targets,mob/user = usr)
if(!targets.len)
user << "No mind found."
return
if(targets.len > 1)
user << "Too many minds! You're not a hive damnit!"//Whaa...aat?
return
var/mob/living/target = targets[1]
if(!(target in oview(range)))//If they are not in overview after selection. Do note that !() is necessary for in to work because ! takes precedence over it.
user << "They are too far away!"
return
if(!(target.type in compatible_mobs))
user << "Their mind isn't compatible with yours."
return
if(target.stat == DEAD)
user << "You didn't study necromancy back at the Space Wizard Federation academy."
return
if(!target.key || !target.mind)
user << "They appear to be catatonic. Not even magic can affect their vacant mind."
return
if(target.mind.special_role in protected_roles)
user << "Their mind is resisting your spell."
return
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
admin_attack_log(caster, victim, "Used mind transfer", "Was the victim of mind transfer", "used mind transfer on")
//NOTE: The caster must ALWAYS keep mind transfer, even when other spells are lost.
var/obj/effect/proc_holder/spell/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.
caster.verbs -= V//But a safety nontheless.
if(victim.mind.special_verbs.len)//Now remove all of the victim's verbs.
for(var/V in victim.mind.special_verbs)
victim.verbs -= V
var/mob/dead/observer/ghost = victim.ghostize(0)
ghost.spell_list = victim.spell_list//If they have spells, transfer them. Now we basically have a backup mob.
caster.mind.transfer_to(victim)
victim.spell_list = caster.spell_list//Now they are inside the victim's body.
if(victim.mind.special_verbs.len)//To add all the special verbs for the original caster.
for(var/V in caster.mind.special_verbs)//Not too important but could come into play.
caster.verbs += V
ghost.mind.transfer_to(caster)
caster.key = ghost.key //have to transfer the key since the mind was not active
caster.spell_list = ghost.spell_list
if(caster.mind.special_verbs.len)//If they had any special verbs, we add them here.
for(var/V in caster.mind.special_verbs)
caster.verbs += V
//MIND TRANSFER END
//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. <b>Your body doesn't seem like your own.</b>"

View File

@@ -0,0 +1,5 @@
/spell/noclothes
name = "No Clothes"
desc = "This is a placeholder for knowing if you dont need clothes for any spell."
spell_flags = NO_BUTTON

View File

@@ -1,83 +0,0 @@
/obj/effect/proc_holder/spell/targeted/projectile
name = "Projectile"
desc = "This spell summons projectiles which try to hit the targets."
var/proj_icon = 'icons/obj/projectiles.dmi'
var/proj_icon_state = "spell"
var/proj_name = "a spell projectile"
var/proj_trail = 0 //if it leaves a trail
var/proj_trail_lifespan = 0 //deciseconds
var/proj_trail_icon = 'icons/obj/wizard.dmi'
var/proj_trail_icon_state = "trail"
var/proj_type = "/obj/effect/proc_holder/spell/targeted" //IMPORTANT use only subtypes of this
var/proj_lingering = 0 //if it lingers or disappears upon hitting an obstacle
var/proj_homing = 1 //if it follows the target
var/proj_insubstantial = 0 //if it can pass through dense objects or not
var/proj_trigger_range = 0 //the range from target at which the projectile triggers cast(target)
var/proj_lifespan = 15 //in deciseconds * proj_step_delay
var/proj_step_delay = 1 //lower = faster
/obj/effect/proc_holder/spell/targeted/projectile/cast(list/targets, mob/user = usr)
for(var/mob/living/target in targets)
spawn(0)
var/obj/effect/proc_holder/spell/targeted/projectile
if(istext(proj_type))
var/projectile_type = text2path(proj_type)
projectile = new projectile_type(user)
if(istype(proj_type,/obj/effect/proc_holder/spell))
projectile = new /obj/effect/proc_holder/spell/targeted/trigger(user)
projectile:linked_spells += proj_type
projectile.icon = proj_icon
projectile.icon_state = proj_icon_state
projectile.set_dir(get_dir(target,projectile))
projectile.name = proj_name
var/current_loc = usr.loc
projectile.loc = current_loc
for(var/i = 0,i < proj_lifespan,i++)
if(!projectile)
break
if(proj_homing)
if(proj_insubstantial)
projectile.set_dir(get_dir(projectile,target))
projectile.loc = get_step_to(projectile,target)
else
step_to(projectile,target)
else
if(proj_insubstantial)
projectile.loc = get_step(projectile,dir)
else
step(projectile,dir)
if(!proj_lingering && projectile.loc == current_loc) //if it didn't move since last time
del(projectile)
break
if(proj_trail && projectile)
spawn(0)
if(projectile)
var/obj/effect/overlay/trail = new /obj/effect/overlay(projectile.loc)
trail.icon = proj_trail_icon
trail.icon_state = proj_trail_icon_state
trail.density = 0
spawn(proj_trail_lifespan)
del(trail)
if(projectile.loc in range(target.loc,proj_trigger_range))
projectile.perform(list(target))
break
current_loc = projectile.loc
sleep(proj_step_delay)
if(projectile)
del(projectile)

View File

@@ -1,302 +0,0 @@
/client/proc/give_spell(mob/T as mob in mob_list) // -- Urist
set category = "Fun"
set name = "Give Spell"
set desc = "Gives a spell to a mob."
var/list/spell_names = list()
for(var/v in spells)
// "/obj/effect/proc_holder/spell/" 30 symbols ~Intercross21
spell_names.Add(copytext("[v]", 31, 0))
var/S = input("Choose the spell to give to that guy", "ABRAKADABRA") as null|anything in spell_names
if(!S) return
var/path = text2path("/obj/effect/proc_holder/spell/[S]")
T.spell_list += new path
feedback_add_details("admin_verb","GS") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
log_admin("[key_name(usr)] gave [key_name(T)] the spell [S].")
message_admins("\blue [key_name_admin(usr)] gave [key_name(T)] the spell [S].", 1)
/obj/effect/proc_holder
var/panel = "Debug"//What panel the proc holder needs to go on.
var/list/spells = typesof(/obj/effect/proc_holder/spell) //needed for the badmin verb for now
/obj/effect/proc_holder/spell
name = "Spell"
desc = "A wizard spell"
density = 0
opacity = 0
var/school = "evocation" //not relevant at now, but may be important later if there are changes to how spells work. the ones I used for now will probably be changed... maybe spell presets? lacking flexibility but with some other benefit?
var/charge_type = "recharge" //can be recharge or charges, see charge_max and charge_counter descriptions; can also be based on the holder's vars now, use "holder_var" for that
var/charge_max = 100 //recharge time in deciseconds if charge_type = "recharge" or starting charges if charge_type = "charges"
var/charge_counter = 0 //can only cast spells if it equals recharge, ++ each decisecond if charge_type = "recharge" or -- each cast if charge_type = "charges"
var/holder_var_type = "bruteloss" //only used if charge_type equals to "holder_var"
var/holder_var_amount = 20 //same. The amount adjusted with the mob's var when the spell is used
var/clothes_req = 1 //see if it requires clothes
var/stat_allowed = 0 //see if it requires being conscious/alive, need to set to 1 for ghostpells
var/invocation = "HURP DURP" //what is uttered when the wizard casts the spell
var/invocation_type = "none" //can be none, whisper and shout
var/range = 7 //the range of the spell; outer radius for aoe spells
var/message = "" //whatever it says to the guy affected by it
var/selection_type = "view" //can be "range" or "view"
var/overlay = 0
var/overlay_icon = 'icons/obj/wizard.dmi'
var/overlay_icon_state = "spell"
var/overlay_lifespan = 0
var/sparks_spread = 0
var/sparks_amt = 0 //cropped at 10
var/smoke_spread = 0 //1 - harmless, 2 - harmful
var/smoke_amt = 0 //cropped at 10
var/critfailchance = 0
var/centcomm_cancast = 1 //Whether or not the spell should be allowed on z2
/obj/effect/proc_holder/spell/proc/cast_check(skipcharge = 0,mob/user = usr) //checks if the spell can be cast based on its settings; skipcharge is used when an additional cast_check is called inside the spell
if(!(src in usr.spell_list))
usr << "\red You shouldn't have this spell! Something's wrong."
return 0
if(usr.z == 2 && !centcomm_cancast) //Certain spells are not allowed on the centcomm zlevel
return 0
if(!skipcharge)
switch(charge_type)
if("recharge")
if(charge_counter < charge_max)
usr << "[name] is still recharging."
return 0
if("charges")
if(!charge_counter)
usr << "[name] has no charges left."
return 0
if(usr.stat && !stat_allowed)
usr << "Not when you're incapacitated."
return 0
if(ishuman(usr) || issmall(usr))
if(istype(usr.wear_mask, /obj/item/clothing/mask/muzzle))
usr << "Mmmf mrrfff!"
return 0
if(clothes_req) //clothes check
if(!istype(usr, /mob/living/carbon/human))
usr << "You aren't a human, Why are you trying to cast a human spell, silly non-human? Casting human spells is for humans."
return 0
if(!istype(usr:wear_suit, /obj/item/clothing/suit/wizrobe) && !istype(user:wear_suit, /obj/item/clothing/suit/space/void/wizard))
usr << "I don't feel strong enough without my robe."
return 0
if(!istype(usr:shoes, /obj/item/clothing/shoes/sandal))
usr << "I don't feel strong enough without my sandals."
return 0
if(!istype(usr:head, /obj/item/clothing/head/wizard) && !istype(user:head, /obj/item/clothing/head/helmet/space/void/wizard))
usr << "I don't feel strong enough without my hat."
return 0
if(!skipcharge)
switch(charge_type)
if("recharge")
charge_counter = 0 //doesn't start recharging until the targets selecting ends
if("charges")
charge_counter-- //returns the charge if the targets selecting fails
if("holdervar")
adjust_var(user, holder_var_type, holder_var_amount)
return 1
/obj/effect/proc_holder/spell/proc/invocation(mob/user = usr) //spelling the spell out and setting it on recharge/reducing charges amount
switch(invocation_type)
if("shout")
if(prob(50))//Auto-mute? Fuck that noise
usr.say(invocation)
else
usr.say(replacetext(invocation," ","`"))
if(usr.gender==MALE)
playsound(usr.loc, pick('sound/misc/null.ogg','sound/misc/null.ogg'), 100, 1)
else
playsound(usr.loc, pick('sound/misc/null.ogg','sound/misc/null.ogg'), 100, 1)
if("whisper")
if(prob(50))
usr.whisper(invocation)
else
usr.whisper(replacetext(invocation," ","`"))
/obj/effect/proc_holder/spell/New()
..()
charge_counter = charge_max
/obj/effect/proc_holder/spell/Click()
if(cast_check())
choose_targets()
return 1
/obj/effect/proc_holder/spell/proc/choose_targets(mob/user = usr) //depends on subtype - /targeted or /aoe_turf
return
/obj/effect/proc_holder/spell/proc/start_recharge()
while(charge_counter < charge_max)
sleep(1)
charge_counter++
/obj/effect/proc_holder/spell/proc/perform(list/targets, recharge = 1) //if recharge is started is important for the trigger spells
before_cast(targets)
invocation()
spawn(0)
if(charge_type == "recharge" && recharge)
start_recharge()
if(prob(critfailchance))
critfail(targets)
else
cast(targets)
after_cast(targets)
/obj/effect/proc_holder/spell/proc/before_cast(list/targets)
if(overlay)
for(var/atom/target in targets)
var/location
if(istype(target,/mob/living))
location = target.loc
else if(istype(target,/turf))
location = target
var/obj/effect/overlay/spell = new /obj/effect/overlay(location)
spell.icon = overlay_icon
spell.icon_state = overlay_icon_state
spell.anchored = 1
spell.density = 0
spawn(overlay_lifespan)
del(spell)
/obj/effect/proc_holder/spell/proc/after_cast(list/targets)
for(var/atom/target in targets)
var/location
if(istype(target,/mob/living))
location = target.loc
else if(istype(target,/turf))
location = target
if(istype(target,/mob/living) && message)
target << text("[message]")
if(sparks_spread)
var/datum/effect/effect/system/spark_spread/sparks = new /datum/effect/effect/system/spark_spread()
sparks.set_up(sparks_amt, 0, location) //no idea what the 0 is
sparks.start()
if(smoke_spread)
if(smoke_spread == 1)
var/datum/effect/effect/system/smoke_spread/smoke = new /datum/effect/effect/system/smoke_spread()
smoke.set_up(smoke_amt, 0, location) //no idea what the 0 is
smoke.start()
else if(smoke_spread == 2)
var/datum/effect/effect/system/smoke_spread/bad/smoke = new /datum/effect/effect/system/smoke_spread/bad()
smoke.set_up(smoke_amt, 0, location) //no idea what the 0 is
smoke.start()
/obj/effect/proc_holder/spell/proc/cast(list/targets)
return
/obj/effect/proc_holder/spell/proc/critfail(list/targets)
return
/obj/effect/proc_holder/spell/proc/revert_cast(mob/user = usr) //resets recharge or readds a charge
switch(charge_type)
if("recharge")
charge_counter = charge_max
if("charges")
charge_counter++
if("holdervar")
adjust_var(user, holder_var_type, -holder_var_amount)
return
/obj/effect/proc_holder/spell/proc/adjust_var(mob/living/target = usr, type, amount) //handles the adjustment of the var when the spell is used. has some hardcoded types
switch(type)
if("bruteloss")
target.adjustBruteLoss(amount)
if("fireloss")
target.adjustFireLoss(amount)
if("toxloss")
target.adjustToxLoss(amount)
if("oxyloss")
target.adjustOxyLoss(amount)
if("stunned")
target.AdjustStunned(amount)
if("weakened")
target.AdjustWeakened(amount)
if("paralysis")
target.AdjustParalysis(amount)
else
target.vars[type] += amount //I bear no responsibility for the runtimes that'll happen if you try to adjust non-numeric or even non-existant vars
return
/obj/effect/proc_holder/spell/targeted //can mean aoe for mobs (limited/unlimited number) or one target mob
var/max_targets = 1 //leave 0 for unlimited targets in range, 1 for one selectable target in range, more for limited number of casts (can all target one guy, depends on target_ignore_prev) in range
var/target_ignore_prev = 1 //only important if max_targets > 1, affects if the spell can be cast multiple times at one person from one cast
var/include_user = 0 //if it includes usr in the target list
/obj/effect/proc_holder/spell/aoe_turf //affects all turfs in view or range (depends)
var/inner_radius = -1 //for all your ring spell needs
/obj/effect/proc_holder/spell/targeted/choose_targets(mob/user = usr)
var/list/targets = list()
switch(max_targets)
if(0) //unlimited
for(var/mob/living/target in view_or_range(range, user, selection_type))
targets += target
if(1) //single target can be picked
if(range < 0)
targets += user
else
var/possible_targets = list()
for(var/mob/living/M in view_or_range(range, user, selection_type))
if(!include_user && user == M)
continue
possible_targets += M
targets += input("Choose the target for the spell.", "Targeting") as mob in possible_targets
else
var/list/possible_targets = list()
for(var/mob/living/target in view_or_range(range, user, selection_type))
possible_targets += target
for(var/i=1,i<=max_targets,i++)
if(!possible_targets.len)
break
if(target_ignore_prev)
var/target = pick(possible_targets)
possible_targets -= target
targets += target
else
targets += pick(possible_targets)
if(!include_user && (user in targets))
targets -= user
if(!targets.len) //doesn't waste the spell
revert_cast(user)
return
perform(targets)
return
/obj/effect/proc_holder/spell/aoe_turf/choose_targets(mob/user = usr)
var/list/targets = list()
for(var/turf/target in view_or_range(range,user,selection_type))
if(!(target in view_or_range(inner_radius,user,selection_type)))
targets += target
if(!targets.len) //doesn't waste the spell
revert_cast()
return
perform(targets)
return

View File

@@ -0,0 +1,341 @@
var/list/spells = typesof(/spell) //needed for the badmin verb for now
/spell
name = "Spell"
desc = "A spell"
parent_type = /atom/movable
var/panel = "Spells"//What panel the proc holder needs to go on.
var/school = "evocation" //not relevant at now, but may be important later if there are changes to how spells work. the ones I used for now will probably be changed... maybe spell presets? lacking flexibility but with some other benefit?
var/charge_type = Sp_RECHARGE //can be recharge or charges, see charge_max and charge_counter descriptions; can also be based on the holder's vars now, use "holder_var" for that
var/charge_max = 100 //recharge time in deciseconds if charge_type = Sp_RECHARGE or starting charges if charge_type = Sp_CHARGES
var/charge_counter = 0 //can only cast spells if it equals recharge, ++ each decisecond if charge_type = Sp_RECHARGE or -- each cast if charge_type = Sp_CHARGES
var/still_recharging_msg = "<span class='notice'>The spell is still recharging.</span>"
var/silenced = 0 //not a binary - the length of time we can't cast this for
var/holder_var_type = "bruteloss" //only used if charge_type equals to "holder_var"
var/holder_var_amount = 20 //same. The amount adjusted with the mob's var when the spell is used
var/spell_flags = NEEDSCLOTHES
var/invocation = "HURP DURP" //what is uttered when the wizard casts the spell
var/invocation_type = SpI_NONE //can be none, whisper, shout, and emote
var/range = 7 //the range of the spell; outer radius for aoe spells
var/message = "" //whatever it says to the guy affected by it
var/selection_type = "view" //can be "range" or "view"
var/atom/movable/holder //where the spell is. Normally the user, can be a projectile
var/duration = 0 //how long the spell lasts
var/list/spell_levels = list(Sp_SPEED = 0, Sp_POWER = 0) //the current spell levels - total spell levels can be obtained by just adding the two values
var/list/level_max = list(Sp_TOTAL = 4, Sp_SPEED = 4, Sp_POWER = 0) //maximum possible levels in each category. Total does cover both.
var/cooldown_reduc = 0 //If set, defines how much charge_max drops by every speed upgrade
var/delay_reduc = 0
var/cooldown_min = 0 //minimum possible cooldown for a charging spell
var/overlay = 0
var/overlay_icon = 'icons/obj/wizard.dmi'
var/overlay_icon_state = "spell"
var/overlay_lifespan = 0
var/sparks_spread = 0
var/sparks_amt = 0 //cropped at 10
var/smoke_spread = 0 //1 - harmless, 2 - harmful
var/smoke_amt = 0 //cropped at 10
var/critfailchance = 0
var/cast_delay = 1
var/cast_sound = ""
var/hud_state = "" //name of the icon used in generating the spell hud object
var/override_base = ""
///////////////////////
///SETUP AND PROCESS///
///////////////////////
/spell/New()
..()
//still_recharging_msg = "<span class='notice'>[name] is still recharging.</span>"
charge_counter = charge_max
/spell/proc/process()
spawn while(charge_counter < charge_max)
charge_counter++
sleep(1)
return
/spell/Click()
..()
perform(usr)
/////////////////
/////CASTING/////
/////////////////
/spell/proc/choose_targets(mob/user = usr) //depends on subtype - see targeted.dm, aoe_turf.dm, dumbfire.dm, or code in general folder
return
/spell/proc/perform(mob/user = usr, skipcharge = 0) //if recharge is started is important for the trigger spells
if(!holder)
holder = user //just in case
if(!cast_check(skipcharge, user))
return
if(cast_delay && !spell_do_after(user, cast_delay))
return
var/list/targets = choose_targets(user)
if(targets && targets.len)
invocation(user, targets)
take_charge(user, skipcharge)
before_cast(targets) //applies any overlays and effects
user.attack_log += text("\[[time_stamp()]\] <font color='red'>[user.real_name] ([user.ckey]) cast the spell [name].</font>")
if(prob(critfailchance))
critfail(targets, user)
else
cast(targets, user)
after_cast(targets) //generates the sparks, smoke, target messages etc.
/spell/proc/cast(list/targets, mob/user) //the actual meat of the spell
return
/spell/proc/critfail(list/targets, mob/user) //the wizman has fucked up somehow
return
/spell/proc/adjust_var(mob/living/target = usr, type, amount) //handles the adjustment of the var when the spell is used. has some hardcoded types
switch(type)
if("bruteloss")
target.adjustBruteLoss(amount)
if("fireloss")
target.adjustFireLoss(amount)
if("toxloss")
target.adjustToxLoss(amount)
if("oxyloss")
target.adjustOxyLoss(amount)
if("stunned")
target.AdjustStunned(amount)
if("weakened")
target.AdjustWeakened(amount)
if("paralysis")
target.AdjustParalysis(amount)
else
target.vars[type] += amount //I bear no responsibility for the runtimes that'll happen if you try to adjust non-numeric or even non-existant vars
return
///////////////////////////
/////CASTING WRAPPERS//////
///////////////////////////
/spell/proc/before_cast(list/targets)
var/valid_targets[0]
for(var/atom/target in targets)
// Check range again (fixes long-range EI NATH)
if(!(target in view_or_range(range,usr,selection_type)))
continue
valid_targets += target
if(overlay)
var/location
if(istype(target,/mob/living))
location = target.loc
else if(istype(target,/turf))
location = target
var/obj/effect/overlay/spell = new /obj/effect/overlay(location)
spell.icon = overlay_icon
spell.icon_state = overlay_icon_state
spell.anchored = 1
spell.density = 0
spawn(overlay_lifespan)
del(spell)
return valid_targets
/spell/proc/after_cast(list/targets)
for(var/atom/target in targets)
var/location = get_turf(target)
if(istype(target,/mob/living) && message)
target << text("[message]")
if(sparks_spread)
var/datum/effect/effect/system/spark_spread/sparks = new /datum/effect/effect/system/spark_spread()
sparks.set_up(sparks_amt, 0, location) //no idea what the 0 is
sparks.start()
if(smoke_spread)
if(smoke_spread == 1)
var/datum/effect/effect/system/smoke_spread/smoke = new /datum/effect/effect/system/smoke_spread()
smoke.set_up(smoke_amt, 0, location) //no idea what the 0 is
smoke.start()
else if(smoke_spread == 2)
var/datum/effect/effect/system/smoke_spread/bad/smoke = new /datum/effect/effect/system/smoke_spread/bad()
smoke.set_up(smoke_amt, 0, location) //no idea what the 0 is
smoke.start()
/////////////////////
////CASTING TOOLS////
/////////////////////
/*Checkers, cost takers, message makers, etc*/
/spell/proc/cast_check(skipcharge = 0,mob/user = usr) //checks if the spell can be cast based on its settings; skipcharge is used when an additional cast_check is called inside the spell
if(!(src in user.spell_list))
user << "<span class='warning'>You shouldn't have this spell! Something's wrong.</span>"
return 0
if(silenced > 0)
return
if(user.z == 2 && spell_flags & Z2NOCAST) //Certain spells are not allowed on the centcomm zlevel
return 0
if(spell_flags & CONSTRUCT_CHECK)
for(var/turf/T in range(holder, 1))
if(findNullRod(T))
return 0
if(istype(user, /mob/living/simple_animal))
var/mob/living/simple_animal/SA = user
if(SA.purge)
SA << "<span class='warning'>The nullrod's power interferes with your own!</span>"
return 0
if(!src.check_charge(skipcharge, user)) //sees if we can cast based on charges alone
return 0
if(!(spell_flags & GHOSTCAST))
if(user.stat && !(spell_flags & STATALLOWED))
usr << "Not when you're incapacitated."
return 0
if(ishuman(user) && !(invocation_type in list(SpI_EMOTE, SpI_NONE)))
if(istype(user.wear_mask, /obj/item/clothing/mask/muzzle))
user << "Mmmf mrrfff!"
return 0
var/spell/noclothes/spell = locate() in user.spell_list
if((spell_flags & NEEDSCLOTHES) && !(spell && istype(spell)))//clothes check
if(!user.wearing_wiz_garb())
return 0
return 1
/spell/proc/check_charge(var/skipcharge, mob/user)
if(!skipcharge)
switch(charge_type)
if(Sp_RECHARGE)
if(charge_counter < charge_max)
user << still_recharging_msg
return 0
if(Sp_CHARGES)
if(!charge_counter)
user << "<span class='notice'>[name] has no charges left.</span>"
return 0
return 1
/spell/proc/take_charge(mob/user = user, var/skipcharge)
if(!skipcharge)
switch(charge_type)
if(Sp_RECHARGE)
charge_counter = 0 //doesn't start recharging until the targets selecting ends
src.process()
return 1
if(Sp_CHARGES)
charge_counter-- //returns the charge if the targets selecting fails
return 1
if(Sp_HOLDVAR)
adjust_var(user, holder_var_type, holder_var_amount)
return 1
return 0
return 1
/spell/proc/invocation(mob/user = usr, var/list/targets) //spelling the spell out and setting it on recharge/reducing charges amount
switch(invocation_type)
if(SpI_SHOUT)
if(prob(50))//Auto-mute? Fuck that noise
user.say(invocation)
else
user.say(replacetext(invocation," ","`"))
if(SpI_WHISPER)
if(prob(50))
user.whisper(invocation)
else
user.whisper(replacetext(invocation," ","`"))
if(SpI_EMOTE)
user.emote("me", 1, invocation) //the 1 means it's for everyone in view, the me makes it an emote, and the invocation is written accordingly.
/////////////////////
///UPGRADING PROCS///
/////////////////////
/spell/proc/can_improve(var/upgrade_type)
if(level_max[Sp_TOTAL] <= ( spell_levels[Sp_SPEED] + spell_levels[Sp_POWER] )) //too many levels, can't do it
return 0
if(upgrade_type && upgrade_type in spell_levels && upgrade_type in level_max)
if(spell_levels[upgrade_type] >= level_max[upgrade_type])
return 0
return 1
/spell/proc/empower_spell()
return
/spell/proc/quicken_spell()
if(!can_improve(Sp_SPEED))
return 0
spell_levels[Sp_SPEED]++
if(delay_reduc && cast_delay)
cast_delay = max(0, cast_delay - delay_reduc)
else if(cast_delay)
cast_delay = round( max(0, initial(cast_delay) * ((level_max[Sp_SPEED] - spell_levels[Sp_SPEED]) / level_max[Sp_SPEED] ) ) )
if(charge_type == Sp_RECHARGE)
if(cooldown_reduc)
charge_max = max(cooldown_min, charge_max - cooldown_reduc)
else
charge_max = round( max(cooldown_min, initial(charge_max) * ((level_max[Sp_SPEED] - spell_levels[Sp_SPEED]) / level_max[Sp_SPEED] ) ) ) //the fraction of the way you are to max speed levels is the fraction you lose
if(charge_max < charge_counter)
charge_counter = charge_max
var/temp = ""
name = initial(name)
switch(level_max[Sp_SPEED] - spell_levels[Sp_SPEED])
if(3)
temp = "You have improved [name] into Efficient [name]."
name = "Efficient [name]"
if(2)
temp = "You have improved [name] into Quickened [name]."
name = "Quickened [name]"
if(1)
temp = "You have improved [name] into Free [name]."
name = "Free [name]"
if(0)
temp = "You have improved [name] into Instant [name]."
name = "Instant [name]"
return temp
/spell/proc/spell_do_after(var/mob/user as mob, delay as num, var/numticks = 5)
if(!user || isnull(user))
return 0
if(numticks == 0)
return 1
var/delayfraction = round(delay/numticks)
var/Location = user.loc
var/originalstat = user.stat
for(var/i = 0, i<numticks, i++)
sleep(delayfraction)
if(!user || (!(spell_flags & (STATALLOWED|GHOSTCAST)) && user.stat != originalstat) || !(user.loc == Location))
return 0
return 1

View File

@@ -0,0 +1,62 @@
/obj/item/projectile/spell_projectile
name = "spell"
icon = 'icons/obj/projectiles.dmi'
nodamage = 1 //Most of the time, anyways
var/spell/targeted/projectile/carried
kill_count = 10 //set by the duration of the spell
var/proj_trail = 0 //if it leaves a trail
var/proj_trail_lifespan = 0 //deciseconds
var/proj_trail_icon = 'icons/obj/wizard.dmi'
var/proj_trail_icon_state = "trail"
var/list/trails = new()
/obj/item/projectile/spell_projectile/Destroy()
..()
for(var/trail in trails)
qdel(trail)
/obj/item/projectile/spell_projectile/ex_act()
return
/obj/item/projectile/spell_projectile/before_move()
if(carried)
var/list/targets = carried.choose_prox_targets(user = carried.holder, spell_holder = src)
if(targets.len)
src.prox_cast(targets)
if(proj_trail && src && src.loc) //pretty trails
var/obj/effect/overlay/trail = PoolOrNew(/obj/effect/overlay, src.loc)
trails += trail
trail.icon = proj_trail_icon
trail.icon_state = proj_trail_icon_state
trail.density = 0
spawn(proj_trail_lifespan)
trails -= trail
qdel(trail)
/obj/item/projectile/spell_projectile/proc/prox_cast(var/list/targets)
if(loc)
carried.prox_cast(targets, src)
qdel(src)
return
/obj/item/projectile/spell_projectile/Bump(var/atom/A)
if(loc)
prox_cast(carried.choose_prox_targets(user = carried.holder, spell_holder = src))
return
/obj/item/projectile/spell_projectile/on_impact()
if(loc)
prox_cast(carried.choose_prox_targets(user = carried.holder, spell_holder = src))
return
/obj/item/projectile/spell_projectile/seeking
name = "seeking spell"
/obj/item/projectile/spell_projectile/seeking/process_step()
..()
if(original && !isnull(src.loc))
current = original //update the target

View File

@@ -1,211 +1,454 @@
// This is a bloody terrible place to put the spellbook, but it doesn't belong in the
// roundmode code and the wizard's staff is in weapons.dm for some fucking reason. ~Z
/obj/item/weapon/spellbook
name = "spell book"
desc = "The legendary book of spells of the wizard."
icon = 'icons/obj/library.dmi'
icon_state ="book"
throw_speed = 1
throw_range = 5
w_class = 2.0
var/uses = 5
var/temp = null
var/max_uses = 5
var/op = 1
/obj/item/weapon/spellbook/attack_self(mob/user as mob)
user.set_machine(src)
var/dat
if(temp)
dat = "[temp]<BR><BR><A href='byond://?src=\ref[src];temp=1'>Clear</A>"
else
dat = "<B>The Book of Spells:</B><BR>"
dat += "Spells left to memorize: [uses]<BR>"
dat += "<HR>"
dat += "<B>Memorize which spell:</B><BR>"
dat += "<I>The number after the spell name is the cooldown time.</I><BR>"
dat += "<A href='byond://?src=\ref[src];spell_choice=magicmissile'>Magic Missile</A> (15)<BR>"
dat += "<A href='byond://?src=\ref[src];spell_choice=fireball'>Fireball</A> (10)<BR>"
//dat += "<A href='byond://?src=\ref[src];spell_choice=disintegrate'>Disintegrate</A> (60)<BR>"
dat += "<A href='byond://?src=\ref[src];spell_choice=disabletech'>Disable Technology</A> (40)<BR>"
dat += "<A href='byond://?src=\ref[src];spell_choice=smoke'>Smoke</A> (12)<BR>"
dat += "<A href='byond://?src=\ref[src];spell_choice=blind'>Blind</A> (30)<BR>"
dat += "<A href='byond://?src=\ref[src];spell_choice=mindswap'>Mind Transfer</A> (60)<BR>"
dat += "<A href='byond://?src=\ref[src];spell_choice=forcewall'>Forcewall</A> (10)<BR>"
dat += "<A href='byond://?src=\ref[src];spell_choice=blink'>Blink</A> (2)<BR>"
dat += "<A href='byond://?src=\ref[src];spell_choice=teleport'>Teleport</A> (60)<BR>"
dat += "<A href='byond://?src=\ref[src];spell_choice=mutate'>Mutate</A> (40)<BR>"
dat += "<A href='byond://?src=\ref[src];spell_choice=etherealjaunt'>Ethereal Jaunt</A> (30)<BR>"
dat += "<A href='byond://?src=\ref[src];spell_choice=knock'>Knock</A> (10)<BR>"
dat += "<A href='byond://?src=\ref[src];spell_choice=horseman'>Curse of the Horseman</A> (15)<BR>"
// if(op)
// dat += "<A href='byond://?src=\ref[src];spell_choice=summonguns'>Summon Guns</A> (One time use, global spell)<BR>"
dat += "<HR>"
dat += "<B>Artefacts:</B><BR>"
dat += "Powerful items imbued with eldritch magics. Summoning one will count towards your maximum number of spells.<BR>"
dat += "It is recommended that only experienced wizards attempt to wield such artefacts.<BR>"
dat += "<HR>"
dat += "<A href='byond://?src=\ref[src];spell_choice=staffchange'>Staff of Change</A><BR>"
dat += "<HR>"
dat += "<A href='byond://?src=\ref[src];spell_choice=mentalfocus'>Mental Focus</A><BR>"
dat += "<HR>"
dat += "<A href='byond://?src=\ref[src];spell_choice=soulstone'>Six Soul Stone Shards and the spell Artificer</A><BR>"
dat += "<HR>"
dat += "<A href='byond://?src=\ref[src];spell_choice=armor'>Mastercrafted Armor Set</A><BR>"
dat += "<HR>"
dat += "<A href='byond://?src=\ref[src];spell_choice=staffanimation'>Staff of Animation</A><BR>"
dat += "<HR>"
dat += "<A href='byond://?src=\ref[src];spell_choice=scrying'>Scrying Orb</A><BR>"
dat += "<HR>"
if(op)
dat += "<A href='byond://?src=\ref[src];spell_choice=rememorize'>Re-memorize Spells</A><BR>"
user << browse(dat, "window=radio")
onclose(user, "radio")
return
/obj/item/weapon/spellbook/Topic(href, href_list)
..()
var/mob/living/carbon/human/H = usr
if(H.stat || H.restrained())
return
if(!istype(H, /mob/living/carbon/human))
return 1
if(loc == H || (in_range(src, H) && istype(loc, /turf)))
H.set_machine(src)
if(href_list["spell_choice"])
if(href_list["spell_choice"] == "rememorize")
var/area/wizard_station/A = locate()
if(usr in A.contents)
uses = max_uses
H.spellremove(usr)
temp = "All spells have been removed. You may now memorize a new set of spells."
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(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", summonguns = "Summon Guns", staffchange = "Staff of Change", mentalfocus = "Mental Focus", 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"]] == aspell.name)
already_knows = 1
temp = "You already know that spell."
uses++
break
/*
*/
if(!already_knows)
switch(href_list["spell_choice"])
if("magicmissile")
feedback_add_details("wizard_spell_learned","MM") //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/targeted/projectile/magic_missile(H)
temp = "This spell fires several, slow moving, magic projectiles at nearby targets. If a projectile hits a target, the target is stunned for some time."
if("fireball")
feedback_add_details("wizard_spell_learned","FB") //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/dumbfire/fireball(H)
temp = "This spell fires a fireball in the direction you're facing and does not require wizard garb. Be careful not to fire it at people that are standing next to you."
if("disintegrate")
feedback_add_details("wizard_spell_learned","DG") //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/targeted/inflict_handler/disintegrate(H)
temp = "This spell instantly kills somebody adjacent to you with the vilest of magick. It has a long cooldown."
if("disabletech")
feedback_add_details("wizard_spell_learned","DT") //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/targeted/emplosion/disable_tech(H)
temp = "This spell releases an EMP from your person disabling most technology within range; computers, doors, prosthetics, etc."
if("smoke")
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.spell_list += new /obj/effect/proc_holder/spell/targeted/smoke(H)
temp = "This spell spawns a cloud of vision obscuring smoke at your location and does not require wizard garb."
if("blind")
feedback_add_details("wizard_spell_learned","BD") //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/targeted/trigger/blind(H)
temp = "This spell temporarly blinds a single person and does not require wizard garb."
if("mindswap")
feedback_add_details("wizard_spell_learned","MT") //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/targeted/mind_transfer(H)
temp = "This spell allows the user to switch bodies with a target. Careful to not lose your memory in the process."
if("forcewall")
feedback_add_details("wizard_spell_learned","FW") //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/aoe_turf/conjure/forcewall(H)
temp = "This spell creates an unbreakable wall that lasts for 30 seconds and does not need wizard garb."
if("blink")
feedback_add_details("wizard_spell_learned","BL") //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/targeted/turf_teleport/blink(H)
temp = "This spell randomly teleports you a short distance. Useful for evasion or getting into areas if you have patience."
if("teleport")
feedback_add_details("wizard_spell_learned","TP") //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/targeted/area_teleport/teleport(H)
temp = "This spell teleports you to an area of your selection, and creates a cloud of smoke around you upon arrival. Very useful if you are in danger.."
if("mutate")
feedback_add_details("wizard_spell_learned","MU") //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/targeted/genetic/mutate(H)
temp = "This spell causes you to turn into a hulk, gaining super strength and the ability to punch down walls! You also gain the ability to fire lasers from your eyes!"
if("etherealjaunt")
feedback_add_details("wizard_spell_learned","EJ") //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/targeted/ethereal_jaunt(H)
temp = "This spell creates your ethereal form, temporarily making you invisible and able to pass through walls."
if("knock")
feedback_add_details("wizard_spell_learned","KN") //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/aoe_turf/knock(H)
temp = "This spell opens nearby doors and does not require wizard garb."
if("horseman")
feedback_add_details("wizard_spell_learned","HH") //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/targeted/horsemask(H)
temp = "This spell will curse a person to wear an unremovable horse mask (it has glue on the inside) and speak like a horse. It does not require a wizard garb. Do note the curse will disintegrate the target's current mask if they are wearing one."
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
rightandwrong()
max_uses--
temp = "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!"
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))
temp = "An artefact that spits bolts of coruscating energy which cause the target's very form to reshape itself"
max_uses--
if("mentalfocus")
feedback_add_details("wizard_spell_learned","MF") //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/focus(get_turf(H))
temp = "An artefact that channels the will of the user into destructive bolts of force."
max_uses--
if("soulstone")
feedback_add_details("wizard_spell_learned","SS") //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/soulstone/full(get_turf(H))
H.spell_list += new /obj/effect/proc_holder/spell/aoe_turf/conjure/construct(H)
temp = "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."
max_uses--
if("armor")
feedback_add_details("wizard_spell_learned","HS") //please do not change the abbreviation to keep data processing consistent. Add a unique id to any new spells
new /obj/item/clothing/shoes/sandal(get_turf(H)) //In case they've lost them.
new /obj/item/clothing/gloves/purple(get_turf(H))//To complete the outfit
new /obj/item/clothing/suit/space/void/wizard(get_turf(H))
new /obj/item/clothing/head/helmet/space/void/wizard(get_turf(H))
temp = "An artefact suit of armor that allows you to cast spells while providing more protection against attacks and the void of space."
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))
temp = "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."
max_uses--
if("scrying")
feedback_add_details("wizard_spell_learned","SO") //please do not change the abbreviation to keep data processing consistent. Add a unique id to any new spells
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 << "<span class='info'>The walls suddenly disappear.</span>"
temp = "You have purchased a scrying orb, and gained x-ray vision."
max_uses--
else
if(href_list["temp"])
temp = null
attack_self(H)
return
/obj/item/weapon/spellbook
name = "spell book"
desc = "The legendary book of spells of the wizard."
icon = 'icons/obj/library.dmi'
icon_state ="spellbook"
throw_speed = 1
throw_range = 5
w_class = 1.0
var/uses = 5
var/temp = null
var/max_uses = 5
var/op = 1
/obj/item/weapon/spellbook/attack_self(mob/user = usr)
if(!user)
return
user.set_machine(src)
var/dat
if(temp)
dat = "[temp]<BR><BR><A href='byond://?src=\ref[src];temp=1'>Clear</A>"
else
// AUTOFIXED BY fix_string_idiocy.py
dat = {"<B>The Book of Spells:</B><BR>
Spells left to memorize: [uses]<BR>
<HR>
<B>Memorize which spell:</B><BR>
<I>The number after the spell name is the cooldown time.</I><BR>
<A href='byond://?src=\ref[src];spell_choice=magicmissile'>Magic Missile</A> (10)<BR>
<I>This spell fires several, slow moving, magic projectiles at nearby targets. If they hit a target, it is paralyzed and takes minor damage.</I><BR>
<A href='byond://?src=\ref[src];spell_choice=fireball'>Fireball</A> (10)<BR>
<I>This spell fires a fireball in the direction you're facing and does not require wizard garb. Be careful not to fire it at people that are standing next to you.</I><BR>
<A href='byond://?src=\ref[src];spell_choice=disintegrate'>Disintegrate</A> (60)<BR>
<I>This spell instantly kills somebody adjacent to you with the vilest of magick. It has a long cooldown.</I><BR>
<A href='byond://?src=\ref[src];spell_choice=disabletech'>Disable Technology</A> (60)<BR>
<I>This spell disables all weapons, cameras and most other technology in range.</I><BR>
<A href='byond://?src=\ref[src];spell_choice=smoke'>Smoke</A> (10)<BR>
<I>This spell spawns a cloud of choking smoke at your location and does not require wizard garb.</I><BR>
<A href='byond://?src=\ref[src];spell_choice=blind'>Blind</A> (30)<BR>
<I>This spell temporarly blinds a single person and does not require wizard garb.</I><BR>
<A href='byond://?src=\ref[src];spell_choice=subjugation'>Subjugation</A> (30)<BR>
<I>This spell temporarily subjugates a target's mind and does not require wizard garb.</I><BR>
<A href='byond://?src=\ref[src];spell_choice=mindswap'>Mind Transfer</A> (60)<BR>
<I>This spell allows the user to switch bodies with a target. Careful to not lose your memory in the process.</I><BR>
<A href='byond://?src=\ref[src];spell_choice=forcewall'>Forcewall</A> (10)<BR>
<I>This spell creates an unbreakable wall that lasts for 30 seconds and does not need wizard garb.</I><BR>
<A href='byond://?src=\ref[src];spell_choice=blink'>Blink</A> (2)<BR>
<I>This spell randomly teleports you a short distance. Useful for evasion or getting into areas if you have patience.</I><BR>
<A href='byond://?src=\ref[src];spell_choice=teleport'>Teleport</A> (60)<BR>
<I>This spell teleports you to a type of area of your selection. Very useful if you are in danger, but has a decent cooldown, and is unpredictable.</I><BR>
<A href='byond://?src=\ref[src];spell_choice=mutate'>Mutate</A> (60)<BR>
<I>This spell causes you to turn into a hulk and gain telekinesis for a short while.</I><BR>
<A href='byond://?src=\ref[src];spell_choice=etherealjaunt'>Ethereal Jaunt</A> (60)<BR>
<I>This spell creates your ethereal form, temporarily making you invisible and able to pass through walls.</I><BR>
<A href='byond://?src=\ref[src];spell_choice=knock'>Knock</A> (10)<BR>
<I>This spell opens nearby doors and does not require wizard garb.</I><BR>
<A href='byond://?src=\ref[src];spell_choice=horseman'>Curse of the Horseman</A> (15)<BR>
<I>This spell will curse a person to wear an unremovable horse mask (it has glue on the inside) and speak like a horse. It does not require wizard garb.</I><BR>
<A href='byond://?src=\ref[src];spell_choice=fleshtostone'>Flesh to Stone</A> (60)<BR>
<I>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.</I><BR>
<A href='byond://?src=\ref[src];spell_choice=noclothes'>Remove Clothes Requirement</A> <b>Warning: this takes away 2 spell choices.</b><BR>
<HR>
<B>Artefacts:</B><BR>
Powerful items imbued with eldritch magics. Summoning one will count towards your maximum number of spells.<BR>
It is recommended that only experienced wizards attempt to wield such artefacts.<BR>
<HR>
<A href='byond://?src=\ref[src];spell_choice=staffchange'>Staff of Change</A><BR>
<I>An artefact that spits bolts of coruscating energy which cause the target's very form to reshape itself.</I><BR>
<HR>
<A href='byond://?src=\ref[src];spell_choice=mentalfocus'>Mental Focus</A><BR>
<I>An artefact that channels the will of the user into destructive bolts of force.</I><BR>
<HR>
<A href='byond://?src=\ref[src];spell_choice=soulstone'>Six Soul Stone Shards and the spell Artificer</A><BR>
<I>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.</I><BR>
<HR>
<A href='byond://?src=\ref[src];spell_choice=armor'>Mastercrafted Armor Set</A><BR>
<I>An artefact suit of armor that allows you to cast spells while providing more protection against attacks and the void of space.</I><BR>
<HR>
<A href='byond://?src=\ref[src];spell_choice=staffanimation'>Staff of Animation</A><BR>
<I>An arcane staff capable of shooting bolts of eldritch energy which cause inanimate objects to come to life. This magic doesn't affect machines.</I><BR>
<HR>
<A href='byond://?src=\ref[src];spell_choice=scrying'>Scrying Orb</A><BR>
<I>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.</I><BR>
<HR>"}
// END AUTOFIX
if(op)
dat += "<A href='byond://?src=\ref[src];spell_choice=rememorize'>Re-memorize Spells</A><BR>"
user << browse(dat, "window=radio")
onclose(user, "radio")
return
/obj/item/weapon/spellbook/Topic(href, href_list)
..()
var/mob/living/carbon/human/H = usr
if(H.stat || H.restrained())
return
if(!istype(H, /mob/living/carbon/human))
return 1
if(H.mind.special_role == "apprentice")
temp = "If you got caught sneaking a peak from your teacher's spellbook, you'd likely be expelled from the Wizard Academy. Better not."
return
if(loc == H || (in_range(src, H) && istype(loc, /turf)))
H.set_machine(src)
if(href_list["spell_choice"])
if(href_list["spell_choice"] == "rememorize")
var/area/wizard_station/A = locate()
if(usr in A.contents)
uses = max_uses
H.spellremove()
temp = "All spells have been removed. You may now memorize a new set of spells."
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(uses >= 1 && max_uses >=1)
if(href_list["spell_choice"] == "noclothes")
if(uses < 2)
return
uses--
/*
*/
var/list/available_spells = list(magicmissile = "Magic Missile", fireball = "Fireball", disintegrate = "Disintegrate", disabletech = "Disable Tech", smoke = "Smoke", blind = "Blind", subjugation = "Subjugation", mindswap = "Mind Transfer", forcewall = "Forcewall", blink = "Blink", teleport = "Teleport", mutate = "Mutate", etherealjaunt = "Ethereal Jaunt", knock = "Knock", horseman = "Curse of the Horseman", staffchange = "Staff of Change", mentalfocus = "Mental Focus", soulstone = "Six Soul Stone Shards and the spell Artificer", armor = "Mastercrafted Armor Set", staffanimate = "Staff of Animation", noclothes = "No Clothes",fleshtostone = "Flesh to Stone")
var/already_knows = 0
for(var/spell/aspell in H.spell_list)
if(available_spells[href_list["spell_choice"]] == initial(aspell.name))
already_knows = 1
if(!aspell.can_improve())
temp = "This spell cannot be improved further."
uses++
break
else
if(aspell.can_improve("speed") && aspell.can_improve("power"))
switch(alert(src, "Do you want to upgrade this spell's speed or power?", "Select Upgrade", "Speed", "Power", "Cancel"))
if("Speed")
temp = aspell.quicken_spell()
if("Power")
temp = aspell.empower_spell()
else
uses++
break
else if (aspell.can_improve("speed"))
temp = aspell.quicken_spell()
else if (aspell.can_improve("power"))
temp = aspell.empower_spell()
/*
*/
if(!already_knows)
switch(href_list["spell_choice"])
if("noclothes")
feedback_add_details("wizard_spell_learned","NC")
H.add_spell(new/spell/noclothes)
temp = "This teaches you how to use your spells without your magical garb, truely you are the wizardest."
uses--
if("magicmissile")
feedback_add_details("wizard_spell_learned","MM") //please do not change the abbreviation to keep data processing consistent. Add a unique id to any new spells
H.add_spell(new/spell/targeted/projectile/magic_missile)
temp = "You have learned magic missile."
if("fireball")
feedback_add_details("wizard_spell_learned","FB") //please do not change the abbreviation to keep data processing consistent. Add a unique id to any new spells
H.add_spell(new/spell/targeted/projectile/dumbfire/fireball)
temp = "You have learned fireball."
if("disintegrate")
feedback_add_details("wizard_spell_learned","DG") //please do not change the abbreviation to keep data processing consistent. Add a unique id to any new spells
H.add_spell(new/spell/targeted/disintegrate)
temp = "You have learned disintegrate."
if("disabletech")
feedback_add_details("wizard_spell_learned","DT") //please do not change the abbreviation to keep data processing consistent. Add a unique id to any new spells
H.add_spell(new/spell/aoe_turf/disable_tech)
temp = "You have learned disable technology."
if("smoke")
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.add_spell(new/spell/aoe_turf/smoke)
temp = "You have learned smoke."
if("blind")
feedback_add_details("wizard_spell_learned","BD") //please do not change the abbreviation to keep data processing consistent. Add a unique id to any new spells
H.add_spell(new/spell/targeted/genetic/blind)
temp = "You have learned blind."
if("subjugation")
feedback_add_details("wizard_spell_learned","SJ") //please do not change the abbreviation to keep data processing consistent. Add a unique id to any new spells
H.add_spell(new/spell/targeted/subjugation)
temp = "You have learned subjugate."
if("mindswap")
feedback_add_details("wizard_spell_learned","MT") //please do not change the abbreviation to keep data processing consistent. Add a unique id to any new spells
H.add_spell(new/spell/targeted/mind_transfer)
temp = "You have learned mindswap."
if("forcewall")
feedback_add_details("wizard_spell_learned","FW") //please do not change the abbreviation to keep data processing consistent. Add a unique id to any new spells
H.add_spell(new/spell/aoe_turf/conjure/forcewall)
temp = "You have learned forcewall."
if("blink")
feedback_add_details("wizard_spell_learned","BL") //please do not change the abbreviation to keep data processing consistent. Add a unique id to any new spells
H.add_spell(new/spell/aoe_turf/blink)
temp = "You have learned blink."
if("teleport")
feedback_add_details("wizard_spell_learned","TP") //please do not change the abbreviation to keep data processing consistent. Add a unique id to any new spells
H.add_spell(new/spell/area_teleport)
temp = "You have learned teleport."
if("mutate")
feedback_add_details("wizard_spell_learned","MU") //please do not change the abbreviation to keep data processing consistent. Add a unique id to any new spells
H.add_spell(new/spell/targeted/genetic/mutate)
temp = "You have learned mutate."
if("etherealjaunt")
feedback_add_details("wizard_spell_learned","EJ") //please do not change the abbreviation to keep data processing consistent. Add a unique id to any new spells
H.add_spell(new/spell/targeted/ethereal_jaunt)
temp = "You have learned ethereal jaunt."
if("knock")
feedback_add_details("wizard_spell_learned","KN") //please do not change the abbreviation to keep data processing consistent. Add a unique id to any new spells
H.add_spell(new/spell/aoe_turf/knock)
temp = "You have learned knock."
if("horseman")
feedback_add_details("wizard_spell_learned","HH") //please do not change the abbreviation to keep data processing consistent. Add a unique id to any new spells
H.add_spell(new/spell/targeted/horsemask)
temp = "You have learned curse of the horseman."
if("fleshtostone")
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.add_spell(new/spell/targeted/flesh_to_stone)
temp = "You have learned flesh to stone."
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))
temp = "You have purchased a staff of change."
max_uses--
if("mentalfocus")
feedback_add_details("wizard_spell_learned","MF") //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/focus(get_turf(H))
temp = "An artefact that channels the will of the user into destructive bolts of force."
max_uses--
if("soulstone")
feedback_add_details("wizard_spell_learned","SS") //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/soulstone/full(get_turf(H))
H.add_spell(new/spell/aoe_turf/conjure/construct)
temp = "You have purchased a belt full of soulstones and have learned the artificer spell."
max_uses--
if("armor")
feedback_add_details("wizard_spell_learned","HS") //please do not change the abbreviation to keep data processing consistent. Add a unique id to any new spells
new /obj/item/clothing/shoes/sandal(get_turf(H)) //In case they've lost them.
new /obj/item/clothing/gloves/purple(get_turf(H))//To complete the outfit
new /obj/item/clothing/suit/space/void/wizard(get_turf(H))
new /obj/item/clothing/head/helmet/space/void/wizard(get_turf(H))
temp = "You have purchased a suit of wizard armor."
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))
temp = "You have purchased a staff of animation."
max_uses--
if("scrying")
feedback_add_details("wizard_spell_learned","SO") //please do not change the abbreviation to keep data processing consistent. Add a unique id to any new spells
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."
temp = "You have purchased a scrying orb, and gained x-ray vision."
max_uses--
else
if(href_list["temp"])
temp = null
attack_self()
return
//Single Use Spellbooks//
/obj/item/weapon/spellbook/oneuse
var/spell = /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/spell/S = new spell(user)
for(var/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 <<"<span class='notice'>You're already far more versed in this spell than this flimsy how-to book can provide.</span>"
else
user <<"<span class='notice'>You've already read this one.</span>"
return
if(used)
recoil(user)
else
user.add_spell(S)
user <<"<span class='notice'>you rapidly read through the arcane book. Suddenly you realize you understand [spellname]!</span>"
user.attack_log += text("\[[time_stamp()]\] <font color='orange'>[user.real_name] ([user.ckey]) learned the spell [spellname] ([S]).</font>")
onlearned(user)
/obj/item/weapon/spellbook/oneuse/proc/recoil(mob/user as mob)
user.visible_message("<span class='warning'>[src] glows in a black light!</span>")
/obj/item/weapon/spellbook/oneuse/proc/onlearned(mob/user as mob)
used = 1
user.visible_message("<span class='caution'>[src] glows dark for a second!</span>")
/obj/item/weapon/spellbook/oneuse/attackby()
return
/obj/item/weapon/spellbook/oneuse/fireball
spell = /spell/targeted/projectile/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)
qdel(src)
/obj/item/weapon/spellbook/oneuse/smoke
spell = /spell/aoe_turf/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 <<"<span class='caution'>Your stomach rumbles...</span>"
if(user.nutrition)
user.nutrition -= 200
if(user.nutrition <= 0)
user.nutrition = 0
/obj/item/weapon/spellbook/oneuse/blind
spell = /spell/targeted/genetic/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 <<"<span class='warning'>You go blind!</span>"
user.eye_blind = 10
/obj/item/weapon/spellbook/oneuse/mindswap
spell = /spell/targeted/mind_transfer
spellname = "mindswap"
icon_state ="bookmindswap"
desc = "This book's cover is pristine, though its pages look ragged and torn."
var/mob/stored_swap = null //Used in used book recoils to store an identity for mindswaps
/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)
..()
if(stored_swap in dead_mob_list)
stored_swap = null
if(!stored_swap)
stored_swap = user
user <<"<span class='warning'>For a moment you feel like you don't even know who you are anymore.</span>"
return
if(stored_swap == user)
user <<"<span class='notice'>You stare at the book some more, but there doesn't seem to be anything else to learn...</span>"
return
if(user.mind.special_verbs.len)
for(var/V in user.mind.special_verbs)
user.verbs -= V
if(stored_swap.mind.special_verbs.len)
for(var/V in stored_swap.mind.special_verbs)
stored_swap.verbs -= V
var/mob/dead/observer/ghost = stored_swap.ghostize(0)
ghost.spell_list = stored_swap.spell_list
user.mind.transfer_to(stored_swap)
stored_swap.spell_list = user.spell_list
if(stored_swap.mind.special_verbs.len)
for(var/V in user.mind.special_verbs)
user.verbs += V
ghost.mind.transfer_to(user)
user.key = ghost.key
user.spell_list = ghost.spell_list
if(user.mind.special_verbs.len)
for(var/V in user.mind.special_verbs)
user.verbs += V
stored_swap <<"<span class='warning'>You're suddenly somewhere else... and someone else?!</span>"
user <<"<span class='warning'>Suddenly you're staring at [src] again... where are you, who are you?!</span>"
stored_swap = null
/obj/item/weapon/spellbook/oneuse/forcewall
spell = /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 <<"<span class='warning'>You suddenly feel very solid!</span>"
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 = /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 <<"<span class='warning'>You're knocked down!</span>"
user.Weaken(20)
/obj/item/weapon/spellbook/oneuse/horsemask
spell = /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 <<"<font size='15' color='red'><b>HOR-SIE HAS RISEN</b></font>"
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)
qdel(src)
else
user <<"<span class='notice'>I say thee neigh</span>"
/obj/item/weapon/spellbook/oneuse/charge
spell = /spell/aoe_turf/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 <<"<span class='warning'>[src] suddenly feels very warm!</span>"
empulse(src, 1, 1)

View File

@@ -0,0 +1,64 @@
/mob/Life()
..()
if(spell_masters && spell_masters.len)
for(var/obj/screen/movable/spell_master/spell_master in spell_masters)
spell_master.update_spells(0, src)
/mob/Stat()
..()
if(spell_list && spell_list.len && statpanel("Spells"))
for(var/spell/S in spell_list)
switch(S.charge_type)
if(Sp_RECHARGE)
statpanel("Spells","[S.charge_counter/10.0]/[S.charge_max/10]",S)
if(Sp_CHARGES)
statpanel("Spells","[S.charge_counter]/[S.charge_max]",S)
if(Sp_HOLDVAR)
statpanel("Spells","[S.holder_var_type] [S.holder_var_amount]",S)
/mob/proc/add_spell(var/spell/spell_to_add, var/spell_base = "wiz_spell_ready", var/master_type = /obj/screen/movable/spell_master)
if(!spell_masters)
spell_masters = list()
if(spell_masters.len)
for(var/obj/screen/movable/spell_master/spell_master in spell_masters)
if(spell_master.type == master_type)
spell_list.Add(spell_to_add)
spell_master.add_spell(spell_to_add)
return 1
var/obj/screen/movable/spell_master/new_spell_master = new master_type //we're here because either we didn't find our type, or we have no spell masters to attach to
if(client)
src.client.screen += new_spell_master
new_spell_master.spell_holder = src
new_spell_master.add_spell(spell_to_add)
if(spell_base)
new_spell_master.icon_state = spell_base
spell_masters.Add(new_spell_master)
spell_list.Add(spell_to_add)
return 1
/mob/proc/remove_spell(var/spell/spell_to_remove)
if(!spell_to_remove || !istype(spell_to_remove))
return
if(!(spell_to_remove in spell_list))
return
if(!spell_masters || !spell_masters.len)
return
spell_list.Remove(spell_to_remove)
for(var/obj/screen/movable/spell_master/spell_master in spell_masters)
spell_master.remove_spell(spell_to_remove)
return 1
/mob/proc/silence_spells(var/amount = 0)
if(!(amount >= 0))
return
if(!spell_masters || !spell_masters.len)
return
for(var/obj/screen/movable/spell_master/spell_master in spell_masters)
spell_master.silence_spells(amount)

View File

@@ -0,0 +1,27 @@
/spell/targeted/disintegrate
name = "Disintegrate"
desc = "This spell instantly kills somebody adjacent to you with the vilest of magick."
school = "evocation"
charge_max = 600
spell_flags = NEEDSCLOTHES
invocation = "EI NATH"
invocation_type = SpI_SHOUT
range = 1
cooldown_min = 200 //100 deciseconds reduction per rank
sparks_spread = 1
sparks_amt = 4
hud_state = "wiz_disint"
/spell/targeted/disintegrate/cast(var/list/targets)
..()
for(var/mob/living/target in targets)
if(ishuman(target))
var/mob/living/carbon/C = target
if(!C.has_brain()) // Their brain is already taken out
var/obj/item/organ/brain/B = new(C.loc)
B.transfer_identity(C)
target.gib()
return

View File

@@ -0,0 +1,98 @@
/spell/targeted/ethereal_jaunt
name = "Ethereal Jaunt"
desc = "This spell creates your ethereal form, temporarily making you invisible and able to pass through walls."
school = "transmutation"
charge_max = 300
spell_flags = Z2NOCAST | NEEDSCLOTHES | INCLUDEUSER
invocation = "none"
invocation_type = SpI_NONE
range = -1
max_targets = 1
cooldown_min = 100 //50 deciseconds reduction per rank
duration = 50 //in deciseconds
hud_state = "wiz_jaunt"
/spell/targeted/ethereal_jaunt/cast(list/targets) //magnets, so mostly hardcoded
for(var/mob/living/target in targets)
target.monkeyizing = 1 //protects the mob from being transformed (replaced) midjaunt and getting stuck in bluespace
if(target.buckled) target.buckled = null
spawn(0)
var/mobloc = get_turf(target.loc)
var/obj/effect/dummy/spell_jaunt/holder = new /obj/effect/dummy/spell_jaunt( mobloc )
var/atom/movable/overlay/animation = new /atom/movable/overlay( mobloc )
animation.name = "water"
animation.density = 0
animation.anchored = 1
animation.icon = 'icons/mob/mob.dmi'
animation.layer = 5
animation.master = holder
target.ExtinguishMob()
if(target.buckled)
target.buckled = null
jaunt_disappear(animation, target)
target.loc = holder
target.monkeyizing=0 //mob is safely inside holder now, no need for protection.
jaunt_steam(mobloc)
sleep(duration)
mobloc = get_turf(target.loc)
animation.loc = mobloc
jaunt_steam(mobloc)
target.canmove = 0
holder.reappearing = 1
sleep(20)
jaunt_reappear(animation, target)
sleep(5)
if(!target.forceMove(mobloc))
for(var/direction in list(1,2,4,8,5,6,9,10))
var/turf/T = get_step(mobloc, direction)
if(T)
if(target.forceMove(T))
break
target.canmove = 1
target.client.eye = target
del(animation)
del(holder)
/spell/targeted/ethereal_jaunt/proc/jaunt_disappear(var/atom/movable/overlay/animation, var/mob/living/target)
animation.icon_state = "liquify"
flick("liquify",animation)
/spell/targeted/ethereal_jaunt/proc/jaunt_reappear(var/atom/movable/overlay/animation, var/mob/living/target)
flick("reappear",animation)
/spell/targeted/ethereal_jaunt/proc/jaunt_steam(var/mobloc)
var/datum/effect/effect/system/steam_spread/steam = new /datum/effect/effect/system/steam_spread()
steam.set_up(10, 0, mobloc)
steam.start()
/obj/effect/dummy/spell_jaunt
name = "water"
icon = 'icons/effects/effects.dmi'
icon_state = "nothing"
var/canmove = 1
var/reappearing = 0
density = 0
anchored = 1
/obj/effect/dummy/spell_jaunt/Destroy()
// Eject contents if deleted somehow
for(var/atom/movable/AM in src)
AM.loc = get_turf(src)
..()
/obj/effect/dummy/spell_jaunt/relaymove(var/mob/user, direction)
if (!src.canmove || reappearing) return
var/turf/newLoc = get_step(src,direction)
if(!(newLoc.flags & NOJAUNT))
loc = newLoc
else
user << "<span class='warning'>Some strange aura is blocking the way!</span>"
src.canmove = 0
spawn(2) src.canmove = 1
/obj/effect/dummy/spell_jaunt/ex_act(blah)
return
/obj/effect/dummy/spell_jaunt/bullet_act(blah)
return

View File

@@ -0,0 +1,21 @@
/spell/targeted/flesh_to_stone
name = "Flesh to Stone"
desc = "This spell turns a single person into an inert statue for a long period of time."
school = "transmutation"
charge_max = 600
spell_flags = NEEDSCLOTHES
range = 3
max_targets = 1
invocation = "STAUN EI"
invocation_type = SpI_SHOUT
amt_stunned = 5//just exists to make sure the statue "catches" them
cooldown_min = 200 //100 deciseconds reduction per rank
hud_state = "wiz_statue"
/spell/targeted/flesh_to_stone/cast(var/list/targets, mob/user)
..()
for(var/mob/living/target in targets)
new /obj/structure/closet/statue(target.loc, target) //makes the statue
return

View File

@@ -0,0 +1,68 @@
/*
Other mutation or disability spells can be found in
code\game\dna\genes\vg_powers.dm //hulk is in this file
code\game\dna\genes\goon_disabilities.dm
code\game\dna\genes\goon_powers.dm
*/
/spell/targeted/genetic
name = "Genetic modifier"
desc = "This spell inflicts a set of mutations and disabilities upon the target."
var/disabilities = 0 //bits
var/list/mutations = list() //mutation strings
duration = 100 //deciseconds
/spell/targeted/genetic/cast(list/targets)
..()
for(var/mob/living/target in targets)
for(var/x in mutations)
target.mutations.Add(x)
target.disabilities |= disabilities
target.update_mutations() //update target's mutation overlays
spawn(duration)
for(var/x in mutations)
target.mutations.Remove(x)
target.disabilities &= ~disabilities
target.update_mutations()
return
/spell/targeted/genetic/blind
name = "Blind"
disabilities = 1
duration = 300
charge_max = 300
spell_flags = 0
invocation = "STI KALY"
invocation_type = SpI_WHISPER
message = "<span class='danger'>Your eyes cry out in pain!</span>"
cooldown_min = 50
range = 7
max_targets = 0
amt_eye_blind = 10
amt_eye_blurry = 20
hud_state = "wiz_blind"
/spell/targeted/genetic/mutate
name = "Mutate"
desc = "This spell causes you to turn into a hulk and gain laser vision for a short while."
school = "transmutation"
charge_max = 400
spell_flags = Z2NOCAST | NEEDSCLOTHES | INCLUDEUSER
invocation = "BIRUZ BENNAR"
invocation_type = SpI_SHOUT
message = "\blue You feel strong! You feel a pressure building behind your eyes!"
range = 0
max_targets = 1
mutations = list(LASER, HULK)
duration = 300
cooldown_min = 300 //25 deciseconds reduction per rank
hud_state = "wiz_hulk"

View File

@@ -0,0 +1,36 @@
/spell/targeted/harvest
name = "Harvest"
desc = "Back to where I come from, and you're coming with me."
school = "transmutation"
charge_max = 200
spell_flags = Z2NOCAST | CONSTRUCT_CHECK | INCLUDEUSER
invocation = ""
invocation_type = SpI_NONE
range = 0
max_targets = 0
overlay = 1
overlay_icon = 'icons/effects/effects.dmi'
overlay_icon_state = "rune_teleport"
overlay_lifespan = 0
hud_state = "const_harvest"
/spell/targeted/harvest/cast(list/targets, mob/user)//because harvest is already a proc
..()
var/destination = null
for(var/obj/machinery/singularity/narsie/large/N in narsie_list)
destination = N.loc
break
if(destination)
var/prey = 0
for(var/mob/living/M in targets)
if(!findNullRod(M))
M.forceMove(destination)
if(M != user)
prey = 1
user << "<span class='sinister'>You warp back to Nar-Sie[prey ? " along with your prey":""].</span>"
else
user << "<span class='danger'>...something's wrong!</span>"//There shouldn't be an instance of Harvesters when Nar-Sie isn't in the world.

View File

@@ -0,0 +1,35 @@
/spell/targeted/horsemask
name = "Curse of the Horseman"
desc = "This spell triggers a curse on a target, causing them to wield an unremovable horse head mask. They will speak like a horse! Any masks they are wearing will be disintegrated. This spell does not require robes."
school = "transmutation"
charge_type = Sp_RECHARGE
charge_max = 150
charge_counter = 0
spell_flags = 0
invocation = "KN'A FTAGHU, PUCK 'BTHNK!"
invocation_type = SpI_SHOUT
range = 7
max_targets = 1
cooldown_min = 30 //30 deciseconds reduction per rank
selection_type = "range"
compatible_mobs = list(/mob/living/carbon/human)
hud_state = "wiz_horse"
/spell/targeted/horsemask/cast(list/targets, mob/user = usr)
..()
for(var/mob/living/target in targets)
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
target.visible_message( "<span class='danger'>[target]'s face lights up in fire, and after the event a horse's head takes its place!</span>", \
"<span class='danger'>Your face burns up, and shortly after the fire you realise you have the face of a horse!</span>")
var/obj/old_mask = target.wear_mask
if(old_mask)
target.drop_from_inventory(old_mask)
qdel(old_mask) //get rid of this shit
target.equip_to_slot_if_possible(magichead, slot_wear_mask, 1, 1)
flick("e_flash", target.flash)

View File

@@ -0,0 +1,73 @@
/spell/targeted/mind_transfer
name = "Mind Transfer"
desc = "This spell allows the user to switch bodies with a target."
school = "transmutation"
charge_max = 600
spell_flags = 0
invocation = "GIN'YU CAPAN"
invocation_type = SpI_WHISPER
max_targets = 1
range = 1
cooldown_min = 200 //100 deciseconds reduction per rank
compatible_mobs = list(/mob/living/carbon/human) //which types of mobs are affected by the spell. NOTE: change at your own risk
var/list/protected_roles = list("Wizard","Changeling","Cultist") //which roles are immune to the spell
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
amt_paralysis = 20 //how much the victim is paralysed for after the spell
hud_state = "wiz_mindswap"
/spell/targeted/mind_transfer/cast(list/targets, mob/user)
..()
for(var/mob/living/target in targets)
if(target.stat == DEAD)
user << "You didn't study necromancy back at the Space Wizard Federation academy."
continue
if(!target.key || !target.mind)
user << "They appear to be catatonic. Not even magic can affect their vacant mind."
continue
if(target.mind.special_role in protected_roles)
user << "Their mind is resisting your spell."
continue
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.
//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.
caster.verbs -= V//But a safety nontheless.
if(victim.mind.special_verbs.len)//Now remove all of the victim's verbs.
for(var/V in victim.mind.special_verbs)
victim.verbs -= V
var/mob/dead/observer/ghost = victim.ghostize(0)
ghost.spell_list = victim.spell_list//If they have spells, transfer them. Now we basically have a backup mob.
caster.mind.transfer_to(victim)
victim.spell_list = caster.spell_list//Now they are inside the victim's body.
if(victim.mind.special_verbs.len)//To add all the special verbs for the original caster.
for(var/V in caster.mind.special_verbs)//Not too important but could come into play.
caster.verbs += V
ghost.mind.transfer_to(caster)
caster.key = ghost.key //have to transfer the key since the mind was not active
caster.spell_list = ghost.spell_list
if(caster.mind.special_verbs.len)//If they had any special verbs, we add them here.
for(var/V in caster.mind.special_verbs)
caster.verbs += V
//MIND TRANSFER END
//Target is handled in ..(), so we handle the caster here
caster.Paralyse(amt_paralysis)
//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. <b>Your body doesn't seem like your own.</b>"

View File

@@ -0,0 +1,13 @@
/spell/targeted/projectile/dumbfire
name = "dumbfire spell"
/spell/targeted/projectile/dumbfire/choose_targets(mob/user = usr)
var/list/targets = list()
var/starting_dir = user.dir //where are we facing at the time of casting?
var/turf/starting_turf = get_turf(user)
var/current_turf = starting_turf
for(var/i = 1; i <= src.range; i++)
current_turf = get_step(current_turf, starting_dir)
targets += current_turf
return targets

View File

@@ -0,0 +1,39 @@
/spell/targeted/projectile/dumbfire/fireball
name = "Fireball"
desc = "This spell fires a fireball at a target and does not require wizard garb."
proj_type = /obj/item/projectile/spell_projectile/fireball
school = "evocation"
charge_max = 100
spell_flags = 0
invocation = "ONI SOMA"
invocation_type = SpI_SHOUT
range = 20
cooldown_min = 20 //10 deciseconds reduction per rank
spell_flags = 0
duration = 20
proj_step_delay = 1
amt_dam_brute = 20
amt_dam_fire = 25
var/ex_severe = -1
var/ex_heavy = 1
var/ex_light = 2
var/ex_flash = 5
hud_state = "wiz_fireball"
/spell/targeted/projectile/dumbfire/fireball/prox_cast(var/list/targets, spell_holder)
for(var/mob/living/M in targets)
apply_spell_damage(M)
explosion(get_turf(spell_holder), ex_severe, ex_heavy, ex_light, ex_flash)
//PROJECTILE
/obj/item/projectile/spell_projectile/fireball
name = "fireball"
icon_state = "fireball"

View File

@@ -0,0 +1,40 @@
/spell/targeted/projectile/magic_missile
name = "Magic Missile"
desc = "This spell fires several, slow moving, magic projectiles at nearby targets."
school = "evocation"
charge_max = 150
spell_flags = NEEDSCLOTHES
invocation = "FORTI GY AMA"
invocation_type = SpI_SHOUT
range = 7
cooldown_min = 90 //15 deciseconds reduction per rank
max_targets = 0
proj_type = /obj/item/projectile/spell_projectile/seeking/magic_missile
duration = 10
proj_step_delay = 5
hud_state = "wiz_mm"
amt_paralysis = 3
amt_stunned = 3
amt_dam_fire = 10
/spell/targeted/projectile/magic_missile/prox_cast(var/list/targets, atom/spell_holder)
spell_holder.visible_message("<span class='danger'>\The [spell_holder] pops with a flash!</span>")
for(var/mob/living/M in targets)
apply_spell_damage(M)
return
//PROJECTILE
/obj/item/projectile/spell_projectile/seeking/magic_missile
name = "magic missile"
icon_state = "magicm"
proj_trail = 1
proj_trail_lifespan = 5
proj_trail_icon_state = "magicmd"

View File

@@ -0,0 +1,53 @@
/*
Projectile spells make special projectiles (obj/item/spell_projectile) and fire them at targets
Dumbfire projectile spells fire directly ahead of the user
spell_projectiles call their spell's (carried) prox_cast when they get in range of a target
If the spell_projectile is seeking, it will update its target every process and follow them
*/
/spell/targeted/projectile
name = "projectile spell"
range = 7
var/proj_type = /obj/item/projectile/spell_projectile //use these. They are very nice
var/proj_step_delay = 1 //lower = faster
var/cast_prox_range = 1
/spell/targeted/projectile/cast(list/targets, mob/user = usr)
if(istext(proj_type))
proj_type = text2path(proj_type) // sanity filters
for(var/atom/target in targets)
var/obj/item/projectile/projectile = new proj_type(user.loc, user.dir)
if(!projectile)
return
projectile.original = target
projectile.starting = get_turf(user)
projectile.shot_from = user //fired from the user
projectile.current = projectile.original
projectile.yo = target.y - user.y
projectile.xo = target.x - user.x
projectile.kill_count = src.duration
projectile.hitscan = !proj_step_delay
projectile.step_delay = proj_step_delay
if(istype(projectile, /obj/item/projectile/spell_projectile))
var/obj/item/projectile/spell_projectile/SP = projectile
SP.carried = src //casting is magical
spawn projectile.process()
return
/spell/targeted/projectile/proc/choose_prox_targets(mob/user = usr, var/atom/movable/spell_holder)
var/list/targets = list()
for(var/mob/living/M in range(spell_holder, cast_prox_range))
if(M == user && !(spell_flags & INCLUDEUSER))
continue
targets += M
return targets
/spell/targeted/projectile/proc/prox_cast(var/list/targets, var/atom/movable/spell_holder)
return targets

View File

@@ -0,0 +1,24 @@
/spell/targeted/ethereal_jaunt/shift
name = "Phase Shift"
desc = "This spell allows you to pass through walls"
charge_max = 200
spell_flags = Z2NOCAST | INCLUDEUSER | CONSTRUCT_CHECK
invocation_type = SpI_NONE
range = -1
duration = 50 //in deciseconds
hud_state = "const_shift"
/spell/targeted/ethereal_jaunt/shift/jaunt_disappear(var/atom/movable/overlay/animation, var/mob/living/target)
animation.icon_state = "phase_shift"
animation.dir = target.dir
flick("phase_shift",animation)
/spell/targeted/ethereal_jaunt/shift/jaunt_reappear(var/atom/movable/overlay/animation, var/mob/living/target)
animation.icon_state = "phase_shift2"
animation.dir = target.dir
flick("phase_shift2",animation)
/spell/targeted/ethereal_jaunt/shift/jaunt_steam(var/mobloc)
return

View File

@@ -0,0 +1,20 @@
/spell/targeted/subjugation
name = "Subjugation"
desc = "This spell temporarily subjugates a target's mind and does not require wizard garb."
school = "transmutation"
charge_max = 300
spell_flags = 0
invocation = "DII ODA BAJI"
invocation_type = SpI_WHISPER
message = "<span class='danger'>You suddenly feel completely overwhelmed!<span>"
max_targets = 1
amt_dizziness = 300
amt_confused = 300
amt_stuttering = 300
compatible_mobs = list(/mob/living/carbon/human)
hud_state = "wiz_subj"

View File

@@ -0,0 +1,145 @@
/*
Targeted spells (with the exception of dumbfire) select from all the mobs in the defined range
Targeted spells have two useful flags: INCLUDEUSER and SELECTABLE. These are explained in setup.dm
*/
/spell/targeted //can mean aoe for mobs (limited/unlimited number) or one target mob
var/max_targets = 1 //leave 0 for unlimited targets in range, more for limited number of casts (can all target one guy, depends on target_ignore_prev) in range
var/target_ignore_prev = 1 //only important if max_targets > 1, affects if the spell can be cast multiple times at one person from one cast
var/amt_weakened = 0
var/amt_paralysis = 0
var/amt_stunned = 0
var/amt_dizziness = 0
var/amt_confused = 0
var/amt_stuttering = 0
//set to negatives for healing
var/amt_dam_fire = 0
var/amt_dam_brute = 0
var/amt_dam_oxy = 0
var/amt_dam_tox = 0
var/amt_eye_blind = 0
var/amt_eye_blurry = 0
var/list/compatible_mobs = list()
/spell/targeted/choose_targets(mob/user = usr)
var/list/targets = list()
if(max_targets == 0) //unlimited
if(range == -2)
targets = living_mob_list
else
for(var/mob/living/target in view_or_range(range, user, selection_type))
targets += target
else if(max_targets == 1) //single target can be picked
if((range == 0 || range == -1) && spell_flags & INCLUDEUSER)
targets += user
else
var/list/possible_targets = list()
var/list/starting_targets
if(range == -2)
starting_targets = living_mob_list
else
starting_targets = view_or_range(range, user, selection_type)
for(var/mob/living/M in starting_targets)
if(!(spell_flags & INCLUDEUSER) && M == user)
continue
if(compatible_mobs && compatible_mobs.len)
if(!is_type_in_list(M, compatible_mobs)) continue
if(compatible_mobs && compatible_mobs.len && !is_type_in_list(M, compatible_mobs))
continue
possible_targets += M
if(possible_targets.len)
if(spell_flags & SELECTABLE) //if we are allowed to choose. see setup.dm for details
var/mob/temp_target = input(user, "Choose the target for the spell.", "Targeting") as null|mob in possible_targets
if(temp_target)
targets += temp_target
else
targets += pick(possible_targets)
//Adds a safety check post-input to make sure those targets are actually in range.
else
var/list/possible_targets = list()
var/list/starting_targets
if(range == -2)
starting_targets = living_mob_list
else
starting_targets = view_or_range(range, user, selection_type)
for(var/mob/living/target in starting_targets)
if(!(spell_flags & INCLUDEUSER) && target == user)
continue
if(compatible_mobs && !is_type_in_list(target, compatible_mobs))
continue
possible_targets += target
if(spell_flags & SELECTABLE)
for(var/i = 1; i<=max_targets, i++)
if(!possible_targets.len)
break
var/mob/M = input(user, "Choose the target for the spell.", "Targeting") as null|mob in possible_targets
if(!M)
break
if(range != -2)
if(!(M in view_or_range(range, user, selection_type)))
continue
targets += M
possible_targets -= M
else
for(var/i=1,i<=max_targets,i++)
if(!possible_targets.len)
break
if(target_ignore_prev)
var/target = pick(possible_targets)
possible_targets -= target
targets += target
else
targets += pick(possible_targets)
if(!(spell_flags & INCLUDEUSER) && (user in targets))
targets -= user
if(compatible_mobs && compatible_mobs.len)
for(var/mob/living/target in targets) //filters out all the non-compatible mobs
if(!is_type_in_list(target, compatible_mobs))
targets -= target
return targets
/spell/targeted/cast(var/list/targets, mob/user)
for(var/mob/living/target in targets)
if(range >= 0)
if(!(target in view_or_range(range, user, selection_type))) //filter at time of casting
targets -= target
continue
apply_spell_damage(target)
/spell/targeted/proc/apply_spell_damage(mob/living/target)
target.adjustBruteLoss(amt_dam_brute)
target.adjustFireLoss(amt_dam_fire)
target.adjustToxLoss(amt_dam_tox)
target.adjustOxyLoss(amt_dam_oxy)
//disabling
target.Weaken(amt_weakened)
target.Paralyse(amt_paralysis)
target.Stun(amt_stunned)
if(amt_weakened || amt_paralysis || amt_stunned)
if(target.buckled)
target.buckled = null
target.eye_blind += amt_eye_blind
target.eye_blurry += amt_eye_blurry
target.dizziness += amt_dizziness
target.confused += amt_confused
target.stuttering += amt_stuttering

View File

@@ -1,28 +0,0 @@
/obj/effect/proc_holder/spell/targeted/trigger
name = "Trigger"
desc = "This spell triggers another spell or a few."
var/list/linked_spells = list() //those are just referenced by the trigger spell and are unaffected by it directly
var/list/starting_spells = list() //those are added on New() to contents from default spells and are deleted when the trigger spell is deleted to prevent memory leaks
/obj/effect/proc_holder/spell/targeted/trigger/New()
..()
for(var/spell in starting_spells)
var/spell_to_add = text2path(spell)
new spell_to_add(src) //should result in adding to contents, needs testing
/obj/effect/proc_holder/spell/targeted/trigger/Del()
for(var/spell in contents)
del(spell)
..()
/obj/effect/proc_holder/spell/targeted/trigger/cast(list/targets)
for(var/mob/living/target in targets)
for(var/obj/effect/proc_holder/spell/spell in contents)
spell.perform(list(target),0)
for(var/obj/effect/proc_holder/spell/spell in linked_spells)
spell.perform(list(target),0)
return

View File

@@ -1,34 +0,0 @@
/obj/effect/proc_holder/spell/targeted/turf_teleport
name = "Turf Teleport"
desc = "This spell teleports the target to the turf in range."
var/inner_tele_radius = 1
var/outer_tele_radius = 2
var/include_space = 0 //whether it includes space tiles in possible teleport locations
var/include_dense = 0 //whether it includes dense tiles in possible teleport locations
/obj/effect/proc_holder/spell/targeted/turf_teleport/cast(list/targets)
for(var/mob/living/target in targets)
var/list/turfs = new/list()
for(var/turf/T in range(target,outer_tele_radius))
if(T in range(target,inner_tele_radius)) continue
if(istype(T,/turf/space) && !include_space) continue
if(T.density && !include_dense) continue
if(T.x>world.maxx-outer_tele_radius || T.x<outer_tele_radius) continue //putting them at the edge is dumb
if(T.y>world.maxy-outer_tele_radius || T.y<outer_tele_radius) continue
turfs += T
if(!turfs.len)
var/list/turfs_to_pick_from = list()
for(var/turf/T in orange(target,outer_tele_radius))
if(!(T in orange(target,inner_tele_radius)))
turfs_to_pick_from += T
turfs += pick(/turf in turfs_to_pick_from)
var/turf/picked = pick(turfs)
if(!picked || !isturf(picked))
return
target.loc = picked

View File

@@ -1,59 +0,0 @@
// Veil render //
/obj/item/weapon/veilrender
name = "veil render"
desc = "A wicked curved blade of alien origin, recovered from the ruins of a vast city."
icon = 'icons/obj/wizard.dmi'
icon_state = "render"
item_state = "render"
force = 15
throwforce = 10
w_class = 3
var/charged = 1
/obj/effect/rend
name = "Tear in the fabric of reality"
desc = "You should run now"
icon = 'icons/obj/wizard.dmi'
icon_state = "rift"
density = 1
unacidable = 1
anchored = 1.0
/obj/effect/rend/New()
spawn(50)
new /obj/machinery/singularity/narsie/wizard(get_turf(src))
del(src)
return
return
/obj/item/weapon/veilrender/attack_self(mob/user as mob)
if(charged == 1)
new /obj/effect/rend(get_turf(usr))
charged = 0
visible_message("\red <B>[src] hums with power as [usr] deals a blow to reality itself!</B>")
else
user << "\red The unearthly energies that powered the blade are now dormant"
// Scrying orb //
/obj/item/weapon/scrying
name = "scrying orb"
desc = "An incandescent orb of otherworldly energy, staring into it gives you vision beyond mortal means."
icon = 'icons/obj/projectiles.dmi'
icon_state = "bluespace"
throw_speed = 3
throw_range = 7
throwforce = 10
damtype = BURN
force = 10
hitsound = 'sound/items/welder2.ogg'
/obj/item/weapon/scrying/attack_self(mob/user as mob)
user << "<span class='info'>You can see... everything!</span>"
visible_message("<span class='danger'>[usr] stares into [src], their eyes glazing over.</span>")
announce_ghost_joinleave(user.ghostize(1), 1, "You feel that they used a powerful artifact to [pick("invade","disturb","disrupt","infest","taint","spoil","blight")] this place with their presence.")
return

View File

@@ -1,327 +0,0 @@
/obj/effect/proc_holder/spell/targeted/projectile/magic_missile
name = "Magic Missile"
desc = "This spell fires several, slow moving, magic projectiles at nearby targets."
school = "evocation"
charge_max = 150
clothes_req = 1
invocation = "FORTI GY AMA"
invocation_type = "shout"
range = 7
max_targets = 0
proj_icon_state = "magicm"
proj_name = "a magic missile"
proj_lingering = 1
proj_type = "/obj/effect/proc_holder/spell/targeted/inflict_handler/magic_missile"
proj_lifespan = 20
proj_step_delay = 5
proj_trail = 1
proj_trail_lifespan = 5
proj_trail_icon_state = "magicmd"
/obj/effect/proc_holder/spell/targeted/inflict_handler/magic_missile
amt_weakened = 5
amt_dam_fire = 10
/obj/effect/proc_holder/spell/targeted/genetic/mutate
name = "Mutate"
desc = "This spell causes you to turn into a hulk and gain laser vision for a short while."
school = "transmutation"
charge_max = 400
clothes_req = 1
invocation = "BIRUZ BENNAR"
invocation_type = "shout"
message = "\blue You feel strong! You feel a pressure building behind your eyes!"
range = -1
include_user = 1
mutations = list(LASER, HULK)
duration = 300
/obj/effect/proc_holder/spell/targeted/inflict_handler/disintegrate
name = "Disintegrate"
desc = "This spell instantly kills somebody adjacent to you with the vilest of magick."
school = "evocation"
charge_max = 600
clothes_req = 1
invocation = "EI NATH"
invocation_type = "shout"
range = 1
destroys = "gib_brain"
sparks_spread = 1
sparks_amt = 4
/obj/effect/proc_holder/spell/targeted/smoke
name = "Smoke"
desc = "This spell spawns a cloud of choking smoke at your location and does not require wizard garb."
school = "conjuration"
charge_max = 120
clothes_req = 0
invocation = "none"
invocation_type = "none"
range = -1
include_user = 1
smoke_spread = 2
smoke_amt = 10
/obj/effect/proc_holder/spell/targeted/emplosion/disable_tech
name = "Disable Tech"
desc = "This spell disables all weapons, cameras and most other technology in range."
charge_max = 400
clothes_req = 1
invocation = "NEC CANTIO"
invocation_type = "shout"
range = -1
include_user = 1
emp_heavy = 6
emp_light = 10
/obj/effect/proc_holder/spell/targeted/turf_teleport/blink
name = "Blink"
desc = "This spell randomly teleports you a short distance."
school = "abjuration"
charge_max = 20
clothes_req = 1
invocation = "none"
invocation_type = "none"
range = -1
include_user = 1
smoke_spread = 1
smoke_amt = 10
inner_tele_radius = 0
outer_tele_radius = 6
centcomm_cancast = 0 //prevent people from getting to centcomm
/obj/effect/proc_holder/spell/targeted/area_teleport/teleport
name = "Teleport"
desc = "This spell teleports you to a type of area of your selection."
school = "abjuration"
charge_max = 600
clothes_req = 1
invocation = "SCYAR NILA"
invocation_type = "shout"
range = -1
include_user = 1
smoke_spread = 1
smoke_amt = 5
/obj/effect/proc_holder/spell/aoe_turf/conjure/forcewall
name = "Forcewall"
desc = "This spell creates an unbreakable wall that lasts for 30 seconds and does not need wizard garb."
school = "transmutation"
charge_max = 100
clothes_req = 0
invocation = "TARCOL MINTI ZHERI"
invocation_type = "whisper"
range = 0
summon_type = list("/obj/effect/forcefield")
summon_lifespan = 300
/obj/effect/proc_holder/spell/aoe_turf/conjure/carp
name = "Summon Carp"
desc = "This spell conjures a simple carp."
school = "conjuration"
charge_max = 1200
clothes_req = 1
invocation = "NOUK FHUNMM SACP RISSKA"
invocation_type = "shout"
range = 1
summon_type = list(/mob/living/simple_animal/hostile/carp)
/obj/effect/proc_holder/spell/aoe_turf/conjure/construct
name = "Artificer"
desc = "This spell conjures a construct which may be controlled by Shades"
school = "conjuration"
charge_max = 600
clothes_req = 0
invocation = "none"
invocation_type = "none"
range = 0
summon_type = list(/obj/structure/constructshell)
/obj/effect/proc_holder/spell/aoe_turf/conjure/creature
name = "Summon Creature Swarm"
desc = "This spell tears the fabric of reality, allowing horrific daemons to spill forth"
school = "conjuration"
charge_max = 1200
clothes_req = 0
invocation = "IA IA"
invocation_type = "shout"
summon_amt = 10
range = 3
summon_type = list(/mob/living/simple_animal/hostile/creature)
/obj/effect/proc_holder/spell/targeted/trigger/blind
name = "Blind"
desc = "This spell temporarily blinds a single person and does not require wizard garb."
school = "transmutation"
charge_max = 300
clothes_req = 0
invocation = "STI KALY"
invocation_type = "whisper"
message = "\blue Your eyes cry out in pain!"
starting_spells = list("/obj/effect/proc_holder/spell/targeted/inflict_handler/blind","/obj/effect/proc_holder/spell/targeted/genetic/blind")
/obj/effect/proc_holder/spell/targeted/inflict_handler/blind
amt_eye_blind = 10
amt_eye_blurry = 20
/obj/effect/proc_holder/spell/targeted/genetic/blind
disabilities = 1
duration = 300
/obj/effect/proc_holder/spell/dumbfire/fireball
name = "Fireball"
desc = "This spell fires a fireball at a target and does not require wizard garb."
school = "evocation"
charge_max = 100
clothes_req = 0
invocation = "ONI SOMA"
invocation_type = "shout"
range = 20
proj_icon_state = "fireball"
proj_name = "a fireball"
proj_type = "/obj/effect/proc_holder/spell/turf/fireball"
proj_lifespan = 200
proj_step_delay = 1
/obj/effect/proc_holder/spell/turf/fireball/cast(var/turf/T)
explosion(T, -1, 1, 2, 3)
/obj/effect/proc_holder/spell/targeted/inflict_handler/fireball
amt_dam_brute = 20
amt_dam_fire = 25
/obj/effect/proc_holder/spell/targeted/explosion/fireball
ex_severe = -1
ex_heavy = -1
ex_light = 2
ex_flash = 5
//////////////////////////////Construct Spells/////////////////////////
/obj/effect/proc_holder/spell/aoe_turf/conjure/construct/lesser
charge_max = 1800
/obj/effect/proc_holder/spell/aoe_turf/conjure/floor
name = "Floor Construction"
desc = "This spell constructs a cult floor"
school = "conjuration"
charge_max = 20
clothes_req = 0
invocation = "none"
invocation_type = "none"
range = 0
summon_type = list(/turf/simulated/floor/engine/cult)
centcomm_cancast = 0 //Stop crashing the server by spawning turfs on transit tiles
/obj/effect/proc_holder/spell/aoe_turf/conjure/wall
name = "Leser Construction"
desc = "This spell constructs a cult wall"
school = "conjuration"
charge_max = 100
clothes_req = 0
invocation = "none"
invocation_type = "none"
range = 0
summon_type = list(/turf/simulated/wall/cult)
centcomm_cancast = 0 //Stop crashing the server by spawning turfs on transit tiles
/obj/effect/proc_holder/spell/aoe_turf/conjure/wall/reinforced
name = "Greater Construction"
desc = "This spell constructs a reinforced metal wall"
school = "conjuration"
charge_max = 300
clothes_req = 0
invocation = "none"
invocation_type = "none"
range = 0
centcomm_cancast = 0 //Stop crashing the server by spawning turfs on transit tiles
delay = 50
summon_type = list(/turf/simulated/wall/r_wall)
/obj/effect/proc_holder/spell/aoe_turf/conjure/soulstone
name = "Summon Soulstone"
desc = "This spell reaches into Nar-Sie's realm, summoning one of the legendary fragments across time and space"
school = "conjuration"
charge_max = 3000
clothes_req = 0
invocation = "none"
invocation_type = "none"
range = 0
summon_type = list(/obj/item/device/soulstone)
/obj/effect/proc_holder/spell/aoe_turf/conjure/lesserforcewall
name = "Shield"
desc = "This spell creates a temporary forcefield to shield yourself and allies from incoming fire"
school = "transmutation"
charge_max = 300
clothes_req = 0
invocation = "none"
invocation_type = "none"
range = 0
summon_type = list(/obj/effect/forcefield)
summon_lifespan = 50
/obj/effect/proc_holder/spell/targeted/ethereal_jaunt/shift
name = "Phase Shift"
desc = "This spell allows you to pass through walls"
school = "transmutation"
charge_max = 200
clothes_req = 0
invocation = "none"
invocation_type = "none"
range = -1
include_user = 1
phaseshift = 1
jaunt_duration = 50 //in deciseconds
centcomm_cancast = 0 //Stop people from getting to centcomm