From a67b544acd8f59655826acdbd2f5ca89a786e9bf Mon Sep 17 00:00:00 2001 From: Neerti Date: Sun, 7 Feb 2016 23:41:02 -0500 Subject: [PATCH] More work done! --- .../technomancer/assistance/assistance.dm | 8 +- .../technomancer/assistance/golem.dm | 30 +++- code/game/gamemodes/technomancer/catalog.dm | 65 ++++--- code/game/gamemodes/technomancer/core_obj.dm | 67 +++++++- .../devices/disposable_teleporter.dm | 2 +- code/game/gamemodes/technomancer/equipment.dm | 14 +- code/game/gamemodes/technomancer/presets.dm | 15 +- .../game/gamemodes/technomancer/spell_objs.dm | 160 +++--------------- .../technomancer/spells/apportation.dm | 11 +- .../technomancer/spells/aspect/aspect.dm | 46 +++++ .../spells/aspect/aspect_weapon.dm | 69 ++++++++ .../technomancer/spells/aspect_aura.dm | 4 +- .../technomancer/spells/aspect_bolt.dm | 4 +- .../gamemodes/technomancer/spells/blink.dm | 7 +- .../gamemodes/technomancer/spells/control.dm | 4 +- .../gamemodes/technomancer/spells/darkness.dm | 7 +- .../technomancer/spells/discharge.dm | 4 +- .../technomancer/spells/flame_tongue.dm | 9 +- .../technomancer/spells/insert/corona.dm | 28 +++ .../technomancer/spells/insert/insert.dm | 25 ++- .../technomancer/spells/insert/mend_burns.dm | 7 +- .../technomancer/spells/insert/mend_wounds.dm | 7 +- .../technomancer/spells/insert/purify.dm | 11 +- .../spells/insert/repel_missiles.dm | 26 +++ .../technomancer/spells/instability_tap.dm | 20 +++ .../technomancer/spells/mark_recall.dm | 83 +++++++++ .../technomancer/spells/oxygenate.dm | 29 ++++ .../gamemodes/technomancer/spells/passwall.dm | 26 +-- .../technomancer/spells/phase_shift.dm | 7 +- .../spells/projectile/chain_lightning.dm | 77 +++++++++ .../spells/projectile/lightning.dm | 40 +++++ .../spells/projectile/projectile.dm | 19 +++ .../gamemodes/technomancer/spells/pulsar.dm | 7 +- .../gamemodes/technomancer/spells/radiance.dm | 7 +- .../gamemodes/technomancer/spells/reflect.dm | 90 ++++++++++ .../technomancer/spells/resurrect.dm | 7 +- .../technomancer/spells/shared_burden.dm | 7 +- .../gamemodes/technomancer/spells/shield.dm | 7 +- .../technomancer/spells/warp_strike.dm | 7 +- code/modules/mob/living/living_defines.dm | 2 + code/modules/mob/mob.dm | 2 +- code/modules/projectiles/effects.dm | 12 ++ code/modules/projectiles/projectile.dm | 2 +- icons/effects/projectiles.dmi | Bin 31111 -> 33088 bytes icons/obj/spells.dmi | Bin 9458 -> 13670 bytes icons/obj/technomancer.dmi | Bin 560 -> 910 bytes polaris.dme | 11 ++ 47 files changed, 802 insertions(+), 290 deletions(-) create mode 100644 code/game/gamemodes/technomancer/spells/aspect/aspect.dm create mode 100644 code/game/gamemodes/technomancer/spells/aspect/aspect_weapon.dm create mode 100644 code/game/gamemodes/technomancer/spells/insert/corona.dm create mode 100644 code/game/gamemodes/technomancer/spells/insert/repel_missiles.dm create mode 100644 code/game/gamemodes/technomancer/spells/instability_tap.dm create mode 100644 code/game/gamemodes/technomancer/spells/mark_recall.dm create mode 100644 code/game/gamemodes/technomancer/spells/oxygenate.dm create mode 100644 code/game/gamemodes/technomancer/spells/projectile/chain_lightning.dm create mode 100644 code/game/gamemodes/technomancer/spells/projectile/lightning.dm create mode 100644 code/game/gamemodes/technomancer/spells/projectile/projectile.dm create mode 100644 code/game/gamemodes/technomancer/spells/reflect.dm diff --git a/code/game/gamemodes/technomancer/assistance/assistance.dm b/code/game/gamemodes/technomancer/assistance/assistance.dm index d46a0d001e..12da7d6c13 100644 --- a/code/game/gamemodes/technomancer/assistance/assistance.dm +++ b/code/game/gamemodes/technomancer/assistance/assistance.dm @@ -1,7 +1,7 @@ -/datum/technomancer_equipment/assistance/ +/datum/technomancer/assistance var/one_use_only = 0 -/datum/technomancer_equipment/assistance/apprentice +/datum/technomancer/assistance/apprentice name = "Friendly Apprentice" desc = "A one-time use teleporter that sends a less powerful manipulator of space to you, who will do their best to protect \ and serve you. They get their own catalog and can buy spells for themselves, however they have a smaller pool to buy with. \ @@ -10,7 +10,7 @@ cost = 300 obj_path = null //TODO -/datum/technomancer_equipment/assistance/golem +/datum/technomancer/assistance/golem name = "Friendly GOLEM unit" desc = "Teleports a specially designed synthetic unit to you, which is very durable, has an advanced AI, and can also use \ functions. It knows Shield, Targeted Blink, Beam, Flame Tongue, Mend Wounds, and Mend Burns. It also has a large storage \ @@ -19,7 +19,7 @@ obj_path = null //TODO one_use_only = 1 -/datum/technomancer_equipment/assistance/ninja +/datum/technomancer/assistance/ninja name = "Neutral Cyberassassin" desc = "Someone almost as enigmatic as you will also arrive at your destination, with their own goals and motivations. \ This could prove to be a problem if they decide to go against you, so this is only recommended as a challenge." diff --git a/code/game/gamemodes/technomancer/assistance/golem.dm b/code/game/gamemodes/technomancer/assistance/golem.dm index eb90636a47..8bb6ef2ea0 100644 --- a/code/game/gamemodes/technomancer/assistance/golem.dm +++ b/code/game/gamemodes/technomancer/assistance/golem.dm @@ -2,6 +2,8 @@ /mob/living/simple_animal/hostile/technomancer_golem name = "G.O.L.E.M." desc = "A rather unusual looking synthetic." + icon = 'icons/mob/robots.dmi' + icon_state = "Security" health = 250 maxHealth = 250 stop_automated_movement = 1 @@ -34,27 +36,37 @@ var/obj/item/weapon/technomancer_core/core = null var/obj/item/weapon/spell/active_spell = null - var/mob/living/owner = null + var/mob/living/master = null -/mob/living/simple_animal/technomancer_golem/New() +/mob/living/simple_animal/hostile/technomancer_golem/New() ..() core = new core(src) -/mob/living/simple_animal/technomancer_golem/Destroy() +/mob/living/simple_animal/hostile/technomancer_golem/Destroy() qdel(core) ..() -/mob/living/simple_animal/technomancer_golem/proc/bind_to_mob(mob/user) - if(!user || owner) +/mob/living/simple_animal/hostile/technomancer_golem/proc/bind_to_mob(mob/user) + if(!user || master) return - owner = user - name = "[owner]'s [initial(name)]" + master = user + name = "[master]'s [initial(name)]" -/mob/living/simple_animal/technomancer_golem/examine(mob/user) +/mob/living/simple_animal/hostile/technomancer_golem/examine(mob/user) ..() if(user.mind && technomancers.is_antagonist(user.mind)) user << "Your pride and joy. It's a very special synthetic robot, capable of using functions similar to you, and you built it \ yourself! It'll always stand by your side, ready to help you out. You have no idea what GOLEM stands for, however..." -/mob/living/simple_animal/technomancer_golem/Life() +/mob/living/simple_animal/hostile/technomancer_golem/Life() + handle_ai() + +/mob/living/simple_animal/hostile/technomancer_golem/proc/handle_ai() + if(!master) + return + if(get_dist(src, master) > 6 || src.z != master.z) + recall_to_master() + + +/mob/living/simple_animal/hostile/technomancer_golem/proc/recall_to_master() return \ No newline at end of file diff --git a/code/game/gamemodes/technomancer/catalog.dm b/code/game/gamemodes/technomancer/catalog.dm index 3517929f2f..3abd65080f 100644 --- a/code/game/gamemodes/technomancer/catalog.dm +++ b/code/game/gamemodes/technomancer/catalog.dm @@ -1,14 +1,15 @@ -var/list/all_technomancer_spells = typesof(/datum/power/technomancer) - /datum/power/technomancer -var/list/all_technomancer_equipment = typesof(/datum/technomancer_equipment/equipment) - /datum/technomancer_equipment/equipment -var/list/all_technomancer_consumables = typesof(/datum/technomancer_equipment/consumable) - /datum/technomancer_equipment/consumable -var/list/all_technomancer_assistance = typesof(/datum/technomancer_equipment/assistance) - /datum/technomancer_equipment/assistance -var/list/all_technomancer_presets = typesof(/datum/technomancer_equipment/presets) - /datum/technomancer_equipment/presets +var/list/all_technomancer_spells = typesof(/datum/technomancer/spell) - /datum/technomancer/spell +var/list/all_technomancer_equipment = typesof(/datum/technomancer/equipment) - /datum/technomancer/equipment +var/list/all_technomancer_consumables = typesof(/datum/technomancer/consumable) - /datum/technomancer/consumable +var/list/all_technomancer_assistance = typesof(/datum/technomancer/assistance) - /datum/technomancer/assistance +var/list/all_technomancer_presets = typesof(/datum/technomancer/presets) - /datum/technomancer/presets -/datum/power/technomancer/ - name = "technomancer function" - desc = "If you can see this, something broke." +/datum/technomancer + var/name = "technomancer thing" + var/desc = "If you can see this, something broke." var/cost = 100 var/hidden = 0 + var/obj_path = null /obj/item/weapon/technomancer_catalog name = "catalog" @@ -81,7 +82,8 @@ var/list/all_technomancer_presets = typesof(/datum/technomancer_equipment/preset dat += "Assistance | " dat += "Presets
" dat += "You currently have a budget of [budget]/[max_budget].

" - for(var/datum/power/technomancer/spell in spell_instances) + dat += "Refund Functions

" + for(var/datum/technomancer/spell in spell_instances) if(spell.hidden) continue dat += "[spell.name]
" @@ -90,7 +92,6 @@ var/list/all_technomancer_presets = typesof(/datum/technomancer_equipment/preset dat += "Purchase ([spell.cost])

" else dat += "Cannot afford!

" - dat += "Refund Functions" user << browse(dat, "window=radio") onclose(user, "radio") if(1) //Equipment @@ -102,7 +103,7 @@ var/list/all_technomancer_presets = typesof(/datum/technomancer_equipment/preset dat += "Assistance | " dat += "Presets
" dat += "You currently have a budget of [budget]/[max_budget].

" - for(var/datum/technomancer_equipment/equipment/E in equipment_instances) + for(var/datum/technomancer/equipment/E in equipment_instances) dat += "[E.name]
" dat += "[E.desc]
" if(E.cost <= budget) @@ -120,7 +121,7 @@ var/list/all_technomancer_presets = typesof(/datum/technomancer_equipment/preset dat += "Assistance | " dat += "Presets
" dat += "You currently have a budget of [budget]/[max_budget].

" - for(var/datum/technomancer_equipment/consumable/C in consumable_instances) + for(var/datum/technomancer/consumable/C in consumable_instances) dat += "[C.name]
" dat += "[C.desc]
" if(C.cost <= budget) @@ -138,7 +139,7 @@ var/list/all_technomancer_presets = typesof(/datum/technomancer_equipment/preset dat += "Assistance | " dat += "Presets
" dat += "You currently have a budget of [budget]/[max_budget].

" - for(var/datum/technomancer_equipment/assistance/A in assistance_instances) + for(var/datum/technomancer/assistance/A in assistance_instances) dat += "[A.name]
" dat += "[A.desc]
" if(A.cost <= budget) @@ -156,7 +157,7 @@ var/list/all_technomancer_presets = typesof(/datum/technomancer_equipment/preset dat += "Assistance | " dat += "Presets
" dat += "You currently have a budget of [budget]/[max_budget].

