mirror of
https://github.com/Aurorastation/Aurora.3.git
synced 2026-08-29 07:59:01 +01:00
Psionics Rework: Kyoushiki Murasaki (#16951)
* Your unbeatable smile wrecks the media We wanna know your secret, so mysterious * Even the things she lacks end up in her area Such a perfect liar, you are * Miss ingenious, godly idol! (You're my savior, you're my saving grace) * So, what'd you eat today? What's your favorite book? * And if you wanna go to play, where are you gonna go? I haven't eaten at all * That's a secret No matter what you ask * She's elusive, evasive * So nonchalant Yet still shining bright; * Her secret: out of sight, as if visible, has the taste of honey There is none, none, none of this * And also none, none, none of that What type of guy do you like? * Who is your partner? Come on, answer me * "I don't understand what falling in love with someone else is like" (Hey! Hey!) I cannot tell what is true from what is a lie (Hey! Hey! Hey! Hey!) * And yet again, someone falls for such words (Hey! Hey! Hey! Hey!) Gently lulled into love * Drawing everyone's eyes You are the perfect, ultimate idol * Never to appear again A reincarnation of Venus * With that smile, with that "I love you" You captivate everyone * Even if those eyes, those words, are false They make up a perfect love (Ai) * Yeah, yeah, that girl stands out, exceptional We were extras from the beginning * BS that acted as adornments for the star's leading role Everything we've accomplished is thanks to her — no! * How impudent How could envy and jealousy not exist? * examine * This isn't some made-up drama for appearances So I cannot forgive * You're not perfect, I cannot forgive you I cannot forgive myself * I cannot accept any version of you other than the one stronger than everyone else * Everybody trusts and worships The very strongest, most invincible idol * Weaknesses and whatnot are not to be found Carrying the morning star within * Showing any weakness is no good, no good (Hey! Hey!) Don't let them see anything that they don't want to know (Hey! Hey! Hey! Hey!) * Anything but being one-of-a-kind is a definite no, no (Hey! Hey! Hey! Hey!) That is the real love (Hey!) * can commune fixes * can commune rename * fix is psi blocked * fixes agian * My signature smile that fires up the media The only secret that I shall keep is this: * My career was built upon fake "I love you"s This is love, in my own way * Even the flowing sweats are beautiful Aqua These eyelids that hid the Ruby within * Sing, dance, flutter, I am Maria — Right, lying is the most exquisite form of love * I have never been loved by anyone Nor have I loved anyone else * That such lies of mine will become true someday I trust in it * Someday, surely, I will have it all in hand I am such a greedy idol * Because I wish to love everybody properly in a life-sized way I shall lie today as well (Hey! Hey! Hey! Hey!) * a * b * c * d * And yet, still, (Hey! Hey!) I have been unable to tell you, and you, alone (Hey! Hey! Hey! Hey!) * jesus christ * Update code/controllers/subsystems/processing/psi.dm Co-authored-by: Fluffy <65877598+FluffyGhoster@users.noreply.github.com> * Update code/controllers/subsystems/processing/psi.dm Co-authored-by: Fluffy <65877598+FluffyGhoster@users.noreply.github.com> * Update code/controllers/subsystems/processing/psi.dm Co-authored-by: Fluffy <65877598+FluffyGhoster@users.noreply.github.com> * Update code/game/gamemodes/technomancer/spell_objs.dm Co-authored-by: Fluffy <65877598+FluffyGhoster@users.noreply.github.com> * Update code/modules/mob/living/carbon/human/human.dm Co-authored-by: Fluffy <65877598+FluffyGhoster@users.noreply.github.com> * Update code/modules/mob/living/carbon/human/human_helpers.dm Co-authored-by: Fluffy <65877598+FluffyGhoster@users.noreply.github.com> * Update code/modules/organs/organ_external.dm Co-authored-by: Fluffy <65877598+FluffyGhoster@users.noreply.github.com> * Update code/modules/psionics/abilities/assay.dm Co-authored-by: Fluffy <65877598+FluffyGhoster@users.noreply.github.com> * Update code/modules/psionics/abilities/command.dm Co-authored-by: Fluffy <65877598+FluffyGhoster@users.noreply.github.com> * Update code/modules/psionics/abilities/emotional_suggestion.dm Co-authored-by: Fluffy <65877598+FluffyGhoster@users.noreply.github.com> * Update code/modules/psionics/abilities/grip.dm Co-authored-by: Fluffy <65877598+FluffyGhoster@users.noreply.github.com> * Update code/modules/psionics/abilities/grip.dm Co-authored-by: Fluffy <65877598+FluffyGhoster@users.noreply.github.com> * Update code/modules/psionics/abilities/mend.dm Co-authored-by: Fluffy <65877598+FluffyGhoster@users.noreply.github.com> * Update code/modules/psionics/abilities/mend.dm Co-authored-by: Fluffy <65877598+FluffyGhoster@users.noreply.github.com> * Update code/modules/psionics/abilities/mend.dm Co-authored-by: Fluffy <65877598+FluffyGhoster@users.noreply.github.com> * Update code/modules/psionics/abilities/psi_search.dm Co-authored-by: Fluffy <65877598+FluffyGhoster@users.noreply.github.com> * Update code/modules/psionics/abilities/shockwave.dm Co-authored-by: Fluffy <65877598+FluffyGhoster@users.noreply.github.com> * Update code/modules/psionics/abilities/shockwave.dm Co-authored-by: Fluffy <65877598+FluffyGhoster@users.noreply.github.com> * Update code/modules/psionics/abilities/singularity.dm Co-authored-by: Fluffy <65877598+FluffyGhoster@users.noreply.github.com> * Update code/modules/psionics/abilities/time_stop.dm Co-authored-by: Fluffy <65877598+FluffyGhoster@users.noreply.github.com> * Update code/modules/psionics/events/mini_spasm.dm Co-authored-by: Fluffy <65877598+FluffyGhoster@users.noreply.github.com> * Update code/modules/psionics/interface/ui_hub.dm Co-authored-by: Fluffy <65877598+FluffyGhoster@users.noreply.github.com> * Update code/modules/psionics/interface/ui_hub.dm Co-authored-by: Fluffy <65877598+FluffyGhoster@users.noreply.github.com> * Update code/modules/psionics/interface/ui_hub.dm Co-authored-by: Fluffy <65877598+FluffyGhoster@users.noreply.github.com> * Update code/modules/psionics/interface/ui_hub.dm Co-authored-by: Fluffy <65877598+FluffyGhoster@users.noreply.github.com> * Update code/modules/psionics/interface/ui_hub.dm Co-authored-by: Fluffy <65877598+FluffyGhoster@users.noreply.github.com> * Update code/modules/psionics/interface/ui_hub.dm Co-authored-by: Fluffy <65877598+FluffyGhoster@users.noreply.github.com> * cl update --------- Co-authored-by: Matt Atlas <liermattia@gmail.com> Co-authored-by: Fluffy <65877598+FluffyGhoster@users.noreply.github.com>
This commit is contained in:
co-authored by
Fluffy
Matt Atlas
parent
a894c77990
commit
d9b79db97b
@@ -0,0 +1,5 @@
|
||||
--
|
||||
-- Adds psionic prefs
|
||||
--
|
||||
|
||||
ALTER TABLE `ss13_characters` ADD COLUMN `psionics` LONGTEXT DEFAULT null AFTER `origin`;
|
||||
+45
-10
@@ -1586,6 +1586,7 @@
|
||||
#include "code\modules\client\preference_setup\general\04_equipment.dm"
|
||||
#include "code\modules\client\preference_setup\general\05_background.dm"
|
||||
#include "code\modules\client\preference_setup\general\06_flavor.dm"
|
||||
#include "code\modules\client\preference_setup\general\07_psionics.dm"
|
||||
#include "code\modules\client\preference_setup\global\01_ui.dm"
|
||||
#include "code\modules\client\preference_setup\global\02_settings.dm"
|
||||
#include "code\modules\client\preference_setup\global\03_language.dm"
|
||||
@@ -2891,32 +2892,66 @@
|
||||
#include "code\modules\projectiles\targeting\targeting_mob.dm"
|
||||
#include "code\modules\projectiles\targeting\targeting_overlay.dm"
|
||||
#include "code\modules\projectiles\targeting\targeting_triggers.dm"
|
||||
#include "code\modules\psionics\abilities\_ability.dm"
|
||||
#include "code\modules\psionics\abilities\air_bullet.dm"
|
||||
#include "code\modules\psionics\abilities\assay.dm"
|
||||
#include "code\modules\psionics\abilities\barrier.dm"
|
||||
#include "code\modules\psionics\abilities\bubble.dm"
|
||||
#include "code\modules\psionics\abilities\charge.dm"
|
||||
#include "code\modules\psionics\abilities\command.dm"
|
||||
#include "code\modules\psionics\abilities\commune.dm"
|
||||
#include "code\modules\psionics\abilities\electrocute.dm"
|
||||
#include "code\modules\psionics\abilities\emotional_suggestion.dm"
|
||||
#include "code\modules\psionics\abilities\focus.dm"
|
||||
#include "code\modules\psionics\abilities\grip.dm"
|
||||
#include "code\modules\psionics\abilities\hollow_purple.dm"
|
||||
#include "code\modules\psionics\abilities\ion.dm"
|
||||
#include "code\modules\psionics\abilities\jump.dm"
|
||||
#include "code\modules\psionics\abilities\lightning.dm"
|
||||
#include "code\modules\psionics\abilities\mend.dm"
|
||||
#include "code\modules\psionics\abilities\mind_muddle.dm"
|
||||
#include "code\modules\psionics\abilities\mirror_shade.dm"
|
||||
#include "code\modules\psionics\abilities\nlom_eyes.dm"
|
||||
#include "code\modules\psionics\abilities\psi_awakening.dm"
|
||||
#include "code\modules\psionics\abilities\psi_drain.dm"
|
||||
#include "code\modules\psionics\abilities\psi_punch.dm"
|
||||
#include "code\modules\psionics\abilities\psi_recovery.dm"
|
||||
#include "code\modules\psionics\abilities\psi_search.dm"
|
||||
#include "code\modules\psionics\abilities\psi_stamina.dm"
|
||||
#include "code\modules\psionics\abilities\psi_sunder.dm"
|
||||
#include "code\modules\psionics\abilities\psi_suppression.dm"
|
||||
#include "code\modules\psionics\abilities\psi_sword.dm"
|
||||
#include "code\modules\psionics\abilities\psi_tool.dm"
|
||||
#include "code\modules\psionics\abilities\pull.dm"
|
||||
#include "code\modules\psionics\abilities\read_mind.dm"
|
||||
#include "code\modules\psionics\abilities\rejuvenate.dm"
|
||||
#include "code\modules\psionics\abilities\rend.dm"
|
||||
#include "code\modules\psionics\abilities\shockwave.dm"
|
||||
#include "code\modules\psionics\abilities\singularity.dm"
|
||||
#include "code\modules\psionics\abilities\skinsight.dm"
|
||||
#include "code\modules\psionics\abilities\spasm.dm"
|
||||
#include "code\modules\psionics\abilities\stasis.dm"
|
||||
#include "code\modules\psionics\abilities\throw.dm"
|
||||
#include "code\modules\psionics\abilities\time_stop.dm"
|
||||
#include "code\modules\psionics\abilities\warp.dm"
|
||||
#include "code\modules\psionics\abilities\zona_absorption.dm"
|
||||
#include "code\modules\psionics\complexus\complexus.dm"
|
||||
#include "code\modules\psionics\complexus\complexus_helpers.dm"
|
||||
#include "code\modules\psionics\complexus\complexus_latency.dm"
|
||||
#include "code\modules\psionics\complexus\complexus_power_cache.dm"
|
||||
#include "code\modules\psionics\complexus\complexus_process.dm"
|
||||
#include "code\modules\psionics\equipment\cerebro_enhancers.dm"
|
||||
#include "code\modules\psionics\equipment\psipower.dm"
|
||||
#include "code\modules\psionics\equipment\psipower_blade.dm"
|
||||
#include "code\modules\psionics\equipment\psipower_tinker.dm"
|
||||
#include "code\modules\psionics\equipment\psipower_tk.dm"
|
||||
#include "code\modules\psionics\events\_psi.dm"
|
||||
#include "code\modules\psionics\events\mini_spasm.dm"
|
||||
#include "code\modules\psionics\events\psi_balm.dm"
|
||||
#include "code\modules\psionics\events\psi_wail.dm"
|
||||
#include "code\modules\psionics\faculties\_faculty.dm"
|
||||
#include "code\modules\psionics\faculties\_power.dm"
|
||||
#include "code\modules\psionics\faculties\coercion.dm"
|
||||
#include "code\modules\psionics\faculties\energistics.dm"
|
||||
#include "code\modules\psionics\faculties\psychokinesis.dm"
|
||||
#include "code\modules\psionics\faculties\redaction.dm"
|
||||
#include "code\modules\psionics\interface\ui.dm"
|
||||
#include "code\modules\psionics\interface\ui_hub.dm"
|
||||
#include "code\modules\psionics\mob\armour.dm"
|
||||
#include "code\modules\psionics\mob\mob.dm"
|
||||
#include "code\modules\psionics\mob\mob_assay.dm"
|
||||
#include "code\modules\psionics\mob\mob_helpers.dm"
|
||||
#include "code\modules\psionics\mob\mob_interactions.dm"
|
||||
#include "code\modules\radiation\radiation.dm"
|
||||
#include "code\modules\random_map\_random_map_setup.dm"
|
||||
#include "code\modules\random_map\random_map.dm"
|
||||
|
||||
@@ -30,11 +30,11 @@
|
||||
#define FONT_SIZE_HUGE 4
|
||||
#define FONT_SIZE_GIANT 5
|
||||
|
||||
#define FONT_SMALL(X) ("<font size='1'>" + X + "</font>")
|
||||
#define FONT_NORMAL(X) ("<font size='2'>" + X + "</font>")
|
||||
#define FONT_LARGE(X) ("<font size='3'>" + X + "</font>")
|
||||
#define FONT_HUGE(X) ("<font size='4'>" + X + "</font>")
|
||||
#define FONT_GIANT(X) ("<font size='5'>" + X + "</font>")
|
||||
#define FONT_SMALL(X) ("<font size=1>" + X + "</font>")
|
||||
#define FONT_NORMAL(X) ("<font size=2>" + X + "</font>")
|
||||
#define FONT_LARGE(X) ("<font size=3>" + X + "</font>")
|
||||
#define FONT_HUGE(X) ("<font size=4>" + X + "</font>")
|
||||
#define FONT_GIANT(X) ("<font size=5>" + X + "</font>")
|
||||
|
||||
#define MATRIX_DANGER(X) (FONT_LARGE(SPAN_DANGER(X)))
|
||||
#define MATRIX_NOTICE(X) (FONT_LARGE(SPAN_NOTICE(X)))
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
#define DAMAGE_FLAG_EXPLODE 16
|
||||
#define DAMAGE_FLAG_DISPERSED 32 // Makes apply_damage calls without specified zone distribute damage rather than randomly choose organ (for humans)
|
||||
#define DAMAGE_FLAG_BIO 64
|
||||
#define DAMAGE_FLAG_PSIONIC 128
|
||||
|
||||
#define STUN "stun"
|
||||
#define WEAKEN "weaken"
|
||||
|
||||
+16
-10
@@ -1,11 +1,17 @@
|
||||
#define PSI_COERCION "coercion"
|
||||
#define PSI_PSYCHOKINESIS "psychokinesis"
|
||||
#define PSI_REDACTION "redaction"
|
||||
#define PSI_ENERGISTICS "energistics"
|
||||
#define PSI_RANK_SENSITIVE 1 /// Psionically sensitive. Skrell.
|
||||
#define PSI_RANK_HARMONIOUS 2 /// Psionically harmonious. Event Skrell, antagonists.
|
||||
#define PSI_RANK_APEX 3 /// Psionic apex. Event people.
|
||||
#define PSI_RANK_LIMITLESS 4 /// Admin-only. Yes, it's a Gojou Satoru reference.
|
||||
|
||||
#define PSI_RANK_BLUNT 0
|
||||
#define PSI_RANK_LATENT 1
|
||||
#define PSI_RANK_OPERANT 2
|
||||
#define PSI_RANK_MASTER 3
|
||||
#define PSI_RANK_GRANDMASTER 4
|
||||
#define PSI_RANK_PARAMOUNT 5
|
||||
#define PSI_FLAG_CANON 1 /// An ability that can be selected by a ship character.
|
||||
#define PSI_FLAG_EVENT 2 /// An ability for event characters, not selectable by ship characters, so technically canon.
|
||||
#define PSI_FLAG_ANTAG 4 /// An ability for antag characters, not selectable by ship characters, not really canon.
|
||||
#define PSI_FLAG_FOUNDATIONAL 8 /// An ability automatically given to Psionically Sensitive users.
|
||||
#define PSI_FLAG_APEX 16 /// An ability automatically given to Psionic Apex users.
|
||||
#define PSI_FLAG_LIMITLESS 32 /// An ability automatically given to Limitless users.
|
||||
#define PSI_FLAG_SPECIAL 64 /// Unselectable in the point shop - must be handed out manually.
|
||||
|
||||
/// Psi shop points given by a certain rank.
|
||||
#define PSI_POINTS_HARMONIOUS 10
|
||||
#define PSI_POINTS_APEX 14
|
||||
#define PSI_POINTS_LIMITLESS 40
|
||||
|
||||
@@ -139,6 +139,24 @@
|
||||
/// forces the mob to speak gibberish, like highly damaged borgs
|
||||
#define TRAIT_SPEAKING_GIBBERISH "speaking_gibberish"
|
||||
|
||||
/// Mob does not need to breathe.
|
||||
#define TRAIT_NO_BREATHE "no_breathe"
|
||||
|
||||
/// Mob has pressure immunity.
|
||||
#define TRAIT_PRESSURE_IMMUNITY "pressure_immunity"
|
||||
|
||||
/// Trait sourced from changeling abilities.
|
||||
#define TRAIT_SOURCE_CHANGELING "changeling"
|
||||
|
||||
/// Mob is psionically deaf.
|
||||
#define TRAIT_PSIONICALLY_DEAF "psionically_deaf"
|
||||
|
||||
/// Zona bovinae absorbed, used by Loner to track a mob that has had its ZB consumed. Doesn't make them psi-deaf.
|
||||
#define TRAIT_ZONA_BOVINAE_ABSORBED "bovinae_absorbed"
|
||||
|
||||
/// Hidden from Psi-Search.
|
||||
#define TRAIT_PSIONIC_SUPPRESSION "psionic_suppression"
|
||||
|
||||
/// lets mobs that traditionally don't hallucinate, hallucinate
|
||||
#define TRAIT_BYPASS_HALLUCINATION_RESTRICTION "bypassing_hallucination_restriction"
|
||||
|
||||
@@ -153,3 +171,6 @@
|
||||
#define TRAIT_OVERLOADER_OD_INITIAL "overloader_od_initial"
|
||||
#define TRAIT_OVERLOADER_OD_MEDIUM "overloader_od_medium"
|
||||
#define TRAIT_OVERLOADER_OD_EFFECT "overloader_od_effect"
|
||||
|
||||
/// Traits given by psionics.
|
||||
#define TRAIT_SOURCE_PSIONICS "psionics"
|
||||
|
||||
@@ -126,6 +126,10 @@
|
||||
for(var/obj/screen/ability/A in ability_objects)
|
||||
remove_ability(A)
|
||||
|
||||
/obj/screen/movable/ability_master/proc/remove_all_psionic_abilities()
|
||||
for(var/obj/screen/ability/obj_based/psionic/A in ability_objects)
|
||||
remove_ability(A)
|
||||
|
||||
/obj/screen/movable/ability_master/proc/get_ability_by_name(name_to_search)
|
||||
for(var/obj/screen/ability/A in ability_objects)
|
||||
if(A.name == name_to_search)
|
||||
@@ -147,7 +151,7 @@
|
||||
/mob/living/LateLogin()
|
||||
. = ..()
|
||||
if(ability_master)
|
||||
ability_master.toggle_open(1)
|
||||
ability_master.toggle_open(2)
|
||||
client.screen -= ability_master
|
||||
|
||||
/mob/living/Initialize()
|
||||
@@ -183,10 +187,15 @@
|
||||
|
||||
overlays += ability_icon_state
|
||||
|
||||
/obj/screen/ability/Click()
|
||||
/obj/screen/ability/Click(var/location, var/control, var/params)
|
||||
if(!usr)
|
||||
return
|
||||
|
||||
var/list/click_params = params2list(params)
|
||||
if(click_params["shift"])
|
||||
examine(usr)
|
||||
return
|
||||
|
||||
activate()
|
||||
|
||||
/obj/screen/ability/MouseDrop(var/atom/A)
|
||||
@@ -283,13 +292,44 @@
|
||||
//////////////////////////////
|
||||
|
||||
/obj/screen/ability/obj_based
|
||||
var/obj/object = null
|
||||
var/obj/object
|
||||
|
||||
/obj/screen/ability/obj_based/activate()
|
||||
if(object)
|
||||
object.Click()
|
||||
|
||||
// Technomancer
|
||||
/// Psionics.
|
||||
/obj/screen/ability/obj_based/psionic
|
||||
icon_state = "nano_spell_base"
|
||||
background_base_state = "nano"
|
||||
var/singleton/psionic_power/connected_power
|
||||
|
||||
/obj/screen/ability/obj_based/psionic/Destroy()
|
||||
connected_power = null
|
||||
return ..()
|
||||
|
||||
/obj/screen/movable/ability_master/proc/add_psionic_ability(var/obj/object_given, var/ability_icon_given, var/singleton/psionic_power/P)
|
||||
if(!object_given)
|
||||
message_admins("ERROR: add_psionic_ability() was not given an object in its arguments.")
|
||||
if(!P)
|
||||
message_admins("Psionic ability added without connected psionic power singleton!")
|
||||
if(get_ability_by_instance(object_given))
|
||||
return // Duplicate
|
||||
var/obj/screen/ability/obj_based/psionic/A = new /obj/screen/ability/obj_based/psionic()
|
||||
A.ability_master = src
|
||||
A.object = object_given
|
||||
A.ability_icon_state = ability_icon_given
|
||||
A.name = object_given.name
|
||||
A.connected_power = P
|
||||
ability_objects.Add(A)
|
||||
if(my_mob.client)
|
||||
toggle_open(2) //forces the icons to refresh on screen
|
||||
|
||||
/obj/screen/ability/obj_based/psionic/examine(mob/user)
|
||||
to_chat(user, SPAN_NOTICE("<font size=4>This ability is <b>[connected_power.name]</b>.</font>"))
|
||||
to_chat(user, SPAN_NOTICE("[connected_power.desc]"))
|
||||
|
||||
/// Technomancer.
|
||||
/obj/screen/ability/obj_based/technomancer
|
||||
icon_state = "wiz_spell_base"
|
||||
background_base_state = "wiz"
|
||||
|
||||
@@ -1,40 +1,100 @@
|
||||
var/global/list/psychic_ranks_to_strings = list("Latent", "Operant", "Masterclass", "Grandmasterclass", "Paramount")
|
||||
var/global/list/psychic_ranks_to_strings = list("Psionically Sensitive", "Psionically Harmonious", "Psionic Apex", "Limitless")
|
||||
|
||||
/var/datum/controller/subsystem/processing/psi/SSpsi
|
||||
|
||||
/datum/controller/subsystem/processing/psi
|
||||
name = "Psychics"
|
||||
name = "Psionics"
|
||||
priority = SS_PRIORITY_PSYCHICS
|
||||
flags = SS_POST_FIRE_TIMING | SS_BACKGROUND
|
||||
flags = SS_BACKGROUND
|
||||
|
||||
var/list/faculties_by_id = list()
|
||||
var/list/faculties_by_name = list()
|
||||
var/list/all_aura_images = list()
|
||||
var/list/all_psi_complexes = list()
|
||||
var/list/psi_dampeners = list()
|
||||
var/list/psi_monitors = list()
|
||||
var/list/armor_faculty_by_type = list()
|
||||
var/list/faculties_by_intent = list()
|
||||
var/checking_nlom = FALSE
|
||||
var/last_nlom_awareness_check = 0
|
||||
var/completing_nlom = FALSE
|
||||
var/complete_nlom_time = 0
|
||||
var/list/nlom_votes = list()
|
||||
var/list/nlom_voters = list()
|
||||
var/list/all_aura_images = list()
|
||||
var/list/all_psi_complexes = list()
|
||||
|
||||
/datum/controller/subsystem/processing/psi/New()
|
||||
NEW_SS_GLOBAL(SSpsi)
|
||||
|
||||
/datum/controller/subsystem/processing/psi/proc/get_faculty(var/faculty)
|
||||
return faculties_by_name[faculty] || faculties_by_id[faculty]
|
||||
/datum/controller/subsystem/processing/psi/fire(resumed)
|
||||
..()
|
||||
if((world.time >= (last_nlom_awareness_check + 30 MINUTES)) && !checking_nlom && !completing_nlom)
|
||||
checking_nlom = TRUE
|
||||
nlom_votes = list(
|
||||
"Calm" = 0,
|
||||
"Happy" = 0,
|
||||
"Sad" = 0,
|
||||
"Fearful" = 0,
|
||||
"Angry" = 0,
|
||||
"Stressed" = 0,
|
||||
"Confused" = 0
|
||||
)
|
||||
for(var/datum/psi_complexus/PC in all_psi_complexes)
|
||||
if(PC.psionic_rank >= PSI_RANK_SENSITIVE)
|
||||
to_chat(PC.owner, SPAN_NOTICE(FONT_HUGE("The Nlom field prompts you for your emotional state.")))
|
||||
to_chat(PC.owner,
|
||||
"<a href='?src=\ref[src];emotion=Calm;voter=[ref(PC)]'>Calm</a> | <a href='?src=\ref[src];emotion=Happy;voter=[ref(PC)]'>Happy</a> | \
|
||||
<a href='?src=\ref[src];emotion=Sad;voter=[ref(PC)]'>Sad</a> | <a href='?src=\ref[src];emotion=Fearful;voter=[ref(PC)]'>Fearful</a> | \
|
||||
<a href='?src=\ref[src];emotion=Angry;voter=[ref(PC)]'>Angry</a> | <a href='?src=\ref[src];emotion=Stressed;voter=[ref(PC)]'>Stressed</a> | \
|
||||
<a href='?src=\ref[src];emotion=Confused;voter=[ref(PC)]'>Confused</a")
|
||||
complete_nlom_time = world.time + 2 MINUTES
|
||||
completing_nlom = TRUE
|
||||
if(completing_nlom && world.time >= complete_nlom_time)
|
||||
var/highest_emotion = "Happy"
|
||||
for(var/emotion in nlom_votes)
|
||||
if(nlom_votes[highest_emotion] < nlom_votes[emotion])
|
||||
highest_emotion = emotion
|
||||
for(var/datum/psi_complexus/PC in all_psi_complexes)
|
||||
if(PC.psionic_rank >= PSI_RANK_SENSITIVE)
|
||||
var/static/nlom_to_span = list(
|
||||
"Calm" = "good",
|
||||
"Happy" = "good",
|
||||
"Sad" = "notice",
|
||||
"Fearful" = "alien",
|
||||
"Angry" = "danger",
|
||||
"Stressed" = "warning",
|
||||
"Confused" = "cult"
|
||||
)
|
||||
var/static/nlom_to_chat_text = list(
|
||||
"Calm" = "calmness",
|
||||
"Happy" = "happiness",
|
||||
"Sad" = "sadness",
|
||||
"Fearful" = "fear",
|
||||
"Angry" = "anger",
|
||||
"Stressed" = "stress",
|
||||
"Confused" = "confusion"
|
||||
)
|
||||
if(nlom_votes[highest_emotion] > 0)
|
||||
to_chat(PC.owner, SPAN_NOTICE(FONT_HUGE("A sense of <b><span class='[nlom_to_span[highest_emotion]]'>[nlom_to_chat_text[highest_emotion]]</span></b> washes over you.")))
|
||||
else
|
||||
to_chat(PC.owner, SPAN_WARNING(FONT_HUGE("The Nlom is silent and still. You feel uneasy.")))
|
||||
checking_nlom = FALSE
|
||||
completing_nlom = FALSE
|
||||
last_nlom_awareness_check = world.time
|
||||
nlom_votes.Cut()
|
||||
nlom_voters.Cut()
|
||||
|
||||
/datum/controller/subsystem/processing/psi/Initialize()
|
||||
/datum/controller/subsystem/processing/psi/Topic(href, href_list)
|
||||
. = ..()
|
||||
if(.)
|
||||
return
|
||||
|
||||
var/list/faculties = subtypesof(/datum/psionic_faculty)
|
||||
for(var/ftype in faculties)
|
||||
var/datum/psionic_faculty/faculty = new ftype
|
||||
faculties_by_id[faculty.id] = faculty
|
||||
faculties_by_name[faculty.name] = faculty
|
||||
faculties_by_intent[faculty.associated_intent] = faculty.id
|
||||
|
||||
var/list/powers = subtypesof(/datum/psionic_power)
|
||||
for(var/ptype in powers)
|
||||
var/datum/psionic_power/power = new ptype
|
||||
if(power.faculty)
|
||||
var/datum/psionic_faculty/faculty = get_faculty(power.faculty)
|
||||
if(faculty)
|
||||
faculty.powers |= power
|
||||
if(href_list["emotion"])
|
||||
var/emotion = href_list["emotion"]
|
||||
var/datum/psi_complexus/PC = locate(href_list["voter"])
|
||||
if(PC in nlom_voters)
|
||||
to_chat(PC.owner, SPAN_WARNING("You have already sent your emotional state to the Nlom."))
|
||||
return
|
||||
if(emotion in nlom_votes)
|
||||
var/base_vote = 1
|
||||
var/psi_rank = PC.get_rank()
|
||||
if(psi_rank == PSI_RANK_HARMONIOUS)
|
||||
base_vote = 2
|
||||
else if(psi_rank == PSI_RANK_APEX)
|
||||
base_vote = 4
|
||||
nlom_votes[emotion] += base_vote
|
||||
to_chat(PC.owner, SPAN_NOTICE("You have transmitted your emotional state to the Nlom."))
|
||||
nlom_voters |= PC
|
||||
|
||||
+11
-6
@@ -112,7 +112,7 @@
|
||||
new_character.make_vampire()
|
||||
if(active)
|
||||
new_character.key = key //now transfer the key to link the client to our new body
|
||||
|
||||
|
||||
|
||||
/datum/mind/proc/store_memory(new_text)
|
||||
. = length(memory + new_text)
|
||||
@@ -179,11 +179,6 @@
|
||||
/datum/mind/Topic(href, href_list)
|
||||
if(!check_rights(R_ADMIN)) return
|
||||
|
||||
if(current && isliving(current))
|
||||
if(href_list["set_psi_faculty"] && href_list["set_psi_faculty_rank"])
|
||||
current.set_psi_rank(href_list["set_psi_faculty"], text2num(href_list["set_psi_faculty_rank"]))
|
||||
return TRUE
|
||||
|
||||
if(href_list["add_antagonist"])
|
||||
var/datum/antagonist/antag = all_antag_types[href_list["add_antagonist"]]
|
||||
if(antag)
|
||||
@@ -441,6 +436,16 @@
|
||||
for(var/datum/objective/objective in objectives)
|
||||
to_chat(current, "<B>Objective #[obj_count]</B>: [objective.explanation_text]")
|
||||
obj_count++
|
||||
|
||||
else if(href_list["set_psi_rank"])
|
||||
current.set_psi_rank(text2num(href_list["set_psi_rank"]))
|
||||
return
|
||||
else if(href_list["set_psi_rank_limitless"])
|
||||
var/sure = input(usr, "Limitless is INTENTIONALLY STUPIDLY OVERPOWERED! YOU SHOULD NOT BE USING THIS WITHOUT KNOWING EXACTLY WHAT YOU'RE DOING!", "Don't Get A Staff Complaint") as anything in list("I know what I'm doing!", "I fear no man. But that thing... it scares me!")
|
||||
if(sure == "I know what I'm doing!")
|
||||
current.set_psi_rank(PSI_RANK_LIMITLESS)
|
||||
return
|
||||
|
||||
edit_memory()
|
||||
|
||||
/datum/mind/proc/find_syndicate_uplink()
|
||||
|
||||
@@ -172,7 +172,6 @@
|
||||
/datum/outfit/admin/syndicate/mercenary/loner
|
||||
name = "Loner"
|
||||
|
||||
head = /obj/item/clothing/head/helmet/space/psi_amp/lesser
|
||||
l_ear = /obj/item/device/radio/headset/syndicate
|
||||
r_pocket = /obj/item/device/special_uplink/burglar
|
||||
|
||||
|
||||
@@ -251,3 +251,8 @@
|
||||
name = ".50 Pistol"
|
||||
telecrystal_cost = 5
|
||||
path = /obj/item/gun/projectile/deagle/adhomai
|
||||
|
||||
/datum/uplink_item/item/visible_weapons/psionic_jumpstarter
|
||||
name = "Psionic Jumpstarter"
|
||||
telecrystal_cost = 19
|
||||
path = /obj/item/psionic_jumpstarter
|
||||
|
||||
@@ -7,8 +7,8 @@ var/datum/antagonist/loner/loners
|
||||
bantype = "loner"
|
||||
antag_indicator = "loner"
|
||||
landmark_id = "lonerspawn"
|
||||
welcome_text = "You are a Loner, someone underequipped to deal with the station. You will probably not survive for the whole round, so don't sweat it if you die!<br>\
|
||||
You are equipped with a lesser cerebro-enhancer, which allows you to unlock your psionic potential. Use it in-hand to choose your boosted faculty, then install it on your head."
|
||||
welcome_text = "You are a Loner, someone underequipped to deal with the station. You will probably not survive for the whole round, so don't sweat it if you die!<br> \
|
||||
You have a special psionic power that allows you to absorb a psionic energy from a being's Zona Bovinae, granting you an extra point to be used in the Point Shop."
|
||||
flags = ANTAG_OVERRIDE_JOB | ANTAG_CLEAR_EQUIPMENT | ANTAG_CHOOSE_NAME | ANTAG_VOTABLE | ANTAG_SET_APPEARANCE
|
||||
antaghud_indicator = "hudloner"
|
||||
required_age = 7
|
||||
@@ -39,8 +39,11 @@ var/datum/antagonist/loner/loners
|
||||
|
||||
player.preEquipOutfit(/datum/outfit/admin/syndicate/mercenary/loner, FALSE)
|
||||
player.equipOutfit(/datum/outfit/admin/syndicate/mercenary/loner, FALSE)
|
||||
player.set_psi_rank(PSI_RANK_HARMONIOUS)
|
||||
var/singleton/psionic_power/P = GET_SINGLETON(/singleton/psionic_power/zona_absorption)
|
||||
P.apply(player)
|
||||
player.force_update_limbs()
|
||||
player.update_eyes()
|
||||
player.regenerate_icons()
|
||||
|
||||
return TRUE
|
||||
return TRUE
|
||||
|
||||
@@ -10,9 +10,7 @@ var/global/list/possible_changeling_IDs = list("Alpha","Beta","Gamma","Delta","E
|
||||
var/chem_recharge_rate = 0.5
|
||||
var/chem_storage = 50
|
||||
var/sting_range = 1
|
||||
var/space_adapted = FALSE
|
||||
var/using_thermals = FALSE
|
||||
var/no_breathing = FALSE
|
||||
var/changelingID = "Changeling"
|
||||
var/geneticdamage = 0
|
||||
var/isabsorbing = 0
|
||||
|
||||
@@ -12,8 +12,7 @@
|
||||
|
||||
//removes the need to breathe, removes effects of very low pressure
|
||||
/mob/proc/changeling_spaceadaption()
|
||||
var/datum/changeling/changeling = mind.antag_datums[MODE_CHANGELING]
|
||||
changeling.space_adapted = TRUE
|
||||
ADD_TRAIT(src, TRAIT_PRESSURE_IMMUNITY, TRAIT_SOURCE_CHANGELING)
|
||||
return TRUE
|
||||
|
||||
/mob/proc/changeling_armor()
|
||||
@@ -22,8 +21,7 @@
|
||||
|
||||
//removes the need to breathe
|
||||
/mob/proc/changeling_nobreathing()
|
||||
var/datum/changeling/changeling = mind.antag_datums[MODE_CHANGELING]
|
||||
changeling.no_breathing = TRUE
|
||||
ADD_TRAIT(src, TRAIT_NO_BREATHE, TRAIT_SOURCE_CHANGELING)
|
||||
return TRUE
|
||||
|
||||
// HIVE MIND UPLOAD/DOWNLOAD DNA
|
||||
@@ -97,4 +95,4 @@ var/list/datum/absorbed_dna/hivemind_bank = list()
|
||||
absorbDNA(chosen_dna)
|
||||
to_chat(src, "<span class='notice'>We absorb the DNA of [S] from the air.</span>")
|
||||
feedback_add_details("changeling_powers", "HD")
|
||||
return TRUE
|
||||
return TRUE
|
||||
|
||||
@@ -356,7 +356,7 @@ var/list/all_technomancer_assistance = typesof(/datum/technomancer/assistance) -
|
||||
return
|
||||
var/obj/item/technomancer_core/core = H.get_technomancer_core()
|
||||
if(core)
|
||||
for(var/obj/spellbutton/spell in core.spells)
|
||||
for(var/obj/spellbutton/technomancer/spell in core.spells)
|
||||
for(var/datum/technomancer/spell/spell_datum in spell_instances)
|
||||
if(spell_datum.obj_path == spell.spellpath)
|
||||
budget += spell_datum.cost
|
||||
@@ -381,7 +381,7 @@ var/list/all_technomancer_assistance = typesof(/datum/technomancer/assistance) -
|
||||
// We sadly need to do special stuff here or else people who refund cores with spells will lose points permanently.
|
||||
if(istype(AM, /obj/item/technomancer_core))
|
||||
var/obj/item/technomancer_core/core = AM
|
||||
for(var/obj/spellbutton/spell in core.spells)
|
||||
for(var/obj/spellbutton/technomancer/spell in core.spells)
|
||||
for(var/datum/technomancer/spell/spell_datum in spell_instances)
|
||||
if(spell_datum.obj_path == spell.spellpath)
|
||||
budget += spell_datum.cost
|
||||
|
||||
@@ -178,17 +178,15 @@
|
||||
/obj/spellbutton
|
||||
name = "generic spellbutton"
|
||||
var/spellpath
|
||||
var/obj/item/technomancer_core/core
|
||||
var/ability_icon_state
|
||||
|
||||
/obj/spellbutton/New(loc, var/path, var/new_name, var/new_icon_state)
|
||||
/obj/spellbutton/Initialize(mapload, var/path, var/new_name, var/new_icon_state)
|
||||
. = ..()
|
||||
if(!path || !ispath(path))
|
||||
message_admins("ERROR: /obj/spellbutton/New() was not given a proper path!")
|
||||
qdel(src)
|
||||
message_admins("ERROR: /obj/spellbutton/Initialize() was not given a proper path!")
|
||||
return INITIALIZE_HINT_QDEL
|
||||
src.name = new_name
|
||||
src.spellpath = path
|
||||
src.loc = loc
|
||||
src.core = loc
|
||||
src.ability_icon_state = new_icon_state
|
||||
|
||||
/obj/spellbutton/Click()
|
||||
@@ -199,6 +197,14 @@
|
||||
/obj/spellbutton/DblClick()
|
||||
return Click()
|
||||
|
||||
/obj/spellbutton/technomancer
|
||||
var/obj/item/technomancer_core/core
|
||||
|
||||
/obj/spellbutton/technomancer/Initialize(mapload, var/path, var/new_name, var/new_icon_state)
|
||||
. = ..()
|
||||
src.loc = loc
|
||||
src.core = loc
|
||||
|
||||
/mob/living/carbon/human/get_status_tab_items()
|
||||
. = ..()
|
||||
|
||||
@@ -216,7 +222,7 @@
|
||||
message_admins("ERROR: /obj/item/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, ability_icon_state)
|
||||
var/obj/spellbutton/technomancer/spell = new(src, path, new_name, ability_icon_state)
|
||||
spells.Add(spell)
|
||||
if(wearer)
|
||||
wearer.ability_master.add_technomancer_ability(spell, ability_icon_state)
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
#define ASPECT_UNSTABLE "unstable" //Heavily RNG-based, causes instability to the victim.
|
||||
#define ASPECT_CHROMATIC "chromatic" //Used to combine with other spells.
|
||||
#define ASPECT_UNHOLY "unholy" //Involves the dead, blood, and most things against divine beings.
|
||||
#define ASPECT_PSIONIC "psionics" //Psionic power. Bypasses core checks.
|
||||
|
||||
/obj/item/spell
|
||||
name = "glowing particles"
|
||||
@@ -32,13 +33,15 @@
|
||||
)
|
||||
throwforce = 0
|
||||
force = 0
|
||||
var/mob/living/carbon/human/owner = null
|
||||
var/obj/item/technomancer_core/core = null
|
||||
flags = NOBLUDGEON
|
||||
var/mob/living/carbon/human/owner
|
||||
var/obj/item/technomancer_core/core
|
||||
var/cast_methods = null // Controls how the spell is casted.
|
||||
var/aspect = null // Used for combining spells.
|
||||
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.
|
||||
var/cast_sound = null // Sound file played when this is used.
|
||||
var/psi_cost = 0 // Psi complexus cost to use this spell.
|
||||
|
||||
/obj/item/spell/examine(mob/user, distance) // Nothing on examine.
|
||||
return
|
||||
@@ -46,38 +49,62 @@
|
||||
// Proc: on_use_cast()
|
||||
// Parameters: 1 (user - the technomancer casting the spell)
|
||||
// Description: Override this for clicking the spell in your hands.
|
||||
/obj/item/spell/proc/on_use_cast(mob/user)
|
||||
return
|
||||
/obj/item/spell/proc/on_use_cast(mob/user, var/bypass_psi_check)
|
||||
SHOULD_CALL_PARENT(TRUE)
|
||||
if(aspect == ASPECT_PSIONIC && !bypass_psi_check)
|
||||
if(!owner.psi.spend_power(psi_cost))
|
||||
return FALSE
|
||||
return TRUE
|
||||
|
||||
// Proc: on_throw_cast()
|
||||
// Parameters: 1 (hit_atom - the atom hit by the spell object)
|
||||
// Description: Override this for throwing effects.
|
||||
/obj/item/spell/proc/on_throw_cast(atom/hit_atom)
|
||||
return
|
||||
/obj/item/spell/proc/on_throw_cast(atom/hit_atom, var/bypass_psi_check)
|
||||
SHOULD_CALL_PARENT(TRUE)
|
||||
if(aspect == ASPECT_PSIONIC && !bypass_psi_check)
|
||||
if(!owner.psi.spend_power(psi_cost))
|
||||
return FALSE
|
||||
return TRUE
|
||||
|
||||
// Proc: on_ranged_cast()
|
||||
// Parameters: 2 (hit_atom - the atom clicked on by the user, user - the technomancer that clicked hit_atom)
|
||||
// Description: Override this for ranged effects.
|
||||
/obj/item/spell/proc/on_ranged_cast(atom/hit_atom, mob/user)
|
||||
return
|
||||
/obj/item/spell/proc/on_ranged_cast(atom/hit_atom, mob/user, var/bypass_psi_check)
|
||||
SHOULD_CALL_PARENT(TRUE)
|
||||
if(aspect == ASPECT_PSIONIC && !bypass_psi_check)
|
||||
if(!owner.psi.spend_power(psi_cost))
|
||||
return FALSE
|
||||
return TRUE
|
||||
|
||||
// Proc: on_melee_cast()
|
||||
// Parameters: 3 (hit_atom - the atom clicked on by the user, user - the technomancer that clicked hit_atom, def_zone - unknown)
|
||||
// Description: Override this for effects that occur at melee range.
|
||||
/obj/item/spell/proc/on_melee_cast(atom/hit_atom, mob/living/user, def_zone)
|
||||
return
|
||||
SHOULD_CALL_PARENT(TRUE)
|
||||
if(aspect == ASPECT_PSIONIC)
|
||||
if(!owner.psi.spend_power(psi_cost))
|
||||
return FALSE
|
||||
return TRUE
|
||||
|
||||
// Proc: on_combine_cast()
|
||||
// Parameters: 2 (I - the item trying to merge with the spell, user - the technomancer who initiated the merge)
|
||||
// Description: Override this for combining spells, like Aspect spells.
|
||||
/obj/item/spell/proc/on_combine_cast(obj/item/I, mob/user)
|
||||
return
|
||||
SHOULD_CALL_PARENT(TRUE)
|
||||
if(aspect == ASPECT_PSIONIC)
|
||||
if(!owner.psi.spend_power(psi_cost))
|
||||
return FALSE
|
||||
return TRUE
|
||||
|
||||
// Proc: on_innate_cast()
|
||||
// Parameters: 1 (user - the entity who is casting innately (without using hands).)
|
||||
// Description: Override this for casting without using hands (and as a result not using spell objects).
|
||||
/obj/item/spell/proc/on_innate_cast(mob/user)
|
||||
return
|
||||
SHOULD_CALL_PARENT(TRUE)
|
||||
if(aspect == ASPECT_PSIONIC)
|
||||
if(!owner.psi.spend_power(psi_cost))
|
||||
return FALSE
|
||||
return TRUE
|
||||
|
||||
// Proc: on_scepter_use_cast()
|
||||
// Parameters: 1 (user - the holder of the Scepter that clicked.)
|
||||
@@ -99,7 +126,9 @@
|
||||
// if they are able to pay, it is deducted automatically.
|
||||
/obj/item/spell/proc/pay_energy(var/amount)
|
||||
if(!core)
|
||||
return 0
|
||||
if(aspect == ASPECT_PSIONIC)
|
||||
return owner.psi.spend_power(amount)
|
||||
return amount
|
||||
return core.pay_energy(amount)
|
||||
|
||||
// Proc: give_energy()
|
||||
@@ -107,7 +136,7 @@
|
||||
// Description: Redirects the call to the core's give_energy().
|
||||
/obj/item/spell/proc/give_energy(var/amount)
|
||||
if(!core)
|
||||
return 0
|
||||
return amount
|
||||
return core.give_energy(amount)
|
||||
|
||||
// Proc: adjust_instability()
|
||||
@@ -141,11 +170,17 @@
|
||||
if(isliving(loc))
|
||||
owner = loc
|
||||
if(owner)
|
||||
core = owner.get_technomancer_core()
|
||||
if(!core)
|
||||
to_chat(owner, "<span class='warning'>You need a Core to do that.</span>")
|
||||
qdel(src)
|
||||
return
|
||||
if(aspect != ASPECT_PSIONIC)
|
||||
core = owner.get_technomancer_core()
|
||||
if(!core)
|
||||
to_chat(owner, "<span class='warning'>You need a Core to do that.</span>")
|
||||
return INITIALIZE_HINT_QDEL
|
||||
else
|
||||
if(owner.psi.get_rank() >= PSI_RANK_APEX)
|
||||
if(force)
|
||||
force *= 1.1
|
||||
armor_penetration *= 1.1
|
||||
|
||||
update_icon()
|
||||
|
||||
// Proc: Destroy()
|
||||
@@ -180,32 +215,37 @@
|
||||
// if it still can't find one. It will also check if the core is being worn properly, and finally checks if the owner is a technomancer.
|
||||
/obj/item/spell/proc/run_checks()
|
||||
if(!owner)
|
||||
return 0
|
||||
if(!core)
|
||||
core = locate(/obj/item/technomancer_core) in owner
|
||||
return FALSE
|
||||
if(aspect != ASPECT_PSIONIC)
|
||||
if(!core)
|
||||
core = locate(/obj/item/technomancer_core) in owner
|
||||
if(!core)
|
||||
to_chat(owner, "<span class='danger'>You need to be wearing a core on your back or your wrists!</span>")
|
||||
return FALSE
|
||||
if(core.loc != owner || (owner.back != core && owner.wrists != core)) //Make sure the core's being worn.
|
||||
to_chat(owner, "<span class='danger'>You need to be wearing a core on your back or your wrists!</span>")
|
||||
return 0
|
||||
if(core.loc != owner || (owner.back != core && owner.wrists != core)) //Make sure the core's being worn.
|
||||
to_chat(owner, "<span class='danger'>You need to be wearing a core on your back or your wrists!</span>")
|
||||
return 0
|
||||
if(!core.simple_operation && !technomancers.is_technomancer(owner.mind)) //Now make sure the person using this is the actual antag.
|
||||
to_chat(owner, "<span class='danger'>You can't seem to figure out how to make the machine work properly.</span>")
|
||||
return 0
|
||||
return 1
|
||||
return FALSE
|
||||
if(!core.simple_operation && !technomancers.is_technomancer(owner.mind)) //Now make sure the person using this is the actual antag.
|
||||
to_chat(owner, SPAN_DANGER("You can't seem to figure out how to make the machine work properly."))
|
||||
return FALSE
|
||||
else
|
||||
if(!owner.psi)
|
||||
return FALSE
|
||||
return TRUE
|
||||
|
||||
// Proc: check_for_scepter()
|
||||
// Parameters: 0
|
||||
// Description: Terrible code to check if a scepter is in the offhand, returns 1 if yes.
|
||||
/obj/item/spell/proc/check_for_scepter()
|
||||
if(!src || !owner) return 0
|
||||
if(!src || !owner)
|
||||
return FALSE
|
||||
if(owner.r_hand == src)
|
||||
if(istype(owner.l_hand, /obj/item/scepter))
|
||||
return 1
|
||||
return TRUE
|
||||
else
|
||||
if(istype(owner.r_hand, /obj/item/scepter))
|
||||
return 1
|
||||
return 0
|
||||
return TRUE
|
||||
return FALSE
|
||||
|
||||
// Proc: get_other_hand()
|
||||
// Parameters: 1 (I - item being compared to determine what the offhand is)
|
||||
@@ -259,7 +299,11 @@
|
||||
if(cast_methods & CAST_RANGED) //Try to use a ranged method if a melee one doesn't exist.
|
||||
on_ranged_cast(target, user)
|
||||
if(cooldown)
|
||||
var/effective_cooldown = round(cooldown * core.cooldown_modifier, 5)
|
||||
var/effective_cooldown
|
||||
if(aspect == ASPECT_PSIONIC)
|
||||
effective_cooldown = cooldown
|
||||
else
|
||||
effective_cooldown = round(cooldown * core.cooldown_modifier, 5)
|
||||
user.setClickCooldown(effective_cooldown)
|
||||
flick("cooldown_[effective_cooldown]",src)
|
||||
|
||||
@@ -330,3 +374,8 @@
|
||||
spawn(20)
|
||||
if(src)
|
||||
qdel(src)
|
||||
|
||||
/obj/item/spell/damage_flags()
|
||||
. = ..()
|
||||
if(aspect == ASPECT_PSIONIC)
|
||||
. |= DAMAGE_FLAG_PSIONIC
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
aspect = ASPECT_TELE
|
||||
|
||||
/obj/item/spell/abjuration/on_ranged_cast(atom/hit_atom, mob/user)
|
||||
. = ..()
|
||||
if(istype(hit_atom, /mob/living) && pay_energy(500) && within_range(hit_atom))
|
||||
var/mob/living/L = hit_atom
|
||||
var/mob/living/simple_animal/SM = null
|
||||
@@ -38,4 +39,4 @@
|
||||
// In case NarNar comes back someday.
|
||||
if(istype(hit_atom, /obj/singularity/narsie))
|
||||
to_chat(user, "<span class='danger'>One does not simply abjurate Nar'sie away.</span>")
|
||||
adjust_instability(200)
|
||||
adjust_instability(200)
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
aspect = ASPECT_TELE
|
||||
|
||||
/obj/item/spell/apportation/on_ranged_cast(atom/hit_atom, mob/user)
|
||||
. = ..()
|
||||
if(istype(hit_atom, /atom/movable))
|
||||
var/atom/movable/AM = hit_atom
|
||||
|
||||
|
||||
@@ -65,6 +65,7 @@
|
||||
var/selected_sound = null
|
||||
|
||||
/obj/item/spell/audible_deception/on_use_cast(mob/user)
|
||||
. = ..()
|
||||
var/list/sound_options = available_sounds
|
||||
if(check_for_scepter())
|
||||
sound_options["!!AIR HORN!!"] = 'sound/items/AirHorn.ogg'
|
||||
@@ -73,6 +74,7 @@
|
||||
selected_sound = sound_options[new_sound]
|
||||
|
||||
/obj/item/spell/audible_deception/on_ranged_cast(atom/hit_atom, mob/living/user)
|
||||
. = ..()
|
||||
var/turf/T = get_turf(hit_atom)
|
||||
if(selected_sound && pay_energy(200))
|
||||
playsound(src, selected_sound, 80, 1, -1)
|
||||
|
||||
@@ -36,5 +36,6 @@
|
||||
adjust_instability(2)
|
||||
|
||||
/obj/item/spell/aura/biomed/on_use_cast(mob/living/user)
|
||||
. = ..()
|
||||
heal_allies_only = !heal_allies_only
|
||||
to_chat(user, "Your aura will now heal [heal_allies_only ? "your allies" : "everyone"] near you.")
|
||||
|
||||
@@ -30,6 +30,7 @@
|
||||
set_light(6, 5, l_color = new_color)
|
||||
|
||||
/obj/item/spell/chroma/on_ranged_cast(atom/hit_atom, mob/user)
|
||||
. = ..()
|
||||
var/turf/T = get_turf(hit_atom)
|
||||
if(T)
|
||||
new /obj/effect/temporary_effect/chroma(T, color_to_use)
|
||||
@@ -37,6 +38,7 @@
|
||||
qdel(src)
|
||||
|
||||
/obj/item/spell/chroma/on_use_cast(mob/user)
|
||||
. = ..()
|
||||
var/new_color = input(user, "Choose the color you want your light to be.", "Color selection") as null|color
|
||||
if(new_color)
|
||||
color_to_use = new_color
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
cooldown = 2 SECONDS
|
||||
|
||||
/obj/item/spell/condensation/on_ranged_cast(atom/hit_atom, mob/user)
|
||||
. = ..()
|
||||
if(pay_energy(200))
|
||||
if(istype(hit_atom, /turf/simulated) && within_range(hit_atom))
|
||||
var/turf/simulated/T = hit_atom
|
||||
@@ -41,4 +42,4 @@
|
||||
log_and_message_admins("has wetted the floor with [src] at [T.x],[T.y],[T.z].")
|
||||
else if(hit_atom.reagents && !ismob(hit_atom)) //TODO: Something for the scepter
|
||||
hit_atom.reagents.add_reagent(/singleton/reagent/water, 60, safety = FALSE)
|
||||
adjust_instability(5)
|
||||
adjust_instability(5)
|
||||
|
||||
@@ -16,5 +16,6 @@
|
||||
aspect = ASPECT_BIOMED
|
||||
|
||||
/obj/item/spell/dispel/on_ranged_cast(atom/hit_atom, mob/living/user)
|
||||
. = ..()
|
||||
user.adjust_instability(10)
|
||||
qdel(src)
|
||||
qdel(src)
|
||||
|
||||
@@ -49,6 +49,7 @@
|
||||
|
||||
|
||||
/obj/item/spell/energy_siphon/on_ranged_cast(atom/hit_atom, mob/user)
|
||||
. = ..()
|
||||
if(istype(hit_atom, /atom/movable) && within_range(hit_atom, 4))
|
||||
var/atom/movable/AM = hit_atom
|
||||
populate_siphon_list(AM)
|
||||
|
||||
@@ -34,9 +34,10 @@
|
||||
|
||||
//Needed to make the spell welder have infinite fuel. Don't worry, it uses energy instead.
|
||||
/obj/item/weldingtool/spell/use(var/amount = 1, var/mob/M = null, var/colourChange = TRUE)
|
||||
return 1
|
||||
return TRUE
|
||||
|
||||
/obj/item/spell/flame_tongue/on_melee_cast(atom/hit_atom, mob/living/user, def_zone)
|
||||
. = ..()
|
||||
if(isliving(hit_atom) && user.a_intent != I_HELP)
|
||||
var/mob/living/L = hit_atom
|
||||
if(pay_energy(1000))
|
||||
|
||||
@@ -26,6 +26,7 @@
|
||||
aspect = ASPECT_UNSTABLE
|
||||
|
||||
/obj/item/spell/gambit/on_use_cast(mob/living/carbon/human/user)
|
||||
. = ..()
|
||||
if(pay_energy(200))
|
||||
adjust_instability(3)
|
||||
if(check_for_scepter())
|
||||
@@ -113,4 +114,4 @@
|
||||
if(!potential_spells.len)
|
||||
potential_spells = all_technomancer_gambit_spells.Copy()
|
||||
|
||||
return pick(potential_spells)
|
||||
return pick(potential_spells)
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
var/mob/living/simple_animal/illusion/illusion = null
|
||||
|
||||
/obj/item/spell/illusion/on_ranged_cast(atom/hit_atom, mob/user)
|
||||
. = ..()
|
||||
if(istype(hit_atom, /atom/movable))
|
||||
var/atom/movable/AM = hit_atom
|
||||
if(pay_energy(100))
|
||||
@@ -38,6 +39,7 @@
|
||||
return 1
|
||||
|
||||
/obj/item/spell/illusion/on_use_cast(mob/user)
|
||||
. = ..()
|
||||
if(illusion)
|
||||
var/choice = alert(user, "Would you like to have \the [illusion] speak, or do an emote?", "Illusion", "Speak","Emote","Cancel")
|
||||
switch(choice)
|
||||
|
||||
@@ -49,11 +49,13 @@
|
||||
qdel(src)
|
||||
|
||||
/obj/item/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/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)
|
||||
insert(L,user)
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
set_light(3, 2, l_color = "#FA58F4")
|
||||
|
||||
/obj/item/spell/instability_tap/on_use_cast(mob/user)
|
||||
. = ..()
|
||||
var/amount = calculate_spell_power(5000)
|
||||
if(check_for_scepter())
|
||||
core.give_energy(amount * 1.5)
|
||||
@@ -27,4 +28,4 @@
|
||||
core.give_energy(amount)
|
||||
adjust_instability(50)
|
||||
playsound(src, 'sound/effects/supermatter.ogg', 75, 1)
|
||||
qdel(src)
|
||||
qdel(src)
|
||||
|
||||
@@ -27,6 +27,7 @@
|
||||
aspect = ASPECT_TELE
|
||||
|
||||
/obj/item/spell/mark/on_use_cast(mob/living/user)
|
||||
. = ..()
|
||||
if(!allowed_to_teleport()) // Otherwise you could teleport back to the admin Z-level.
|
||||
to_chat(user, "<span class='warning'>You can't teleport here!</span>")
|
||||
return 0
|
||||
@@ -63,6 +64,7 @@
|
||||
aspect = ASPECT_TELE
|
||||
|
||||
/obj/item/spell/recall/on_use_cast(mob/living/user)
|
||||
. = ..()
|
||||
if(pay_energy(3000))
|
||||
if(!mark_spell_ref)
|
||||
to_chat(user, "<span class='danger'>There's no Mark!</span>")
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
light_color = "#FF5C5C"
|
||||
|
||||
/obj/item/spell/mend_organs/on_melee_cast(atom/hit_atom, mob/living/user, def_zone)
|
||||
. = ..()
|
||||
if(isliving(hit_atom))
|
||||
var/mob/living/L = hit_atom
|
||||
var/heal_power = calculate_spell_power(40)
|
||||
|
||||
@@ -14,11 +14,13 @@
|
||||
set_light(spell_light_range, spell_light_intensity, l_color = light_color)
|
||||
|
||||
/obj/item/spell/modifier/on_melee_cast(atom/hit_atom, mob/user)
|
||||
. = ..()
|
||||
if(isliving(hit_atom))
|
||||
return on_add_modifier(hit_atom)
|
||||
return FALSE
|
||||
|
||||
/obj/item/spell/modifier/on_ranged_cast(atom/hit_atom, mob/user)
|
||||
. = ..()
|
||||
if(isliving(hit_atom))
|
||||
return on_add_modifier(hit_atom)
|
||||
return FALSE
|
||||
@@ -45,4 +47,4 @@
|
||||
|
||||
/datum/modifier/technomancer/stop()
|
||||
..()
|
||||
to_chat(target, SPAN_WARNING(on_expired_text))
|
||||
to_chat(target, SPAN_WARNING(on_expired_text))
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
cooldown = 30
|
||||
|
||||
/obj/item/spell/oxygenate/on_ranged_cast(atom/hit_atom, mob/user)
|
||||
. = ..()
|
||||
if(!within_range(hit_atom))
|
||||
return
|
||||
if(ishuman(hit_atom))
|
||||
@@ -30,4 +31,4 @@
|
||||
T.assume_gas("oxygen", 200)
|
||||
T.assume_gas("nitrogen", 800)
|
||||
playsound(src, 'sound/effects/spray.ogg', 50, 1, -3)
|
||||
adjust_instability(10)
|
||||
adjust_instability(10)
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
var/busy = 0
|
||||
|
||||
/obj/item/spell/passwall/on_melee_cast(atom/hit_atom, mob/user)
|
||||
. = ..()
|
||||
if(busy) //Prevent someone from trying to get two uses of the spell from one instance.
|
||||
return 0
|
||||
if(!allowed_to_teleport())
|
||||
|
||||
@@ -46,7 +46,7 @@
|
||||
L.forceMove(get_turf(src))
|
||||
L.visible_message(SPAN_WARNING("\The [src] ejects [L]!"))
|
||||
|
||||
/obj/effect/phase_shift/relaymove(mob/user as mob)
|
||||
/obj/effect/phase_shift/relaymove(mob/user)
|
||||
if(user.stat)
|
||||
return
|
||||
|
||||
@@ -55,6 +55,7 @@
|
||||
qdel(src)
|
||||
|
||||
/obj/item/spell/phase_shift/on_use_cast(mob/user)
|
||||
. = ..()
|
||||
if(isturf(user.loc)) //Check if we're not already in a rift.
|
||||
if(pay_energy(2000))
|
||||
var/obj/effect/phase_shift/PS = new(get_turf(user))
|
||||
|
||||
@@ -10,9 +10,11 @@
|
||||
var/fire_sound = null
|
||||
|
||||
/obj/item/spell/projectile/on_melee_cast(atom/hit_atom, mob/living/user, def_zone)
|
||||
. = ..()
|
||||
on_ranged_cast(hit_atom, user, hit_atom)
|
||||
|
||||
/obj/item/spell/projectile/on_ranged_cast(atom/hit_atom, mob/living/user, atom/pb_target)
|
||||
. = ..(hit_atom, user, TRUE)
|
||||
if(set_up(hit_atom, user))
|
||||
var/obj/item/projectile/new_projectile = make_projectile(spell_projectile, user)
|
||||
new_projectile.old_style_target(hit_atom)
|
||||
@@ -20,18 +22,28 @@
|
||||
log_and_message_admins("has casted [src] at \the [hit_atom].")
|
||||
if(fire_sound)
|
||||
playsound(src, fire_sound, 75, 1)
|
||||
adjust_instability(instability_per_shot)
|
||||
return 1
|
||||
return 0
|
||||
if(aspect != ASPECT_PSIONIC)
|
||||
adjust_instability(instability_per_shot)
|
||||
return TRUE
|
||||
return FALSE
|
||||
|
||||
/obj/item/spell/projectile/proc/make_projectile(obj/item/projectile/projectile_type, mob/living/user)
|
||||
var/obj/item/projectile/P = new projectile_type(get_turf(user))
|
||||
P.damage = calculate_spell_power(P.damage)
|
||||
P.firer = user
|
||||
if(aspect != ASPECT_PSIONIC)
|
||||
P.damage = calculate_spell_power(P.damage)
|
||||
else
|
||||
if(owner.psi.get_rank() >= PSI_RANK_APEX)
|
||||
if(P.damage)
|
||||
P.damage *= 1.1
|
||||
P.armor_penetration *= 1.1
|
||||
P.damage_flags |= DAMAGE_FLAG_PSIONIC
|
||||
return P
|
||||
|
||||
/obj/item/spell/projectile/proc/set_up(atom/hit_atom, mob/living/user)
|
||||
if(spell_projectile)
|
||||
if(pay_energy(energy_cost_per_shot))
|
||||
/// Psionic energy payment is handled at the beginning of on_ranged_cast.
|
||||
if(pay_energy(aspect == ASPECT_PSIONIC ? psi_cost : energy_cost_per_shot))
|
||||
if(pre_shot_delay)
|
||||
var/image/target_image = image(icon = 'icons/obj/spells.dmi', loc = get_turf(hit_atom), icon_state = "target")
|
||||
user << target_image
|
||||
@@ -42,4 +54,4 @@
|
||||
return TRUE
|
||||
return FALSE // We got dropped before the firing occurred.
|
||||
return TRUE // No delay, no need to check.
|
||||
return FALSE
|
||||
return FALSE
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
aspect = ASPECT_FORCE
|
||||
|
||||
/obj/item/spell/raise_wall/on_ranged_cast(atom/hit_atom, mob/user)
|
||||
. = ..()
|
||||
var/turf/target_turf = isturf(hit_atom) ? hit_atom : get_turf(hit_atom)
|
||||
if(target_turf.density)
|
||||
return
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
aspect = ASPECT_BIOMED
|
||||
|
||||
/obj/item/spell/resurrect/on_melee_cast(atom/hit_atom, mob/living/user, def_zone)
|
||||
. = ..()
|
||||
if(isliving(hit_atom))
|
||||
var/mob/living/L = hit_atom
|
||||
if(L == user)
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
aspect = ASPECT_UNSTABLE
|
||||
|
||||
/obj/item/spell/shared_burden/on_melee_cast(atom/hit_atom, mob/living/user, def_zone)
|
||||
. = ..()
|
||||
if(ishuman(hit_atom) && within_range(hit_atom))
|
||||
var/mob/living/carbon/human/H = hit_atom
|
||||
if(H == user)
|
||||
@@ -27,4 +28,4 @@
|
||||
var/instability_to_drain = min(H.instability, 25)
|
||||
to_chat(user, "<span class='notice'>You draw instability away from \the [H] and towards you.</span>")
|
||||
adjust_instability(instability_to_drain)
|
||||
H.adjust_instability(-calculate_spell_power(instability_to_drain))
|
||||
H.adjust_instability(-calculate_spell_power(instability_to_drain))
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
..()
|
||||
|
||||
/obj/item/spell/spawner/pulsar/on_throw_cast(atom/hit_atom, mob/user)
|
||||
. = ..()
|
||||
empulse(hit_atom, 1, 1, 1, 1, log=1)
|
||||
|
||||
// Does something every so often. Deletes itself when pulses_remaining hits zero.
|
||||
@@ -40,7 +41,7 @@
|
||||
|
||||
/obj/effect/temporary_effect/pulse/proc/pulse_loop()
|
||||
set waitfor = FALSE
|
||||
|
||||
|
||||
while(pulses_remaining)
|
||||
sleep(pulse_delay)
|
||||
on_pulse()
|
||||
|
||||
@@ -7,9 +7,10 @@
|
||||
var/obj/effect/spawner_type = null
|
||||
|
||||
/obj/item/spell/spawner/on_ranged_cast(atom/hit_atom, mob/user)
|
||||
. = ..()
|
||||
var/turf/T = get_turf(hit_atom)
|
||||
if(T)
|
||||
new spawner_type(T)
|
||||
to_chat(user, "<span class='notice'>You shift \the [src] onto \the [T].</span>")
|
||||
log_and_message_admins("has casted [src] at [T.x],[T.y],[T.z].")
|
||||
qdel(src)
|
||||
qdel(src)
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
var/instability_cost = 0
|
||||
|
||||
/obj/item/spell/summon/on_ranged_cast(atom/hit_atom, mob/living/user)
|
||||
. = ..()
|
||||
var/turf/T = get_turf(hit_atom)
|
||||
if(summoned_mob_type && core.summoned_mobs.len < core.max_summons && within_range(hit_atom) && pay_energy(energy_cost))
|
||||
var/obj/effect/E = new(T)
|
||||
@@ -30,6 +31,7 @@
|
||||
user.adjust_instability(instability_cost)
|
||||
|
||||
/obj/item/spell/summon/on_use_cast(mob/living/user)
|
||||
. = ..()
|
||||
if(summon_options.len)
|
||||
var/choice = input(user, "Choose a creature to kidnap from somewhere!", "Summon") as null|anything in summon_options
|
||||
if(choice)
|
||||
@@ -37,4 +39,4 @@
|
||||
|
||||
// Called when a new mob is summoned, override for special behaviour.
|
||||
/obj/item/spell/summon/proc/on_summon(var/mob/living/summoned)
|
||||
return
|
||||
return
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
aspect = ASPECT_FORCE //idk?
|
||||
|
||||
/obj/item/spell/targeting_matrix/on_ranged_cast(atom/hit_atom, mob/user)
|
||||
. = ..()
|
||||
var/turf/T = get_turf(hit_atom)
|
||||
if(T)
|
||||
var/mob/living/chosen_target = targeting_assist(T,5) //The person who's about to get attacked.
|
||||
|
||||
@@ -27,6 +27,7 @@ var/list/technomancer_belongings = list()
|
||||
return ..()
|
||||
|
||||
/obj/item/spell/track/on_use_cast(mob/user)
|
||||
. = ..()
|
||||
if(tracking)
|
||||
tracking = 0
|
||||
to_chat(user, "<span class='notice'>You stop tracking for \the [tracked]'s whereabouts.</span>")
|
||||
@@ -75,4 +76,4 @@ var/list/technomancer_belongings = list()
|
||||
icon_state = "track_far"
|
||||
|
||||
spawn(5)
|
||||
.()
|
||||
.()
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
aspect = ASPECT_TELE
|
||||
|
||||
/obj/item/spell/warp_strike/on_ranged_cast(atom/hit_atom, mob/user)
|
||||
. = ..()
|
||||
var/turf/T = get_turf(hit_atom)
|
||||
if(T)
|
||||
if(!within_range(T))
|
||||
|
||||
@@ -6,7 +6,7 @@ would spawn and follow the beaker, even if it is carried or thrown.
|
||||
*/
|
||||
|
||||
|
||||
/obj/effect/effect
|
||||
/obj/effect
|
||||
name = "effect"
|
||||
icon = 'icons/effects/effects.dmi'
|
||||
mouse_opacity = MOUSE_OPACITY_TRANSPARENT
|
||||
|
||||
@@ -105,7 +105,7 @@ CIGARETTE PACKETS ARE IN FANCY.DM
|
||||
|
||||
/obj/item/flame/match/proc/light()
|
||||
lit = TRUE
|
||||
damtype = "burn"
|
||||
damtype = "fire"
|
||||
icon_state = "match_lit"
|
||||
item_state = "match_lit"
|
||||
if(ismob(loc))
|
||||
|
||||
@@ -163,6 +163,12 @@
|
||||
else
|
||||
to_chat(user, SPAN_WARNING("You need at least [glass_needed] sheets of [MATERIAL_GLASS_REINFORCED_PHORON] to finished the window."))
|
||||
|
||||
/obj/structure/window_frame/hitby(atom/movable/AM, speed)
|
||||
. = ..()
|
||||
var/obj/structure/window/W = locate() in get_turf(src)
|
||||
if(istype(W))
|
||||
W.hitby(AM)
|
||||
|
||||
/obj/structure/window_frame/unanchored // Used during in-game construction.
|
||||
should_check_mapload = FALSE // No glass.
|
||||
anchored = FALSE
|
||||
|
||||
@@ -106,18 +106,16 @@ var/global/enabled_spooking = 0
|
||||
var/mob/living/psyker = M
|
||||
if(psyker.psi)
|
||||
body += "<a href='?src=\ref[src];remove_psionics=\ref[psyker.psi]'>Remove psionics.</a><br/><br/>"
|
||||
body += "<a href='?src=\ref[src];trigger_psi_latencies\ref[psyker.psi]'>Trigger latencies.</a><br/>"
|
||||
body += "<table width = '100%'>"
|
||||
for(var/faculty in list(PSI_COERCION, PSI_PSYCHOKINESIS, PSI_REDACTION, PSI_ENERGISTICS))
|
||||
var/datum/psionic_faculty/faculty_decl = SSpsi.get_faculty(faculty)
|
||||
var/faculty_rank = psyker.psi ? psyker.psi.get_rank(faculty) : 0
|
||||
body += "<tr><td><b>[faculty_decl.name]</b></td>"
|
||||
for(var/i = 1 to LAZYLEN(psychic_ranks_to_strings))
|
||||
var/psi_title = psychic_ranks_to_strings[i]
|
||||
if(i == faculty_rank)
|
||||
psi_title = "<b>[psi_title]</b>"
|
||||
body += "<td><a href='?src=\ref[psyker.mind];set_psi_faculty_rank=[i];set_psi_faculty=[faculty]'>[psi_title]</a></td>"
|
||||
body += "</tr>"
|
||||
for(var/psi_rank in list(PSI_RANK_SENSITIVE, PSI_RANK_HARMONIOUS, PSI_RANK_APEX, PSI_RANK_LIMITLESS))
|
||||
var/owner_rank = psyker.psi ? psyker.psi.get_rank() : 0
|
||||
var/psi_title = psychic_ranks_to_strings[psi_rank]
|
||||
if(psi_rank == owner_rank)
|
||||
psi_title = "<b>[psi_title]</b>"
|
||||
if(psi_rank != PSI_RANK_LIMITLESS)
|
||||
body += "<tr><a href='?src=\ref[psyker.mind];set_psi_rank=[psi_rank]'>[psi_title]</a></tr>"
|
||||
else
|
||||
body += "<tr><a href='?src=\ref[psyker.mind];set_psi_rank_limitless=1'><font color='red'>[psi_title]</font></a></tr>"
|
||||
body += "</table>"
|
||||
|
||||
if (M.client)
|
||||
|
||||
@@ -432,8 +432,8 @@
|
||||
|
||||
else if(href_list["trigger_psi_latencies"])
|
||||
var/datum/psi_complexus/psi = locate(href_list["trigger_psi_latencies"])
|
||||
log_and_message_admins("triggered psi latencies for [key_name(psi.owner)].")
|
||||
psi.check_latency_trigger(100, "outside intervention", redactive = TRUE)
|
||||
log_and_message_admins("triggered psionics for [key_name(psi.owner)].")
|
||||
psi.check_psionic_trigger(100, "outside intervention", redactive = TRUE)
|
||||
|
||||
else if(href_list["monkeyone"])
|
||||
if(!check_rights(R_SPAWN)) return
|
||||
|
||||
@@ -42,10 +42,11 @@
|
||||
/obj/effect/bmode//Cleaning up the tree a bit
|
||||
density = 1
|
||||
anchored = 1
|
||||
layer = SCREEN_LAYER
|
||||
layer = SCREEN_LAYER + 1
|
||||
dir = NORTH
|
||||
icon = 'icons/misc/buildmode.dmi'
|
||||
var/obj/effect/bmode/buildholder/master = null
|
||||
mouse_opacity = MOUSE_OPACITY_OPAQUE
|
||||
var/obj/effect/bmode/buildholder/master
|
||||
|
||||
/obj/effect/bmode/Destroy()
|
||||
if(master && master.cl)
|
||||
|
||||
@@ -0,0 +1,135 @@
|
||||
/datum/category_item/player_setup_item/general/psionics
|
||||
name = "Psionics"
|
||||
sort_order = 7
|
||||
|
||||
/datum/category_item/player_setup_item/general/psionics/load_character(var/savefile/S)
|
||||
S["psionics"] >> pref.psionics
|
||||
|
||||
/datum/category_item/player_setup_item/general/psionics/save_character(var/savefile/S)
|
||||
var/list/psionics = pref.psionics
|
||||
for(var/psi in psionics)
|
||||
var/singleton/psionic_power/P = GET_SINGLETON(text2path(psi))
|
||||
if(!istype(P))
|
||||
continue
|
||||
psionics |= P.type
|
||||
S["psionics"] << json_encode(psionics)
|
||||
|
||||
/datum/category_item/player_setup_item/general/psionics/gather_load_query()
|
||||
return list(
|
||||
"ss13_characters" = list(
|
||||
"vars" = list(
|
||||
"psionics" = "psionics",
|
||||
),
|
||||
"args" = list("id")
|
||||
)
|
||||
)
|
||||
|
||||
/datum/category_item/player_setup_item/general/psionics/gather_load_parameters()
|
||||
return list("id" = pref.current_character)
|
||||
|
||||
/datum/category_item/player_setup_item/general/psionics/gather_save_query()
|
||||
return list(
|
||||
"ss13_characters" = list(
|
||||
"psionics",
|
||||
"id" = 1
|
||||
)
|
||||
)
|
||||
|
||||
/datum/category_item/player_setup_item/general/psionics/gather_save_parameters()
|
||||
var/list/sanitized_psionics = list()
|
||||
for(var/S in pref.psionics)
|
||||
var/singleton/psionic_power/P = GET_SINGLETON(text2path(S))
|
||||
if(!istype(P))
|
||||
continue
|
||||
sanitized_psionics |= "[P.type]"
|
||||
return list(
|
||||
"psionics" = json_encode(sanitized_psionics),
|
||||
"char_id" = pref.current_character,
|
||||
"ckey" = PREF_CLIENT_CKEY
|
||||
)
|
||||
|
||||
/datum/category_item/player_setup_item/general/psionics/load_special(savefile/S)
|
||||
var/before = pref.psionics
|
||||
try
|
||||
pref.psionics = json_decode(pref.psionics)
|
||||
catch (var/exception/e)
|
||||
log_debug("PSIONICS: Caught [e]. Initial value: [before]")
|
||||
pref.psionics = list()
|
||||
|
||||
/datum/category_item/player_setup_item/general/psionics/sanitize_character(var/sql_load = 0)
|
||||
var/datum/species/mob_species = all_species[pref.species]
|
||||
if(length(pref.psionics) && !mob_species.has_psionics)
|
||||
to_chat(pref.client, SPAN_WARNING("This species does not have psionics! Resetting..."))
|
||||
pref.psionics = list()
|
||||
return
|
||||
var/list/bought_psionic_powers = list()
|
||||
for(var/S in pref.psionics)
|
||||
var/singleton/psionic_power/P = GET_SINGLETON(text2path(S))
|
||||
if(istype(P))
|
||||
if(!(P.ability_flags & PSI_FLAG_CANON))
|
||||
pref.psionics -= S
|
||||
to_chat(pref.client, SPAN_WARNING("[P.name] is an invalid psionic!"))
|
||||
continue
|
||||
bought_psionic_powers |= P
|
||||
else
|
||||
to_chat(pref.client, SPAN_WARNING("[S] is an invalid psionic!"))
|
||||
pref.psionics -= S
|
||||
continue
|
||||
if(length(bought_psionic_powers) > mob_species.character_creation_psi_points)
|
||||
to_chat(pref.client, SPAN_WARNING("You have more psionics than possible! Resetting..."))
|
||||
pref.psionics = list()
|
||||
|
||||
/datum/category_item/player_setup_item/general/psionics/content(var/mob/user)
|
||||
var/datum/species/mob_species = all_species[pref.species]
|
||||
if(!(mob_species.has_psionics))
|
||||
return
|
||||
var/list/bought_psionic_powers = list()
|
||||
for(var/S in pref.psionics)
|
||||
var/singleton/psionic_power/P = GET_SINGLETON(text2path(S))
|
||||
if(istype(P))
|
||||
bought_psionic_powers |= P
|
||||
|
||||
var/list/dat = list(
|
||||
"<b>Psionics:</b><br>"
|
||||
)
|
||||
for(var/singleton/psionic_power/P in bought_psionic_powers)
|
||||
dat += "- [P.name] <a href='?src=\ref[src];remove_psi_power=[P.type]'>-</a><br>"
|
||||
dat += "<a href='?src=\ref[src];add_psi_power=1'>Add Psionic Power</a><br>"
|
||||
. = dat.Join()
|
||||
|
||||
/datum/category_item/player_setup_item/general/psionics/OnTopic(var/href,var/list/href_list, var/mob/user)
|
||||
if(href_list["remove_psi_power"])
|
||||
var/power_to_remove = href_list["remove_psi_power"]
|
||||
if(power_to_remove && (power_to_remove in pref.psionics))
|
||||
pref.psionics -= power_to_remove
|
||||
return TOPIC_REFRESH
|
||||
|
||||
else if(href_list["add_psi_power"])
|
||||
var/datum/species/mob_species = all_species[pref.species]
|
||||
var/total_psi_points = mob_species.character_creation_psi_points
|
||||
var/list/available_psionics = list()
|
||||
var/list/psionic_map = list()
|
||||
var/list/bought_psionic_powers = list()
|
||||
|
||||
for(var/S in pref.psionics)
|
||||
var/singleton/psionic_power/P = GET_SINGLETON(text2path(S))
|
||||
if(istype(P))
|
||||
bought_psionic_powers |= P
|
||||
total_psi_points = max(0, total_psi_points - P.point_cost)
|
||||
|
||||
for(var/singleton/psionic_power/P in GET_SINGLETON_SUBTYPE_LIST(/singleton/psionic_power))
|
||||
if((P.ability_flags & PSI_FLAG_CANON) && (P.point_cost <= total_psi_points) && !(P in bought_psionic_powers))
|
||||
available_psionics |= "[P.name]"
|
||||
psionic_map[P.name] = P.type
|
||||
|
||||
if(!length(available_psionics))
|
||||
to_chat(user, SPAN_WARNING("You ran out of points!"))
|
||||
return
|
||||
|
||||
var/new_power = input(user, "Choose a psionic power to add.", "Psionics") as null|anything in available_psionics
|
||||
if(new_power)
|
||||
var/singleton/psionic_power/P = GET_SINGLETON(psionic_map[new_power])
|
||||
if(istype(P))
|
||||
pref.psionics += "[P.type]"
|
||||
return TOPIC_REFRESH
|
||||
|
||||
@@ -144,8 +144,7 @@
|
||||
display_name = "psionic receiver"
|
||||
description = "An augment installed into the head that functions as a surrogate for a missing zona bovinae, also functioning as a filter for the psionically-challenged."
|
||||
path = /obj/item/organ/internal/augment/psi
|
||||
whitelisted = list(SPECIES_HUMAN, SPECIES_HUMAN_OFFWORLD, SPECIES_TAJARA, SPECIES_TAJARA_ZHAN, SPECIES_TAJARA_MSAI, SPECIES_VAURCA_WORKER, SPECIES_VAURCA_WARRIOR, SPECIES_VAURCA_BULWARK, SPECIES_VAURCA_BREEDER, SPECIES_IPC, SPECIES_IPC_G1, SPECIES_IPC_G2, SPECIES_IPC_XION, SPECIES_IPC_ZENGHU, SPECIES_IPC_BISHOP, SPECIES_IPC_SHELL)
|
||||
|
||||
whitelisted = list(SPECIES_HUMAN, SPECIES_HUMAN_OFFWORLD, SPECIES_TAJARA, SPECIES_TAJARA_ZHAN, SPECIES_TAJARA_MSAI, SPECIES_UNATHI, SPECIES_VAURCA_WORKER, SPECIES_VAURCA_WARRIOR, SPECIES_VAURCA_BULWARK, SPECIES_VAURCA_BREEDER, SPECIES_IPC, SPECIES_IPC_G1, SPECIES_IPC_G2, SPECIES_IPC_XION, SPECIES_IPC_ZENGHU, SPECIES_IPC_BISHOP, SPECIES_IPC_SHELL)
|
||||
/datum/gear/augment/memory_inhibitor
|
||||
display_name = "memory inhibitor"
|
||||
description = "A Zeng Hu implant that allows one to have control over their memories, allowing you to set a timer and remove any memories developed within it."
|
||||
|
||||
@@ -99,6 +99,8 @@ var/list/preferences_datums = list()
|
||||
var/culture
|
||||
var/origin
|
||||
|
||||
var/list/psionics = list()
|
||||
|
||||
var/list/char_render_holders //Should only be a key-value list of north/south/east/west = obj/screen.
|
||||
var/static/list/preview_screen_locs = list(
|
||||
"1" = "character_preview_map:1,5:-12",
|
||||
@@ -471,6 +473,12 @@ var/list/preferences_datums = list()
|
||||
|
||||
character.headset_choice = headset_choice
|
||||
|
||||
if(length(psionics) && character.client)
|
||||
for(var/power in psionics)
|
||||
var/singleton/psionic_power/P = GET_SINGLETON(text2path(power))
|
||||
if(istype(P) && (P.ability_flags & PSI_FLAG_CANON))
|
||||
P.apply(character)
|
||||
|
||||
if(icon_updates)
|
||||
character.force_update_limbs()
|
||||
character.update_mutations(0)
|
||||
@@ -638,6 +646,7 @@ var/list/preferences_datums = list()
|
||||
|
||||
ccia_actions = list()
|
||||
disabilities = list()
|
||||
psionics = list()
|
||||
|
||||
economic_status = ECONOMICALLY_AVERAGE
|
||||
|
||||
|
||||
@@ -23,12 +23,9 @@
|
||||
/mob/living/carbon/proc/breathe(var/volume_needed = BREATH_VOLUME)
|
||||
if(species && (species.flags & NO_BREATHE))
|
||||
return
|
||||
var/datum/changeling/changeling = get_antag_datum(MODE_CHANGELING)
|
||||
if(changeling?.space_adapted)
|
||||
if(HAS_TRAIT(src, TRAIT_PRESSURE_IMMUNITY))
|
||||
return
|
||||
if(changeling?.no_breathing)
|
||||
return
|
||||
|
||||
|
||||
volume_needed *= (species?.breath_vol_mul || 1)
|
||||
|
||||
var/datum/gas_mixture/breath = null
|
||||
|
||||
@@ -1485,6 +1485,9 @@
|
||||
|
||||
species.set_default_tail(src)
|
||||
|
||||
if(species.psi_deaf || HAS_FLAG(species.flags, IS_MECHANICAL) || HAS_FLAG(species.flags, NO_SCAN))
|
||||
ADD_TRAIT(src, TRAIT_PSIONICALLY_DEAF, INNATE_TRAIT)
|
||||
|
||||
if(client)
|
||||
client.init_verbs()
|
||||
|
||||
|
||||
@@ -185,7 +185,7 @@
|
||||
|
||||
return O
|
||||
|
||||
/mob/living/carbon/human/proc/awaken_psi_basic(var/source, var/allow_latency = TRUE)
|
||||
/mob/living/carbon/human/proc/awaken_psi_basic(var/source)
|
||||
var/static/list/psi_operancy_messages = list(
|
||||
"There's something in your skull!",
|
||||
"Something is eating your thoughts!",
|
||||
@@ -197,13 +197,10 @@
|
||||
)
|
||||
to_chat(src, SPAN_DANGER("An indescribable, brain-tearing sound hisses from [source], and you collapse in a seizure!"))
|
||||
seizure()
|
||||
var/new_latencies = rand(2,4)
|
||||
var/list/faculties = list(PSI_COERCION, PSI_REDACTION, PSI_ENERGISTICS, PSI_PSYCHOKINESIS)
|
||||
for(var/i = 1 to new_latencies)
|
||||
custom_pain(SPAN_DANGER("<font size = 3>[pick(psi_operancy_messages)]</font>"), 25)
|
||||
set_psi_rank(pick_n_take(faculties), allow_latency ? PSI_RANK_LATENT : PSI_RANK_OPERANT) // if set to latent, it spikes anywhere from OPERANT to PARAMOUNT
|
||||
sleep(30)
|
||||
addtimer(CALLBACK(psi, TYPE_PROC_REF(/datum/psi_complexus, check_latency_trigger), 100, source, TRUE), 4.5 SECONDS)
|
||||
custom_pain(SPAN_DANGER(FONT_LARGE("[pick(psi_operancy_messages)]")), 25)
|
||||
set_psi_rank(PSI_RANK_HARMONIOUS)
|
||||
sleep(30)
|
||||
addtimer(CALLBACK(psi, TYPE_PROC_REF(/datum/psi_complexus, check_psionic_trigger), 100, source, TRUE), 4.5 SECONDS)
|
||||
|
||||
/mob/living/carbon/human/get_resist_power()
|
||||
return species.resist_mod
|
||||
@@ -349,8 +346,7 @@
|
||||
/mob/living/carbon/human/proc/pressure_resistant()
|
||||
if(HAS_FLAG(mutations, COLD_RESISTANCE))
|
||||
return TRUE
|
||||
var/datum/changeling/changeling = get_antag_datum(MODE_CHANGELING)
|
||||
if(changeling?.space_adapted)
|
||||
if(HAS_TRAIT(src, TRAIT_PRESSURE_IMMUNITY))
|
||||
return TRUE
|
||||
return FALSE
|
||||
|
||||
@@ -418,7 +414,7 @@
|
||||
|
||||
/mob/living/carbon/human/proc/get_tail_accessory()
|
||||
var/obj/item/organ/external/groin/G = organs_by_name[BP_GROIN]
|
||||
if(!G)
|
||||
if(!istype(G))
|
||||
return
|
||||
if(!G.tail_storage)
|
||||
return
|
||||
|
||||
@@ -239,14 +239,16 @@
|
||||
|
||||
|
||||
// Simple mobs cannot use Skrellepathy
|
||||
/mob/proc/can_commune()
|
||||
/mob/proc/has_psionics()
|
||||
return FALSE
|
||||
|
||||
/mob/living/carbon/human/can_commune()
|
||||
/mob/living/carbon/human/has_psionics()
|
||||
if(HAS_TRAIT(src, TRAIT_PSIONICALLY_DEAF))
|
||||
return FALSE
|
||||
if(psi)
|
||||
return TRUE
|
||||
else
|
||||
return species ? species.can_commune() : FALSE
|
||||
return species ? species.has_psionics() : FALSE
|
||||
|
||||
/mob/living/carbon/human/proc/commune()
|
||||
set category = "Abilities"
|
||||
@@ -322,14 +324,14 @@
|
||||
to_chat(M,"<span class='notice'>[src] telepathically says to [target]:</span> [text]")
|
||||
|
||||
var/mob/living/carbon/human/H = target
|
||||
if (target.can_commune())
|
||||
if (target.has_psionics())
|
||||
to_chat(H,"<span class='psychic'>You instinctively sense [src] sending their thoughts into your mind, hearing:</span> [text]")
|
||||
else if(prob(25) && (target.mind && target.mind.assigned_role=="Chaplain"))
|
||||
to_chat(H,"<span class='changeling'>You sense [src]'s thoughts enter your mind, whispering quietly:</span> [text]")
|
||||
else
|
||||
to_chat(H,"<span class='alium'>You feel pressure behind your eyes as alien thoughts enter your mind:</span> [text]")
|
||||
if(istype(H))
|
||||
if (target.can_commune())
|
||||
if (target.has_psionics())
|
||||
return
|
||||
if(prob(10) && !(H.species.flags & NO_BLOOD))
|
||||
to_chat(H,"<span class='warning'>Your nose begins to bleed...</span>")
|
||||
|
||||
@@ -295,6 +295,13 @@
|
||||
|
||||
var/use_alt_hair_layer = FALSE
|
||||
|
||||
/// Species psionics. FALSE for no psionics. Otherwise, set to the PSI_RANK define you want.
|
||||
var/has_psionics = FALSE
|
||||
/// Number of psi points in character creation.
|
||||
var/character_creation_psi_points = 0
|
||||
/// Is this species psionically deaf?
|
||||
var/psi_deaf = FALSE
|
||||
|
||||
/datum/species/proc/get_eyes(var/mob/living/carbon/human/H)
|
||||
return
|
||||
|
||||
@@ -470,6 +477,8 @@
|
||||
if(!H.client || !H.client.prefs || !H.client.prefs.gender)
|
||||
H.gender = pick(default_genders)
|
||||
H.pronouns = H.gender
|
||||
if(has_psionics)
|
||||
H.set_psi_rank(has_psionics)
|
||||
|
||||
/datum/species/proc/handle_death(var/mob/living/carbon/human/H, var/gibbed = 0) //Handles any species-specific death events (such as dionaea nymph spawns).
|
||||
return
|
||||
@@ -739,11 +748,8 @@
|
||||
/datum/species/proc/get_digestion_product()
|
||||
return /singleton/reagent/nutriment
|
||||
|
||||
/datum/species/proc/can_commune()
|
||||
return FALSE
|
||||
|
||||
/datum/species/proc/has_psi_potential()
|
||||
return TRUE
|
||||
/datum/species/proc/has_psionics()
|
||||
return has_psionics
|
||||
|
||||
/datum/species/proc/handle_despawn()
|
||||
return
|
||||
|
||||
@@ -129,6 +129,7 @@
|
||||
)
|
||||
|
||||
alterable_internal_organs = list()
|
||||
psi_deaf = TRUE
|
||||
|
||||
/datum/species/diona/can_understand(var/mob/other)
|
||||
var/mob/living/carbon/alien/diona/D = other
|
||||
@@ -184,9 +185,6 @@
|
||||
if(SB)
|
||||
SB.handle_item_insertion(new /obj/item/device/flashlight/survival(get_turf(H)), TRUE)
|
||||
|
||||
/datum/species/diona/has_psi_potential()
|
||||
return FALSE
|
||||
|
||||
/datum/species/diona/is_naturally_insulated()
|
||||
return TRUE
|
||||
|
||||
|
||||
@@ -98,6 +98,8 @@ var/global/list/golem_types = list(SPECIES_GOLEM_COAL,
|
||||
|
||||
hud_type = /datum/hud_data/construct
|
||||
|
||||
psi_deaf = TRUE
|
||||
|
||||
var/turn_into_materials = TRUE //the golem will turn into materials upon its death
|
||||
var/golem_designation = "Coal" //used in the creation of the name
|
||||
|
||||
@@ -124,9 +126,6 @@ var/global/list/golem_types = list(SPECIES_GOLEM_COAL,
|
||||
return TRUE
|
||||
return FALSE
|
||||
|
||||
/datum/species/golem/has_psi_potential()
|
||||
return FALSE
|
||||
|
||||
/datum/species/golem/iron
|
||||
name = SPECIES_GOLEM_IRON
|
||||
name_plural = "iron golems"
|
||||
|
||||
@@ -143,6 +143,7 @@
|
||||
var/move_charge_factor = 1
|
||||
|
||||
use_alt_hair_layer = TRUE
|
||||
psi_deaf = TRUE
|
||||
|
||||
/datum/species/machine/handle_post_spawn(var/mob/living/carbon/human/H)
|
||||
. = ..()
|
||||
@@ -373,9 +374,6 @@
|
||||
. = ..()
|
||||
check_tag(H, H.client)
|
||||
|
||||
/datum/species/machine/has_psi_potential()
|
||||
return FALSE
|
||||
|
||||
/datum/species/machine/handle_death_check(var/mob/living/carbon/human/H)
|
||||
if(H.get_total_health() <= config.health_threshold_dead)
|
||||
return TRUE
|
||||
|
||||
@@ -107,6 +107,9 @@
|
||||
|
||||
alterable_internal_organs = list(BP_HEART, BP_EYES, BP_LUNGS, BP_LIVER, BP_KIDNEYS, BP_STOMACH)
|
||||
|
||||
has_psionics = PSI_RANK_SENSITIVE
|
||||
character_creation_psi_points = 4
|
||||
|
||||
/datum/species/skrell/handle_trail(var/mob/living/carbon/human/H, var/turf/T)
|
||||
var/list/trail_info = ..()
|
||||
if(!length(trail_info) && !H.shoes)
|
||||
@@ -117,10 +120,6 @@
|
||||
|
||||
return trail_info
|
||||
|
||||
/datum/species/skrell/handle_post_spawn(mob/living/carbon/human/H)
|
||||
..()
|
||||
H.set_psi_rank(PSI_COERCION, PSI_RANK_OPERANT)
|
||||
|
||||
/datum/species/skrell/handle_strip(var/mob/user, var/mob/living/carbon/human/H, var/action)
|
||||
switch(action)
|
||||
if("headtail")
|
||||
@@ -142,6 +141,3 @@
|
||||
|
||||
/datum/species/skrell/can_breathe_water()
|
||||
return TRUE
|
||||
|
||||
/datum/species/skrell/can_commune()
|
||||
return TRUE
|
||||
|
||||
@@ -141,6 +141,7 @@
|
||||
|
||||
|
||||
alterable_internal_organs = list(BP_HEART, BP_EYES, BP_LUNGS, BP_STOMACH, BP_APPENDIX)
|
||||
psi_deaf = TRUE
|
||||
|
||||
/datum/species/bug/before_equip(var/mob/living/carbon/human/H)
|
||||
. = ..()
|
||||
@@ -158,9 +159,6 @@
|
||||
H.gender = NEUTER
|
||||
return ..()
|
||||
|
||||
/datum/species/bug/has_psi_potential()
|
||||
return FALSE
|
||||
|
||||
/datum/species/bug/is_naturally_insulated()
|
||||
return TRUE
|
||||
|
||||
@@ -168,3 +166,4 @@
|
||||
if(I.w_class <= ITEMSIZE_SMALL)
|
||||
return TRUE
|
||||
return FALSE
|
||||
|
||||
|
||||
@@ -18,6 +18,10 @@
|
||||
var/natural_armor = GetComponent(/datum/component/armor)
|
||||
if(natural_armor)
|
||||
. += natural_armor
|
||||
if(psi)
|
||||
var/armor = psi.GetComponent(/datum/component/armor/psionic)
|
||||
if(armor)
|
||||
. += armor
|
||||
|
||||
/mob/living/bullet_act(var/obj/item/projectile/P, var/def_zone, var/used_weapon = null)
|
||||
|
||||
@@ -247,7 +251,7 @@
|
||||
|
||||
// End BS12 momentum-transfer code.
|
||||
|
||||
/mob/living/attack_generic(var/mob/user, var/damage, var/attack_message, var/armor_penetration, var/attack_flags)
|
||||
/mob/living/attack_generic(var/mob/user, var/damage, var/attack_message, var/armor_penetration, var/attack_flags, var/damage_type = DAMAGE_BRUTE)
|
||||
if(!damage)
|
||||
return
|
||||
|
||||
@@ -257,7 +261,7 @@
|
||||
src.visible_message("<span class='danger'>[user] has [attack_message] [src]!</span>")
|
||||
user.do_attack_animation(src)
|
||||
|
||||
apply_damage(damage, DAMAGE_BRUTE, user.zone_sel?.selecting, armor_pen = armor_penetration, damage_flags = attack_flags)
|
||||
apply_damage(damage, damage_type, user.zone_sel?.selecting, armor_pen = armor_penetration, damage_flags = attack_flags)
|
||||
updatehealth()
|
||||
|
||||
return TRUE
|
||||
|
||||
@@ -453,8 +453,8 @@
|
||||
if(chemicals < 150)
|
||||
to_chat(src, SPAN_WARNING("You don't have enough chemicals!"))
|
||||
return
|
||||
if(!host.species.has_psi_potential())
|
||||
to_chat(src, SPAN_WARNING("\The [host] lacks a zona bovinidae to psionically enlighten! How disturbing..."))
|
||||
if(host.species.psi_deaf)
|
||||
to_chat(src, SPAN_WARNING("\The [host] lacks a zona bovinae to psionically enlighten! How disturbing..."))
|
||||
if(host.psi)
|
||||
to_chat(src, SPAN_WARNING("Your host is already psionically active!"))
|
||||
return
|
||||
@@ -481,13 +481,14 @@
|
||||
return
|
||||
|
||||
to_chat(src, SPAN_NOTICE("You succeed in interfacing with the host's zona bovinae, this will be a painful process for them."))
|
||||
host.awaken_psi_basic("something in your head", FALSE)
|
||||
host.awaken_psi_basic("something in your head")
|
||||
host.psi.psi_points = 3 /// You don't get a lot at the start.
|
||||
host.add_language(LANGUAGE_TCB) // if we don't have TCB, give them TCB | this allows monkey borers to RP
|
||||
|
||||
/mob/living/simple_animal/borer/verb/advance_faculty()
|
||||
/mob/living/simple_animal/borer/verb/advance_psionics()
|
||||
set category = "Abilities"
|
||||
set name = "Advance Psionic Faculty (75)"
|
||||
set desc = "Advance one of your host's psionic faculties by one step."
|
||||
set name = "Advance Psionics (75)"
|
||||
set desc = "Advance your host's psionic capability by one step."
|
||||
|
||||
if(!host)
|
||||
to_chat(src, SPAN_NOTICE("You are not inside a host body."))
|
||||
@@ -507,18 +508,8 @@
|
||||
to_chat(src, SPAN_WARNING("\The [host]'s mind is shielded against your powers."))
|
||||
return
|
||||
|
||||
var/list/faculties = list(capitalize(PSI_COERCION), capitalize(PSI_REDACTION), capitalize(PSI_ENERGISTICS), capitalize(PSI_PSYCHOKINESIS))
|
||||
var/selected_faculty = input(src, "Choose a faculty to upgrade.") as null|anything in faculties
|
||||
if(!selected_faculty)
|
||||
return
|
||||
selected_faculty = lowertext(selected_faculty)
|
||||
var/max_rank = islesserform(host) ? PSI_RANK_OPERANT : PSI_RANK_MASTER
|
||||
if(host.psi.get_rank(selected_faculty) >= max_rank)
|
||||
to_chat(src, SPAN_NOTICE("This faculty has already been pushed to the max potential you can achieve!"))
|
||||
return
|
||||
|
||||
var/faculty_time = 10 SECONDS
|
||||
if(!start_ability(host, faculty_time))
|
||||
var/upgrade_time = 10 SECONDS
|
||||
if(!start_ability(host, upgrade_time))
|
||||
to_chat(src, SPAN_WARNING("You're busy doing something else, complete that task first."))
|
||||
return
|
||||
|
||||
@@ -526,19 +517,16 @@
|
||||
to_chat(src, SPAN_NOTICE("You probe your tendrils deep within your host's zona bovinae, seeking to upgrade their abilities."))
|
||||
to_chat(host, SPAN_WARNING("You feel a burning, tingling sensation at the back of your head..."))
|
||||
|
||||
addtimer(CALLBACK(src, PROC_REF(faculty_upgrade), selected_faculty), faculty_time)
|
||||
addtimer(CALLBACK(src, PROC_REF(upgrade_rank)), upgrade_time)
|
||||
|
||||
/mob/living/simple_animal/borer/proc/faculty_upgrade(var/selected_faculty)
|
||||
/mob/living/simple_animal/borer/proc/upgrade_rank()
|
||||
if(!host)
|
||||
return
|
||||
|
||||
var/host_psi_rank = host.psi.get_rank(selected_faculty)
|
||||
var/next_rank = host_psi_rank > PSI_RANK_BLUNT ? host_psi_rank + 1 : PSI_RANK_OPERANT
|
||||
host.psi.set_rank(selected_faculty, next_rank)
|
||||
host.psi.update(TRUE)
|
||||
to_chat(src, SPAN_NOTICE("You successfully manage to upgrade your host to [psychic_ranks_to_strings[host.psi.ranks[selected_faculty]]] [selected_faculty]."))
|
||||
host.psi.psi_points++
|
||||
to_chat(src, SPAN_NOTICE("You successfully manage to expand your living host's control over their Zona Bovinae. They know have an extra psionic point to spend."))
|
||||
to_chat(host, SPAN_GOOD("A breeze of fresh air washes over your mind, you feel powerful!"))
|
||||
to_chat(host, SPAN_NOTICE("You have been psionically enlightened. You are now a [psychic_ranks_to_strings[host.psi.ranks[selected_faculty]]] in the [selected_faculty] faculty."))
|
||||
to_chat(host, SPAN_NOTICE("Your control over the Nlom has expanded. You now have an extra psionic point to spend in the Point Shop."))
|
||||
|
||||
/mob/living/simple_animal/borer/verb/host_health_scan()
|
||||
set category = "Abilities"
|
||||
|
||||
@@ -214,7 +214,7 @@
|
||||
var/atom/target
|
||||
if(isliving(target_mob))
|
||||
var/mob/living/L = target_mob
|
||||
on_attack_mob(L, L.attack_generic(src, rand(melee_damage_lower, melee_damage_upper), attacktext, armor_penetration, attack_flags))
|
||||
on_attack_mob(L, L.attack_generic(src, rand(melee_damage_lower, melee_damage_upper), attacktext, armor_penetration, attack_flags, damage_type))
|
||||
target = L
|
||||
else if(istype(target_mob, /obj/machinery/bot))
|
||||
var/obj/machinery/bot/B = target_mob
|
||||
|
||||
@@ -14,6 +14,9 @@
|
||||
mob_swap_flags = MONKEY|SLIME|SIMPLE_ANIMAL
|
||||
mob_push_flags = MONKEY|SLIME|SIMPLE_ANIMAL
|
||||
|
||||
/// The type of damage this mob deals.
|
||||
var/damage_type = DAMAGE_BRUTE
|
||||
|
||||
var/show_stat_health = 1 //does the percentage health show in the stat panel for the mob
|
||||
|
||||
var/icon_living = ""
|
||||
@@ -538,7 +541,7 @@
|
||||
simple_harm_attack(user)
|
||||
|
||||
/mob/living/simple_animal/proc/simple_harm_attack(var/mob/living/user)
|
||||
apply_damage(harm_intent_damage, DAMAGE_BRUTE, used_weapon = "Attack by [user.name]")
|
||||
apply_damage(harm_intent_damage, damage_type, used_weapon = "Attack by [user.name]")
|
||||
user.visible_message(SPAN_WARNING("<b>\The [user]</b> [response_harm] \the [src]!"), SPAN_WARNING("You [response_harm] \the [src]!"))
|
||||
user.do_attack_animation(src, FIST_ATTACK_ANIMATION)
|
||||
poke(TRUE)
|
||||
|
||||
@@ -348,11 +348,6 @@
|
||||
if(!affecting)
|
||||
return
|
||||
|
||||
if(ishuman(user) && affecting == M)
|
||||
var/mob/living/carbon/human/H = user
|
||||
if(H.check_psi_grab(src))
|
||||
return
|
||||
|
||||
if(world.time < (last_action + 20))
|
||||
return
|
||||
|
||||
|
||||
@@ -284,8 +284,26 @@
|
||||
var/laser = (damage_flags & DAMAGE_FLAG_LASER)
|
||||
var/sharp = (damage_flags & DAMAGE_FLAG_SHARP)
|
||||
var/edge = (damage_flags & DAMAGE_FLAG_EDGE)
|
||||
var/psionic = HAS_FLAG(damage_flags, DAMAGE_FLAG_PSIONIC)
|
||||
var/blunt = !!(brute && !sharp && !edge)
|
||||
|
||||
/// Psionics and psionically deaf species take varying amounts of damage from psionic abilities.
|
||||
if(psionic)
|
||||
if(!owner.has_psionics())
|
||||
brute *= 0.9
|
||||
burn *= 0.9
|
||||
else if(owner.psi)
|
||||
var/psi_rank = owner.psi.get_rank()
|
||||
if(psi_rank == PSI_RANK_SENSITIVE)
|
||||
brute *= 1.05
|
||||
burn *= 1.05
|
||||
else if(psi_rank == PSI_RANK_HARMONIOUS)
|
||||
brute *= 1.1
|
||||
burn *= 1.1
|
||||
else if(psi_rank == PSI_RANK_APEX)
|
||||
brute *= 1.2
|
||||
burn *= 1.2
|
||||
|
||||
if(status & ORGAN_BROKEN && prob(40) && brute)
|
||||
if(owner && (owner.can_feel_pain()) && owner.stat == CONSCIOUS)
|
||||
owner.emote(pick("scream", "groan")) //getting hit on broken hand hurts
|
||||
|
||||
@@ -529,7 +529,6 @@
|
||||
organ_tag = BP_AUG_COCHLEAR
|
||||
parent_organ = BP_HEAD
|
||||
|
||||
// Snakebitten!
|
||||
/obj/item/organ/internal/augment/psi
|
||||
name = "psionic receiver"
|
||||
desc = "An augment installed into the head that functions as a surrogate for a missing zona bovinae, also functioning as a filter for the psionically-challenged."
|
||||
|
||||
@@ -112,7 +112,7 @@ Pins Below.
|
||||
fail_message = "<span class='warning'>PSIONICS CHECK FAILED.</span>"
|
||||
|
||||
/obj/item/device/firing_pin/psionic/pin_auth(mob/living/user)
|
||||
if(user.can_commune())
|
||||
if(user.has_psionics())
|
||||
return 1
|
||||
else
|
||||
return 0
|
||||
|
||||
@@ -469,15 +469,6 @@
|
||||
if(isliving(target))
|
||||
tesla_zap(target, 5, 5000)
|
||||
|
||||
/obj/item/projectile/beam/tesla/master
|
||||
damage = 15
|
||||
|
||||
/obj/item/projectile/beam/tesla/grandmaster
|
||||
damage = 20
|
||||
|
||||
/obj/item/projectile/beam/tesla/paramount
|
||||
damage = 25
|
||||
|
||||
/obj/item/projectile/beam/freezer
|
||||
name = "freezing ray"
|
||||
icon_state = "bluelaser"
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
/singleton/psionic_power
|
||||
/// Ability name.
|
||||
var/name
|
||||
/// Description of what the ability does.
|
||||
var/desc
|
||||
/// Spell object to spawn. Must be a path.
|
||||
var/spell_path
|
||||
/// Spell icon state.
|
||||
var/icon_state
|
||||
/// Ability flags define who can pick an ability - ship characters, adminspawn characters, antags.
|
||||
var/ability_flags
|
||||
/// Minimum required rank to use an ability.
|
||||
var/minimum_rank = PSI_RANK_SENSITIVE
|
||||
/// Point shop cost.
|
||||
var/point_cost = 1
|
||||
|
||||
/// Called when a power is given to a mob.
|
||||
/singleton/psionic_power/proc/apply(var/mob/living/carbon/human/H)
|
||||
if(H.ability_master)
|
||||
var/obj/spellbutton/spell = new(H, spell_path, name, icon_state)
|
||||
H.ability_master.add_psionic_ability(spell, icon_state, src)
|
||||
H.psi.psionic_powers |= type
|
||||
return TRUE
|
||||
else
|
||||
log_debug("Psionic power [src.name] given to mob [H] without ability master!")
|
||||
return FALSE
|
||||
|
||||
/// A psionic power is made up of two elements: the psionic power singleton (which defines the ability metadata such as its name, description, and cost)
|
||||
/// and the physical spell object, which defines its behaviour when used. Keep in mind that ALL psionic abilities MUST have the ASPECT_PSIONIC aspect!
|
||||
@@ -0,0 +1,58 @@
|
||||
/singleton/psionic_power/air_bullet
|
||||
name = "Air Bullet"
|
||||
desc = "Wrap air in a psionic bubble, compress it, then send it flying at your enemies. Activate the spell in hand to create up to six air bullets, then \
|
||||
fire them by clicking something."
|
||||
icon_state = "tech_frostaura"
|
||||
point_cost = 3
|
||||
ability_flags = PSI_FLAG_ANTAG
|
||||
spell_path = /obj/item/spell/projectile/air_bullet
|
||||
|
||||
/obj/item/spell/projectile/air_bullet
|
||||
name = "air bullet"
|
||||
desc = "Not really a big bang attack, but it's actually pretty close."
|
||||
icon_state = "force_missile"
|
||||
cast_methods = CAST_RANGED|CAST_USE
|
||||
aspect = ASPECT_PSIONIC
|
||||
spell_projectile = /obj/item/projectile/air_bullet
|
||||
fire_sound = 'sound/weapons/wave.ogg'
|
||||
cooldown = 5
|
||||
psi_cost = 0
|
||||
var/bullets = 0
|
||||
var/max_bullets = 6
|
||||
|
||||
/obj/item/spell/projectile/air_bullet/on_use_cast(mob/user)
|
||||
. = ..()
|
||||
if(!.)
|
||||
return
|
||||
if(!isliving(user))
|
||||
return
|
||||
var/mob/living/L = user
|
||||
if(bullets < max_bullets)
|
||||
if(do_after(L, 0.5 SECONDS))
|
||||
to_chat(L, SPAN_NOTICE("You compress some air bullets between your fingers."))
|
||||
bullets = min(bullets + 2, 6)
|
||||
maptext = SMALL_FONTS(7, bullets)
|
||||
playsound(L, 'sound/weapons/unjam.ogg', 25)
|
||||
L.psi.spend_power(3)
|
||||
if(bullets >= 6)
|
||||
to_chat(L, SPAN_NOTICE("You finish compressing all the bullets you can hold."))
|
||||
return
|
||||
on_use_cast(L)
|
||||
|
||||
/obj/item/spell/projectile/air_bullet/on_ranged_cast(atom/hit_atom, mob/living/user, atom/pb_target)
|
||||
if(!bullets)
|
||||
to_chat(user, SPAN_WARNING("You flick your fingers, but find that you don't have any air bullets left!"))
|
||||
return
|
||||
. = ..(hit_atom, user, pb_target)
|
||||
if(.)
|
||||
bullets--
|
||||
maptext = SMALL_FONTS(7, bullets)
|
||||
|
||||
/obj/item/projectile/air_bullet
|
||||
name = "air bullet"
|
||||
icon_state = "plasma_bolt"
|
||||
damage = 30
|
||||
armor_penetration = 10
|
||||
impact_sounds = list(BULLET_IMPACT_MEAT = SOUNDS_BULLET_MEAT, BULLET_IMPACT_METAL = SOUNDS_BULLET_METAL)
|
||||
damage_flags = DAMAGE_FLAG_BULLET
|
||||
damage_type = DAMAGE_BRUTE
|
||||
@@ -0,0 +1,80 @@
|
||||
/singleton/psionic_power/assay
|
||||
name = "Assay"
|
||||
desc = "Assay a creature's psionic level. Using Assay will also allow you to see psionic auras."
|
||||
icon_state = "wiz_blind"
|
||||
point_cost = 0
|
||||
ability_flags = PSI_FLAG_FOUNDATIONAL
|
||||
spell_path = /obj/item/spell/assay
|
||||
|
||||
/obj/item/spell/assay
|
||||
name = "assay"
|
||||
desc = "Read someone's psionic potential."
|
||||
icon_state = "generic"
|
||||
cast_methods = CAST_MELEE|CAST_INNATE
|
||||
aspect = ASPECT_PSIONIC
|
||||
cooldown = 10
|
||||
psi_cost = 2
|
||||
|
||||
/obj/item/spell/assay/on_innate_cast(mob/user)
|
||||
if(!isliving(user))
|
||||
return
|
||||
|
||||
. = ..()
|
||||
if(!.)
|
||||
return
|
||||
|
||||
var/mob/living/L = user
|
||||
|
||||
to_chat(user, SPAN_NOTICE("You can now see psionic auras."))
|
||||
L.psi.show_auras()
|
||||
|
||||
/obj/item/spell/assay/Destroy()
|
||||
if(isliving(owner))
|
||||
var/mob/living/L = owner
|
||||
to_chat(L, SPAN_NOTICE("You can no longer see psionic auras."))
|
||||
L.psi.hide_auras()
|
||||
|
||||
return ..()
|
||||
|
||||
/obj/item/spell/assay/on_melee_cast(atom/hit_atom, mob/living/user, def_zone)
|
||||
. = ..()
|
||||
if(!.)
|
||||
return
|
||||
|
||||
if(!ishuman(hit_atom))
|
||||
return
|
||||
|
||||
if(!isliving(user))
|
||||
return
|
||||
|
||||
var/mob/living/carbon/human/target = hit_atom
|
||||
|
||||
if(target.stat == DEAD || HAS_FLAG(target.status_flags, FAKEDEATH))
|
||||
to_chat(user, SPAN_WARNING("Psionic power does not flow through a dead person."))
|
||||
return
|
||||
|
||||
var/psi_blocked = target.is_psi_blocked()
|
||||
if(psi_blocked)
|
||||
to_chat(user, psi_blocked)
|
||||
return
|
||||
|
||||
user.visible_message(SPAN_NOTICE("[user] lays both [user.get_pronoun("his")] palms on [target]'s temples..."),
|
||||
SPAN_NOTICE("You lay your palms on [target]'s temples and begin tracing their Nlom signature..."))
|
||||
if(do_mob(user, target, 4 SECONDS))
|
||||
if(!target.psi)
|
||||
to_chat(user, SPAN_NOTICE("[target] is psionically perceptive, but nothing more: [target.get_pronoun("he")] cannot manipulate the fabric that weaves \
|
||||
this universe."))
|
||||
if(target.psi)
|
||||
switch(target.psi.get_rank())
|
||||
if(PSI_RANK_SENSITIVE)
|
||||
to_chat(user, SPAN_NOTICE("[target] is psionically sensitive, just like your typical Skrell. They can manipulate psionics, but not to a very \
|
||||
precise degree."))
|
||||
if(PSI_RANK_HARMONIOUS)
|
||||
to_chat(user, SPAN_WARNING("[target] is psionically harmonious. This isn't a feat just about anyone can manage: only those born with a certain \
|
||||
psionic attitude among Skrell can reach this level, and with strenuous training. They are capable of using psionics \
|
||||
with very fine precision."))
|
||||
if(PSI_RANK_APEX)
|
||||
to_chat(user, SPAN_DANGER("Your psionic power is dwarfed by [target]. Just like a supernova in the night sky, their signature is absolutely brilliant \
|
||||
beyond comprehension. This is the apex of psionic power, you are sure."))
|
||||
if(PSI_RANK_LIMITLESS)
|
||||
to_chat(user, SPAN_DANGER("A psionic power like this shouldn't be possible... what in the Stars is going on?"))
|
||||
@@ -0,0 +1,30 @@
|
||||
/singleton/psionic_power/barrier
|
||||
name = "Psionic Barrier"
|
||||
desc = "Activate in hand to give yourself psionic armour. This armour is slightly worse than generic heavy armour, and has a small passive upkeep."
|
||||
icon_state = "const_mend"
|
||||
point_cost = 1
|
||||
ability_flags = PSI_FLAG_ANTAG
|
||||
spell_path = /obj/item/spell/barrier
|
||||
|
||||
/obj/item/spell/barrier
|
||||
name = "psionic barrier"
|
||||
icon_state = "generic"
|
||||
cast_methods = CAST_USE
|
||||
aspect = ASPECT_PSIONIC
|
||||
cooldown = 20
|
||||
psi_cost = 30
|
||||
|
||||
/obj/item/spell/barrier/on_use_cast(mob/user, bypass_psi_check)
|
||||
if(!ishuman(user))
|
||||
return
|
||||
. = ..()
|
||||
if(!.)
|
||||
return
|
||||
|
||||
var/mob/living/carbon/human/H = user
|
||||
var/armor = H.psi.GetComponent(/datum/component/armor/psionic)
|
||||
if(armor)
|
||||
to_chat(H, SPAN_WARNING("You are already enveloped by psionic armour!"))
|
||||
return
|
||||
to_chat(H, SPAN_NOTICE("You are enveloped by a protective warmth."))
|
||||
H.psi.AddComponent(/datum/component/armor/psionic, list(laser = ARMOR_LASER_MEDIUM, bullet = ARMOR_BALLISTIC_CARBINE, energy = ARMOR_ENERGY_RESISTANT, melee = ARMOR_MELEE_RESISTANT))
|
||||
@@ -0,0 +1,33 @@
|
||||
/singleton/psionic_power/bubble
|
||||
name = "Bubble"
|
||||
desc = "Create a protective bubble around you that removes your need to breathe or wear voidsuits in EVA."
|
||||
icon_state = "tech_condensation"
|
||||
point_cost = 1
|
||||
ability_flags = PSI_FLAG_ANTAG
|
||||
spell_path = /obj/item/spell/bubble
|
||||
|
||||
/obj/item/spell/bubble
|
||||
name = "bubble"
|
||||
icon_state = "shield"
|
||||
cast_methods = CAST_INNATE
|
||||
aspect = ASPECT_PSIONIC
|
||||
cooldown = 10
|
||||
psi_cost = 10
|
||||
|
||||
/obj/item/spell/bubble/Destroy()
|
||||
to_chat(owner, SPAN_NOTICE("Your bubble fades away."))
|
||||
REMOVE_TRAIT(owner, TRAIT_NO_BREATHE, TRAIT_SOURCE_PSIONICS)
|
||||
REMOVE_TRAIT(owner, TRAIT_PRESSURE_IMMUNITY, TRAIT_SOURCE_PSIONICS)
|
||||
return ..()
|
||||
|
||||
/obj/item/spell/bubble/on_innate_cast(mob/user)
|
||||
if(!ishuman(user))
|
||||
return
|
||||
. = ..()
|
||||
if(!.)
|
||||
return
|
||||
|
||||
var/mob/living/carbon/human/H = user
|
||||
H.visible_message(SPAN_NOTICE("A protective bubble forms around [H]."), SPAN_NOTICE("You form a protective bubble around yourself."))
|
||||
ADD_TRAIT(H, TRAIT_NO_BREATHE, TRAIT_SOURCE_PSIONICS)
|
||||
ADD_TRAIT(H, TRAIT_PRESSURE_IMMUNITY, TRAIT_SOURCE_PSIONICS)
|
||||
@@ -0,0 +1,32 @@
|
||||
/singleton/psionic_power/charge
|
||||
name = "Charge"
|
||||
desc = "Use this spell on an item with a cell to charge it."
|
||||
icon_state = "wiz_charge"
|
||||
point_cost = 1
|
||||
ability_flags = PSI_FLAG_ANTAG
|
||||
spell_path = /obj/item/spell/charge
|
||||
|
||||
/obj/item/spell/charge
|
||||
name = "charge"
|
||||
icon_state = "audible_deception"
|
||||
cast_methods = CAST_USE
|
||||
aspect = ASPECT_PSIONIC
|
||||
cooldown = 5
|
||||
psi_cost = 5
|
||||
|
||||
/obj/item/spell/charge/on_melee_cast(atom/hit_atom, mob/living/user, def_zone)
|
||||
var/obj/item/cell/C = hit_atom.get_cell()
|
||||
if(!C)
|
||||
return
|
||||
if(C.percent() >= 100)
|
||||
to_chat(user, SPAN_WARNING("That cell is already charged."))
|
||||
return
|
||||
psi_cost = C.maxcharge * 0.001
|
||||
. = ..()
|
||||
if(!.)
|
||||
return
|
||||
user.visible_message(SPAN_NOTICE("[user] lays [get_pronoun("his")] hand on \the [C]..."), SPAN_NOTICE("You lay your hand on \the [C]..."),)
|
||||
if(do_after(user, 1 SECOND))
|
||||
to_chat(user, SPAN_WARNING("You restore some power to \the [C]."))
|
||||
C.give(C.maxcharge * 0.1)
|
||||
psi_cost = initial(psi_cost)
|
||||
@@ -0,0 +1,78 @@
|
||||
/singleton/psionic_power/command
|
||||
name = "Command"
|
||||
desc = "Send a psionic command to a target. It must be one word. The suggestion ends when they finish the task, when a minute passes or \
|
||||
when they take notable damage."
|
||||
icon_state = "wiz_blink"
|
||||
spell_path = /obj/item/spell/command
|
||||
ability_flags = PSI_FLAG_EVENT
|
||||
|
||||
/obj/item/spell/command
|
||||
name = "command"
|
||||
desc = "Send a psionic command to a target."
|
||||
icon_state = "apportation"
|
||||
cast_methods = CAST_RANGED|CAST_MELEE
|
||||
aspect = ASPECT_PSIONIC
|
||||
cooldown = 10
|
||||
psi_cost = 50
|
||||
|
||||
/obj/item/spell/command/on_melee_cast(atom/hit_atom, mob/living/user, def_zone)
|
||||
. = ..()
|
||||
if(!.)
|
||||
return
|
||||
command(hit_atom, user)
|
||||
|
||||
/obj/item/spell/command/on_ranged_cast(atom/hit_atom, mob/user)
|
||||
. = ..()
|
||||
if(!.)
|
||||
return
|
||||
command(hit_atom, user)
|
||||
|
||||
/obj/item/spell/command/proc/command(atom/hit_atom, mob/user)
|
||||
if(!isliving(hit_atom))
|
||||
return
|
||||
|
||||
if(!isliving(user))
|
||||
return
|
||||
|
||||
var/mob/living/L = user
|
||||
var/multi_word = L.psi.get_rank() > PSI_RANK_HARMONIOUS
|
||||
|
||||
var/mob/living/target = hit_atom
|
||||
if(target.stat == DEAD)
|
||||
to_chat(user, SPAN_WARNING("Not even a psion of your level can speak to the dead."))
|
||||
return
|
||||
|
||||
var/psi_blocked = target.is_psi_blocked()
|
||||
if(psi_blocked)
|
||||
to_chat(user, psi_blocked)
|
||||
return
|
||||
|
||||
user.visible_message(SPAN_CULT("[user] opens a palm and aims it at [hit_atom]..."))
|
||||
var/text = input("Enter your command. [multi_word ? "This command may be up to 5 words." : "This command may only be one word."]", "Command", null, null)
|
||||
if(!text)
|
||||
return
|
||||
text = formalize_text(text)
|
||||
|
||||
if(target.stat == DEAD)
|
||||
to_chat(user, SPAN_WARNING("Not even a psion of your level can speak to the dead."))
|
||||
return
|
||||
|
||||
log_say("[key_name(user)] issued a [multi_word ? "multi-word" : "single-word"] command to [key_name(target)]: [text]",ckey=key_name(src))
|
||||
|
||||
to_chat(user, SPAN_CULT("You psionically command to [target]: [text]"))
|
||||
|
||||
for (var/mob/M in player_list)
|
||||
if (istype(M, /mob/abstract/new_player))
|
||||
continue
|
||||
else if(M.stat == DEAD && HAS_FLAG(M.client.prefs.toggles, CHAT_GHOSTEARS))
|
||||
to_chat(M, "<span class='notice'>[user] psionically commands to [target]:</span> [text]")
|
||||
|
||||
var/mob/living/carbon/human/H = target
|
||||
if(H.has_psionics())
|
||||
to_chat(H, SPAN_CULT("<b>You are psionically commanded to carry out the following task:</b> [text]."))
|
||||
else if(target.has_psi_aug())
|
||||
to_chat(H, SPAN_CULT("<b>You sense [user]'s psyche link with your psi-receiver, a command sliding into your mind:</b> [text]"))
|
||||
else
|
||||
to_chat(H, SPAN_CULT("<b>A thought from outside your consciousness slips into your mind:</b> [text]"))
|
||||
to_chat(H, SPAN_DANGER("You are required to follow this command. It ends when a minute has passed, when you carry it out, or when you take a significant amount \
|
||||
of damage. [multi_word ? "You are required to follow up to five words." : "You are required to only follow the first word of the command."]"))
|
||||
@@ -0,0 +1,71 @@
|
||||
/singleton/psionic_power/commune
|
||||
name = "Commune"
|
||||
desc = "Psionically commune with the target."
|
||||
icon_state = "tech_audibledeception"
|
||||
point_cost = 0
|
||||
ability_flags = PSI_FLAG_FOUNDATIONAL
|
||||
spell_path = /obj/item/spell/commune
|
||||
|
||||
/obj/item/spell/commune
|
||||
name = "commune"
|
||||
desc = "Déjà-vu."
|
||||
icon_state = "overload"
|
||||
cast_methods = CAST_RANGED|CAST_MELEE
|
||||
aspect = ASPECT_PSIONIC
|
||||
cooldown = 10
|
||||
psi_cost = 15
|
||||
|
||||
/obj/item/spell/commune/on_melee_cast(atom/hit_atom, mob/living/user, def_zone)
|
||||
. = ..()
|
||||
if(!.)
|
||||
return
|
||||
commune(hit_atom, user)
|
||||
|
||||
/obj/item/spell/commune/on_ranged_cast(atom/hit_atom, mob/user)
|
||||
. = ..()
|
||||
if(!.)
|
||||
return
|
||||
commune(hit_atom, user)
|
||||
|
||||
/obj/item/spell/commune/proc/commune(atom/hit_atom, mob/user)
|
||||
if(!isliving(hit_atom))
|
||||
return
|
||||
|
||||
var/mob/living/target = hit_atom
|
||||
if(target.stat == DEAD)
|
||||
to_chat(user, SPAN_WARNING("Not even a psion of your level can speak to the dead."))
|
||||
return
|
||||
|
||||
var/psi_blocked = target.is_psi_blocked()
|
||||
if(psi_blocked)
|
||||
to_chat(user, psi_blocked)
|
||||
return
|
||||
|
||||
user.visible_message(SPAN_NOTICE("<i>[user] blinks, their eyes briefly developing an unnatural shine.</i>"))
|
||||
var/text = input("What would you like to say?", "Speak to creature", null, null)
|
||||
text = sanitize(text)
|
||||
if(!text)
|
||||
return
|
||||
text = formalize_text(text)
|
||||
|
||||
if(target.stat == DEAD)
|
||||
to_chat(user, SPAN_WARNING("Not even a psion of your level can speak to the dead."))
|
||||
return
|
||||
|
||||
log_say("[key_name(user)] communed to [key_name(target)]: [text]",ckey=key_name(src))
|
||||
|
||||
to_chat(user, SPAN_CULT("You psionically say to [target]: [text]"))
|
||||
|
||||
for (var/mob/M in player_list)
|
||||
if (istype(M, /mob/abstract/new_player))
|
||||
continue
|
||||
else if(M.stat == DEAD && M.client.prefs.toggles & CHAT_GHOSTEARS)
|
||||
to_chat(M, "<span class='notice'>[user] psionically says to [target]:</span> [text]")
|
||||
|
||||
var/mob/living/carbon/human/H = target
|
||||
if(H.has_psionics())
|
||||
to_chat(H, SPAN_CULT("<b>You instinctively sense [user] passing a thought into your mind:</b> [text]"))
|
||||
else if(target.has_psi_aug())
|
||||
to_chat(H, SPAN_CULT("<b>You sense [user]'s psyche link with your psi-receiver, a thought sliding into your mind:</b> [text]"))
|
||||
else
|
||||
to_chat(H, SPAN_ALIEN("<b>A thought from outside your consciousness slips into your mind:</b> [text]"))
|
||||
@@ -0,0 +1,30 @@
|
||||
/singleton/psionic_power/electrocute
|
||||
name = "Electrocute"
|
||||
desc = "Administer a painful amount of psionic shock to the nervous system of a foe in melee range, causing burn and agony damage. "
|
||||
icon_state = "tech_shockaura"
|
||||
point_cost = 2
|
||||
ability_flags = PSI_FLAG_ANTAG
|
||||
spell_path = /obj/item/spell/electrocute
|
||||
|
||||
/obj/item/spell/electrocute
|
||||
name = "electrocute"
|
||||
icon_state = "chain_lightning"
|
||||
cast_methods = CAST_MELEE
|
||||
aspect = ASPECT_PSIONIC
|
||||
cooldown = 10
|
||||
psi_cost = 5
|
||||
hitsound = 'sound/effects/psi/power_evoke.ogg'
|
||||
attack_verb = list("lays a palm on")
|
||||
|
||||
/obj/item/spell/electrocute/on_melee_cast(atom/hit_atom, mob/living/user, def_zone)
|
||||
if(!ishuman(hit_atom))
|
||||
to_chat(user, SPAN_WARNING("That won't work!"))
|
||||
return
|
||||
. = ..()
|
||||
if(!.)
|
||||
return
|
||||
var/mob/living/carbon/human/H = hit_atom
|
||||
H.adjustHalLoss(20)
|
||||
H.adjustFireLoss(20)
|
||||
H.flash_pain(20)
|
||||
to_chat(H, SPAN_DANGER("A sharp, stinging pain enters your mind!"))
|
||||
@@ -0,0 +1,70 @@
|
||||
/singleton/psionic_power/emotional_suggestion
|
||||
name = "Emotional Suggestion"
|
||||
desc = "Allows you to psionically commune with the target."
|
||||
icon_state = "tech_gambit"
|
||||
ability_flags = PSI_FLAG_EVENT|PSI_FLAG_CANON
|
||||
spell_path = /obj/item/spell/emotional_suggestion
|
||||
|
||||
/obj/item/spell/emotional_suggestion
|
||||
name = "emotional suggestion"
|
||||
desc = "Suggest an emotion to someone."
|
||||
icon_state = "generic"
|
||||
cast_methods = CAST_RANGED|CAST_MELEE
|
||||
aspect = ASPECT_PSIONIC
|
||||
cooldown = 10
|
||||
psi_cost = 15
|
||||
|
||||
/obj/item/spell/emotional_suggestion/on_melee_cast(atom/hit_atom, mob/living/user, def_zone)
|
||||
. = ..()
|
||||
if(!.)
|
||||
return
|
||||
emotional_suggestion(hit_atom, user)
|
||||
|
||||
/obj/item/spell/emotional_suggestion/on_ranged_cast(atom/hit_atom, mob/user)
|
||||
. = ..()
|
||||
if(!.)
|
||||
return
|
||||
emotional_suggestion(hit_atom, user)
|
||||
|
||||
/obj/item/spell/emotional_suggestion/proc/emotional_suggestion(atom/hit_atom, mob/user)
|
||||
if(!isliving(hit_atom))
|
||||
return
|
||||
|
||||
var/mob/living/target = hit_atom
|
||||
if(target.stat == DEAD)
|
||||
to_chat(user, SPAN_WARNING("Not even a psion of your level can suggest to the dead."))
|
||||
return
|
||||
|
||||
var/psi_blocked = target.is_psi_blocked()
|
||||
if(psi_blocked)
|
||||
to_chat(user, psi_blocked)
|
||||
return
|
||||
|
||||
user.visible_message(SPAN_NOTICE("<i>[user] blinks, their eyes briefly developing an unnatural shine.</i>"))
|
||||
var/text = input("Which emotion would you like to suggest?", "Emotional Suggestion") as null|anything in list("Calm", "Happiness", "Sadness", "Fear", "Anger", "Stress", "Confusion")
|
||||
if(!text)
|
||||
return
|
||||
|
||||
text = lowertext(text)
|
||||
|
||||
if(target.stat == DEAD)
|
||||
to_chat(user, SPAN_WARNING("Not even a psion of your level can suggest to the dead."))
|
||||
return
|
||||
|
||||
log_say("[key_name(user)] suggested an emotion to [key_name(target)]: [text]",ckey=key_name(src))
|
||||
|
||||
to_chat(user, SPAN_CULT("You psionically suggest an emotion to [target]: [text]"))
|
||||
|
||||
for (var/mob/M in player_list)
|
||||
if (istype(M, /mob/abstract/new_player))
|
||||
continue
|
||||
else if(M.stat == DEAD && HAS_FLAG(M.client.prefs.toggles, CHAT_GHOSTEARS))
|
||||
to_chat(M, "<span class='notice'>[user] psionically suggests an emotion to [target]:</span> [text]")
|
||||
|
||||
var/mob/living/carbon/human/H = target
|
||||
if(H.has_psionics())
|
||||
to_chat(H, SPAN_NOTICE("You feel an emotion of <b>[text]</b> washing through your mind."))
|
||||
else if(target.has_psi_aug())
|
||||
to_chat(H, SPAN_NOTICE("You sense [user]'s psyche link with your psi-receiver, and an emotion envelops your mind: <b>[text]</b>."))
|
||||
else
|
||||
to_chat(H, SPAN_NOTICE("An emotion from outside your consciousness slips into your mind: <b>[text]</b>."))
|
||||
@@ -0,0 +1,28 @@
|
||||
/singleton/psionic_power/focus
|
||||
name = "Focus"
|
||||
desc = "Activate this spell in your hand to generate five units of synaptizine in your bloodstream."
|
||||
icon_state = "tech_phaseshift"
|
||||
point_cost = 1
|
||||
ability_flags = PSI_FLAG_EVENT
|
||||
spell_path = /obj/item/spell/focus
|
||||
|
||||
/obj/item/spell/focus
|
||||
name = "focus"
|
||||
desc = "Psionic drugs? No way."
|
||||
icon_state = "blink"
|
||||
cast_methods = CAST_USE
|
||||
aspect = ASPECT_PSIONIC
|
||||
cooldown = 50
|
||||
psi_cost = 20
|
||||
|
||||
/obj/item/spell/focus/on_use_cast(mob/user)
|
||||
if(!ishuman(user))
|
||||
return
|
||||
. = ..()
|
||||
if(!.)
|
||||
return
|
||||
var/mob/living/carbon/human/H = user
|
||||
if(do_after(user, 1 SECOND))
|
||||
to_chat(H, SPAN_WARNING("A calm rush envelops your mind.."))
|
||||
H.reagents.add_reagent(/singleton/reagent/synaptizine, 5)
|
||||
H.update_canmove()
|
||||
@@ -0,0 +1,51 @@
|
||||
/singleton/psionic_power/grip
|
||||
name = "Grip"
|
||||
desc = "Grip a victim with psionic energy. You can squeeze your grip to crush them."
|
||||
icon_state = "ling_bioelectrogenesis"
|
||||
point_cost = 3
|
||||
ability_flags = PSI_FLAG_ANTAG
|
||||
spell_path = /obj/item/spell/grip
|
||||
|
||||
/obj/item/spell/grip
|
||||
name = "stasis"
|
||||
desc = "General Kenobi..."
|
||||
icon_state = "blink"
|
||||
cast_methods = CAST_RANGED|CAST_USE
|
||||
aspect = ASPECT_PSIONIC
|
||||
cooldown = 15
|
||||
psi_cost = 5
|
||||
var/mob/living/victim
|
||||
|
||||
/obj/item/spell/grip/Destroy()
|
||||
victim.captured = FALSE
|
||||
victim.update_canmove()
|
||||
victim = null
|
||||
return ..()
|
||||
|
||||
/obj/item/spell/grip/on_use_cast(mob/user, bypass_psi_check)
|
||||
if(!victim)
|
||||
to_chat(user, SPAN_WARNING("You need to grip someone first!"))
|
||||
return
|
||||
. = ..()
|
||||
if(!.)
|
||||
return
|
||||
user.visible_message(SPAN_WARNING("[user] squeezes [user.get_pronoun("his")] hand!"), SPAN_WARNING("You squeeze your hand to tighten the psionic force around [victim]."))
|
||||
to_chat(victim, SPAN_DANGER(FONT_HUGE("You are crushed by an invisible force!")))
|
||||
victim.apply_damage(30, DAMAGE_BRUTE, armor_pen = 30, damage_flags = DAMAGE_FLAG_DISPERSED)
|
||||
|
||||
/obj/item/spell/grip/on_ranged_cast(atom/hit_atom, mob/user, bypass_psi_check)
|
||||
if(!isliving(hit_atom))
|
||||
return
|
||||
if(victim)
|
||||
to_chat(user, SPAN_WARNING("You can't target more than one person with this!"))
|
||||
return
|
||||
. = ..()
|
||||
if(!.)
|
||||
return
|
||||
var/mob/living/M = hit_atom
|
||||
user.visible_message(SPAN_DANGER("[user] extends [user.get_pronoun("his")] arm and makes a grab motion towards [M]!"),
|
||||
SPAN_DANGER("You extend your arm and grab [M] with your psionic energy!"))
|
||||
to_chat(M, SPAN_DANGER(FONT_HUGE("You feel an invisible force tighten around you!")))
|
||||
M.captured = TRUE
|
||||
M.update_canmove()
|
||||
victim = M
|
||||
@@ -0,0 +1,106 @@
|
||||
/singleton/psionic_power/hollow_purple
|
||||
name = "Hollow Technique: Purple"
|
||||
desc = "This technique brings the concept of motion and reversal into reality. Purple is born from merging both infinites: Blue and Red, \
|
||||
to produce an imaginary mass that rushes forth and erases everything in its path. Rather than the attraction of Blue or the repulsion of Red, \
|
||||
Purple is an extraordinarily destructive energy wave of annihilation that rips whatever it hits from existence."
|
||||
icon_state = "hollow_purple"
|
||||
point_cost = 0
|
||||
ability_flags = PSI_FLAG_LIMITLESS
|
||||
minimum_rank = PSI_FLAG_LIMITLESS
|
||||
spell_path = /obj/item/spell/projectile/hollow_purple
|
||||
|
||||
/obj/item/spell/projectile/hollow_purple
|
||||
name = "hollow purple"
|
||||
desc = "Throughout Heaven and Earth, I alone am the honored one!"
|
||||
icon_state = "destablize"
|
||||
cast_methods = CAST_RANGED
|
||||
aspect = ASPECT_PSIONIC
|
||||
spell_projectile = /obj/item/projectile/hollow_purple
|
||||
fire_sound = 'sound/magic/WandODeath.ogg'
|
||||
cooldown = 10
|
||||
psi_cost = 50
|
||||
var/stage = 0
|
||||
|
||||
/obj/item/spell/projectile/hollow_purple/on_ranged_cast(atom/hit_atom, mob/living/user, atom/pb_target)
|
||||
if(!isliving(user))
|
||||
return
|
||||
|
||||
stage = 1
|
||||
user.visible_message(SPAN_NOTICE("<b><font size=4>[user] puts [user.get_pronoun("his")] palms together...</font></b>"))
|
||||
START_PROCESSING(SSprocessing, src)
|
||||
user.say("Cursed Technique Amplification: Blue...")
|
||||
user.set_light(7, 10, COLOR_BLUE)
|
||||
color = COLOR_BLUE
|
||||
if(do_after(user, 4 SECONDS))
|
||||
stage = 2
|
||||
color = COLOR_RED
|
||||
user.say("Cursed Technique Reversal: Red...")
|
||||
user.set_light(0)
|
||||
user.set_light(7, 10, COLOR_RED)
|
||||
if(do_after(user, 4 SECONDS))
|
||||
user.say("Hollow Technique: Purple!")
|
||||
user.set_light(0)
|
||||
user.visible_message(SPAN_CULT("<b><font size=4>[user] fires a gigantic purple sphere from [user.get_pronoun("his")] hand!</font></b>"))
|
||||
. = ..()
|
||||
|
||||
STOP_PROCESSING(SSprocessing, src)
|
||||
color = initial(color)
|
||||
user.set_light(0)
|
||||
stage = 0
|
||||
|
||||
/obj/item/spell/projectile/hollow_purple/process()
|
||||
if(stage >= 1)
|
||||
for(var/mob/living/L in get_hearers_in_view(7, src))
|
||||
shake_camera(L, 5, 5)
|
||||
|
||||
/obj/item/projectile/hollow_purple
|
||||
name = "hollow purple"
|
||||
icon_state = "hollow_purple"
|
||||
color = COLOR_PURPLE
|
||||
damage = 1000
|
||||
armor_penetration = 1000
|
||||
penetrating = 100
|
||||
range = 250
|
||||
accuracy = 100
|
||||
anti_materiel_potential = 100
|
||||
damage_type = DAMAGE_BRUTE
|
||||
|
||||
/obj/item/projectile/hollow_purple/Initialize()
|
||||
. = ..()
|
||||
set_light(10, 10, COLOR_PURPLE)
|
||||
|
||||
/obj/item/projectile/hollow_purple/Destroy()
|
||||
return ..()
|
||||
|
||||
/obj/item/projectile/hollow_purple/on_impact(var/atom/A)
|
||||
if(ismob(A))
|
||||
if(A != firer)
|
||||
var/mob/M = A
|
||||
M.gib()
|
||||
explosion(A, 5, 5, 5)
|
||||
..()
|
||||
|
||||
/obj/item/projectile/hollow_purple/on_hit(atom/target, blocked, def_zone)
|
||||
if(ismob(target))
|
||||
if(target != firer)
|
||||
var/mob/M = target
|
||||
M.gib()
|
||||
explosion(target, 5, 5, 5)
|
||||
..()
|
||||
|
||||
/obj/item/projectile/hollow_purple/check_penetrate(atom/A)
|
||||
on_hit(A)
|
||||
return TRUE
|
||||
|
||||
/obj/item/projectile/hollow_purple/after_move()
|
||||
for(var/a in range(3, src))
|
||||
if(isliving(a) && a != firer)
|
||||
var/mob/living/M = a
|
||||
M.gib()
|
||||
playsound(src, 'sound/magic/LightningShock.ogg', 75, 1)
|
||||
else if(isturf(a) || isobj(a))
|
||||
var/atom/A = a
|
||||
if(!A.density)
|
||||
continue
|
||||
A.ex_act(3)
|
||||
playsound(src, 'sound/magic/LightningShock.ogg', 75, 1)
|
||||
@@ -0,0 +1,24 @@
|
||||
/singleton/psionic_power/ion
|
||||
name = "Ion Blast"
|
||||
desc = "Activate in hand to release a 3x3 ion blast around you. Be careful, this ability is expensive to use."
|
||||
icon_state = "const_mend"
|
||||
point_cost = 3
|
||||
ability_flags = PSI_FLAG_ANTAG
|
||||
spell_path = /obj/item/spell/ion
|
||||
|
||||
/obj/item/spell/ion
|
||||
name = "ion blast"
|
||||
icon_state = "generic"
|
||||
cast_methods = CAST_USE
|
||||
aspect = ASPECT_PSIONIC
|
||||
cooldown = 20
|
||||
psi_cost = 30
|
||||
|
||||
/obj/item/spell/ion/on_use_cast(mob/user, bypass_psi_check)
|
||||
. = ..()
|
||||
if(!.)
|
||||
return
|
||||
|
||||
user.visible_message(SPAN_DANGER("<font size=4>[user] opens their arms and releases an ion blast around them!</font>"),
|
||||
SPAN_DANGER("<font size=4>You open your arms and release an ion blast around you!</font>"))
|
||||
empulse(get_turf(user), 3, 3)
|
||||
@@ -0,0 +1,22 @@
|
||||
/singleton/psionic_power/jump
|
||||
name = "Jump"
|
||||
desc = "Teleport to a destination you click on."
|
||||
icon_state = "tech_dispel"
|
||||
point_cost = 3
|
||||
ability_flags = PSI_FLAG_ANTAG
|
||||
spell_path = /obj/item/spell/jump
|
||||
|
||||
/obj/item/spell/jump
|
||||
name = "jump"
|
||||
icon_state = "warp_strike"
|
||||
cast_methods = CAST_RANGED
|
||||
aspect = ASPECT_PSIONIC
|
||||
cooldown = 50
|
||||
psi_cost = 15
|
||||
|
||||
/obj/item/spell/jump/on_ranged_cast(atom/hit_atom, mob/user, bypass_psi_check)
|
||||
. = ..()
|
||||
if(!.)
|
||||
return
|
||||
user.visible_message(SPAN_WARNING("[user] warps and disappears!"), SPAN_WARNING("You weave the Nlom to bring you to your destination!"))
|
||||
do_teleport(user, hit_atom)
|
||||
@@ -0,0 +1,59 @@
|
||||
/singleton/psionic_power/lightning
|
||||
name = "Lightning"
|
||||
desc = "Fire a concentrated lightning bolt. Activate this spell in hand to switch to a second mode that hits living beings in a 4x3 area in front of you."
|
||||
icon_state = "tech_instabilitytapold"
|
||||
point_cost = 0
|
||||
ability_flags = PSI_FLAG_APEX
|
||||
minimum_rank = PSI_RANK_APEX
|
||||
spell_path = /obj/item/spell/projectile/psi_lightning
|
||||
|
||||
/obj/item/spell/projectile/psi_lightning
|
||||
name = "lightning"
|
||||
icon_state = "chain_lightning"
|
||||
cast_methods = CAST_RANGED|CAST_USE
|
||||
aspect = ASPECT_PSIONIC
|
||||
spell_projectile = /obj/item/projectile/beam/psi_lightning
|
||||
fire_sound = 'sound/magic/LightningShock.ogg'
|
||||
cooldown = 10
|
||||
psi_cost = 15
|
||||
var/mode = 0
|
||||
|
||||
/obj/item/spell/projectile/psi_lightning/on_use_cast(mob/user, bypass_psi_check)
|
||||
. = ..(user, TRUE)
|
||||
mode = !mode
|
||||
if(mode)
|
||||
to_chat(user, SPAN_NOTICE("You will now fire area-of-effect lightning in a 4x3 area in front of you."))
|
||||
spell_projectile = /obj/item/projectile/beam/psi_lightning/wide
|
||||
|
||||
else
|
||||
to_chat(user, SPAN_NOTICE("You will now fire a normal lightning bolt."))
|
||||
spell_projectile = /obj/item/projectile/beam/psi_lightning
|
||||
|
||||
/obj/item/projectile/beam/psi_lightning
|
||||
name = "psionic lightning"
|
||||
damage = 30
|
||||
armor_penetration = 30
|
||||
damage_type = DAMAGE_BURN
|
||||
pass_flags = PASSTABLE | PASSGRILLE | PASSRAILING
|
||||
range = 40
|
||||
accuracy = 100
|
||||
|
||||
muzzle_type = /obj/effect/projectile/muzzle/tesla
|
||||
tracer_type = /obj/effect/projectile/tracer/tesla
|
||||
impact_type = /obj/effect/projectile/impact/tesla
|
||||
|
||||
|
||||
/obj/item/projectile/beam/psi_lightning/pellet
|
||||
damage = 20
|
||||
armor_penetration = 20
|
||||
|
||||
/obj/item/projectile/beam/psi_lightning/wide
|
||||
damage = 20
|
||||
armor_penetration = 20
|
||||
|
||||
/obj/item/projectile/beam/psi_lightning/wide/Initialize()
|
||||
for(var/i = 1 to 4)
|
||||
var/turf/new_turf = get_random_turf_in_range(get_turf(firer), i + rand(0, i), 0, TRUE, FALSE)
|
||||
var/obj/item/projectile/beam/psi_lightning/pellet/pellet = new type(new_turf)
|
||||
var/turf/front_turf = get_step(pellet, pellet.dir)
|
||||
pellet.launch_projectile(front_turf)
|
||||
@@ -0,0 +1,69 @@
|
||||
/singleton/psionic_power/mend
|
||||
name = "Mend"
|
||||
desc = "Mend a creature's wounds. This handles internal wounds as well, such as ruptured organs and broken bones."
|
||||
icon_state = "tech_biomedaura"
|
||||
point_cost = 2
|
||||
ability_flags = PSI_FLAG_ANTAG
|
||||
spell_path = /obj/item/spell/mend
|
||||
|
||||
/obj/item/spell/mend
|
||||
name = "mend"
|
||||
desc = "Clear!"
|
||||
icon_state = "mend_wounds"
|
||||
cast_methods = CAST_MELEE
|
||||
aspect = ASPECT_PSIONIC
|
||||
cooldown = 50
|
||||
psi_cost = 30
|
||||
|
||||
/obj/item/spell/mend/on_melee_cast(atom/hit_atom, mob/living/user, def_zone)
|
||||
if(!ishuman(hit_atom))
|
||||
return
|
||||
|
||||
var/mob/living/carbon/human/H = hit_atom
|
||||
if(!H.has_zona_bovinae())
|
||||
to_chat(user, SPAN_WARNING("Psionic power cannot flow through this being."))
|
||||
return
|
||||
|
||||
if(H.stat == DEAD || H.status_flags & FAKEDEATH)
|
||||
to_chat(user, SPAN_WARNING("Psionic power does not flow through a dead person."))
|
||||
return
|
||||
|
||||
. = ..()
|
||||
if(!.)
|
||||
return
|
||||
|
||||
user.visible_message(SPAN_NOTICE("[user] lays a palm on [H]..."), SPAN_NOTICE("You lay your palm on [H] and get to work."))
|
||||
to_chat(user, SPAN_NOTICE("You start by flowing your regenerative psionic energy through their vital organs..."))
|
||||
for(var/obj/item/organ/O in H.internal_organs)
|
||||
if(do_mob(user, H, 15 SECONDS))
|
||||
if(O.damage > 0) // Fix internal damage
|
||||
to_chat(SPAN_NOTICE("You mend their [O]'s bruising."))
|
||||
O.heal_damage(O.damage)
|
||||
if(HAS_FLAG(O.status, ORGAN_BROKEN))
|
||||
to_chat(SPAN_NOTICE("You restart their [O]'s functionality."))
|
||||
O.status &= ~ORGAN_BROKEN
|
||||
if(O.damage <= 5 && O.organ_tag == BP_EYES) // Fix eyes
|
||||
H.sdisabilities &= ~BLIND
|
||||
|
||||
to_chat(user, SPAN_NOTICE("You continue by flowing your regenerative psionic energy through their limbs..."))
|
||||
for(var/obj/item/organ/external/O in H.organs) // Fix limbs
|
||||
if(!O.robotic < ORGAN_ROBOT) // No robot parts for this.
|
||||
continue
|
||||
if(do_mob(user, H, 15 SECONDS))
|
||||
to_chat(SPAN_NOTICE("You mend their [O]'s bruising."))
|
||||
O.heal_damage(0, O.damage, internal = TRUE, robo_repair = FALSE)
|
||||
|
||||
to_chat(user, SPAN_NOTICE("Finally, you flowing your regenerative psionic energy through their broken limbs..."))
|
||||
for(var/obj/item/organ/E in H.bad_external_organs) // Fix bones
|
||||
var/obj/item/organ/external/affected = E
|
||||
if(do_mob(user, H, 10 SECONDS))
|
||||
if((affected.damage < affected.min_broken_damage * config.organ_health_multiplier) && (affected.status & ORGAN_BROKEN))
|
||||
to_chat(SPAN_NOTICE("You mend their [affected] together."))
|
||||
affected.status &= ~ORGAN_BROKEN
|
||||
if(HAS_FLAG(affected.status, ORGAN_ARTERY_CUT))
|
||||
to_chat(SPAN_NOTICE("You mend a spliced artery in their [affected]."))
|
||||
affected.status &= ~ORGAN_ARTERY_CUT
|
||||
if(HAS_FLAG(affected.status, ORGAN_DEAD))
|
||||
to_chat(SPAN_NOTICE("You mend some necrosis from their [affected]."))
|
||||
affected.status &= ~ORGAN_DEAD
|
||||
user.visible_message(SPAN_NOTICE("[user] raises their palm from [H]."), SPAN_NOTICE("You raise your palm, having finished your work."))
|
||||
@@ -0,0 +1,29 @@
|
||||
/singleton/psionic_power/mind_muddle
|
||||
name = "Mind Muddle"
|
||||
desc = "Use this at range to confuse a target and give them a little bit of pain."
|
||||
icon_state = "wiz_tele"
|
||||
point_cost = 1
|
||||
ability_flags = PSI_FLAG_EVENT
|
||||
spell_path = /obj/item/spell/mind_muddle
|
||||
|
||||
/obj/item/spell/mind_muddle
|
||||
name = "mind muddle"
|
||||
desc = "Confuse people. That's all it does. Oh, and the pain."
|
||||
icon_state = "warp_strike"
|
||||
cast_methods = CAST_RANGED
|
||||
aspect = ASPECT_PSIONIC
|
||||
cooldown = 20
|
||||
psi_cost = 10
|
||||
|
||||
/obj/item/spell/mind_muddle/on_ranged_cast(atom/hit_atom, mob/user, bypass_psi_check)
|
||||
if(!ishuman(hit_atom))
|
||||
to_chat(user, SPAN_WARNING("That won't work on them!"))
|
||||
return
|
||||
. = ..()
|
||||
if(!.)
|
||||
return
|
||||
var/mob/living/carbon/human/H = hit_atom
|
||||
H.confused += 20
|
||||
to_chat(H, SPAN_DANGER("A stinging sensation fills your mind! You feel nauseated..."))
|
||||
H.adjustHalLoss(15)
|
||||
|
||||
@@ -0,0 +1,53 @@
|
||||
/singleton/psionic_power/mirror_shade
|
||||
name = "Mirror Shade"
|
||||
desc = "Activate this spell to generate two psionic copies of yourself that will attack nearby mobs. These clones are not dense, will deal pain damage, and disappear \
|
||||
after thirty seconds."
|
||||
icon_state = "wiz_jaunt"
|
||||
point_cost = 2
|
||||
ability_flags = PSI_FLAG_EVENT
|
||||
spell_path = /obj/item/spell/mirror_shade
|
||||
|
||||
/obj/item/spell/mirror_shade
|
||||
name = "mirror shade"
|
||||
desc = "Photocopy yourself."
|
||||
icon_state = "darkness"
|
||||
cast_methods = CAST_USE
|
||||
aspect = ASPECT_PSIONIC
|
||||
cooldown = 100
|
||||
psi_cost = 20
|
||||
|
||||
/obj/item/spell/mirror_shade/on_use_cast(mob/user)
|
||||
. = ..()
|
||||
if(!.)
|
||||
return
|
||||
if(do_after(user, 1 SECOND))
|
||||
to_chat(user, SPAN_WARNING("You weave your psionic force into two copies of yourself!"))
|
||||
for(var/i = 1 to 2)
|
||||
var/mob/living/simple_animal/hostile/mirror_shade/MS = new(pick(get_adjacent_open_turfs(user)))
|
||||
MS.appearance = user.appearance
|
||||
MS.name = user.name
|
||||
MS.owner = user
|
||||
|
||||
/mob/living/simple_animal/hostile/mirror_shade
|
||||
damage_type = DAMAGE_PAIN
|
||||
density = FALSE
|
||||
destroy_surroundings = FALSE
|
||||
melee_damage_lower = 10
|
||||
melee_damage_upper = 15
|
||||
attack_emote = "tries shambling towards"
|
||||
attacktext = "phases its arms through"
|
||||
var/mob/living/carbon/human/owner
|
||||
|
||||
/mob/living/simple_animal/hostile/mirror_shade/Initialize()
|
||||
. = ..()
|
||||
friends += owner
|
||||
QDEL_IN(src, 30 SECONDS)
|
||||
|
||||
/mob/living/simple_animal/hostile/mirror_shade/examine(mob/user)
|
||||
/// Technically suspicious, but these have 30 seconds of lifetime so it's probably fine.
|
||||
return owner.examine(user)
|
||||
|
||||
/mob/living/simple_animal/hostile/mirror_shade/Destroy()
|
||||
owner = null
|
||||
visible_message(SPAN_WARNING("[src] dissipates into nothingness, as if it were air all along!"))
|
||||
return ..()
|
||||
@@ -0,0 +1,76 @@
|
||||
/singleton/psionic_power/nlom_eyes
|
||||
name = "Nlom Eyes"
|
||||
desc = "Roughly locate a mob on your z-level."
|
||||
icon_state = "tech_control"
|
||||
point_cost = 2
|
||||
ability_flags = PSI_FLAG_ANTAG
|
||||
spell_path = /obj/item/spell/nlom_eyes
|
||||
|
||||
/obj/item/spell/nlom_eyes
|
||||
name = "nlom eyes"
|
||||
desc = "Psionic drugs? No way."
|
||||
icon_state = "track"
|
||||
cast_methods = CAST_USE
|
||||
aspect = ASPECT_PSIONIC
|
||||
cooldown = 10
|
||||
psi_cost = 5
|
||||
/// The mob we are tracking.
|
||||
var/mob/living/tracked
|
||||
/// If we are tracking a mob.
|
||||
var/tracking = FALSE
|
||||
|
||||
/obj/item/spell/nlom_eyes/Destroy()
|
||||
tracked = null
|
||||
tracking = 0
|
||||
STOP_PROCESSING(SSprocessing, src)
|
||||
return ..()
|
||||
|
||||
/obj/item/spell/nlom_eyes/on_use_cast(mob/user)
|
||||
if(tracking)
|
||||
tracking = FALSE
|
||||
to_chat(user, SPAN_NOTICE("You stop looking in the Nlom for \the [tracked]'s whereabouts."))
|
||||
tracked = null
|
||||
STOP_PROCESSING(SSprocessing, src)
|
||||
icon_state = "track"
|
||||
return
|
||||
. = ..()
|
||||
if(!.)
|
||||
return
|
||||
|
||||
var/list/mob_choices = list()
|
||||
for(var/mob/living/L in mob_list)
|
||||
if(L == user)
|
||||
continue
|
||||
if(!L.is_psi_blocked())
|
||||
continue
|
||||
if(GET_Z(L) != GET_Z(user))
|
||||
continue
|
||||
mob_choices += L
|
||||
var/choice = input(user, "Decide who to track.", "Nlom Eyes") as null|anything in mob_choices
|
||||
if(choice)
|
||||
tracked = choice
|
||||
tracking = TRUE
|
||||
START_PROCESSING(SSprocessing, src)
|
||||
|
||||
/obj/item/spell/track/process()
|
||||
if(!tracking)
|
||||
icon_state = "track"
|
||||
return
|
||||
|
||||
if(!tracked)
|
||||
icon_state = "track_unknown"
|
||||
|
||||
if(GET_Z(tracked) != GET_Z(owner))
|
||||
icon_state = "track_unknown"
|
||||
|
||||
else
|
||||
set_dir(get_dir(src,get_turf(tracked)))
|
||||
switch(get_dist(src,get_turf(tracked)))
|
||||
if(0)
|
||||
icon_state = "track_direct"
|
||||
if(1 to 8)
|
||||
icon_state = "track_close"
|
||||
if(9 to 16)
|
||||
icon_state = "track_medium"
|
||||
if(16 to INFINITY)
|
||||
icon_state = "track_far"
|
||||
@@ -0,0 +1,43 @@
|
||||
/singleton/psionic_power/awaken
|
||||
name = "Awaken"
|
||||
desc = "Stimulate a living being's Zona Bovinae and bring them to Psionically Harmonious rank."
|
||||
icon_state = "tech_corona"
|
||||
point_cost = 0
|
||||
ability_flags = PSI_FLAG_APEX
|
||||
minimum_rank = PSI_RANK_APEX
|
||||
spell_path = /obj/item/spell/awaken
|
||||
|
||||
/obj/item/spell/awaken
|
||||
name = "awaken"
|
||||
icon_state = "energy_siphon_drain"
|
||||
cast_methods = CAST_MELEE
|
||||
aspect = ASPECT_PSIONIC
|
||||
cooldown = 20
|
||||
psi_cost = 100
|
||||
|
||||
/obj/item/spell/awaken/on_melee_cast(atom/hit_atom, mob/living/user, def_zone)
|
||||
if(!isliving(hit_atom))
|
||||
return
|
||||
|
||||
var/mob/living/L = hit_atom
|
||||
if(!L.has_zona_bovinae())
|
||||
to_chat(user, SPAN_WARNING("This being doesn't have a Zona Bovinae."))
|
||||
return
|
||||
|
||||
if(L.psi && L.psi.get_rank() >= PSI_RANK_HARMONIOUS)
|
||||
to_chat(user, SPAN_WARNING("This wouldn't do anything on them."))
|
||||
return
|
||||
|
||||
. = ..()
|
||||
if(!.)
|
||||
return
|
||||
|
||||
user.visible_message(SPAN_DANGER("[user] grabs [L]'s head..."), SPAN_DANGER("You grab [L]'s head..."))
|
||||
if(do_mob(user, L, 5 SECONDS))
|
||||
L.set_psi_rank(PSI_RANK_HARMONIOUS)
|
||||
L.flash_pain(50)
|
||||
L.adjustHalLoss(20)
|
||||
playsound(get_turf(L), 'sound/effects/psi/power_feedback.ogg', 100)
|
||||
user.visible_message(SPAN_DANGER("[user] unleashes a psionic shock through [L]'s head!"),
|
||||
SPAN_DANGER("You unleash a psionic shock through [L]'s head, targeting their Zona Bovinae and stimulating it it."))
|
||||
to_chat(L, SPAN_HIGHDANGER("A large, painful shock courses through your head. You can see the weave of the universe... and manipulate it."))
|
||||
@@ -0,0 +1,57 @@
|
||||
/singleton/psionic_power/psi_drain
|
||||
name = "Psi-Drain"
|
||||
desc = "Drain psi-stamina from a living being. This can be used both in melee and at range."
|
||||
icon_state = "gen_project"
|
||||
point_cost = 0
|
||||
ability_flags = PSI_FLAG_APEX
|
||||
minimum_rank = PSI_RANK_APEX
|
||||
spell_path = /obj/item/spell/psi_drain
|
||||
|
||||
/obj/item/spell/psi_drain
|
||||
name = "psi-drain"
|
||||
icon_state = "chain_lightning"
|
||||
cast_methods = CAST_MELEE|CAST_RANGED
|
||||
aspect = ASPECT_PSIONIC
|
||||
cooldown = 10
|
||||
psi_cost = 5
|
||||
|
||||
/obj/item/spell/psi_drain/on_melee_cast(atom/hit_atom, mob/living/user, def_zone)
|
||||
if(!isliving(hit_atom))
|
||||
return
|
||||
|
||||
var/mob/living/L = hit_atom
|
||||
|
||||
if(!L.has_zona_bovinae())
|
||||
to_chat(user, SPAN_WARNING("This being doesn't have a Zona Bovinae."))
|
||||
return
|
||||
|
||||
. = ..()
|
||||
if(!.)
|
||||
return
|
||||
|
||||
psi_drain(L, user)
|
||||
|
||||
/obj/item/spell/psi_drain/on_ranged_cast(atom/hit_atom, mob/user, bypass_psi_check)
|
||||
if(!isliving(hit_atom))
|
||||
return
|
||||
|
||||
var/mob/living/L = hit_atom
|
||||
if(!L.has_zona_bovinae())
|
||||
to_chat(user, SPAN_WARNING("This being doesn't have a Zona Bovinae."))
|
||||
return
|
||||
|
||||
. = ..()
|
||||
if(!.)
|
||||
return
|
||||
psi_drain(L, user)
|
||||
|
||||
/obj/item/spell/psi_drain/proc/psi_drain(mob/living/L, mob/living/user)
|
||||
user.visible_message(SPAN_DANGER("[user] squeezes [user.get_pronoun("his")] hand at [L]!"), SPAN_DANGER("You squeeze your hand at [L] and siphon [L.get_pronoun("his")] psionic energy!"))
|
||||
var/psi_taken = min(user.psi.max_stamina, rand(10, 25))
|
||||
if(L.psi)
|
||||
L.psi.spend_power(psi_taken)
|
||||
else
|
||||
L.adjustHalLoss(psi_taken * 1.5)
|
||||
L.flash_pain(psi_taken * 1.5)
|
||||
playsound(get_turf(user), 'sound/effects/psi/power_evoke.ogg', 100)
|
||||
to_chat(L, SPAN_DANGER("You feel a headache split apart your mind!"))
|
||||
@@ -0,0 +1,31 @@
|
||||
/singleton/psionic_power/punch
|
||||
name = "Psi-Punch"
|
||||
desc = "Imbue your fists with psionic power."
|
||||
icon_state = "const_fist"
|
||||
point_cost = 2
|
||||
ability_flags = PSI_FLAG_ANTAG
|
||||
spell_path = /obj/item/spell/punch
|
||||
|
||||
/obj/item/spell/punch
|
||||
name = "psi-punch"
|
||||
icon_state = "generic"
|
||||
cast_methods = CAST_MELEE
|
||||
aspect = ASPECT_PSIONIC
|
||||
force = 20
|
||||
armor_penetration = 20
|
||||
cooldown = 0
|
||||
psi_cost = 3
|
||||
flags = 0
|
||||
hitsound = 'sound/weapons/resonator_blast.ogg'
|
||||
|
||||
/obj/item/spell/punch/on_melee_cast(atom/hit_atom, mob/living/user, def_zone)
|
||||
if(!isliving(hit_atom))
|
||||
return
|
||||
. = ..()
|
||||
if(!.)
|
||||
return
|
||||
var/mob/living/M = hit_atom
|
||||
if(prob(15))
|
||||
M.throw_at(get_edge_target_turf(loc, loc.dir), 2, 7)
|
||||
M.visible_message(SPAN_DANGER("[M] is floored by psychic energy!"), SPAN_DANGER("You are floored by psychic energy!"))
|
||||
M.apply_effect(2, WEAKEN)
|
||||
@@ -0,0 +1,37 @@
|
||||
/singleton/psionic_power/psi_recovery
|
||||
name = "Psionic Recovery"
|
||||
desc = "Activate in hand to regenerate psi-stamina."
|
||||
icon_state = "swarm_zeropoint"
|
||||
point_cost = 0
|
||||
ability_flags = PSI_FLAG_FOUNDATIONAL
|
||||
spell_path = /obj/item/spell/psi_recovery
|
||||
|
||||
/obj/item/spell/psi_recovery
|
||||
name = "psionic recovery"
|
||||
desc = "It's an aura recharge."
|
||||
icon_state = "generic"
|
||||
cast_methods = CAST_USE
|
||||
aspect = ASPECT_PSIONIC
|
||||
cooldown = 5
|
||||
psi_cost = 0
|
||||
|
||||
/obj/item/spell/psi_recovery/on_use_cast(mob/user)
|
||||
. = ..()
|
||||
if(!.)
|
||||
return
|
||||
if(!isliving(user))
|
||||
return
|
||||
|
||||
var/mob/living/L = user
|
||||
L.visible_message(SPAN_NOTICE("[user] puts [user.get_pronoun("his")] hands together and focuses..."),
|
||||
SPAN_NOTICE("You put your hands together and begin focusing on recovering your psionic energy..."))
|
||||
psi_recovery(user)
|
||||
|
||||
/obj/item/spell/psi_recovery/proc/psi_recovery(mob/user)
|
||||
var/mob/living/L = user
|
||||
if(do_after(user, 0.5 SECONDS))
|
||||
L.psi.stamina = min(L.psi.max_stamina, L.psi.stamina + rand(1,3))
|
||||
if(L.psi.stamina >= L.psi.max_stamina)
|
||||
to_chat(user, SPAN_NOTICE("You've recovered all your psionic energy."))
|
||||
return TRUE
|
||||
psi_recovery(user)
|
||||
@@ -0,0 +1,68 @@
|
||||
/singleton/psionic_power/psi_search
|
||||
name = "Psionic Search"
|
||||
desc = "Scan your Z-level for Nlom signatures. The distance will be slightly inaccurate for weak signatures."
|
||||
icon_state = "wiz_shield"
|
||||
point_cost = 0
|
||||
ability_flags = PSI_FLAG_FOUNDATIONAL
|
||||
spell_path = /obj/item/spell/psi_search
|
||||
|
||||
/obj/item/spell/psi_search
|
||||
name = "psionic search"
|
||||
desc = "A psionic magnifying glass."
|
||||
icon_state = "generic"
|
||||
cast_methods = CAST_USE
|
||||
aspect = ASPECT_PSIONIC
|
||||
cooldown = 5
|
||||
psi_cost = 10
|
||||
|
||||
/obj/item/spell/psi_search/on_use_cast(mob/user)
|
||||
. = ..()
|
||||
if(!.)
|
||||
return
|
||||
if(!isliving(user))
|
||||
return
|
||||
var/mob/living/L = user
|
||||
L.visible_message(SPAN_NOTICE("[L] puts two fingers to [L.get_pronoun("his")] forehead and focuses..."),
|
||||
SPAN_NOTICE("You put two fingers to your temple and focus on locating Nlom signatures..."))
|
||||
if(do_after(L, 3 SECONDS))
|
||||
var/list/level_humans = list()
|
||||
var/found_apex = FALSE
|
||||
for(var/mob/living/carbon/human/H in human_mob_list)
|
||||
if(H == L)
|
||||
continue
|
||||
if((GET_Z(H) == GET_Z(L)) && !H.is_psi_blocked())
|
||||
if(HAS_TRAIT(H, TRAIT_PSIONIC_SUPPRESSION))
|
||||
continue
|
||||
level_humans |= H
|
||||
if(H.psi)
|
||||
if(H.psi.get_rank() >= PSI_RANK_APEX)
|
||||
found_apex = TRUE
|
||||
if(!length(level_humans))
|
||||
to_chat(L, SPAN_WARNING("The Nlom is quiet and empty here."))
|
||||
return TRUE
|
||||
if(found_apex)
|
||||
to_chat(L, SPAN_DANGER(FONT_HUGE("You reach out into the Nlom and your senses are overwhelmed by a massive signature!")))
|
||||
L.flash_pain(20)
|
||||
L.adjustHalLoss(20)
|
||||
return
|
||||
var/list/signatures = list()
|
||||
var/harmonious_signatures = 0
|
||||
var/sensitive_signatures = 0
|
||||
var/perceptive_signatures = 0
|
||||
for(var/mob/living/carbon/human/H in level_humans)
|
||||
if(!H.psi)
|
||||
perceptive_signatures++
|
||||
continue
|
||||
if(H.psi && H.psi.get_rank() == PSI_RANK_SENSITIVE)
|
||||
sensitive_signatures++
|
||||
continue
|
||||
if(H.psi && H.psi.get_rank() == PSI_RANK_HARMONIOUS)
|
||||
harmonious_signatures++
|
||||
continue
|
||||
if(perceptive_signatures)
|
||||
signatures += "[perceptive_signatures] weak signature[perceptive_signatures > 1 ? "s" : ""]"
|
||||
if(sensitive_signatures)
|
||||
signatures += "[sensitive_signatures] robust signature[sensitive_signatures > 1 ? "s" : ""]"
|
||||
if(harmonious_signatures)
|
||||
signatures += "[harmonious_signatures] very powerful signature[harmonious_signatures > 1 ? "s" : ""]"
|
||||
to_chat(user, SPAN_NOTICE("Reaching out into the Nlom, you sense [english_list(signatures)]."))
|
||||
@@ -0,0 +1,27 @@
|
||||
/singleton/psionic_power/psi_stamina
|
||||
name = "Psi-Stamina Weave"
|
||||
desc = "Activate this spell in your hand to regenerate your psi-stamina a little bit."
|
||||
icon_state = "tech_mend_template"
|
||||
point_cost = 1
|
||||
ability_flags = PSI_FLAG_EVENT|PSI_FLAG_CANON
|
||||
spell_path = /obj/item/spell/psi_stamina
|
||||
|
||||
/obj/item/spell/psi_stamina
|
||||
name = "psi-stamina weave"
|
||||
desc = "Kind of like charging up your aura."
|
||||
icon_state = "generic"
|
||||
cast_methods = CAST_USE
|
||||
aspect = ASPECT_PSIONIC
|
||||
cooldown = 0
|
||||
psi_cost = 0
|
||||
|
||||
/obj/item/spell/psi_stamina/on_use_cast(mob/user)
|
||||
. = ..()
|
||||
if(!.)
|
||||
return
|
||||
if(do_after(user, 1 SECOND))
|
||||
to_chat(user, SPAN_NOTICE("You feel a bit more refreshed."))
|
||||
owner.psi.stamina = min(owner.psi.max_stamina, owner.psi.stamina + rand(2,5))
|
||||
if(owner.psi.stamina >= owner.psi.max_stamina)
|
||||
to_chat(user, SPAN_NOTICE("You're ready to go again!"))
|
||||
return TRUE
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user