diff --git a/code/datums/spell.dm b/code/datums/spell.dm index 23f1001de6..f89d81b499 100644 --- a/code/datums/spell.dm +++ b/code/datums/spell.dm @@ -1,19 +1,32 @@ -var/list/spells = list(/obj/spell/blind,/obj/spell/blink,/obj/spell/conjure,/obj/spell/disable_tech,/obj/spell/disintegrate,/obj/spell/ethereal_jaunt,/obj/spell/fireball,/obj/spell/forcewall,/obj/spell/knock,/obj/spell/magic_missile,/obj/spell/mind_transfer,/obj/spell/mutate,/obj/spell/smoke,/obj/spell/teleport) //needed for the badmin verb for now +var/list/spells = typesof(/obj/spell) //needed for the badmin verb for now /obj/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 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/clothes_req = 1 //see if it requires clothes - var/stat_allowed = 0 //see if it requires being conscious + 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 - var/message = "derp herp" //whatever it says to the guy affected by it. not always needed + 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 = '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 /obj/spell/proc/cast_check() //checks if the spell can be cast based on its settings @@ -23,7 +36,7 @@ var/list/spells = list(/obj/spell/blind,/obj/spell/blink,/obj/spell/conjure,/obj switch(charge_type) if("recharge") - if(charge_counter != charge_max) + if(charge_counter < charge_max) usr << "[name] is still recharging." return 0 if("charges") @@ -46,6 +59,12 @@ var/list/spells = list(/obj/spell/blind,/obj/spell/blink,/obj/spell/conjure,/obj usr << "I don't feel strong enough without my hat." return 0 + 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 + return 1 /obj/spell/proc/invocation() //spelling the spell out and setting it on recharge/reducing charges amount @@ -60,18 +79,181 @@ var/list/spells = list(/obj/spell/blind,/obj/spell/blink,/obj/spell/conjure,/obj if("whisper") usr.whisper(invocation) - switch(charge_type) - if("recharge") - charge_counter = 0 - - spawn(0) - while(charge_counter < charge_max) - sleep(1) - charge_counter++ - if("charges") - charge_counter-- - /obj/spell/New() ..() - charge_counter = charge_max \ No newline at end of file + charge_counter = charge_max + +/obj/spell/Click() + ..() + + if(!cast_check()) + return + + choose_targets() + +/obj/spell/proc/choose_targets() //depends on subtype - /targeted or /aoe_turf + return + +/obj/spell/proc/start_recharge() + while(charge_counter < charge_max) + sleep(1) + charge_counter++ + +/obj/spell/proc/perform(list/targets) + before_cast(targets) + invocation() + spawn(0) + if(charge_type == "recharge") + start_recharge() + cast(targets) + after_cast(targets) + +/obj/spell/proc/before_cast(list/targets) + if(overlay) + for(var/atom/target in targets) + var/location + if(istype(target,/mob)) + location = target.loc + else if(istype(target,/turf)) + location = target + var/obj/overlay/spell = new /obj/overlay(location) + spell.icon = overlay_icon + spell.icon_state = overlay_icon_state + spell.anchored = 1 + spell.density = 0 + spawn(overlay_lifespan) + del(spell) + +/obj/spell/proc/after_cast(list/targets) + for(var/atom/target in targets) + var/location + if(istype(target,/mob)) + location = target.loc + else if(istype(target,/turf)) + location = target + if(istype(target,/mob) && message) + target << text("[message]") + if(sparks_spread) + var/datum/effects/system/spark_spread/sparks = new /datum/effects/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/effects/system/harmless_smoke_spread/smoke = new /datum/effects/system/harmless_smoke_spread() + smoke.set_up(smoke_amt, 0, location) //no idea what the 0 is + smoke.start() + else if(smoke_spread == 2) + var/datum/effects/system/bad_smoke_spread/smoke = new /datum/effects/system/bad_smoke_spread() + smoke.set_up(smoke_amt, 0, location) //no idea what the 0 is + smoke.start() + +/obj/spell/proc/cast(list/targets) + return + +/obj/spell/proc/revert_cast() //resets recharge or readds a charge + switch(charge_type) + if("recharge") + charge_counter = charge_max + if("charges") + charge_counter++ + + return + + +/obj/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_usr = 0 //if it includes usr in the target list + +/obj/spell/aoe_turf //affects all turfs in view or range (depends) + var/inner_radius = -1 //for all your ring spell needs + +/obj/spell/targeted/choose_targets() + var/list/targets = list() + + switch(selection_type) + if("range") + switch(max_targets) + if(0) + for(var/mob/target in range(usr,range)) + targets += target + if(1) + if(range < 0) + targets += usr + else + var/possible_targets = range(usr,range) + if(!include_usr && usr in possible_targets) + possible_targets -= usr + targets += input("Choose the target for the spell.", "Targeting") as mob in possible_targets + else + var/list/possible_targets = list() + for(var/mob/target in range(usr,range)) + 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("view") + switch(max_targets) + if(0) + for(var/mob/target in view(usr,range)) + targets += target + if(1) + if(range < 0) + targets += usr + else + var/possible_targets = view(usr,range) + if(!include_usr && usr in possible_targets) + possible_targets -= usr + targets += input("Choose the target for the spell.", "Targeting") as mob in possible_targets + else + var/list/possible_targets = list() + for(var/mob/target in view(usr,range)) + 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_usr && (usr in targets)) + targets -= usr + + if(!targets.len) //doesn't waste the spell + revert_cast() + return + + perform(targets) + + return + +/obj/spell/aoe_turf/choose_targets() + var/list/targets = list() + + switch(selection_type) + if("range") + for(var/turf/target in range(usr,range)) + if(!(target in range(usr,inner_radius))) + targets += target + if("view") + for(var/turf/target in view(usr,range)) + if(!(target in view(usr,inner_radius))) + targets += target + + if(!targets.len) //doesn't waste the spell + revert_cast() + return + + perform(targets) + + return \ No newline at end of file diff --git a/code/datums/spells/area_teleport.dm b/code/datums/spells/area_teleport.dm new file mode 100644 index 0000000000..eb87980df0 --- /dev/null +++ b/code/datums/spells/area_teleport.dm @@ -0,0 +1,63 @@ +/obj/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/spell/targeted/area_teleport/perform(list/targets) + var/thearea = before_cast(targets) + if(!thearea) + revert_cast() + return + invocation(thearea) + spawn(0) + if(charge_type == "recharge") + start_recharge() + cast(targets,thearea) + after_cast(targets) + +/obj/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/spell/targeted/area_teleport/cast(list/targets,area/thearea) + for(var/mob/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 + + target.loc = pick(L) + + return + +/obj/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('vs_chant_conj_hm.wav','vs_chant_conj_lm.wav','vs_chant_ench_hm.wav','vs_chant_ench_lm.wav','vs_chant_evoc_hm.wav','vs_chant_evoc_lm.wav','vs_chant_illu_hm.wav','vs_chant_illu_lm.wav','vs_chant_necr_hm.wav','vs_chant_necr_lm.wav'), 100, 1) + else + playsound(usr.loc, pick('vs_chant_conj_hf.wav','vs_chant_conj_lf.wav','vs_chant_ench_hf.wav','vs_chant_ench_lf.wav','vs_chant_evoc_hf.wav','vs_chant_evoc_lf.wav','vs_chant_illu_hf.wav','vs_chant_illu_lf.wav','vs_chant_necr_hf.wav','vs_chant_necr_lf.wav'), 100, 1) + if("whisper") + usr.whisper("[invocation] [uppertext(chosenarea.name)]") + + return \ No newline at end of file diff --git a/code/datums/spells/blink.dm b/code/datums/spells/blink.dm deleted file mode 100644 index b588422acf..0000000000 --- a/code/datums/spells/blink.dm +++ /dev/null @@ -1,53 +0,0 @@ -/obj/spell/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 //can affect only the user by default, but with var editing can be a teleport other spell - var/outer_teleport_radius = 6 //the radius of the area in which it picks turfs to teleport to - var/inner_teleport_radius = 0 //so with var fuckery you can have it teleport in a ring, not in a circle - var/smoke_spread = 1 //if set to 0, no smoke spreads when teleporting - -/obj/spell/blink/Click() - ..() - - if(!cast_check()) - return - - var/mob/M - - if(range>=0) - M = input("Choose whom to blink", "ABRAKADABRA") as mob in view(usr,range) - else - M = usr - - if(!M) - return - - invocation() - - var/list/turfs = new/list() - for(var/turf/T in orange(M,outer_teleport_radius)) - if(T in orange(M,inner_teleport_radius)) continue - if(istype(T,/turf/space)) continue - if(T.density) continue - if(T.x>world.maxx-outer_teleport_radius || T.xworld.maxy-outer_teleport_radius || T.y0) - M.take_overall_damage(abs(damage_amount),abs(damage_amount)) - M.toxloss+=abs(damage_amount) - M.oxyloss+=abs(damage_amount) - else - M.heal_overall_damage(abs(damage_amount),abs(damage_amount)) - M.toxloss+=abs(damage_amount) - M.oxyloss+=abs(damage_amount) -/* - for(var/i=0,i0) - M.bruteloss++ - else - M.bruteloss-- - if("toxin") - if(damage_amount>0) - M.toxloss++ - else - M.toxloss-- - if("oxygen") - if(damage_amount>0) - M.oxyloss++ - else - M.oxyloss-- - if("fire") - if(damage_amount>0) - M.fireloss++ - else - M.fireloss-- -*/ \ No newline at end of file diff --git a/code/datums/spells/emplosion.dm b/code/datums/spells/emplosion.dm new file mode 100644 index 0000000000..1d358865ca --- /dev/null +++ b/code/datums/spells/emplosion.dm @@ -0,0 +1,13 @@ +/obj/spell/targeted/emplosion + name = "Emplosion" + desc = "This spell emplodes an area." + + var/emp_heavy = 2 + var/emp_light = 3 + +/obj/spell/targeted/emplosion/cast(list/targets) + + for(var/mob/target in targets) + empulse(target.loc, emp_heavy, emp_light) + + return \ No newline at end of file diff --git a/code/datums/spells/ethereal_jaunt.dm b/code/datums/spells/ethereal_jaunt.dm index b442bf17e5..25c8c92159 100644 --- a/code/datums/spells/ethereal_jaunt.dm +++ b/code/datums/spells/ethereal_jaunt.dm @@ -1,4 +1,4 @@ -/obj/spell/ethereal_jaunt +/obj/spell/targeted/ethereal_jaunt name = "Ethereal Jaunt" desc = "This spell creates your ethereal form, temporarily making you invisible and able to pass through walls." @@ -7,58 +7,44 @@ clothes_req = 1 invocation = "none" invocation_type = "none" - range = -1 //can affect only the user by default, but with var editing can be an invis other spell + range = -1 + include_usr = 1 + var/jaunt_duration = 50 //in deciseconds -/obj/spell/ethereal_jaunt/Click() - ..() - - if(!cast_check()) - return - - var/mob/M - - if(range>=0) - M = input("Choose whom to jaunt", "ABRAKADABRA") as mob in view(usr,range) - else - M = usr - - if(!M) - return - - invocation() - - spawn(0) - var/mobloc = get_turf(M.loc) - var/obj/dummy/spell_jaunt/holder = new /obj/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 = 'mob.dmi' - animation.icon_state = "liquify" - animation.layer = 5 - animation.master = holder - flick("liquify",animation) - M.loc = holder - M.client.eye = holder - var/datum/effects/system/steam_spread/steam = new /datum/effects/system/steam_spread() - steam.set_up(10, 0, mobloc) - steam.start() - sleep(jaunt_duration) - mobloc = get_turf(M.loc) - animation.loc = mobloc - steam.location = mobloc - steam.start() - M.canmove = 0 - sleep(20) - flick("reappear",animation) - sleep(5) - M.loc = mobloc - M.canmove = 1 - M.client.eye = M - del(animation) - del(holder) +/obj/spell/targeted/ethereal_jaunt/cast(list/targets) //magnets, so mostly hardcoded + for(var/mob/target in targets) + spawn(0) + var/mobloc = get_turf(target.loc) + var/obj/dummy/spell_jaunt/holder = new /obj/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 = 'mob.dmi' + animation.icon_state = "liquify" + animation.layer = 5 + animation.master = holder + flick("liquify",animation) + target.loc = holder + target.client.eye = holder + var/datum/effects/system/steam_spread/steam = new /datum/effects/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) + target.loc = mobloc + target.canmove = 1 + target.client.eye = target + del(animation) + del(holder) /obj/dummy/spell_jaunt name = "water" diff --git a/code/datums/spells/explosion.dm b/code/datums/spells/explosion.dm new file mode 100644 index 0000000000..96e02e6899 --- /dev/null +++ b/code/datums/spells/explosion.dm @@ -0,0 +1,15 @@ +/obj/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/spell/targeted/explosion/cast(list/targets) + + for(var/mob/target in targets) + explosion(target.loc,ex_severe,ex_heavy,ex_light,ex_flash) + + return \ No newline at end of file diff --git a/code/datums/spells/fireball.dm b/code/datums/spells/fireball.dm deleted file mode 100644 index 832c7ea99c..0000000000 --- a/code/datums/spells/fireball.dm +++ /dev/null @@ -1,48 +0,0 @@ -/obj/spell/fireball - name = "Fireball" - desc = "This spell fires a fireball at a target and does not require wizard garb." - - school = "evocation" - charge_max = 200 - clothes_req = 0 - invocation = "ONI SOMA" - invocation_type = "shout" - var/radius_devastation = -1 - var/radius_heavy = -1 - var/radius_light = 2 - var/radius_flash = 2 - var/bruteloss = 20 // apparently fireball deals damage in addition to the explosion - var/fireloss = 25 // huh - var/lifetime = 200 // in deciseconds - -/obj/spell/fireball/Click() - ..() - - if(!cast_check()) - return - - var/mob/M = input("Choose whom to fireball", "ABRAKADABRA") as mob in oview(usr,range) - - if(!M) - return - - invocation() - - var/obj/overlay/A = new /obj/overlay( usr.loc ) - A.icon_state = "fireball" - A.icon = 'wizard.dmi' - A.name = "a fireball" - A.anchored = 0 - A.density = 0 - var/i - for(i=0, i 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.toxloss += amt_dam_tox + target.oxyloss += amt_dam_oxy + //disabling + target.weakened += amt_weaken + target.paralysis += amt_paralysis \ No newline at end of file diff --git a/code/datums/spells/knock.dm b/code/datums/spells/knock.dm index 499ad94892..dafa286f91 100644 --- a/code/datums/spells/knock.dm +++ b/code/datums/spells/knock.dm @@ -1,4 +1,4 @@ -/obj/spell/knock +/obj/spell/aoe_turf/knock name = "Knock" desc = "This spell opens nearby doors and does not require wizard garb." @@ -9,16 +9,11 @@ invocation_type = "whisper" range = 3 -/obj/spell/knock/Click() - ..() - - if(!cast_check()) - return - - invocation() - - for(var/obj/machinery/door/G in oview(usr,range)) - spawn(1) - G:locked = 0 - G.open() +/obj/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)) + door:locked = 0 + door.open() return \ No newline at end of file diff --git a/code/datums/spells/magic_missile.dm b/code/datums/spells/magic_missile.dm deleted file mode 100644 index 28d455efe8..0000000000 --- a/code/datums/spells/magic_missile.dm +++ /dev/null @@ -1,57 +0,0 @@ -/obj/spell/magic_missile - name = "Magic Missile" - desc = "This spell fires several, slow moving, magic projectiles at nearby targets." - - school = "evocation" - charge_max = 100 - clothes_req = 1 - invocation = "FORTI GY AMA" - invocation_type = "shout" - range = 7 - var/max_targets = 0 //max targets for the spell. set to 0 for no limit - var/missile_lifespan = 20 //in deciseconds * missile_step_delay - var/missile_step_delay = 5 //lower = faster missile - var/missile_weaken_amt = 5 //the amount by which the missile weakens the target it hits - var/missile_damage = 10 //the amount of fireloss each missile deals - -/obj/spell/magic_missile/Click() - ..() - - if(!cast_check()) - return - - invocation() - - var/targets = 0 - for (var/mob/living/M as mob in oview(usr,range)) - if(max_targets) - if(targets >= max_targets) - break - spawn(0) - var/obj/overlay/A = new /obj/overlay( usr.loc ) - A.icon_state = "magicm" - A.icon = 'wizard.dmi' - A.name = "a magic missile" - A.anchored = 0 - A.density = 0 - A.layer = 4 - var/i - for(i=0, i 1) + usr << "Too many minds! You're not a hive damnit!" + return + + var/mob/target = targets[1] if(!target.client || !target.mind) usr << "They appear to be brain-dead." @@ -41,8 +44,6 @@ usr << "You didn't study necromancy back at the Space Wizard Federation academy." return - invocation() - var/mob/victim = target //mostly copypastaed, I have little idea how this works var/mob/caster = usr //losing spells @@ -51,14 +52,14 @@ for(var/i=1,i<=spell_loss_amount,i++) var/spell_loss_chance = base_spell_loss_chance var/list/checked_spells = usr.spell_list - checked_spells -= src //MT can't be lost + checked_spells -= src //MT can't be lost //doesn't work for(var/j=1,j<=checked_spells.len,j++) if(prob(spell_loss_chance)) if(checked_spells.len) usr.spell_list -= pick(checked_spells) spawn(msg_wait) - caster << "The mind transfer has robbed you of a spell." + victim << "The mind transfer has robbed you of a spell." break else spell_loss_chance += spell_loss_chance_modifier @@ -96,6 +97,6 @@ victim.paralysis += paralysis_amount_victim spawn(msg_wait) - victim << "Your body doesn't feel like itself." + caster << "Your body doesn't feel like itself." del(temp_ghost) \ No newline at end of file diff --git a/code/datums/spells/mutate.dm b/code/datums/spells/mutate.dm deleted file mode 100644 index 42c7ad7886..0000000000 --- a/code/datums/spells/mutate.dm +++ /dev/null @@ -1,50 +0,0 @@ -/obj/spell/mutate - name = "Mutate" - desc = "This spell causes you to turn into a hulk and gain telekinesis for a short while." - - school = "transmutation" - charge_max = 400 - clothes_req = 1 - invocation = "BIRUZ BENNAR" - invocation_type = "shout" - message = "\blue You feel strong! Your mind expands!" - range = -1 //can affect only the user by default, but with var editing can be a mutate other spell - var/mutate_duration = 300 //in deciseconds - var/list/mutation_types = list("hulk","tk") //right now understands only "hulk", "tk", "cold resist", "xray" and "clown" - -/obj/spell/mutate/Click() - ..() - - if(!cast_check()) - return - - var/mob/M - - if(range>=0) - M = input("Choose whom to mutate", "ABRAKADABRA") as mob in view(usr,range) - else - M = usr - - if(!M) - return - - invocation() - - M << text("[message]") - var/mutation = 0 - for(var/MT in mutation_types) - switch(MT) - if("tk") - mutation |= 1 - if("cold resist") - mutation |= 2 - if("xray") - mutation |= 4 - if("hulk") - mutation |= 8 - if("clown") - mutation |= 16 - M.mutations |= mutation - spawn (mutate_duration) - M.mutations &= ~mutation - return \ No newline at end of file diff --git a/code/datums/spells/projectile.dm b/code/datums/spells/projectile.dm new file mode 100644 index 0000000000..2a869b734b --- /dev/null +++ b/code/datums/spells/projectile.dm @@ -0,0 +1,75 @@ +/obj/spell/targeted/projectile + name = "Projectile" + desc = "This spell summons projectiles which try to hit the targets." + + var/proj_icon = '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 = 'wizard.dmi' + var/proj_trail_icon_state = "trail" + + var/proj_type = "/obj/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 = 1 //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/spell/targeted/projectile/cast(list/targets) + + for(var/mob/target in targets) + spawn(0) + var/projectile_type = text2path(proj_type) + var/obj/spell/targeted/projectile = new projectile_type(usr) + projectile.icon = proj_icon + projectile.icon_state = proj_icon_state + projectile.dir = get_dir(target,projectile) + projectile.name = proj_name + + var/current_loc = usr.loc + + for(var/i = 0,i < proj_lifespan,i++) + if(!projectile) + break + + if(proj_homing) + if(proj_insubstantial) + 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/overlay/trail = new /obj/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) \ No newline at end of file diff --git a/code/datums/spells/smoke.dm b/code/datums/spells/smoke.dm deleted file mode 100644 index 8227eea8a3..0000000000 --- a/code/datums/spells/smoke.dm +++ /dev/null @@ -1,23 +0,0 @@ -/obj/spell/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 //originates from the user and I don't give a shit atm - var/smoke_amount = 10 //above 10 gets reduced to 10 anyway by the set_up proc - -/obj/spell/smoke/Click() - ..() - - if(!cast_check()) - return - - invocation() - - var/datum/effects/system/bad_smoke_spread/smoke = new /datum/effects/system/bad_smoke_spread() - smoke.set_up(smoke_amount, 0, usr.loc) - smoke.start() \ No newline at end of file diff --git a/code/datums/spells/teleport.dm b/code/datums/spells/teleport.dm deleted file mode 100644 index e60bbfab39..0000000000 --- a/code/datums/spells/teleport.dm +++ /dev/null @@ -1,64 +0,0 @@ -/obj/spell/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 = "none" //hardcoded into the spell due to its specifics - range = -1 //can affect only the user by default, but with var editing can be a teleport other spell - var/smoke_spread = 1 //if set to 0, no smoke spreads when teleporting - -/obj/spell/teleport/Click() - ..() - - if(!cast_check()) - return - - var/mob/M - - if(range>=0) - M = input("Choose whom to teleport", "ABRAKADABRA") as mob in view(usr,range) - else - M = usr - - if(!M) - return - - invocation() - - var/A - - A = input("Area to jump to", "BOOYEA", A) in teleportlocs - - var/area/thearea = teleportlocs[A] - - usr.say("[invocation] [uppertext(A)]") - if(usr.gender=="male") - playsound(usr.loc, pick('vs_chant_conj_hm.wav','vs_chant_conj_lm.wav','vs_chant_ench_hm.wav','vs_chant_ench_lm.wav','vs_chant_evoc_hm.wav','vs_chant_evoc_lm.wav','vs_chant_illu_hm.wav','vs_chant_illu_lm.wav','vs_chant_necr_hm.wav','vs_chant_necr_lm.wav'), 100, 1) - else - playsound(usr.loc, pick('vs_chant_conj_hf.wav','vs_chant_conj_lf.wav','vs_chant_ench_hf.wav','vs_chant_ench_lf.wav','vs_chant_evoc_hf.wav','vs_chant_evoc_lf.wav','vs_chant_illu_hf.wav','vs_chant_illu_lf.wav','vs_chant_necr_hf.wav','vs_chant_necr_lf.wav'), 100, 1) - - var/datum/effects/system/harmless_smoke_spread/smoke = new /datum/effects/system/harmless_smoke_spread() - - if(smoke_spread) - smoke.set_up(5, 0, usr.loc) - smoke.attach(usr) - smoke.start() - - 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 - - M.loc = pick(L) - - if(smoke_spread) - smoke.start() \ No newline at end of file diff --git a/code/datums/spells/turf_teleport.dm b/code/datums/spells/turf_teleport.dm new file mode 100644 index 0000000000..49d3d6a595 --- /dev/null +++ b/code/datums/spells/turf_teleport.dm @@ -0,0 +1,34 @@ +/obj/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/spell/targeted/turf_teleport/cast(list/targets) + for(var/mob/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.xworld.maxy-outer_tele_radius || T.y: [user.name]([user.key]) emagged [src.name]([src.key])") - set_zeroth_law("Only [usr] is a syndicate operative.") + set_zeroth_law("Only [user.name] and people he designates as being such are syndicate agents.") src << "\red ALERT: Foreign software detected." sleep(5) src << "\red Initiating diagnostics..." diff --git a/icons/obj/projectiles.dmi b/icons/obj/projectiles.dmi index 3857a27188..d8cd49aab9 100644 Binary files a/icons/obj/projectiles.dmi and b/icons/obj/projectiles.dmi differ diff --git a/tgstation.dme b/tgstation.dme index d42aa0902f..21af7e5ff3 100644 --- a/tgstation.dme +++ b/tgstation.dme @@ -201,20 +201,19 @@ #include "code\datums\diseases\xeno_transformation.dm" #include "code\datums\helper_datums\construction_datum.dm" #include "code\datums\helper_datums\global_iterator.dm" +#include "code\datums\spells\area_teleport.dm" #include "code\datums\spells\blind.dm" -#include "code\datums\spells\blink.dm" #include "code\datums\spells\conjure.dm" -#include "code\datums\spells\disable_tech.dm" -#include "code\datums\spells\disintegrate.dm" +#include "code\datums\spells\emplosion.dm" #include "code\datums\spells\ethereal_jaunt.dm" -#include "code\datums\spells\fireball.dm" -#include "code\datums\spells\forcewall.dm" +#include "code\datums\spells\explosion.dm" +#include "code\datums\spells\genetic.dm" +#include "code\datums\spells\inflict_handler.dm" #include "code\datums\spells\knock.dm" -#include "code\datums\spells\magic_missile.dm" #include "code\datums\spells\mind_transfer.dm" -#include "code\datums\spells\mutate.dm" -#include "code\datums\spells\smoke.dm" -#include "code\datums\spells\teleport.dm" +#include "code\datums\spells\projectile.dm" +#include "code\datums\spells\turf_teleport.dm" +#include "code\datums\spells\wizard.dm" #include "code\defines\atom.dm" #include "code\defines\client.dm" #include "code\defines\global.dm"