" - for(var/datum/technomancer_equipment/presets/P in preset_instances) + for(var/datum/technomancer/presets/P in preset_instances) dat += "[P.name]
" dat += "[P.desc]
" if(P.cost <= budget) @@ -184,17 +185,41 @@ var/list/all_technomancer_presets = typesof(/datum/technomancer_equipment/preset if(href_list["tab_choice"]) tab = text2num(href_list["tab_choice"]) if(href_list["spell_choice"]) - var/datum/power/technomancer/new_spell = null + var/datum/technomancer/new_spell = null //Locate the spell. - for(var/datum/power/technomancer/spell in spell_instances) + for(var/datum/technomancer/spell/spell in spell_instances) if(spell.name == href_list["spell_choice"]) new_spell = spell break - if(new_spell) + + var/obj/item/weapon/technomancer_core/core = null + if(istype(H.back, /obj/item/weapon/technomancer_core)) + core = H.back + + if(new_spell && core) if(new_spell.cost <= budget) - budget -= new_spell.cost - H << "You have just bought [new_spell.name]." - else + if(!core.has_spell(new_spell)) + budget -= new_spell.cost + H << "You have just bought [new_spell.name]." + core.add_spell(new_spell.obj_path, new_spell.name) + else //We already own it. + H << "You already have [new_spell.name]!" + return + else //Can't afford. H << "You can't afford that!" return + + if(href_list["refund_functions"]) + if(H.z != 2) + H << "You can only refund at your base, it's too late now!" + return + var/obj/item/weapon/technomancer_core/core = null + if(istype(H.back, /obj/item/weapon/technomancer_core)) + core = H.back + for(var/obj/spellbutton/spell in core.spells) + for(var/datum/technomancer/spell/spell_datum in spell_instances) + if(spell_datum.obj_path == spell.spellpath && !spell.was_bought_by_preset) + budget += spell_datum.cost + core.remove_spell(spell) + break attack_self(H) \ No newline at end of file diff --git a/code/game/gamemodes/technomancer/core_obj.dm b/code/game/gamemodes/technomancer/core_obj.dm index bb2400cb0b..2cce8fd41b 100644 --- a/code/game/gamemodes/technomancer/core_obj.dm +++ b/code/game/gamemodes/technomancer/core_obj.dm @@ -16,6 +16,7 @@ var/max_energy = 10000 var/regen_rate = 50 //200 seconds to full var/mob/living/wearer = null + var/list/spells = list() /obj/item/weapon/technomancer_core/New() ..() @@ -39,6 +40,10 @@ return 1 return 0 +/obj/item/weapon/technomancer_core/proc/give_energy(amount) + energy = max(energy + amount, max_energy) + return 1 + /obj/item/weapon/technomancer_core/process() regenerate() @@ -48,6 +53,66 @@ var/mob/living/carbon/human/H = wearer H.wiz_energy_update_hud() +/obj/spellbutton + name = "generic spellbutton" + var/spellpath = null + var/was_bought_by_preset = 0 + +/obj/spellbutton/New(loc, var/path, var/new_name) + if(!path || !ispath(path)) + message_admins("ERROR: /obj/spellbutton/New() was not given a proper path!") + qdel(src) + src.name = new_name + src.spellpath = path + src.loc = loc + +/obj/spellbutton/Click() + if(ishuman(usr)) + var/mob/living/carbon/human/H = usr + H.place_spell_in_hand(spellpath) + +/obj/spellbutton/DblClick() + return Click() + +/mob/living/carbon/human/Stat() + . = ..() + + if(. && istype(back,/obj/item/weapon/technomancer_core)) + var/obj/item/weapon/technomancer_core/core = back + setup_technomancer_stat(core) + +/mob/living/carbon/human/proc/setup_technomancer_stat(var/obj/item/weapon/technomancer_core/core) + if(core && statpanel("Spell Core")) + var/charge_status = "[core.energy]/[core.max_energy] ([round( (core.energy / core.max_energy) * 100)]%)" + var/instability_status = "[src.instability]" + stat("Core charge", charge_status) + stat("User instability", instability_status) + for(var/obj/spellbutton/button in core.spells) + stat(button) + +/obj/item/weapon/technomancer_core/proc/add_spell(var/path, var/new_name) + if(!path || !ispath(path)) + message_admins("/obj/item/weapon/technomancer_core/add_spell() was not given a proper path! The path supplied was [path].") + return + var/obj/spellbutton/spell = new(src, path, new_name) + spells.Add(spell) + +/obj/item/weapon/technomancer_core/proc/remove_spell(var/obj/spellbutton/spell_to_remove) + if(spell_to_remove in spells) + spells.Remove(spell_to_remove) + qdel(spell_to_remove) + +/obj/item/weapon/technomancer_core/proc/remove_all_spells() + for(var/obj/spellbutton/spell in spells) + spells.Remove(spell) + qdel(spell) + +/obj/item/weapon/technomancer_core/proc/has_spell(var/datum/technomancer/spell_to_check) + for(var/obj/spellbutton/spell in spells) + if(spell.spellpath == spell_to_check.obj_path) + return 1 + return 0 + /mob var/obj/screen/wizard/energy/wiz_energy_display = null //Unfortunately, this needs to be a mob var due to HUD code. @@ -88,7 +153,7 @@ if(loc && ishuman(loc)) var/mob/living/carbon/human/H = loc instability_bonus = H.instability * 1.5 - energy += min(energy + regen_rate + instability_bonus, max_energy) + energy = min(energy + regen_rate + instability_bonus, max_energy) if(loc && ishuman(loc)) var/mob/living/carbon/human/H = loc H.wiz_energy_update_hud() diff --git a/code/game/gamemodes/technomancer/devices/disposable_teleporter.dm b/code/game/gamemodes/technomancer/devices/disposable_teleporter.dm index aeb7a6b93b..063e642c42 100644 --- a/code/game/gamemodes/technomancer/devices/disposable_teleporter.dm +++ b/code/game/gamemodes/technomancer/devices/disposable_teleporter.dm @@ -1,4 +1,4 @@ -/datum/technomancer_equipment/consumable/disposable_teleporter +/datum/technomancer/consumable/disposable_teleporter name = "Disposable Teleporter" desc = "An ultra-safe teleportation device that can directly teleport you to a number of locations at minimal risk, however \ it has a limited amount of charges." diff --git a/code/game/gamemodes/technomancer/equipment.dm b/code/game/gamemodes/technomancer/equipment.dm index 6ada16d6c7..8c988f1acb 100644 --- a/code/game/gamemodes/technomancer/equipment.dm +++ b/code/game/gamemodes/technomancer/equipment.dm @@ -1,11 +1,11 @@ -/datum/technomancer_equipment/equipment/classic_core +/datum/technomancer.equipment/classic_core name = "Classic Core" desc = "A core cleverly disguised as an ordinary cloth cape, perfect for those wanting to make others think they are a \ real magician. This version has the same performance as the default core." cost = 100 obj_path = /obj/item/weapon/technomancer_core/classic -/datum/technomancer_equipment/equipment/default_core +/datum/technomancer/equipment/default_core name = "Manipulation Core" desc = "The default core that you most likely already have. This is here in-case you change your mind after buying \ another core, don't forget to refund the old core. This has a capacity of 10,000 units of energy, and recharges at a \ @@ -13,14 +13,14 @@ cost = 100 obj_path = /obj/item/weapon/technomancer_core -/datum/technomancer_equipment/equipment/rapid_core +/datum/technomancer/equipment/rapid_core name = "Rapid Core" desc = "A core optimized for passive regeneration, however at the cost of capacity. Has a capacity of 7,000 units of energy, and \ recharges at a rate of 70 units." cost = 150 obj_path = /obj/item/weapon/technomancer_core/rapid -/datum/technomancer_equipment/equipment/bulky_core +/datum/technomancer/equipment/bulky_core name = "Bulky Core" desc = "This core has very large capacitors, however it also has a subpar fractal reactor. The user is recommended to \ purchase one or more energy-generating Functions as well if using this core. Has a capacity of 20,000 units of energy, \ @@ -28,7 +28,7 @@ cost = 150 obj_path = /obj/item/weapon/technomancer_core/bulky -/datum/technomancer_equipment/equipment/unstable +/datum/technomancer/equipment/unstable name = "Unstable Core" desc = "This core feeds off unstable energies around the user in addition to a fractal reactor. This means that it performs \ better as the user has more instability, which could prove dangerous to the inexperienced or unprepared. Has a capacity of 13,000 \ @@ -37,7 +37,7 @@ cost = 150 obj_path = /obj/item/weapon/technomancer_core/unstable -/datum/technomancer_equipment/equipment/hypo_belt +/datum/technomancer/equipment/hypo_belt name = "Hypo Belt" desc = "A medical belt designed to carry autoinjectors and other medical equipment. Comes with one of each hypo." cost = 100 @@ -58,7 +58,7 @@ new /obj/item/weapon/reagent_containers/hypospray/autoinjector/biginjector/combat(src) ..() -/datum/technomancer_equipment/equipment/thermals +/datum/technomancer/equipment/thermals name = "Thermoncle" desc = "A fancy monocle with a thermal optics lens installed. Allows you to see people across walls." cost = 150 diff --git a/code/game/gamemodes/technomancer/presets.dm b/code/game/gamemodes/technomancer/presets.dm index 9bc29e141d..1752490cb5 100644 --- a/code/game/gamemodes/technomancer/presets.dm +++ b/code/game/gamemodes/technomancer/presets.dm @@ -1,10 +1,10 @@ -/datum/technomancer_equipment/presets +/datum/technomancer/presets name = "Preset Template" desc = "If you see me, I'm broken." obj_path = null var/list/bundled = list() -/datum/technomancer_equipment/presets/summoner +/datum/technomancer/presets/summoner name = "Summoner" desc = "This preset includes a few functions to teleport creatures to you, if you can't find any when you leave, as well as \ the Control function, to command said creatures. It also includes Aspect Aura and Mend Wounds to allow for an area of effect \ @@ -12,14 +12,21 @@ over your creatures." cost = 600 -/datum/technomancer_equipment/presets/healer +/datum/technomancer/presets/healer name = "Healer" desc = "This preset is recommended for apprentices who wish to support their master. It contains many healing and support \ functions, such as Mend Wounds, Mend Burns, Purify, Oxygenate, Aspect Aura, Shared Burden, Link, Resurrect, and Great Mend Wounds. \ Be aware that a lot of these functions create a lot of instability, so prepare for that if you can." cost = 600 -/datum/technomancer_equipment/presets/rainbow +/datum/technomancer/presets/support + name = "Support" + desc = "This preset is recommended for apprentices who wish to support their master. It contains many functions focused on \ + augmenting you and your master's survival and capabilities, with functions such as Repel Missiles, Aspect Aura, Shared Burden, \ + ." + cost = 600 + +/datum/technomancer/presets/rainbow name = "Rainbow Mage" desc = "This preset includes many Aspect functions, such as Aspect Aura, Aspect Bolt, Aspect Cloud, Aspect Weapon, etc, as well as \ cheap functions beloning to each aspect, for the purposes of combining with an aspect function. This allows you to be \ diff --git a/code/game/gamemodes/technomancer/spell_objs.dm b/code/game/gamemodes/technomancer/spell_objs.dm index f985f66e11..a7f8125d75 100644 --- a/code/game/gamemodes/technomancer/spell_objs.dm +++ b/code/game/gamemodes/technomancer/spell_objs.dm @@ -20,7 +20,6 @@ #define ASPECT_UNSTABLE "unstable" //Heavily RNG-based, causes instability to the victim. #define ASPECT_CHROMATIC "chromatic" //Used to combine with other spells. - /obj/item/weapon/spell name = "glowing particles" desc = "Your hands appear to be glowing brightly." @@ -38,6 +37,7 @@ var/cast_methods = null var/aspect = null var/toggled = 0 //Mainly used for overlays + var/cooldown = 0 //If set, will add a cooldown overlay and adjust click delay. Must be a multiple of 5 for overlays. /obj/item/weapon/spell/proc/on_use_cast(mob/user) return @@ -54,6 +54,9 @@ /obj/item/weapon/spell/proc/on_combine_cast(obj/item/W, mob/user) return +/obj/item/weapon/spell/proc/on_innate_cast(mob/user) + return + //TODO /obj/item/weapon/spell/proc/pay_energy(var/amount) if(!core) @@ -146,162 +149,37 @@ else if(cast_methods & CAST_RANGED) //Try to use a ranged method if a melee one doesn't exist. on_ranged_cast(target, user) world << "range cast called" + if(cooldown) + user.setClickCooldown(cooldown) + flick("cooldown_[cooldown]",src) -/obj/spellbutton - name = "generic spellbutton" - var/spellpath = null +/mob/living/proc/place_spell_in_hand(var/path) + return -//debug test verbs, kill Neerti if this makes it live. -/mob/verb/apportation() - set category = "Functions" - set name = "Apportation()" - set src = usr - if(!ishuman(src)) - return 0 - - var/mob/living/carbon/human/H = src - - H.place_spell_in_hand(/obj/item/weapon/spell/apportation) - -/mob/verb/blink() - set category = "Functions" - set name = "Blink()" - set src = usr - if(!ishuman(src)) - return 0 - - var/mob/living/carbon/human/H = src - - H.place_spell_in_hand(/obj/item/weapon/spell/blink) - -/mob/verb/darkness() - set category = "Functions" - set name = "Darkness()" - set src = usr - if(!ishuman(src)) - return 0 - - var/mob/living/carbon/human/H = src - - H.place_spell_in_hand(/obj/item/weapon/spell/darkness) - -/mob/verb/radiance() - set category = "Functions" - set name = "Radiance()" - set src = usr - if(!ishuman(src)) - return 0 - - var/mob/living/carbon/human/H = src - - H.place_spell_in_hand(/obj/item/weapon/spell/radiance) - -/mob/verb/purify() - set category = "Functions" - set name = "Purify()" - set src = usr - if(!ishuman(src)) - return 0 - - var/mob/living/carbon/human/H = src - - H.place_spell_in_hand(/obj/item/weapon/spell/insert/purify) - -/mob/verb/disable_technology() - set category = "Functions" - set name = "Disable_Technology()" - set src = usr - if(!ishuman(src)) - return 0 - - var/mob/living/carbon/human/H = src - - H.place_spell_in_hand(/obj/item/weapon/spell/pulsar) - -/mob/verb/passwall() - set category = "Functions" - set name = "Passwall()" - set src = usr - if(!ishuman(src)) - return 0 - - var/mob/living/carbon/human/H = src - - H.place_spell_in_hand(/obj/item/weapon/spell/passwall) - -/mob/verb/phase_shift() - set category = "Functions" - set name = "Phase_Shift()" - set src = usr - if(!ishuman(src)) - return 0 - - var/mob/living/carbon/human/H = src - - H.place_spell_in_hand(/obj/item/weapon/spell/phase_shift) - -/mob/verb/warp_strike() - set category = "Functions" - set name = "Warp_Strike()" - set src = usr - if(!ishuman(src)) - return 0 - - var/mob/living/carbon/human/H = src - - H.place_spell_in_hand(/obj/item/weapon/spell/warp_strike) - -/mob/verb/discharge() - set category = "Functions" - set name = "Discharge()" - set src = usr - if(!ishuman(src)) - return 0 - - var/mob/living/carbon/human/H = src - - H.place_spell_in_hand(/obj/item/weapon/spell/discharge) - -/mob/verb/aspect_aura() - set category = "Functions" - set name = "Aspect Aura()" - set src = usr - if(!ishuman(src)) - return 0 - - var/mob/living/carbon/human/H = src - - H.place_spell_in_hand(/obj/item/weapon/spell/aspect_aura) - -/mob/verb/control() - set category = "Functions" - set name = "Control()" - set src = usr - if(!ishuman(src)) - return 0 - - var/mob/living/carbon/human/H = src - - H.place_spell_in_hand(/obj/item/weapon/spell/control) - -/mob/living/carbon/human/proc/place_spell_in_hand(var/path) +/mob/living/carbon/human/place_spell_in_hand(var/path) if(!path || !ispath(path)) return 0 + + var/obj/item/weapon/spell/S = PoolOrNew(path, src) + + //No hands needed for innate casts. + if(S.cast_methods & CAST_INNATE) + if(S.run_checks()) + S.on_innate_cast(src) + if(l_hand && r_hand) //Make sure our hands aren't full. if(istype(r_hand, /obj/item/weapon/spell)) //If they are full, perhaps we can still be useful. var/obj/item/weapon/spell/r_spell = r_hand if(r_spell.aspect == ASPECT_CHROMATIC) //Check if we can combine the new spell with one in our hands. - var/obj/item/weapon/spell/S = PoolOrNew(path, src) r_spell.on_combine_cast(S, src) else if(istype(l_hand, /obj/item/weapon/spell)) var/obj/item/weapon/spell/l_spell = l_hand if(l_spell.aspect == ASPECT_CHROMATIC) //Check the other hand too. - var/obj/item/weapon/spell/S = PoolOrNew(path, src) l_spell.on_combine_cast(S, src) else //Welp src << "You require a free hand to use this function." return 0 - var/obj/item/weapon/spell/S = PoolOrNew(path, src) + if(S.run_checks()) put_in_hands(S) return 1 diff --git a/code/game/gamemodes/technomancer/spells/apportation.dm b/code/game/gamemodes/technomancer/spells/apportation.dm index 1c7d1da230..e4aaf1c969 100644 --- a/code/game/gamemodes/technomancer/spells/apportation.dm +++ b/code/game/gamemodes/technomancer/spells/apportation.dm @@ -1,12 +1,9 @@ -/datum/power/technomancer/apportation +/datum/technomancer/spell/apportation name = "Apportation" desc = "This allows you to teleport objects into your hand, or to pull people towards you. If they're close enough, the function \ will grab them automatically." cost = 50 - verbpath = /mob/living/carbon/human/proc/technomancer_apportation - -/mob/living/carbon/human/proc/technomancer_apportation() - place_spell_in_hand(/obj/item/weapon/spell/apportation) + obj_path = /obj/item/weapon/spell/apportation /obj/item/weapon/spell/apportation name = "apportation" @@ -34,8 +31,6 @@ s2.set_up(2, 1, I) s1.start() s2.start() -// new /obj/effect/effect/sparks(get_turf(I)) -// new /obj/effect/effect/sparks(get_turf(user)) I.visible_message("\The [I] vanishes into thin air!") I.forceMove(get_turf(user)) user.drop_item(src) @@ -53,8 +48,6 @@ s2.set_up(2, 1, L) s1.start() s2.start() -// new /obj/effect/effect/sparks(get_turf(L)) -// new /obj/effect/effect/sparks(get_turf(user)) L.throw_at(get_step(get_turf(src),get_turf(L)), 4, 1, src) user.drop_item(src) src.loc = null diff --git a/code/game/gamemodes/technomancer/spells/aspect/aspect.dm b/code/game/gamemodes/technomancer/spells/aspect/aspect.dm new file mode 100644 index 0000000000..dd2d2cce5f --- /dev/null +++ b/code/game/gamemodes/technomancer/spells/aspect/aspect.dm @@ -0,0 +1,46 @@ +/obj/item/weapon/spell/aspect + name = "aspect template" + desc = "Combine this with another spell to finish the function." + cast_methods = CAST_COMBINE + aspect = ASPECT_CHROMATIC + var/fire_result = null + var/frost_result = null + var/shock_result = null + var/air_result = null + var/force_result = null + var/tele_result = null + var/biomed_result = null + var/dark_result = null + var/light_result = null + var/unstable_result = null + +/obj/item/weapon/spell/aspect/on_combine_cast(obj/item/W, mob/user) + if(istype(W, /obj/item/weapon/spell)) + var/obj/item/weapon/spell/spell = W + if(!spell.aspect || spell.aspect == ASPECT_CHROMATIC) + user << "You cannot combine \the [spell] with \the [src], as the aspects are incompatable." + return + user.drop_item(src) + src.loc = null + switch(spell.aspect) + if(ASPECT_FIRE) + user.put_in_hands(fire_result) + if(ASPECT_FROST) + user.put_in_hands(frost_result) + if(ASPECT_SHOCK) + user.put_in_hands(shock_result) + if(ASPECT_AIR) + user.put_in_hands(air_result) + if(ASPECT_FORCE) + user.put_in_hands(force_result) + if(ASPECT_TELE) + user.put_in_hands(tele_result) + if(ASPECT_BIOMED) + user.put_in_hands(biomed_result) + if(ASPECT_DARK) + user.put_in_hands(dark_result) + if(ASPECT_LIGHT) + user.put_in_hands(light_result) + if(ASPECT_UNSTABLE) + user.put_in_hands(unstable_result) + qdel(src) \ No newline at end of file diff --git a/code/game/gamemodes/technomancer/spells/aspect/aspect_weapon.dm b/code/game/gamemodes/technomancer/spells/aspect/aspect_weapon.dm new file mode 100644 index 0000000000..3efc5c1f05 --- /dev/null +++ b/code/game/gamemodes/technomancer/spells/aspect/aspect_weapon.dm @@ -0,0 +1,69 @@ +/datum/technomancer/spell/aspect_weapon + name = "Aspect Weapon" + desc = "This bolt function takes on the properties of other functions based on which aspect is introduced to it, making a temporary \ + weapon that has the properties of the aspect introduced to it." + cost = 200 + obj_path = /obj/item/weapon/spell/aspect/weapon + +/obj/item/weapon/spell/aspect/weapon + name = "aspect weapon" + desc = "Combine this with another spell to finish the function." + fire_result = null + frost_result = null + shock_result = null + air_result = null + force_result = null + tele_result = null + biomed_result = null + dark_result = null + light_result = null + unstable_result = /obj/item/weapon/conjured/unstable_blade + +/obj/item/weapon/conjured + anchored = 1 + throwforce = 0 + throw_range = 0 + throw_speed = 0 + var/mob/living/carbon/human/user = null + +/obj/item/weapon/conjured/New(location) + ..() + if(ishuman(loc)) + user = loc + +/obj/item/weapon/conjured/Destroy(location) + user = null + ..() + +/obj/item/weapon/conjured/dropped() + qdel(src) + +/obj/item/weapon/conjured/unstable_blade + name = "unstable blade" + desc = "This thing seems to warp before your eyes. Perhaps this can enable you to land stronger hits, if you feel lucky." + force = 20 + sharp = 1 + edge = 1 + attack_verb = list("attacked", "slashed", "stabbed", "sliced", "torn", "ripped", "diced", "cut") + +/obj/item/weapon/conjured/unstable_blade/New(location) + ..() + processing_objects |= src + +/obj/item/weapon/conjured/unstable_blade/Destroy() + processing_objects -= src + ..() + +/obj/item/weapon/conjured/unstable_blade/process() + if(user) + user.adjust_instability(1) + + +//The only weapon in SS13 with the ability for 'critical hits', to tie in with the theme for randomness for the Unstable aspect. +/obj/item/weapon/conjured/unstable_blade/afterattack(atom/target, var/mob/living/carbon/human/user, proximity_flag, click_parameters) + if(prob(20) && proximity_flag) + visible_message("\The [user] lands a devastating blow on \the [target]!") + force = force * 2 + attack(target, user) + force = initial(force) + user.adjust_instability(2) diff --git a/code/game/gamemodes/technomancer/spells/aspect_aura.dm b/code/game/gamemodes/technomancer/spells/aspect_aura.dm index a613d1bf29..0315ee3465 100644 --- a/code/game/gamemodes/technomancer/spells/aspect_aura.dm +++ b/code/game/gamemodes/technomancer/spells/aspect_aura.dm @@ -1,9 +1,9 @@ -/datum/power/technomancer/aspect_aura +/datum/technomancer/spell/aspect_aura name = "Aspect Aura" desc = "This aura function takes on the properties of other functions based on which aspect is introduced to it, applying \ it to everyone nearby." cost = 200 - verbpath = /mob/living/carbon/human/proc/technomancer_aspect_aura + obj_path = /mob/living/carbon/human/proc/technomancer_aspect_aura /mob/living/carbon/human/proc/technomancer_aspect_aura() place_spell_in_hand(/obj/item/weapon/spell/aspect_aura) diff --git a/code/game/gamemodes/technomancer/spells/aspect_bolt.dm b/code/game/gamemodes/technomancer/spells/aspect_bolt.dm index 11d992a130..19d278297c 100644 --- a/code/game/gamemodes/technomancer/spells/aspect_bolt.dm +++ b/code/game/gamemodes/technomancer/spells/aspect_bolt.dm @@ -1,9 +1,9 @@ -/datum/power/technomancer/aspect_bolt +/datum/technomancer/spell/aspect_bolt name = "Aspect Bolt" desc = "This bolt function takes on the properties of other functions based on which aspect is introduced to it, with the \ delivery method being a projectile." cost = 150 - verbpath = /mob/living/carbon/human/proc/technomancer_aspect_bolt + obj_path = /mob/living/carbon/human/proc/technomancer_aspect_bolt /mob/living/carbon/human/proc/technomancer_aspect_bolt() place_spell_in_hand(/obj/item/weapon/spell/aspect_bolt) diff --git a/code/game/gamemodes/technomancer/spells/blink.dm b/code/game/gamemodes/technomancer/spells/blink.dm index b1896ba262..8e544e9220 100644 --- a/code/game/gamemodes/technomancer/spells/blink.dm +++ b/code/game/gamemodes/technomancer/spells/blink.dm @@ -1,12 +1,9 @@ -/datum/power/technomancer/blink +/datum/technomancer/spell/blink name = "Blink" desc = "Force the target to teleport a short distance away. This target could be anything from something lying on the ground, to someone trying to \ fight you, or even yourself." cost = 100 - verbpath = /mob/living/carbon/human/proc/technomancer_blink - -/mob/living/carbon/human/proc/technomancer_blink() - place_spell_in_hand(/obj/item/weapon/spell/blink) + obj_path = /obj/item/weapon/spell/blink /obj/item/weapon/spell/blink name = "blink" diff --git a/code/game/gamemodes/technomancer/spells/control.dm b/code/game/gamemodes/technomancer/spells/control.dm index 7ee1c8a12a..638f4359d2 100644 --- a/code/game/gamemodes/technomancer/spells/control.dm +++ b/code/game/gamemodes/technomancer/spells/control.dm @@ -1,4 +1,4 @@ -/datum/power/technomancer/control +/datum/technomancer/spell/control name = "Control" desc = "This function allows you to exert control over simple-minded entities to an extent, such as spiders and carp. \ Controlled entities will not be hostile towards you, and you may direct them to move to specific areas or to attack specific \ @@ -6,7 +6,7 @@ not true mind control, but merely pheromone synthesis for living animals, and electronic hacking for simple robots. The green web \ around the entity is merely a hologram used to allow the user to know if the creature is safe or not." cost = 200 - verbpath = /mob/living/carbon/human/proc/technomancer_resurrect + obj_path = /obj/item/weapon/spell/control /mob/living/carbon/human/proc/technomancer_control() place_spell_in_hand(/obj/item/weapon/spell/control) diff --git a/code/game/gamemodes/technomancer/spells/darkness.dm b/code/game/gamemodes/technomancer/spells/darkness.dm index 0b58239e61..a632bc084b 100644 --- a/code/game/gamemodes/technomancer/spells/darkness.dm +++ b/code/game/gamemodes/technomancer/spells/darkness.dm @@ -1,11 +1,8 @@ -/datum/power/technomancer/darkness +/datum/technomancer/spell/darkness name = "Darkness" desc = "Disrupts photons moving in a local area, causing darkness to shroud yourself or a position of your choosing." cost = 30 - verbpath = /mob/living/carbon/human/proc/technomancer_darkness - -/mob/living/carbon/human/proc/technomancer_darkness() - place_spell_in_hand(/obj/item/weapon/spell/darkness) + obj_path = /obj/item/weapon/spell/darkness /obj/item/weapon/spell/darkness name = "darkness" diff --git a/code/game/gamemodes/technomancer/spells/discharge.dm b/code/game/gamemodes/technomancer/spells/discharge.dm index 0aa5c7e40c..638ec34601 100644 --- a/code/game/gamemodes/technomancer/spells/discharge.dm +++ b/code/game/gamemodes/technomancer/spells/discharge.dm @@ -1,8 +1,8 @@ -/datum/power/technomancer/discharge +/datum/technomancer/spell/discharge name = "Discharge" desc = "Attempts to steal energy from your target, electrocuting it and anyone holding it." cost = 70 - verbpath = /mob/living/carbon/human/proc/technomancer_discharge + obj_path = /obj/item/weapon/spell/discharge /mob/living/carbon/human/proc/technomancer_discharge() place_spell_in_hand(/obj/item/weapon/spell/discharge) diff --git a/code/game/gamemodes/technomancer/spells/flame_tongue.dm b/code/game/gamemodes/technomancer/spells/flame_tongue.dm index 6ff4c1545f..e5c22e0e2f 100644 --- a/code/game/gamemodes/technomancer/spells/flame_tongue.dm +++ b/code/game/gamemodes/technomancer/spells/flame_tongue.dm @@ -1,11 +1,8 @@ -/datum/power/technomancer/flame_tongue +/datum/technomancer/spell/flame_tongue name = "Flame Tongue" desc = "Using a miniturized flamethrower in your gloves, you can emit a flame strong enough to melt both your enemies and walls." cost = 100 - verbpath = /mob/living/carbon/human/proc/technomancer_flame_tongue - -/mob/living/carbon/human/proc/technomancer_flame_tongue() - place_spell_in_hand(/obj/item/weapon/spell/flame_tongue) + obj_path = /obj/item/weapon/spell/flame_tongue /obj/item/weapon/spell/flame_tongue name = "flame tongue" @@ -41,7 +38,7 @@ return /obj/item/weapon/spell/flame_tongue/on_melee_cast(atom/hit_atom, mob/living/user, def_zone) - if(isliving(hit_atom)) + if(isliving(hit_atom) && user.a_intent != I_HELP) var/mob/living/L = hit_atom if(pay_energy(1000)) visible_message("\The [user] reaches out towards \the [L] with the flaming hand, and they ignite!") diff --git a/code/game/gamemodes/technomancer/spells/insert/corona.dm b/code/game/gamemodes/technomancer/spells/insert/corona.dm new file mode 100644 index 0000000000..f29164f43a --- /dev/null +++ b/code/game/gamemodes/technomancer/spells/insert/corona.dm @@ -0,0 +1,28 @@ +/datum/technomancer/spell/corona + name = "Corona" + desc = "Causes the victim to glow very brightly, which while harmless in itself, makes it easier for them to be hit. The \ + bright glow also makes it very difficult to be stealthy. The effect lasts for one minute." + cost = 100 + obj_path = /obj/item/weapon/spell/insert/corona + +/obj/item/weapon/spell/insert/corona + name = "corona" + desc = "How brillient!" + icon_state = "radiance" + cast_methods = CAST_RANGED + aspect = ASPECT_LIGHT + light_color = "#D9D900" + spell_light_intensity = 5 + spell_light_range = 3 + inserting = /obj/item/weapon/inserted_spell/corona + +/obj/item/weapon/inserted_spell/corona/on_insert() + spawn(1) + if(isliving(host)) + var/mob/living/L = host + L.evasion -= 2 + L.visible_message("You start to glow very brightly!") + spawn(1 MINUTE) + L.evasion += 2 + L << "Your glow has ended." + qdel(src) \ No newline at end of file diff --git a/code/game/gamemodes/technomancer/spells/insert/insert.dm b/code/game/gamemodes/technomancer/spells/insert/insert.dm index cc1e872aef..d7500e1aeb 100644 --- a/code/game/gamemodes/technomancer/spells/insert/insert.dm +++ b/code/game/gamemodes/technomancer/spells/insert/insert.dm @@ -1,25 +1,32 @@ +//Template for spells which put something inside someone else, good for buffs/debuffs, damage over times and heals over time. + /obj/item/weapon/spell/insert name = "insert template" desc = "Tell a coder if you can read this in-game." icon_state = "purify" cast_methods = CAST_MELEE var/spell_color = "#03A728" + var/spell_light_intensity = 2 + var/spell_light_range = 3 var/obj/item/weapon/inserted_spell/inserting = null + var/allow_stacking = 0 /obj/item/weapon/spell/insert/New() ..() - set_light(3, 2, l_color = light_color) + set_light(spell_light_range, spell_light_intensity, l_color = light_color) /obj/item/weapon/inserted_spell var/mob/living/carbon/human/origin = null var/mob/living/host = null -/obj/item/weapon/inserted_spell/New(var/newloc, var/user, var/spell_color) +/obj/item/weapon/inserted_spell/New(var/newloc, var/user, var/obj/item/weapon/spell/insert/inserter) ..(newloc) host = newloc origin = user if(light_color) - set_light(3, 2, l_color = spell_color) + spawn(1) + world << "Woo!" + set_light(inserter.spell_light_range, inserter.spell_light_intensity, inserter.spell_color) on_insert() /obj/item/weapon/inserted_spell/proc/on_insert() @@ -28,10 +35,20 @@ /obj/item/weapon/spell/insert/proc/insert(var/mob/living/L, mob/user) world << "insert() called" if(inserting) - new inserting(L,user,light_color) + if(!allow_stacking) + for(var/obj/item/weapon/inserted_spell/IS in L.contents) + if(IS.type == inserting) + user << "\The [L] is already affected by \the [src]." + return + new inserting(L,user,src) qdel(src) /obj/item/weapon/spell/insert/on_melee_cast(atom/hit_atom, mob/user) + if(istype(hit_atom, /mob/living)) + var/mob/living/L = hit_atom + insert(L,user) + +/obj/item/weapon/spell/insert/on_ranged_cast(atom/hit_atom, mob/user) if(istype(hit_atom, /mob/living)) var/mob/living/L = hit_atom insert(L,user) \ No newline at end of file diff --git a/code/game/gamemodes/technomancer/spells/insert/mend_burns.dm b/code/game/gamemodes/technomancer/spells/insert/mend_burns.dm index 081f83461c..9b45c1be44 100644 --- a/code/game/gamemodes/technomancer/spells/insert/mend_burns.dm +++ b/code/game/gamemodes/technomancer/spells/insert/mend_burns.dm @@ -1,11 +1,8 @@ -/datum/power/technomancer/mend_burns +/datum/technomancer/spell/mend_burns name = "Mend Burns" desc = "Heals minor burns, such as from exposure to flame, electric shock, or lasers." cost = 120 - verbpath = /mob/living/carbon/human/proc/technomancer_mend_wounds - -/mob/living/carbon/human/proc/technomancer_mend_burns() - place_spell_in_hand(/obj/item/weapon/spell/insert/mend_wounds) + obj_path = /obj/item/weapon/spell/insert/mend_burns /obj/item/weapon/spell/insert/mend_burns name = "mend burns" diff --git a/code/game/gamemodes/technomancer/spells/insert/mend_wounds.dm b/code/game/gamemodes/technomancer/spells/insert/mend_wounds.dm index 79e685d02d..c684a2361f 100644 --- a/code/game/gamemodes/technomancer/spells/insert/mend_wounds.dm +++ b/code/game/gamemodes/technomancer/spells/insert/mend_wounds.dm @@ -1,11 +1,8 @@ -/datum/power/technomancer/mend_wounds +/datum/technomancer/spell/mend_wounds name = "Mend Wounds" desc = "Heals minor wounds, such as cuts, bruises, and other non-lifethreatening injuries." cost = 120 - verbpath = /mob/living/carbon/human/proc/technomancer_mend_wounds - -/mob/living/carbon/human/proc/technomancer_mend_wounds() - place_spell_in_hand(/obj/item/weapon/spell/insert/mend_wounds) + obj_path = /obj/item/weapon/spell/insert/mend_wounds /obj/item/weapon/spell/insert/mend_wounds name = "mend wounds" diff --git a/code/game/gamemodes/technomancer/spells/insert/purify.dm b/code/game/gamemodes/technomancer/spells/insert/purify.dm index 32cbd57a32..61078d84b8 100644 --- a/code/game/gamemodes/technomancer/spells/insert/purify.dm +++ b/code/game/gamemodes/technomancer/spells/insert/purify.dm @@ -1,11 +1,8 @@ -/datum/power/technomancer/purify +/datum/technomancer/spell/purify name = "Purify" desc = "Clenses the body of harmful impurities, such as toxins, radiation, viruses, and such." cost = 100 - verbpath = /mob/living/carbon/human/proc/technomancer_purify - -/mob/living/carbon/human/proc/technomancer_purify() - place_spell_in_hand(/obj/item/weapon/spell/insert/purify) + obj_path = /obj/item/weapon/spell/insert/purify /obj/item/weapon/spell/insert/purify name = "purify" @@ -22,8 +19,8 @@ var/mob/living/carbon/human/H = host H.sdisabilities = 0 H.disabilities = 0 - for(var/datum/disease/D in H.viruses) - D.cure() +// for(var/datum/disease/D in H.viruses) +// D.cure() for(var/i = 0, i<25,i++) if(H) H.adjustToxLoss(-1) diff --git a/code/game/gamemodes/technomancer/spells/insert/repel_missiles.dm b/code/game/gamemodes/technomancer/spells/insert/repel_missiles.dm new file mode 100644 index 0000000000..ecda82462f --- /dev/null +++ b/code/game/gamemodes/technomancer/spells/insert/repel_missiles.dm @@ -0,0 +1,26 @@ +/datum/technomancer/spell/repel_missiles + name = "Repel Missiles" + desc = "Places a repulsion field around you, which attempts to deflect incoming bullets and lasers, making them 30% less likely \ + to hit you. The field lasts for two minutes and can be granted to yourself or an ally." + cost = 60 + obj_path = /obj/item/weapon/spell/insert/repel_missiles + +/obj/item/weapon/spell/insert/repel_missiles + name = "repel missiles" + desc = "Use it before they start shooting at you!" + icon_state = "generic" + cast_methods = CAST_RANGED + aspect = ASPECT_FORCE + light_color = "#FF5C5C" + inserting = /obj/item/weapon/inserted_spell/repel_missiles + +/obj/item/weapon/inserted_spell/repel_missiles/on_insert() + spawn(1) + if(isliving(host)) + var/mob/living/L = host + L.evasion += 2 + L << "You have a repulsion field around you, which will attempt to deflect projectiles." + spawn(2 MINUTES) + L.evasion -= 2 + L << "Your repulsion field has expired." + qdel(src) \ No newline at end of file diff --git a/code/game/gamemodes/technomancer/spells/instability_tap.dm b/code/game/gamemodes/technomancer/spells/instability_tap.dm new file mode 100644 index 0000000000..c28f8c4583 --- /dev/null +++ b/code/game/gamemodes/technomancer/spells/instability_tap.dm @@ -0,0 +1,20 @@ +/datum/technomancer/spell/instability_tap + name = "Instability Tap" + desc = "Creates a large sum of energy, at the cost of a very large amount of instability afflicting you." + cost = 120 + obj_path = /obj/item/weapon/spell/instability_tap + +/obj/item/weapon/spell/instability_tap + name = "instability tap" + desc = "Short term gain for long term consequences never end bad, right?" + cast_methods = CAST_USE + aspect = ASPECT_UNSTABLE + +/obj/item/weapon/spell/instability_tap/New() + ..() + set_light(3, 2, l_color = "#FA58F4") + +/obj/item/weapon/spell/instability_tap/on_use_cast(mob/user) + core.give_energy(5000) + owner.adjust_instability(50) + qdel(src) \ No newline at end of file diff --git a/code/game/gamemodes/technomancer/spells/mark_recall.dm b/code/game/gamemodes/technomancer/spells/mark_recall.dm new file mode 100644 index 0000000000..468bf45608 --- /dev/null +++ b/code/game/gamemodes/technomancer/spells/mark_recall.dm @@ -0,0 +1,83 @@ +/datum/technomancer/spell/mark + name = "Mark" + desc = "This function places a specific 'mark' beacon under you, which is used by the Recall function as a destination. \ + Note that using Mark again will move the destination instead of creating a second destination, and only one destination \ + can exist, regardless of who casted Mark." + cost = 50 + obj_path = /obj/item/weapon/spell/mark + +//The object to teleport to when Recall is used. +/obj/effect/mark_spell + name = "mark" + desc = "This is a strange looking disturbance." + opacity = 0 + density = 0 + anchored = 1 + +//This is global, to avoid looping through a list of all objects, or god forbid, looping through world. +/var/global/obj/effect/mark_spell/mark_spell_ref = null + +/obj/item/weapon/spell/mark + name = "mark" + icon_state = "mark" + desc = "Marks a specific location to be used by Recall." + cast_methods = CAST_USE + aspect = ASPECT_TELE + +/obj/item/weapon/spell/mark/on_use_cast(mob/living/user) + if(pay_energy(1000)) + if(!mark_spell_ref) + mark_spell_ref = new(get_turf(user)) + user << "You mark \the [get_turf(user)] under you." + else + mark_spell_ref.forceMove(get_turf(user)) + user << "Your mark is moved from its old position to \the [get_turf(user)] under you." + owner.adjust_instability(5) + return 1 + else + user << "You can't afford the energy cost!" + return 0 + +//Recall + +/datum/technomancer/spell/recall + name = "Recall" + desc = "This function teleports you to where you placed a mark using the Mark function. Without the Mark function, this \ + function is useless. Note that teleporting takes three seconds. Being incapacitated while teleporting will cancel it." + cost = 50 + obj_path = /obj/item/weapon/spell/recall + +/obj/item/weapon/spell/recall + name = "recall" + icon_state = "recall" + desc = "This will bring you to your Mark." + cast_methods = CAST_USE + aspect = ASPECT_TELE + +/obj/item/weapon/spell/recall/on_use_cast(mob/living/user) + if(pay_energy(3000)) + if(!mark_spell_ref) + user << "There's no Mark!" + return 0 + else + visible_message("\The [user] starts glowing!") + var/light_intensity = 2 + var/time_left = 3 + while(time_left) + if(user.incapacitated()) + visible_message("\The [user]'s glow fades.") + user << "You cannot Recall while incapacitated!" + return 0 + light_intensity++ + set_light(light_intensity, light_intensity, l_color = "#006AFF") + time_left-- + sleep(1 SECOND) + user.forceMove(get_turf(mark_spell_ref)) + user << "You are teleported to your Mark." + owner.adjust_instability(25) + qdel(src) + return 1 + else + user << "You can't afford the energy cost!" + return 0 + diff --git a/code/game/gamemodes/technomancer/spells/oxygenate.dm b/code/game/gamemodes/technomancer/spells/oxygenate.dm new file mode 100644 index 0000000000..13439383e6 --- /dev/null +++ b/code/game/gamemodes/technomancer/spells/oxygenate.dm @@ -0,0 +1,29 @@ +/datum/technomancer/spell/darkness + name = "Oxygenate" + desc = "This function creates oxygen at a location of your chosing. If used on a humanoid entity, it heals oxygen deprivation. \ + If casted on the envirnment, air (oxygen and nitrogen) is moved from a distant location to your target." + cost = 70 + obj_path = /obj/item/weapon/spell/oxygenate + +/obj/item/weapon/spell/oxygenate + name = "oxygenate" + desc = "Atmospherics is obsolete." + icon_state = "darkness" //wip + cast_methods = CAST_RANGED + aspect = ASPECT_AIR + cooldown = 30 + +/obj/item/weapon/spell/oxygenate/on_ranged_cast(atom/hit_atom, mob/user) + if(ishuman(hit_atom)) + var/mob/living/carbon/human/H = hit_atom + if(pay_energy(1500)) + H.adjustOxyLoss(-35) + owner.adjust_instability(10) + return + else if(isturf(hit_atom)) + var/turf/T = hit_atom + if(pay_energy(1500)) + T.assume_gas("oxygen", 200) + T.assume_gas("nitrogen", 800) + playsound(src.loc, 'sound/effects/spray.ogg', 50, 1, -3) + owner.adjust_instability(10) \ No newline at end of file diff --git a/code/game/gamemodes/technomancer/spells/passwall.dm b/code/game/gamemodes/technomancer/spells/passwall.dm index 20bfbb7bfe..cc54f2b287 100644 --- a/code/game/gamemodes/technomancer/spells/passwall.dm +++ b/code/game/gamemodes/technomancer/spells/passwall.dm @@ -1,12 +1,9 @@ -/datum/power/technomancer/passwall +/datum/technomancer/spell/passwall name = "Passwall" desc = "An uncommon function that allows the user to phase through matter (usually walls) in order to enter or exit a room. Be careful you don't pass into \ somewhere dangerous." cost = 100 - verbpath = /mob/living/carbon/human/proc/technomancer_passwall - -/mob/living/carbon/human/proc/technomancer_passwall() - place_spell_in_hand(/obj/item/weapon/spell/passwall) + obj_path = /obj/item/weapon/spell/passwall /obj/item/weapon/spell/passwall name = "passwall" @@ -39,7 +36,7 @@ while(i) checked_turf = get_step(checked_turf, direction) //Advance in the given direction - total_cost += 1000 //Phasing through matter's expensive, you know. + total_cost += 800 //Phasing through matter's expensive, you know. i-- if(!checked_turf.density) //If we found a destination (a non-dense turf), then we can stop. var/dense_objs_on_turf = 0 @@ -56,11 +53,16 @@ if(user.loc != our_turf) user << "You need to stand still in order to phase through the wall." return 0 - visible_message("[user] appears to phase through \the [T]!") - user << "You find a destination on the other side of \the [T], and phase through it." - spark_system.start() - user.forceMove(found_turf) - qdel(src) - return 1 + if(pay_energy(total_cost) && !user.incapacitated() ) + visible_message("[user] appears to phase through \the [T]!") + user << "You find a destination on the other side of \the [T], and phase through it." + spark_system.start() + user.forceMove(found_turf) + qdel(src) + return 1 + else + user << "You don't have enough energy to phase through these walls!" + busy = 0 else user << "You weren't able to find an open space to go to." + busy = 0 diff --git a/code/game/gamemodes/technomancer/spells/phase_shift.dm b/code/game/gamemodes/technomancer/spells/phase_shift.dm index f366c46164..cd6a87df1f 100644 --- a/code/game/gamemodes/technomancer/spells/phase_shift.dm +++ b/code/game/gamemodes/technomancer/spells/phase_shift.dm @@ -1,12 +1,9 @@ -/datum/power/technomancer/phase_shift +/datum/technomancer/spell/phase_shift name = "Phase Shift" desc = "Hides you in the safest possible place, where no harm can come to you. Unfortunately you can only stay inside for a few moments before \ draining your powercell." cost = 80 - verbpath = /mob/living/carbon/human/proc/technomancer_phase_shift - -/mob/living/carbon/human/proc/technomancer_phase_shift() - place_spell_in_hand(/obj/item/weapon/spell/phase_shift) + obj_path = /obj/item/weapon/spell/phase_shift /obj/item/weapon/spell/phase_shift name = "phase shift" diff --git a/code/game/gamemodes/technomancer/spells/projectile/chain_lightning.dm b/code/game/gamemodes/technomancer/spells/projectile/chain_lightning.dm new file mode 100644 index 0000000000..0ce0b8a141 --- /dev/null +++ b/code/game/gamemodes/technomancer/spells/projectile/chain_lightning.dm @@ -0,0 +1,77 @@ +/datum/technomancer/spell/chain_lightning + name = "Chain Lightning" + desc = "This dangerous function shoots lightning that will strike someone, then bounce to a nearby person. Be careful that \ + it does not bounce to you. The lighting prefers to bounce to people with the least resistance to electricity. It will \ + strike up to four targets, including yourself if conditions allow it to occur." + cost = 150 + obj_path = /obj/item/weapon/spell/projectile/chain_lightning + +/obj/item/weapon/spell/projectile/chain_lightning + name = "chain lightning" + icon_state = "chain_lightning" + desc = "Fry the whole security team! Just don't kill yourself in the process.." + cast_methods = CAST_RANGED + aspect = ASPECT_SHOCK + spell_projectile = /obj/item/projectile/beam/chain_lightning + energy_cost_per_shot = 3000 + instability_per_shot = 10 + cooldown = 20 + +/obj/item/projectile/beam/chain_lightning + name = "lightning" + icon_state = "lightning" + nodamage = 1 + damage_type = HALLOSS + + muzzle_type = /obj/effect/projectile/lightning/muzzle + tracer_type = /obj/effect/projectile/lightning/tracer + impact_type = /obj/effect/projectile/lightning/impact + + var/bounces = 3 //How many times it 'chains'. Note that the first hit is not counted as it counts /bounces/. + var/list/hit_mobs = list() //Mobs which were already hit. + var/power = 30 //How hard it will hit for with electrocute_act(), decreases with each bounce. + +/obj/item/projectile/beam/chain_lightning/attack_mob(var/mob/living/target_mob, var/distance, var/miss_modifier=0) + //First we shock the guy we just hit. + if(ishuman(target_mob)) + var/mob/living/carbon/human/H = target_mob + var/obj/item/organ/external/affected = H.get_organ(check_zone(BP_TORSO)) + H.electrocute_act(power, src, H.get_siemens_coefficient_organ(affected), affected) + else + target_mob.electrocute_act(power, src, 1.0, BP_TORSO) + hit_mobs |= target_mob + + //Each bounce reduces the damage of the bolt. + power = power * 0.80 + if(bounces) + //All possible targets. + var/list/potential_targets = view(target_mob, 3) + + //Filtered targets, so we don't hit the same person twice. + var/list/filtered_targets = list() + for(var/mob/living/L in potential_targets) + if(L in hit_mobs) + continue + filtered_targets |= L + + var/mob/living/new_target = null + var/siemens_comparison = 0 + + for(var/mob/living/carbon/human/H in filtered_targets) + var/obj/item/organ/external/affected = H.get_organ(check_zone(BP_TORSO)) + var/their_siemens = H.get_siemens_coefficient_organ(affected) + if(their_siemens > siemens_comparison) //We want as conductive as possible, so higher is better. + new_target = H + siemens_comparison = their_siemens + + if(new_target) + var/turf/curloc = get_turf(target_mob) + curloc.visible_message("\The [src] bounces to \the [new_target]!") + redirect(new_target.x, new_target.y, curloc, firer) + bounces-- + + return 0 + return 1 + + + diff --git a/code/game/gamemodes/technomancer/spells/projectile/lightning.dm b/code/game/gamemodes/technomancer/spells/projectile/lightning.dm new file mode 100644 index 0000000000..40d1dba4d9 --- /dev/null +++ b/code/game/gamemodes/technomancer/spells/projectile/lightning.dm @@ -0,0 +1,40 @@ +/datum/technomancer/spell/lightning + name = "Lightning" + desc = "This uses a hidden electrolaser, which creates a laser beam to ionize the enviroment, allowing for ideal conditions \ + for a directed lightning strike to occur. The lightning is very strong, however it requires a few seconds to prepare a \ + strike." + cost = 150 + obj_path = /obj/item/weapon/spell/projectile/lightning + +/obj/item/weapon/spell/projectile/lightning + name = "lightning" + icon_state = "lightning" + desc = "Send instability from the target to you, for whatever reason you'd want to." + cast_methods = CAST_RANGED + aspect = ASPECT_SHOCK + spell_projectile = /obj/item/projectile/beam/lightning + energy_cost_per_shot = 2500 + instability_per_shot = 10 + cooldown = 20 + pre_shot_delay = 2 + +/obj/item/projectile/beam/lightning + name = "lightning" + icon_state = "lightning" + nodamage = 1 + damage_type = HALLOSS + + muzzle_type = /obj/effect/projectile/lightning/muzzle + tracer_type = /obj/effect/projectile/lightning/tracer + impact_type = /obj/effect/projectile/lightning/impact + + var/power = 40 //How hard it will hit for with electrocute_act(). + +/obj/item/projectile/beam/lightning/attack_mob(var/mob/living/target_mob, var/distance, var/miss_modifier=0) + if(ishuman(target_mob)) + var/mob/living/carbon/human/H = target_mob + var/obj/item/organ/external/affected = H.get_organ(check_zone(BP_TORSO)) + H.electrocute_act(power, src, H.get_siemens_coefficient_organ(affected), affected) + else + target_mob.electrocute_act(power, src, 1.0, BP_TORSO) + return 1 \ No newline at end of file diff --git a/code/game/gamemodes/technomancer/spells/projectile/projectile.dm b/code/game/gamemodes/technomancer/spells/projectile/projectile.dm new file mode 100644 index 0000000000..0327bc542d --- /dev/null +++ b/code/game/gamemodes/technomancer/spells/projectile/projectile.dm @@ -0,0 +1,19 @@ +/obj/item/weapon/spell/projectile + name = "projectile template" + icon_state = "generic" + desc = "This is a generic template that shoots projectiles. If you can read this, the game broke!" + cast_methods = CAST_RANGED + var/obj/item/projectile/spell_projectile = null + var/energy_cost_per_shot = 0 + var/instability_per_shot = 0 + var/pre_shot_delay = 0 //Mesured in seconds + +/obj/item/weapon/spell/projectile/on_ranged_cast(atom/hit_atom, mob/living/user) + if(spell_projectile) + if(pay_energy(energy_cost_per_shot)) + if(pre_shot_delay) + user.Stun(pre_shot_delay) + sleep(pre_shot_delay SECONDS) + var/obj/item/projectile/new_projectile = new spell_projectile(get_turf(user)) + new_projectile.launch(hit_atom) + owner.adjust_instability(instability_per_shot) \ No newline at end of file diff --git a/code/game/gamemodes/technomancer/spells/pulsar.dm b/code/game/gamemodes/technomancer/spells/pulsar.dm index 0e616fde7b..dff8e4399c 100644 --- a/code/game/gamemodes/technomancer/spells/pulsar.dm +++ b/code/game/gamemodes/technomancer/spells/pulsar.dm @@ -1,11 +1,8 @@ -/datum/power/technomancer/pulsar +/datum/technomancer/spell/pulsar name = "Pulsar" desc = "Emits electronic pulses to destroy, disable, or otherwise harm devices and machines. Be sure to not hit yourself with this." cost = 150 - verbpath = /mob/living/carbon/human/proc/technomancer_pulsar - -/mob/living/carbon/human/proc/technomancer_pulsar() - place_spell_in_hand(/obj/item/weapon/spell/pulsar) + obj_path = /obj/item/weapon/spell/pulsar /obj/item/weapon/spell/pulsar name = "pulsar" diff --git a/code/game/gamemodes/technomancer/spells/radiance.dm b/code/game/gamemodes/technomancer/spells/radiance.dm index 03b9b81bba..b8eb1401f1 100644 --- a/code/game/gamemodes/technomancer/spells/radiance.dm +++ b/code/game/gamemodes/technomancer/spells/radiance.dm @@ -1,11 +1,8 @@ -/datum/power/technomancer/radiance +/datum/technomancer/spell/radiance name = "Radiance" desc = "Causes you to be very radiant, glowing brightly in visible light, thermal energy, and deadly ionizing radiation." cost = 180 - verbpath = /mob/living/carbon/human/proc/technomancer_radiance - -/mob/living/carbon/human/proc/technomancer_radiance() - place_spell_in_hand(/obj/item/weapon/spell/darkness) + obj_path = /obj/item/weapon/spell/radiance /obj/item/weapon/spell/radiance name = "radiance" diff --git a/code/game/gamemodes/technomancer/spells/reflect.dm b/code/game/gamemodes/technomancer/spells/reflect.dm new file mode 100644 index 0000000000..9e82efea40 --- /dev/null +++ b/code/game/gamemodes/technomancer/spells/reflect.dm @@ -0,0 +1,90 @@ +/datum/technomancer/spell/reflect + name = "Reflect" + desc = "Emits a protective shield fron your hand in front of you, which will reflect one attack back at the attacker." + cost = 120 + obj_path = /obj/item/weapon/spell/reflect + +/obj/item/weapon/spell/reflect + name = "\proper reflect shield" + icon_state = "shield" + desc = "A very protective combat shield that'll reflect the next attack at the unfortunate person who tried to shoot you." + aspect = ASPECT_FORCE + toggled = 1 + var/damage_to_energy_multiplier = 60.0 //Determines how much energy to charge for blocking, e.g. 20 damage attack = 1200 energy cost + var/datum/effect/effect/system/spark_spread/spark_system = null + +/obj/item/weapon/spell/reflect/New() + ..() + set_light(3, 2, l_color = "#006AFF") + spark_system = PoolOrNew(/datum/effect/effect/system/spark_spread) + spark_system.set_up(5, 0, src) + owner << "Your shield will expire in 20 seconds." + spawn(20 SECONDS) + if(src) + owner << "Your shield expires!" + qdel(src) + +/obj/item/weapon/spell/reflect/Destroy() + spark_system = null + ..() + +/obj/item/weapon/spell/reflect/handle_shield(mob/user, var/damage, atom/damage_source = null, mob/attacker = null, var/def_zone = null, var/attack_text = "the attack") + if(user.incapacitated()) + return 0 + + var/damage_to_energy_cost = (damage_to_energy_multiplier * damage) + + if(!pay_energy(damage_to_energy_cost)) + owner << "Your shield fades due to lack of energy!" + qdel(src) + return 0 + + //block as long as they are not directly behind us + var/bad_arc = reverse_direction(user.dir) //arc of directions from which we cannot block + if(check_shield_arc(user, bad_arc, damage_source, attacker)) + + if(istype(damage_source, /obj/item/projectile)) + var/obj/item/projectile/P = damage_source + + if(P.starting) + visible_message("\The [user]'s [src.name] reflects [attack_text]!") + + var/turf/curloc = get_turf(user) + + // redirect the projectile + P.redirect(P.starting.x, P.starting.y, curloc, user) + + spark_system.start() + playsound(user.loc, 'sound/weapons/blade1.ogg', 50, 1) + + spawn(1 SECOND) //To ensure that most or all of a burst fire cycle is reflected. + owner << "Your shield fades due being used up!" + qdel(src) + + return PROJECTILE_CONTINUE // complete projectile permutation + + + return 1 + return 0 + +/* +/obj/item/clothing/suit/armor/laserproof/handle_shield(mob/user, var/damage, atom/damage_source = null, mob/attacker = null, var/def_zone = null, var/attack_text = "the attack") + if(istype(damage_source, /obj/item/projectile/energy) || istype(damage_source, /obj/item/projectile/beam)) + var/obj/item/projectile/P = damage_source + + var/reflectchance = 40 - round(damage/3) + if(!(def_zone in list(BP_TORSO, BP_GROIN))) + reflectchance /= 2 + if(P.starting && prob(reflectchance)) + visible_message("\The [user]'s [src.name] reflects [attack_text]!") + + // Find a turf near or on the original location to bounce to + var/new_x = P.starting.x + pick(0, 0, 0, 0, 0, -1, 1, -2, 2) + var/new_y = P.starting.y + pick(0, 0, 0, 0, 0, -1, 1, -2, 2) + var/turf/curloc = get_turf(user) + + // redirect the projectile + P.redirect(new_x, new_y, curloc, user) + + return PROJECTILE_CONTINUE // complete projectile permutation +*/ diff --git a/code/game/gamemodes/technomancer/spells/resurrect.dm b/code/game/gamemodes/technomancer/spells/resurrect.dm index d8dab0b305..512e9e4db9 100644 --- a/code/game/gamemodes/technomancer/spells/resurrect.dm +++ b/code/game/gamemodes/technomancer/spells/resurrect.dm @@ -1,13 +1,10 @@ -/datum/power/technomancer/resurrect +/datum/technomancer/spell/resurrect name = "Resurrect" desc = "This function injects various regenetive medical compounds and nanomachines, in an effort to restart the body, \ however this must be done soon after they die, as this will have no effect on people who have died long ago. It also doesn't \ resolve whatever caused them to die originally." cost = 250 - verbpath = /mob/living/carbon/human/proc/technomancer_resurrect - -/mob/living/carbon/human/proc/technomancer_resurrect() - place_spell_in_hand(/obj/item/weapon/spell/resurrect) + obj_path = /obj/item/weapon/spell/resurrect /obj/item/weapon/spell/resurrect name = "resurrect" diff --git a/code/game/gamemodes/technomancer/spells/shared_burden.dm b/code/game/gamemodes/technomancer/spells/shared_burden.dm index dd96e3c835..c7e8e35107 100644 --- a/code/game/gamemodes/technomancer/spells/shared_burden.dm +++ b/code/game/gamemodes/technomancer/spells/shared_burden.dm @@ -1,11 +1,8 @@ -/datum/power/technomancer/shared_burden +/datum/technomancer/spell/shared_burden name = "Shared Burden" desc = "One of the few functions able to adjust instability, this allows you to take someone else's instability." cost = 50 - verbpath = /mob/living/carbon/human/proc/technomancer_shared_burden - -/mob/living/carbon/human/proc/technomancer_shared_burden() - place_spell_in_hand(/obj/item/weapon/spell/shared_burden) + obj_path = /obj/item/weapon/spell/shared_burden /obj/item/weapon/spell/shared_burden name = "shared burden" diff --git a/code/game/gamemodes/technomancer/spells/shield.dm b/code/game/gamemodes/technomancer/spells/shield.dm index 2a573d62c4..5661a9cac5 100644 --- a/code/game/gamemodes/technomancer/spells/shield.dm +++ b/code/game/gamemodes/technomancer/spells/shield.dm @@ -1,12 +1,9 @@ -/datum/power/technomancer/shield +/datum/technomancer/spell/shield name = "Shield" desc = "Emits a protective shield fron your hand in front of you, which will protect you from almost anything able to harm \ you, so long as you can power it." cost = 120 - verbpath = /mob/living/carbon/human/proc/technomancer_shield - -/mob/living/carbon/human/proc/technomancer_shield() - place_spell_in_hand(/obj/item/weapon/spell/shield) + obj_path = /obj/item/weapon/spell/shield /obj/item/weapon/spell/shield name = "\proper energy shield" diff --git a/code/game/gamemodes/technomancer/spells/warp_strike.dm b/code/game/gamemodes/technomancer/spells/warp_strike.dm index 4751e50a93..9b57789e89 100644 --- a/code/game/gamemodes/technomancer/spells/warp_strike.dm +++ b/code/game/gamemodes/technomancer/spells/warp_strike.dm @@ -1,11 +1,8 @@ -/datum/power/technomancer/warp_strike +/datum/technomancer/spell/warp_strike name = "Warp Strike" desc = "Teleports you next to your target, and attacks them with whatever is in your off-hand, spell or object." cost = 200 - verbpath = /mob/living/carbon/human/proc/technomancer_warp_strike - -/mob/living/carbon/human/proc/technomancer_warp_strike() - place_spell_in_hand(/obj/item/weapon/spell/warp_strike) + obj_path = /obj/item/weapon/spell/warp_strike /obj/item/weapon/spell/warp_strike name = "warp strike" diff --git a/code/modules/mob/living/living_defines.dm b/code/modules/mob/living/living_defines.dm index c547211ecf..7cfe5f34b5 100644 --- a/code/modules/mob/living/living_defines.dm +++ b/code/modules/mob/living/living_defines.dm @@ -44,3 +44,5 @@ var/failed_last_breath = 0 //This is used to determine if the mob failed a breath. If they did fail a brath, they will attempt to breathe each tick, otherwise just once per 4 ticks. var/lastpuke = 0 + + var/evasion = 0 //Makes attacks harder to land. Each number equals 15% more likely to miss. Negative numbers increase hit chance. diff --git a/code/modules/mob/mob.dm b/code/modules/mob/mob.dm index 01a0e9105a..7927178dd9 100644 --- a/code/modules/mob/mob.dm +++ b/code/modules/mob/mob.dm @@ -157,7 +157,7 @@ return buckled ? FULLY_BUCKLED : UNBUCKLED /mob/proc/incapacitated(var/incapacitation_flags = INCAPACITATION_DEFAULT) - if (stat || paralysis || stunned || weakened || resting || sleeping || (status_flags & FAKEDEATH)) + if (stat || paralysis || weakened || resting || sleeping || (status_flags & FAKEDEATH)) return 1 if((incapacitation_flags & INCAPACITATION_RESTRAINED) && restrained()) diff --git a/code/modules/projectiles/effects.dm b/code/modules/projectiles/effects.dm index 7874eeb383..2235f188e7 100644 --- a/code/modules/projectiles/effects.dm +++ b/code/modules/projectiles/effects.dm @@ -124,3 +124,15 @@ //---------------------------- /obj/effect/projectile/bullet/muzzle icon_state = "muzzle_bullet" + +//---------------------------- +// Lightning beam +//---------------------------- +/obj/effect/projectile/lightning/tracer + icon_state = "lightning" + +/obj/effect/projectile/lightning/muzzle + icon_state = "muzzle_lightning" + +/obj/effect/projectile/lightning/impact + icon_state = "impact_lightning" \ No newline at end of file diff --git a/code/modules/projectiles/projectile.dm b/code/modules/projectiles/projectile.dm index ff561b5250..f4fbc6989e 100644 --- a/code/modules/projectiles/projectile.dm +++ b/code/modules/projectiles/projectile.dm @@ -169,7 +169,7 @@ return //roll to-hit - miss_modifier = max(15*(distance-2) - round(15*accuracy) + miss_modifier, 0) + miss_modifier = max(15*(distance-2) - round(15*accuracy) + miss_modifier + round(15*target_mob.evasion), 0) var/hit_zone = get_zone_with_miss_chance(def_zone, target_mob, miss_modifier, ranged_attack=(distance > 1 || original != target_mob)) //if the projectile hits a target we weren't originally aiming at then retain the chance to miss var/result = PROJECTILE_FORCE_MISS diff --git a/icons/effects/projectiles.dmi b/icons/effects/projectiles.dmi index 703d8f8c3dc4b206b8a1efec9fa0147e20ef333d..5598cf6f8499dc91aad71cb71c57d513fc3d778b 100644 GIT binary patch delta 5420 zcmV+{71Qd6^8vtu0+1Jfzz7Ba002_lYzF`U0S$UoSad{Xb7OL8aCB*JZU6vyoR!qE zZo?oD2H@E|#VJ{Qed72GV!jFF3KL&)vQ` zQhjLDS*Ga5fi!)*zNzZRb;**Z_pPd|xZbA6CMHfonpS4?X{D-v&P|atZB+F=agfLQ z7lnMgd1+1dUjETrRdwR|N}4t=e@cyTK+pFaWm?28ocJq&_%iVoZ4cSf9kNC^w8m$F zFBq{U0c4GEXvZ)(Gy!Bw0?0~mDFF{v`lGx=K)DePtrb4Q!|+7K{2+Km2B)`VL3s)C z|%Ck{n6%2nZv2h&f`Kzj)2WLo%q8_#-ifc<8w(a$hBG=B?Q7h7B<3*Cuf!;%q zEDSitQc1>_hQ zks^oeneML2p}U&R;ZT%B%6#>A;Y@e+gEim(*Z==j{q=us8&%Z>gu+E^X%Iwl762_3 z`TwKzJdtvTk0O)4rHU<>d_UF*@NMhE2MF+_@X#Z`a_Yke2=JsZ?+CC`^x*>pc#@bm z7vH@-g3oW61Q$LRA2z*2K0I$x#HtjOisAcx{WJRTW>MhQ)oYlZtj6{x0mI-W{i<~( zUK?`t;RAp22UxL~Hw5};T-Vw`al$y&c#9KW*AeOAw&Zr@$Z5} zUx7vHK$J#=B2Ac@r~PfdwESWlA308 zKJtIM4)7#K#BwihB(x#XV&I2OV3(zBf zh(do=8(3%yfH;)UC>u1tzTf5Q!#h%WTOjxjSmv`}p*BoJ z_F=f@bvnFppK^6W5_iH4FeZ(P`taMrI5&U6@o!(3066;am0pf8A2iMABt&-~*Bm}J zL;jub0$5flmz9QGE_!yhlUO{AHmy^SkPZO2SVxXY^6#1y@4{L;{qN-f%c&1v4ox$X zgyjrP+``}Wx^9s`aaXZ-qe*Wbs6JD-Bk z5fsM1K{$E^k=P`-eIHX31ysfD$C1c($$wY~^$-9sHZ*A4%?I7xy?$@EUJap~=x%?c z;JlnK>wbPLM`0wjq#h@S)q*$#0QrA<3?}Zw>3^5}G9+3HhCl&FAKw1*O9i8s9esEq z8UQ?t_=aXjAO7j4KmCcN{9f87Tb>f+&fTdZCP+QP)wM8-Gy3q{-U!MVZvp@cXnA1CM=weslW0dZH1>h2<3ztzC`v&)Jj`ei5Jn}-X8Sfw30qi`@ z*ic69vu$N?rsd8z=kspvkKTWt%SGR*;3>U*m97oUj4JbZ*?C8uhZ&VBwW)MnlzDLf zz3kmPa6$<6kZ&Z+0LZ$d<_Kd$8P{om5WP{ho$sFfkltSjVaHDJ(-$c5`k!**_5ZFh z@#cKq-)Pf1MYU+JI(7P;@=~dP-<;!8?x@o1v^P>(Qhu(qf1%?awvB&6|MMPMj6S?^ z@77lPncA1|9Q_RSWE6;gfdcyX|AyV@d3o@m^=ah~FNB%~h6jP+J%A+s&eH(;+@`%w zQasxTd}QeJ5j>@72Fk*wcVv6t_7r@E;TlS>|GrQbQdBq|xm>i%cT6Rsr(_!+G64EC z&5$8XAIiw@|38FK4>^C{T|Ew;*Qb=EIoG>wTZMESoTK|;``<`vNhnCEib!7s85{=P z0|-z~26uv=CX;UeTj;%5M~>}EYO{>MNNPz@Co*IbeICITq>Q8nf7m4VN#ih5S`ri~ zFtkT=IcMK%S|_;E|K5I%-g1M8_WF(o5dApU(I~5TQLz5;ycEki|mS*gaJU6bP7i*@AK zPVm!TZy-N6_i0}LH*t|2GHGLTHOKVcJx8ieoqh)vdi8%eIjknNLwcMXZVvGgX()hz zk<_vXIsIRe{I6-9dBTn+sGS7>Bc(x--XnhqnLKBigl*6CosZ~#1DRt~00{o}!zh4S zn570V){L6^1cqzhXf~g2dHc^T_R0$sx2CxBA_5^WZOo_yGb%885BTWU6uqBl}Xyk{Y8yIFtklU{vLp3`*-Bd&3$85=4;Mv@(s z`i^taed<)}0XzWG`{!$MG*KoTl4n5TJ`Rd%(LM~ihf~qg#6^~jkt`IXM73xqlcXyCp$6GrLtmz5bWvO$Zxc$a>%1QKFIoN#gsj!7&$|$(N9eN6)qQVaf4gd4Qjc1rK0DTV-Hm+l0T$x z(+DAYV_A%w1ppybaIVAWO#z35jqZQ`5x8+SAmjEHfB4f*DaqJ&^T8Qo8uDF+_(y_X zA=DJ-I$WaDe;WO z-If+Y^+pB1!&ofx%ptA(E<$`{$fS+HO#hRD)Bh?2bP%XTaa>NAi8_&S+oOLu#79UG zeR5wkm+MNpA)4`;)(M7oYKJljVIR~L-a+k9I`6v|3g1XzqF1Ffr7I@#&M{s)UEv+7 zMbo;%yIW6vbihby$pp2X{%2^1aOQvs{{1$?wTo3SrZz%|Z4kT(u^JVlb-%Oi+K$)W z`iU8S@g9Ef!x42?wZ z*M83~gr8-0b!~xnndZENmldE&UQK#rpEu4jHZ%wTw%y#~mi{EUXN5*?SR%`CUafq- zYLC0E6SEW1BfjcNpBt*RRH!g{#0LPzh7O)Q+0x}}<1YvL>-PR_+X;WsUlBq*F7MsV zH#*_wG_o(;V?5%!eUO$8Lyk<9s$S)g6(AZB>GCj0w@5dQh%_&f?&c65A!8()ug4$& zB<`X`kCVfIOYXAJDB7Rv^2(rc`xwc}1iHN11I*+BUPVZTHPp_+Mqi$=qY2w?nU&xpEJ&4n{pm?k?XL-1(;+=DY5>#uzfo;4e|Vs?r{acUthU0 zhx~uPV+Z-^<;&i7U()Hdk+HFi@m(W0BuNhd?hoDKwm-a3>Cb;p@CQ|FFi$DcS6`oR zzn2FrR2HpZeDd1c0bKQ0jpXtW8NTIm(XPFF2TlNxBVM~SR5y$ofzQ|%g3+dRmgfPw z<%BCT#^*)Stro-~NqPXF5s^;ZbrN_viT0pLGNVoF^d{9FP_db11U^HNWS@7xFArF# zEJ}KMda(b}OB8?CFGXM$Yf&;b1K5FBO(UZ5W_%TSy>V(rAO6}kg8%-7!q4>V#KTJKo{J2W(<~whtbIfBT$jvQ%E{F>A z10MP1`P?}H85YTrNfrn)cm(nTGot|DkQ#8}ecf_M?@xbVCE+E?OQH`n0N=#e1KU-Y z3-A-(JI8~J1T*E)O7NCK>_7Lcf?HRjFiX`4g}1^o8^Ks3YB%p7UsN5ay0W>cy^VyP zdPdNT7l=4}adh0?Io5+s#;;&cokvam9oXhgjNckV(J1!3vH7tS52Oc_3*n^qcjInv z5!OPUeyx8zFHlx;EuS#+zVF*NC>BG037HVfg>cgQC+_2*e-Ye5o_@7FFEC>O`DTi{ zqYPFt0?Vv{650aGd?w`kZZv7IQL+4QyzXqqW zGmdE7#I|kryRv19x+ z>i9Vjat*+BR8@~78ZTkfR+GdT9!DP@m}3O9V*W>&-d_(W56zZpMW|;4WikIkG5%_T zX8?acywgfb1)E^>8bM7x!S&$?%u+2V+XN-F3Dbp*sIA|Q8do3wa{ip74_`Zp>AQJU z#iwBwZz5cE7d4xT;HC-76i`C^QS{;ckU4?Bj_qG98W_Qoh0Fy7xpm;n&KN=sCJT`~S}( zsHq1Uo&`p4C@2{b6vjh{Z`gq1)Mk{7YJ{T}s_Rm)tT7mqeF#M^U}_=`MG+vBLkWMG zsHrdf&F?nwh8Pup@vl9i=l3IvGJ=5cbMbBFL2HHZ<)|o(wOsn}0Rnv6sHh4d$qxW; z?+o*I+hbO8Td0I+{5BNjHYkhZ{@pJzF*X3RGzrVximIr>|7?5d_1|uuLb$33$_UP% z6`v1$gCD$5=bih1>VJ#;mG!+qCNY1&iom?OK+CNUA0WWDfd{HXuOxl=00Eu^9;gnz zQuN^i1b9+d_BX`r-@kuZuODE2V@1CqCP08Ejlci`tZM`Y5MW&+Fn|E-8i4@>Sl3um z12EcFt^{6y0F|&L1|W$a?O$69r2?#dEQtX``*UZd5d@<^fYpRW8GzBICH;Ti-)Pg4 z!6*=5HQ}+Aq)DPnvKwt$5@DneLc7tXWf4XSCG-Zy5MZU_kw$=WZ*QcuPS5L?&4 z_j`S6(XgHxL*|_%@y8FEt=K|=}s^k31&l%2Fvx&1qiSZXx?T=0YHBzq#I%PMFL?A z8k%+lVWf16G#Z+AL?@&JCNg=(oLA+T$jEJgV-yKyLlv{7v2}|yB0zu@3MIkpg8;Tu zi~cMRq!V#Ft6QX7HJz6ls6rrbFsRISj6~s36)~b)q>)-Q4dzIICfFlOfd&Y$>`Bt)_qcVRR2q7!OqXe@L>V$Ntig1KjO=PG|k%-z^&%;|tt4u&Aq+1mt zowwP%7Yz_#r9knjG$r(^VF57vj84casww)Sy}2%}wAixU5oJS(PNiA2OUXBm|V5GE8osfSHRXDG=iT38Y243BJ z0svGYjw6KjyumVZWKb0`f&#J+nh*;fi43rum@^aXlJ#tP{oYT0X%qvm?mgiPiy+C5 z0DCiOEeP8Ct)-X?1jc9>~yYsnsCvd&sv-%AAD^&Ftj!Osn31#YBb{T75+hay$Q` zP%alQoh{zW9lg}57td!hw0QYbYJ~&(zUL(IA$DQUpBcob$Y-=YWNUZGTH(-HUj+VO z#MT6mwZfsB!syThkgW+IE5YRq4661=d5wT_D;&B(_y8}%6BR!L!7B>5y)_HUYmg^j z-xr_Y4NbX>4=scgYS{nmoHo0Lnr*AE`=fIrHCBkkvpNALU;-E-vtnTt41aC0Q5|Ra zn=@zEd+{3Em`i*MAZM2lY`}rKDTmrsORCmXB6(=lHc}b|S}iZ_E3GQ^sl2t7qQ(zU z^`SgeYL!H7+(=bPOxPqPGzQxQvTHD4V*|e5eRj`f`fz4;$Ln2V8;B7;-;2F-=FFL$ z^Zoz)|Li&63|sIQ&cNeMVt+#=BdYTN(8D7CUsBtNkULzCO!@{ty>Ifpq8Z@J)`xfT z=+M;EwAx)*RV;Z1SWSI+7cL$Z@}?pS^x;4Kkp1nfstSGhv+cJ$3-sY{_Nb`YMN#Uv zf8U)-`c)_&V-Lgh46E&5`EwyITs$h|HGtg}1-LY15L~;&KB(DAK7Y7sDhT*hq>|pr z_KO*Pcq7R$)IWf^=|WW0FzC9SiuaqhgGC;$55MBg5nQ-<)W{nG{XzYV{d~KRZGYue zXLE$2G9LgxW+wbd=_Lq+c0=`SglTx7&`kgWm>TtCcCrA}qrx-*{sxxZ?&;t@a#Y{* zP{JWi(`z3_J1*8P@_)_%tDz6S9B7(e8;kk69;_7?YaMxKfZi|qJcxJraN|l4L@9$l zTL#7|Q4o9%#J3M7DF#ui;VG!W?35qCdJu&QefW}%0UH*S7e{u@yGAJS5&Plfr%Mir zvc0^f>9v}sA6fP{T?24u#N}gw0k9qWNz)nTh0gWiO;hN@M}H6q?SY}}#!cf{#0$QQ z8UG$o&jtWNsGdO(lGcYG8!^a_o+)5|+!J7cqYvLSxNBLVk083ZvCiL~(*WRl{|vqz$0yy*bj?)YX7EsR~OcgYuCv;HhDQQ&u*VSUgTM2zy zbz?!}cU8-IVgnF8SG!{^!@As;kNKSD^HzpmMHIz#?#Zva?TDVN6$v6!!GzLRjV zRHSo&)zpX2hNkJYgv1Y@JGbkQrd{a(wtXa%-}Q73WX~^*z#W_AA#DJwsShuMlm7%` zk>i@C*HUWMSr*;^wzY$kf2~jXg6QJ=^YLf^P_Jov3xEILbreg00yz5c*5{wA80>TO z;Tfw0um!<&VMiZ+bIng)H`Q-7TV%r~Mn*)qNM`imZL0(d^*pFPJVyhi ziB8K3x4;Q`q#Nqw0omXQa;~KLi3kg1!xxJIlGi^Epq-HT2>|B_iJx#63+@l)>y3>B z1HBo2cz;SAefU6VJ8rH!SYvK@?gu}1^x+GA8GZOb&*oYZ_cg&=v=bihR(QPYFgZ%m z-)-a8!VQU+f{gd~RKeM56qF{SlqNczJm5+P4~bsM<=uE$gQn?kiuSTRf#*R^Fs zS*{^1#n6^wpfa(u`x1-!x(*!ZcsGmmQ88`+>VFl5Gy{k-7U?A`Rf>Y z5Pf)kY-pqPRMAdsRX#&083cTnF@uXu|D$)?_I55=pH@ucj76G(o=%`=KLA*k+Ueu~ zXy;YWJH{~I2>AI?0PV4u?-(y`&@>%cVbd{DUn*|^P%j-j0-k6~$IoY9FYA27V!l(- zIe*B}zXnl9LKHx|rs)lEj6NOe$>)jh!C2(D{{^x>~vE8BeSy0UTV#=Ym5ZJ5lMonTNdfhhlJI`i}esPs1OS(CVCaH&Ft z0XEv+8dxw(5E4JkSOk=s>Fq@*HS26U-haoKXTOsK_ndYN;>O<_8;!82XIbGELgLko zMWAW=o1Dx%6mUqxSfp1n6!3UC3d}PMnfym6O`POm7-VCT$RDLN5w)zayd_FQmN5tg z?rft19KxUE|Igc2MYJD_`Ht~fAqt>HQAo38r6m>X8H+UAcDz+Gf@Wvz5~AKQxPQnA zf?t2&15gAbRS8PN2$epAo}!n+#^$=$erD2r&ng(2wVjO!7{i>NQ3<9B!{8Y3@rMdN zJfpIip%Iuf6Sf_k9cKY_vw(RC)V_?7VwIWa8`^AID)8l+doPTK?qK^c^#xQ z0m}*>1yB$4?01sla0>vD?9~Hkr++kYQa;bJ!Y!OQX~Oe!qQXN;b&v9Y>v`Q4IK&j6 z<$fTmu4uPC7W19bH2qD)uWOnCK9(I$5az1+B)DNSUbBgl?i zV`tl}_1w8#hjQF|0Pf?^D%1zlhp#GU_;#~}ny^jo4HRQ+xI~$oAjOuU)PLC~sb)6W zYZWVX);i^iWhg@g7_%+X3unvXS>SBCGuby#Dmy7|Jcl4M$99+ zIM243AR7SG%f`crRjnvQuG`D|Q7_2LKevdwmKAQ{`9+lXB~5-oe5cI>0FovqpK&S_ zh5QCcH1nCPm9a<^0Gt^y0e{PifRK2rZ3D6qSyukBb8&yDC|tQd{Dn^xv|mu{8#jqH zG-#NnXIf`OpN3_QK|v1!tVDZ<>2dZ9p^>xF$W2cQ!fFNZMq*4q<3h20~ z;Jx=0>)O5HNvnFc8-FEwFBCG38FCjB_C+#hU#0=|PSNw$jCTvQ3X5j!Q-+b3@M0xH z@~)Xq5)t1z-WWiOvoZu&R=AF@fCzHW3ypYKB342~d5fH6X0IrTJV2@=!kQNFaLcm7 zby-R75#HCsQdn~I?Af|gQXP3kCf%2;vI;`t`xuM7Bl^zsjejHHIgJ<#eomVBd<>d} z!{B4tA}tCmz*-N1$XDN=QvUmCw+Ay5K`>SVW|t!nssZ)vB=M5(>@M6`^YZtFK0LwQ z;raUT)>gd>r0nQ zNoS^mJT?|#3V%0(?<9q$4VGhV$gRGu^RLNfMTSn~$Z*4Bom8#@);xlsTk zS%j2c2A~RoP&ItPFuo`_SUsE3haVUq_~%=yec|HNoPV)*`V0z3+c5iZ^x>uTY=|UL zO7@OJN?@~AT^11de#FalUaori+RfEQ9wR|);nL@Qk!_eV`9*sN4s^ULg+=Ysij`R1 zT9o{NYXIq&;+w8)Q89Ge2P0Jok9Q+XqZ*V}qo}NkT=pOG-!7}E-$Oi`o?^=NYlL-O zADpnZjeoacz5YI|*{cYZj=(bRVPa?;Nj=&2QrU_W4}=F455fuW&*Sd&LvZ)=^iRrj zF2YcYCa>b@p|?@yxe9-90M5$J1bjgQ<$vYYO7-DoBM`|frHRh7XX}Veh$n&I zD}ns`Kvo%+J2q?G05WfcJx2QQ{3e1YcZV5^oVRV(D&k#DTRg^p(!sy`Jn}D=)Vs)! z^bGLg$S#tau?PkS2tuU7->^-w+QF*j3!qS6Y4xITPe_Z3GUzGxbAquuZa z=YL=%@4@RIMQD8zwqd|D7*vnF9DR5hA}5f4$dR8Gb#L^8W3A5s=@(-Dy}pC(*yLdt zA7%&yEO-i1Q0O#lYZOMR5B}gNQghuH?f)2b{0_E1U5Txw1DG5A1gd%uMluDj-}%jK za)_X4z4E*7J;Ppop>oBYi^Y6h=g#dqB!3#g`8^1j+$HegJrFo7aA$K48|Cds6TPhoP#&P-qa7qn~4H zyaPsR8m6%kexGXpv?6uzYvEaV{Yfa4;A$7U)Nu>ne6~2<_PT4;iT zNH5X?(m@O@lt7ZRTzjvz*It?Pd7e4<%5xJV9Tr9&MgRa< z^mMgv0RRL|Ip}G@mfWst3}{3@F}L#5cJjUV$kp4=)yoqA0@KRk2Ry?BPeqpFFX{&C zM>($6FnJ})>q|~pN|~GJaWMBMHxnglzSo}~c9KpD562yoQ7v+T)0neH_K#IMa8p)U zr@yw+p7$AMTH<*V#@uDveto*G@3sH1&zrD>A%F2}HeWbSc82oh`j~T1JYsr;_TiJ3 zSY=rd)UbIcc#M7MeeSLQ?v-3`g_zV<=E%qPMG04}pP0Gd;N$x!XE_zME&Yyl*=5Xi zzVM{AVM>p^Jlgr<@FH7OVzcs=$*Yu?zeXi;n4Ln4<0NyMMVp^aO^-x%`!+3bJ~pno z`!RdW@{0;Xdz}aMzM<^>y0}k^5ktkzPaeD_X42IZ;OdL2#2-5< z@pLLr`-@IQ(h&|$zO~lR54KR835ZiNj!w#ggv?967B2EvASE|X#(hIFOgK_4k5$;E z7%=A3pHwUekI0YDTRD8*LL+w}svzD$+up^H-axF|&JuNa7%vZE#dZcCrpx%s& zoliNetm&qn_zSLn3!^!8t#(ajSGi#SiG>sUh^0m31;V9n!AJZFPV5m*_T26l+SR?; zt#uYB3;>VTM<*~Mrip%kLBI}mpEFwjgO%I#wxvgl;ocfh$ z1+A@4bB>l-(q-r76$5Ky?mO!#B=kq-M?G&oeS4p@-XfD*zg8Q23k7*M;M)yZ zv@UY4NlfDwC*Z1k+v43*FJ?hUo|&WF0S+KY-hR>n7zlTd+;5H_t_F0Ge=X71`|ly@ zr6G{FMkmibp>Nn{1~g?`0Y@N@g%%J>YytnHaRAsgKeYfi;ea$iFLe7&1aRv#`!rP) zM4evfSz&3`%XgUK+nTlDrRtFY1H4dSlw6F<*At7oH?29N3CwhVzrP~%sjp;Cub4;sS$S} z*8vB2GqXwBv){bGbG_w`7p$mMGUD+c&t+e5^^GTk@5xjrjedbk+9(Ga9uZ$(^tjVO zyi)WOtK>E|oF9<*iSF*$hGJ21TZxK7b&;Wmo0&4tS;`Z4u-;OjH=q~NW&@Xs{^Kcd znZm6YDSq?F=u44o8}b3T3{e1b-XI4F+S+zk=YM>9z;d1yEnA9fr+5;y=S`wa6xT<_ z2UE!*+>aj!8eohiAxQYoxub>A@9ACb+t6Qi$GmF?uu)>qaJ=B z)l@0GAEwKxvGZD{j`w$1jAm`i7TfL%m%Slp;ElNkG#^rsfLvOiqq%O?Yy04iHVUhs z0a2gGgbbneaLv9PJ0k-Y!-mS;>)gP_Fj@m>4fjwOCSPE0yL%4zXuCT%+kNVk8bEP` ztMb@j6sK{VXX-5W`FqLI^$S+{b&CvZ!LS0)GjG1JxGFM*zKh&fJEHEr-8pQ?&Gt5; z_gv)zV|xzsF?3ZwRpnXG55Dp=;xmN1*W;V>C$WdGG3(aqK??Sh-!y@(nUnG1BaQQE z1vcVpM%?CuXMjsA<9>DQ(&ju;I8~ul%}K$E)d|FHswg>o|6Jls{IR_oj|*25ZC3RU zDj8SLY)Eb;8O8+B9&QabHt2t7Ane}`=vdkOuXy2EKx*N1c~K*VCDdpYt|N@{J-)coOvbPT!~nZVuDj ze=;rTW|lhfb0E6@TBG|0($>4O7WsShYz`9#aa@ja&k-G5tm3SvdZ>JTS$QyiAp9;;Cz zgF5OeRJW!k8skifio8t?ssD}{0czpo{6>p+JID{wW993k!$rIa+qWGg%AAB((GYbR z{h$)5XXmffl2qX)o}C(ow)G#a+GJ*Q2;J9n=M;_F!TCTtzrClHu;elNIaNP4tWe_h z0vzB2IHt`LXpjCndS4*1g0D2aXY|XhhJ4m(c|_}20``(@;%LaWO+;jIokw#$#3nHG{aJ=v7R)3V-?ATz|Itshv zb(-g0*ScoDTFjW4#rrfOcI~JJ$mY4(lPSW@fp71d zA0ee{=FNFAd>u6w)_{(hGL?hRowUr%}UcS-$H5nf1S1HQyM12IhdfIvc4JPY>264&SIF-5*3vX>vzw=T zPi)ttmdFP@ltZl(L!9DeGkJ|U>MDnKJbh?lC5Oz}MKR-=W(; z%ogvaKk`bq|9Onq_1XO>al0L7lc<>&f`7B)%w8^lobkFs%dGH;FS47eFg?MHGL54; zH35efh4QL!ZRX}*=5J$YzUJOLWAgTncoXwYzfl8>Z~k>ysebP{)`SMpU!c1uflCW;& zcGftUYd4){_@UIt)QkQ{wtS%kr0^f9G5*d}ZLG3aze+Lm9)6p^(_k@S_l;+1+l9a3`<{%kaR_^ay#1s?DtfOz zbf5StI+_Xy2nd)!;<%;RQ7>G)i=EvOhGyFHgB*ZoldI_TE7>(4SXBM-|mKz7h<8jvye`05-(Q8SVgQBlKKLc$gH14eiq!A7WYtyT%tFHld z-g9mKvGeCdtXYP&dnd2 zSiVEl4|8(p%0j^=(2T$GX)t=jgUGLG#J__icp*dO0Afrd>_`k%c_OLz9apPDG+;% zy2=djR$uIcf}Fa5S~*UbCL z?D*cb;J{Agx1ieIaMc})k9^_SmL{pX@W&{Dd>l9CH;EJx5y68V^|!loCwV&=G3hgV zfnHlP6EFB~Ww3SnRp(WqkF}>B&0HXiEP~Ox`9RR z>|aQ@`EH8XEA;@SvhkYb!q9%QaVn|f_ot=@!PC?h_Tp8wJKIr=;`-r@s&eO(<_fJ5G0 z@@?S2P~*BsWqFX3Hf)^Wl8%Ab8XFLEdE27abh6AZ&22CCWC=7|m*sytEm&G!apoq7 zdo{w3h(hCx?4FP)o~YsvQL?MgxSNVM*T(R}TZC|1Q->>8uE-u&Goj*rgM*cSw~L)# zn=JEEzEqAe0kq3hyX7?|@karwG#tNQoM=7TjM#-yxgfcku!pcH-geB?m)B&3*s8j> zJF%Cylu6wiKz*=qZ>!4dW+y3XV*}e9B?yk)9+;I8K56N~18Bbc}A9-Jbb4 zQlLc;T)J^C(xT^hU5Gqo3 zLsY_x57nL}<6{W5&+E|!IH~IhRf0or|Hg(#dAal`T?}DZ%(1YM^n8@+TtG!#onl2r zMgJ(?ykz7PVynojws`|Q$ww{Pb^r?(Z9X2ZwZR6M-$nhSzZD|H!rApHnMzdNeKnxl zMkiH%GS_hMdYoJ;z4Z0$JL=K%vUkViDdK*%qY*DL7 z_V3|H?-<%?!r8^Ggw}91A=7UQvi;k)7uz#eBhQ)@N!}7Y?Pr^3-X7*?^!ZS>@**O0 zhZszj&%=rJvaK(2oK)Ugd~H>QZcM?!(fc1 zN1Nzwn4JF4WzJE_l%n2%U~+v8Acr7cA8?3rm6?`Jp!vFlk5OeAzKUY=Si;REmp`N3 z@w%)N)x4kc>e1H~HQj9ohM^d@x=OrohHyJ!xckhVCeqd(wVEvX`Ev%KWohYwjbI^t zn8^^4w4XvImt)%3W9SyRyvJk!ow<|!UQH6`=cy{6*FTd16#LEeYdKK5tFrgWGh^?Y zB|KoRgMDlGm{UNjHA<)TR1H<}{8g_fv{(*m{%2hlT;47K%{6zLul=4SLA)!Wy2ZFM zd!E`xR|Gk~zBSZI&xS>%Y%$Kz8tXju$f=m=tCkL@fu${*maU0tuSvj=tOuc~KJVD< zs#9_eN^q*j8l-++s+cetnMjjfHDlneXF)v8}sk8!veU8yncAagt1Q z^M{~K4dVOqvLDR$w#e7Ey9DLMo6zg{u^ao&f*$p*7j@3~-=jf0lUmu|SQOfscR9~6 zr<6Z7&|zsbyj;r1!@v_;B;^u;h9HbB$By=&>0#E(FQJvXb6o^}%bpm`t|Su0gti>L z^Z99aYN-ua>hiOgH4N~kPi&?0k90l8#6%dA?O4p0+u^PfS_*@*`k{pI+!%v$nzyv` zhFaY8LL#imo)EB*@Z31}Ov}W?#1wd>t@!+WTYE_$z~-4w7c<`w!6@sNFJnT=iqD!^ z24NT%;mu_4;o;%w7Q z`9sN=0>FMA+xOwggO{NHKlA7ckq`Uvvf1pzu&5}`2-33DdAX#_;@V5~NuSIOs3w9k zy=itvpzl~e??h*3XGLWt6<-SCtIw>I;Qa`+b2IX6pLfQtH-MiPSCGPWINIlp^1B#Cw{JJrzXa3^x3J&&mS~5c(LGImO zH#V3_*W9WI(*1jPTXse?h#nOpt|#Gl?reRBD~(8^27G>H9xmO%mIa6gZ7xxkumEZ9 zs7hyYDZ%@2d(mX;AN(yYFFy1BG{T~qo$?%q1DuR#kf0)Aw#SCi8yg!^J4uZAB4hA2 z@Ma`d!`@gWmyCH0o*3<`wq|)F%g$#BA60k1jdx!e z!yfEcm4MSRZL3Qsr1F-RM&fyIQ6|$YQ1lRzEQ7)zd!CAqC~VE;P*%baaZw!bBCY=V zl^turMkI_#Zj9<>JxsAiLq&-~L6C#u-PT*MZ3QL{K`F3W({YOn2xoV^IG7k( z5$l`|muvPzc`VE+OcuWFiM^eWUUWO}kFE|#Q`#)Ipz63ROzHn$t^ zdJ?(DUKM)X&M4HGkTpr~Y++v!ksQOMuGZn*a`6^mnXH;k2fR(-Wq!T&-F{@p2s&`t2LNTQdn3uOm zii@LowdZ`}G}^BQ`=-L6uSv+|+_F$l#JGd4yhHiRoPuAC(|!cotENP|v2UomyLNj@ zH+I_q!6L1WcVVIhIR<(JvSG6AiFuZ*fjF#bXa{YMq-9#_2={(LehP zoss3hIj2uw_Mso`@K2O0I;6veVf0HUePVZt>u48W_?qoqyYAn3ueitLgQ7yiYS+jE zCiMMC*^%t{&Wz4J53F_EIyttpnc~DaMrRsH5-&`|QqA63 zwv+=728sT93w7>=AQvk<6me$_9`{KOG~>)!>ybUWfP-KEdfJal8OD7FaS6nBM?WER0H`;?om^yocz{poG$>Um?=u1 zz1G7&`#KwExc>I6n$HK+;HYux;c00Wz^W@f@h44;0$Eay+ImSq1FLo8n)wh4 z?{s!v0;pr4ElaOoTO=E&boU!OcHBXbr}?E`J`(S?`C-_%FrkK0kbevj4CGVadE9LM zD31MW12XrHI*6Sfdm|plv^S&2Vu9d6;}$45isP=*1GX`Bcr0gLD}ccudD+{ zXE3PKCNR?v*Zq&bHY%y1)OL2(jei(1=R~dE#s*Ste~>%{jO;rrd0K7uU@9v^Z|U`N z34$xccJ)=}p$QB_7^%0R=VwY0z|XICO|Xl;Q$m7hI%<$LF@3ST+$sPi1+t8>Kvle% z9lZMY7O++TM?E^z?txewX1iWULlJD71ux-GgM%A(mh>b4g-&n`POw6Z|2K-UvZ-mB z@cDL$9xpve5A!QMJoI@;d3;ld2}(c-uN+$=R)LXpySI`s@&L2-s&ohh?lwZIg8c32 zC)MG_@ksU;N!YIem; z>D?k@A}eATpM)l?4wR2p_c&X_S2QXrkcFV=9CoWt^p^eUVnP9JHT>c_Q#s8kJ__7+ zV-^2J4e7|-5p~WpXRIgr*PibD7cft;f%UE{5z3()An57_v!dCj!4!7yuDhqRv(Bnt zhaI87IHR*Ec>mK{h8ltg*u;;)q5b=$uzLPtd|w6(&NMWVm$B5BQK$w*-;Wy@7?|i1 zK)qt(l<<4{^#~#DxAOSv`2>QpvNDj;S!jkG!jp}P4zfC*2_Rj5lQLka=Dh+Kk)cmz z$KVnSmAyR2rB2;#6LAdy>r@FIs_*>$?h41I^sTJ87+SDg=_T0p%pV`_$XSTLkwTy@ zt1ln1Jwz0a?pyO~*xC|gV5nr!r_(iAfMQSEqxi_hvbHp5H&VvXjrZlTWUZ#EDl=;v zn-ZFb>X#nE@AT8zYh$ql`Wkw_l_PkL_EZ5bBJCnVa)G=RgBlJMe^W>RMS8Nj)9Xty zgvthV_FAx0+?RF97v4;0Xr_qa)2%O@a)6bM%|j;4z<_CKS=q=99i1YtkEFw$ z<<~3VQu3pS>+l52uc3tbd7XzaozEmq2)lfprT_Z*cw50?+^{A0;Mr-_NGy3d0~HM( z{C%qXce?~v^7ND5j!hJ1cp^sn>~{xI_z}z3Yn1Lo>Qyq(PT8RMA@`m%wj1;Fw`3vJ z@P;bD$|{x4koWbz^T&KZ1DX)O4Cq30a&i3 zp55i7h3LUw{?WUg=zBG=(ImjrGeJ3qqLpy3y@9v2jJ|O}{!RgIo$nOXqzaKOFM2f7%;nAHWzJT}!J z`I&+VE1QAwOgdMmt^IuWlHcdqPtkowM$91MbuP)8gqsz$q$kI!+JYHgUwZR+n7vV! z{55H1i%SVo^74@h38&rNXRK(@vpzsC7D4Sgbfd_tq1h}W?H!lr5a#1&CLq3QqYGlc zlW@7Ag>d!`ToZiYazbn;0E*HH(gt}u`0dT}21ehFXc`#rt0UHGSC7<=k;LZ>0?hY{ z6gLzfrOtyIab`DyO7Qnw{%jHoMC`n{lw_0PT3f8R-wK`Du?F!R`rHdjfCsZbgrV)% z4!%6Bwyru8_47Y~4-?523IEwBW9w5RH6N|N5tFBe-^m6sm5GUo1yz6WrM9+KxdUAK zwXOk4ev&0clndPaD=x>$r|yHOi1#hK9WT!gs@tvs%*P<7TKcIX(NY8`FoQ;uYA!ZX z&~K-+_|Nr$LSv#Z@p6O3<3-u&YUC-|LtAhPIM+Xz`TwY8=tBi3!P=EDDI`r)Kz7?FN_K3ss?{?zX~ zp?O6x001FyRE>0S?{1xUR{O%Q-$us7-=?7ED7i{#f0m^a#pej7X5L8>wp3`=s>z=} zFBZvywGGw3<6z0$g>7lv&l2>KuB9UTepJu19M_t8qxKT^Ag#B#85f)NJ=w5970iGY zD%^NRO}M)B9057?#A2-tJ#3sW;L6Bg_3=!+ytc1}-&uf9XAtE4*PWkd+3Y9o?_=6YYg)hGb4lB#eT}@1s0QVV zl#-J5kgNA_Or+<@-L|fBuk44N!Ppscll@@l``gvJX^jZf;rK@lzTnM^dq(LI!T6$& ziHv$;AcDwZKoElhon2k0PnXm-dm60Mxh5k9_62q$)D?*K7gk0kEty}j9Aj{wx}VGV ztq zMqpbCY*nLFW40Va;(8vRDH`7w%{b zB_8keZGp#pvh(|kkd_E0&PMo%gl&Cp>|xjItM?xEHrxj_E8ZZ(bwvDY2O4 zkyeKaY;Xd$`60!_VykoGnV(b>PPC@Lo@?bA<5pHydehU>GYBjczC{*M@A|LN;&Iar z&cm}M^M8zc){TM{zAF7O@4_>qCqCeo?NRXB`*fv;@pbfcXlEqCF2}v*)doSsT6E>8 zmeqEx_Fg@W_x2vq2~f0}wC~N(zOgd&kh1)^$csZvLke3`DXaTzxj8iURfiNWY*Z!= zuIKl}T4)!9@W{a?@z?vES{#%}&pw(bwhpc4dpX{r9})+Kmax_j&M|Td`Cp@sRDYU# zh0X&UbO2ZLTXWOZDuJMpo|#{qCsglBiy9?re_B0*UQHpB*4lN+4#e0gD!%uUx7lM| zc-!7y{$Y4ZIdvwY(%1KFOQ3}Z%l8KeV_rasKai2n()46>HcqI7&%>C+(=Rsd^Wm)5 zF3Lh#2HNvEpi%mG!&!Zc4^YoNFZfVH-b-5jZgSKx;Y~65M^CJc8WJ(L_wZ1BIbUHt zyK(W8LB*6TX4M~9ccRl@-|=3*y3O+S7O|z0Zl*LTr@$_(O9*p0--#4Tn8D>HwtrG% z__A9U7K~p-`+DR`Hs#B+nBbZVyYxnAciwyo|mZbaq_Ld>uufTEG8BS zvG={_%X6Wv$b9w(m`erY*$h1&)f83v+}l|x8v8L1c6}^;5HQ+=-gC(%;Zbrb~$Hym=F&%HW_IPEiy2qy6c+l8JfA$x*>vF<0Rlh3< zJ!`G*K&+UYoGctkNp%pHkhp~418GU2$XJ)lrxPIH$>bO^9>sI17gi|Q$aU9S^hVk3 zA;K51uwuA&GEV1Q8Erk7dRQO!btHirgVJv%>J(V_(A*9i1~)UXYgYcVu_uDEfg>?4 z@I;B(g}&=SO{HBG7OOg{aP#}kC@+1beP=i~FZ=1wc4hunqXKjBwSBtc4`i}PXe1iAb%`o?e zuoyK(WqI*;O}I>0GrQ}Fb$^@OPl`Fq+wqYu!x1-pXa1<`#2^zdQOp7Yj0c@Okrkw` zWE$x?ZKI|*-qkum`#y~;>oDHHK9!t%324;G@MvIo-d}e<{Q`((R~&OFt$?zZ<~dmp zJu$|IB$1x+C0G#?(9)dxhWf0{;B$~5zCq;=jW0ogigi&D4Sb?scEytMcDOhxegXh~ ze`e4#`6zVV+-gTGsDqZQ=MMk@Q{f`-JRuZn;|9PXlNP2?w*&xnl9%R*!G09LQcGR~8+CB%=IONPxOHWftd5}IbTm8zPwc|GT zn%4OqXGwPTjj{T+$NCAe+3p!?M3i-`r?IbJ!e9tegX?s3ba{UmUgC8?#L`ly+7%#v zqG>T9O7}0G`K{{9%Edz!>36C`xlHosuKok2II5J+BTdF``{*V!=bR>fVADK>^yfJT zGcRMvk|R2`C4oU$bm6YD#0anoBe*i5oAx^t6huW>-mwbquMI(#Cv@A*>ED6V{fm<0 zUwQ_A=#dAEMQKAA^sfFHDS(3CXUeojzlxN*y|jAYv8hS{JWUt$p(yHC5$L5afGg=R z6tqNMg`+#a0AWjBT9%eGVD0T3$A(a*tF(FwN{wQ1rwe7?qgddUEB0)_Rw$F80b0!z zi~g)o<~GG5Q7rZmq0C|$^_^NM_*UZuLnPY3{1f0p+G_y>wV}nD>H$pXB`;3!?f7WP zElWM-oTSJNf(W+GGK2N$_8xbUzNNMYWcTQ}NS-WtILS;~xx+vQ)-!a%BaQV*(m`vML-1SY^QzP@>A< zbKXl{lEK1=Vu!>&1e5*$?)o~1oUaH!M=%F}usk2-ZzScG&riH-Ce`aTkVV)4DCm!m zK$2a&*G22|yR~3k*?;ta^f7$b(R=MWGh&CUSWD2dA9W&D1(5XuL#4kgxQCAJ2z0oX z_>;m#jR)b>4)ogLqk^mr6^JYBxh0yoDj9H34j8j#SrPfj!sd z1C(lVPoCHRrmw5OMfIy66&I@rn1iF=9F0qQV<$!3kx3R2_5li~;*8#25tS4o+SBho zBgMb^UJDq_G-H?reZT2P(KCn4P`bW6)6zO|V=2z^%q4jqvDHwa{<8#QnG;%8DVz@RItuNP-MYxx#PyO$hxnJ}p#~)Pym$7+s zN}a6t2e$f7E5X441x%F~)1^HWW-$}8XI!4x>fEf&aNv~GS6-e8E?*?o$3Bf6Mm@st z6tYk}3{=Lh0dyKWEfpbO>Qr`gw$hM3;O;!Apcoeu$f7<2#|*J_P(d9o2FUA|J~X}9 z$PW^l=54@N?g=gRA;-J2D9wd-;H!|5mU`D;Yq$mYda+(p9UrC$o*QljzDg@;sxSUy zf&H!(YpGj+4sRUwgbO&s&J0N|bb<6AGYmkXEho$)(7(?By&3EXDd0*QNawQ@w6?83 z=f>1hW*Ph;ym;a`cy<3WFMee0B$2u9!^3)JkO!Ds&ivPQy(|A20$}ukr5us>9UG^* zeNF8ogL$~{J9z^5r>3!oq*NQn_n}8s<*zmv#U3?T8>7l$p}$>Qf{u=V=9f3oWD=N+ zhzEqf%rM%y61VGrmv?9kuAo)>M;wPkJtK}h8&{QftXJ$Thv6sjKWVhBng8JhEr0q2 zMyQSBi~ln&Mnu3T)8%CjiE^1aVfL1iqOh^<`Bc<|h>6{BA&G$d4qfNOn_AeT(4FGa z*ByE@qQGGGkfJ`9?W%8J3Ie*RJ@AGVbo!O?6K1DC{cX+#h@6T9{Kl{U*fBxU$|KMD%#4~mBbK`Ae96>lUFj_%_>Z98zPJL32jR}%YaP9D8YVqqu zq3{m5V{ELfRGfWZF9Sp|j^|KNqR~gPOouNy-u;W_3NxPr?iNE>M+Bg@=j?IGzAgRi zQX=}|{AEYV#JHcKx#;|@<~N}-@9zC~gc$z~Hz-B%wS1Nzl=44mFn3pZhKsa!_4h9) z*X5~TT=f)OAx_eOj-4o$Ox8`NS+GMWRRlZc{^Sc=3gL#n^a|ypNK?|;%97NxZ#CKB9_>M*H4^CmhKw5wl z;%Gas&0h_uhaD4KwsFmCFU$3X4VkCwYa21-vwM~Tj-dQr{l$eL4I7s?zb3^OOJssL zDZSf!udtcnb6X22RQ|W@TCN#&MX0G_0Cnp$fKFEs;z+5@J?TW@ps+9mU#Z9Jx91$7 z+@Y>HG%luU3Eur#llq4KHOL4Q5p+(T0JZ`ZJE9_*L;r}N%2ytw_F_J!-paX3{ihW zEJEE^y2Ws|JDlU>qYr13+|d6>FOUYDlzO8O|34Q@Hy;F03x_YTb@>=@wz`c|Q6$s9 z_+pL9%~S6&1_<$ggR1Xupr`{DYVbv@u*Q7Of#FEiM>VD_4 zXfnanhC&E;I&7YVfK3#E_3wN^iaN^Z1RXkBd{rBykOfF2FhIflrhkP)E4!c)D55Tb zkp@ymoDLV2wp_B;eR6Y|C= z27lTU4l4xx^2E=`*QfcJK?R?!FhkD%wM?Nl4d zm!iI(oegFPVw9gB=$o9Ts^|adxRM3M-O$enl>c9G;P#mbW+xUE<*lh=whb?y> zwk$E;y*gX}VO0ivarMQAZ|HgjPtAYq4R literal 9458 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 diff --git a/icons/obj/technomancer.dmi b/icons/obj/technomancer.dmi index 7fc48d0a753305b3a4f820165738b126dd574059..668ee5f06c1455c18b3bf01fc159ee3b31063156 100644 GIT binary patch delta 730 zcmV<00ww*h1da!gBms(%B|2$INlC}Y$E&NWnwpw-cXwZ3UuFh@Ej5CI^Ijc&eSKM3S(yL;*Z=?k001Lp{s1%o0L=gY{{a90|4LI@|IB7! zf|mLK0004WQchC^7sGttfKt8D-P0vkz0K~z|U?N(t^qc9YNCZR=X8`F>wMec01B_96&zjym^ zs*WV6_~qtgXY|V^n|&{jY?EZhjDHX5f-TbNJXIQ~!NvvethSf*Kc#Yg;#W%e~jqfco#zspR&=$sQGuLow(BSli#gkFXhE!m z^8pba77JJ`(r6P$`6Q89%F!gAW^xjr2$@}BP_8m5Ch<4{bHHg1Vh%6|oaP|n02Xs5 zSw2$2D32AA?uW^#{EQhhejF6xJNtJ#U786B)+%M`a065kfq#+wx27aGXZjLcNMS7h zt#Qs>yPMkeCETiVsDR{YkpE3EJQW0fl{c`UZh6fUEkH`5=@|m z)r*6`er5JG0UJ$^z)hkAj_~B65|q{lbHKiXGY(DAE^v_$VC(IMg#@g=ub**mc4((7 zjSZF1|2_znV1IS}a6Fyb<3nw=B@6{9{{>1Af&9n4*T<9hkL{5J^dEG>cJCD^|Ix%i z{wvpEmw)u$SK2z9uPnOpUIFV7Rl&fMuPO-i4!XfbN}2;sb1-nAl(u_M z7WVtI1AH075*p-xGb{leLl4>~@2LmmphOSMunDpJCr`h)g|>aU1vu!w@JTD9-pql1 zcA&oUCUlrYOpkE}-_-8hgU|0L6L?Je=LEngnki4xt62BFNAbVIU-3FKcn`}qIRF3v M07*qoM6N<$g6DKrasU7T delta 394 zcmV;50d@Y42e1T?BmqB>B|09!z`%;9r!|6tHca~D00001bW%=J06^y0W&i*Hfsx2r ze^rT#GbOXA7$|4R#hF%=n41b>8v{jCa}p~-!a6|6rL5rU=K{770M8d9mhsF3tN;K3 z5=lfsR9J=WR>7{rAPj>hp<|;h6Z`*foil0g^g^VZcED15aY$?$$xUft;rEa?+H#zy zjaV4(C|~j}B6}|XS9tu5O1#Ts&5E zxgGu##LlY)MtE}6f;OPzIw{-$7C!$6Q45;?0t;g1zX#2KT%w)-9+3YXi`32h_Z46V oSoa{P02T)Fe}pZp{9lOU4Thc!5+)w7^Z)<=07*qoM6N<$f<5WCqyPW_ diff --git a/polaris.dme b/polaris.dme index fe46804c7e..bf4d3b3eaf 100644 --- a/polaris.dme +++ b/polaris.dme @@ -356,18 +356,29 @@ #include "code\game\gamemodes\technomancer\spells\darkness.dm" #include "code\game\gamemodes\technomancer\spells\discharge.dm" #include "code\game\gamemodes\technomancer\spells\flame_tongue.dm" +#include "code\game\gamemodes\technomancer\spells\instability_tap.dm" +#include "code\game\gamemodes\technomancer\spells\mark_recall.dm" +#include "code\game\gamemodes\technomancer\spells\oxygenate.dm" #include "code\game\gamemodes\technomancer\spells\passwall.dm" #include "code\game\gamemodes\technomancer\spells\phase_shift.dm" #include "code\game\gamemodes\technomancer\spells\pulsar.dm" #include "code\game\gamemodes\technomancer\spells\radiance.dm" +#include "code\game\gamemodes\technomancer\spells\reflect.dm" #include "code\game\gamemodes\technomancer\spells\resurrect.dm" #include "code\game\gamemodes\technomancer\spells\shared_burden.dm" #include "code\game\gamemodes\technomancer\spells\shield.dm" #include "code\game\gamemodes\technomancer\spells\warp_strike.dm" +#include "code\game\gamemodes\technomancer\spells\aspect\aspect.dm" +#include "code\game\gamemodes\technomancer\spells\aspect\aspect_weapon.dm" +#include "code\game\gamemodes\technomancer\spells\insert\corona.dm" #include "code\game\gamemodes\technomancer\spells\insert\insert.dm" #include "code\game\gamemodes\technomancer\spells\insert\mend_burns.dm" #include "code\game\gamemodes\technomancer\spells\insert\mend_wounds.dm" #include "code\game\gamemodes\technomancer\spells\insert\purify.dm" +#include "code\game\gamemodes\technomancer\spells\insert\repel_missiles.dm" +#include "code\game\gamemodes\technomancer\spells\projectile\chain_lightning.dm" +#include "code\game\gamemodes\technomancer\spells\projectile\lightning.dm" +#include "code\game\gamemodes\technomancer\spells\projectile\projectile.dm" #include "code\game\gamemodes\traitor\traitor.dm" #include "code\game\gamemodes\wizard\wizard.dm" #include "code\game\jobs\_access_defs.dm"