mirror of
https://github.com/Aurorastation/Aurora.3.git
synced 2026-08-22 04:22:39 +01:00
Psi Rework Part 2: Scenes From A Memory (#21736)
The next step in the Psi Reworks is here, this time adding all of the remaining sources and applications of Psi-sensitivity and Psi-protection that were on my To-Do list. Aside from a variety of tweaks and bugfixes to powers, the most player-facing addition is the new Psi-sensitivity related traits, which are High Psi-sensitivity, and Low Psi-sensitivity. These traits modify the character's psi-sensitivity, which messes with their interactions with psionics in a variety of ways. All of these new sources and interactions with psionics are handled entirely through components, which operate on the previously added COMSIG_PSI signals. Check the changelog file for more specific details on what all was fixed. I've fixed quite a lot of bugs and issues with the various psi powers. I have actually tested this PR and verified that it works as advertised. <img width="1902" height="1015" alt="image" src="https://github.com/user-attachments/assets/e922593c-0595-4b63-bee4-36080d9cb8b4" />
This commit is contained in:
@@ -497,6 +497,8 @@
|
||||
#include "code\datums\components\multitool\circuitboards\circuitboards.dm"
|
||||
#include "code\datums\components\overhead_emote\overhead_emote_datum.dm"
|
||||
#include "code\datums\components\overhead_emote\overhead_emote_singleton.dm"
|
||||
#include "code\datums\components\psionics\psi_sensitivity.dm"
|
||||
#include "code\datums\components\psionics\psi_suppression.dm"
|
||||
#include "code\datums\components\synthetic_endoskeleton\synthetic_endoskeleton.dm"
|
||||
#include "code\datums\components\turf_click\turf_hand.dm"
|
||||
#include "code\datums\elements\_element.dm"
|
||||
|
||||
@@ -156,9 +156,6 @@
|
||||
/// 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"
|
||||
|
||||
|
||||
@@ -0,0 +1,72 @@
|
||||
/**
|
||||
* The parent of all Psi-Sensitivity modifying components.
|
||||
* Mobs/Objects with any child of this component will have their Psi-sensitivity modified by the stored amount when called to check by various psionic abilities.
|
||||
* A Mob/Object is allowed to have any number of this component's children, but cannot have two of the same child.
|
||||
* The mob's psi-sensitivity gets returned as the sum of all sensitivity_modifier values.
|
||||
* If you wish to add a new source of Psi-sensitivity, simply add a new child to this component, then use AddComponent() to place it on a datum.
|
||||
*/
|
||||
/datum/component/psi_sensitivity
|
||||
|
||||
/**
|
||||
* The amount this component will modify its owner psi_sensitivity by when they are called by psychic phenomena to check.
|
||||
* This var is allowed to be a floating point, as well as negative values.
|
||||
* See /proc/check_psi_sensitivity() for more information.
|
||||
*/
|
||||
var/sensitivity_modifier = 0
|
||||
|
||||
/datum/component/psi_sensitivity/Initialize()
|
||||
. = ..()
|
||||
// Components have their parent set before Initialize() is triggered, so it's generally not possible for the component to be missing a parent at this stage.
|
||||
// However, we have unit tests that will fire Initialize() against every datum to check if we checked, just in case someone down the line adds a new Initialize() call.
|
||||
if (!parent)
|
||||
return
|
||||
|
||||
// This is a fundamental pattern for Entity-Component-Systems (ECS).
|
||||
// When this component is given to a datum via AddComponent(), such as on a player character
|
||||
// the component tells the datum it wishes to do something when this signal happens to the datum.
|
||||
// When SendSignal() is later activated on that character, this component will react with its prepared proc.
|
||||
RegisterSignal(parent, COMSIG_PSI_CHECK_SENSITIVITY, PROC_REF(modify_sensitivity), override = TRUE)
|
||||
|
||||
/datum/component/psi_sensitivity/Destroy()
|
||||
. = ..()
|
||||
if (!parent)
|
||||
return
|
||||
|
||||
// This is the second half of the fundamental pattern for Entity-Component-Systems (ECS)
|
||||
// When this component is taken away from a datum via RemoveComponent(), such as from a player character
|
||||
// The component tells the character it no longer wishes to do anything when a specific signal happens.
|
||||
// We MUST do this for garbage collection reasons, else we'll get hard deletes.
|
||||
UnregisterSignal(parent, COMSIG_PSI_CHECK_SENSITIVITY)
|
||||
|
||||
/datum/component/psi_sensitivity/proc/modify_sensitivity(var/parent, var/effective_sensitivity)
|
||||
SIGNAL_HANDLER
|
||||
// Earlier, SendSignal() sent effective_sensitivity as a pointer by marking it as &effective_sensitivity.
|
||||
// That means that for this proc, we have the memory address for the original var/effective_sensitivity located in /atom/movable/proc/check_psi_sensitivity()
|
||||
// By marking it with the asterisk (*), I'm telling the game "Actually, add directly to the original variable from /atom/movable/proc/check_psi_sensitivity()"
|
||||
// The reason we're doing this via pointer is that this allows any number of psi_sensitivity components to touch that variable.
|
||||
// If we did this by a Return statement, only the first component would have been allowed to touch it, and all others get ignored.
|
||||
*effective_sensitivity += sensitivity_modifier
|
||||
|
||||
/**
|
||||
* When attached to any datum, this component subscribes to COMSIG_PSI_CHECK_SENSITIVITY on behalf of its owner.
|
||||
* It provides a +1 modifier to Psi Sensitivity Checks.
|
||||
*/
|
||||
#define HIGH_PSI_SENSITIVITY_COMPONENT /datum/component/psi_sensitivity/high
|
||||
/datum/component/psi_sensitivity/high
|
||||
sensitivity_modifier = 1
|
||||
|
||||
/**
|
||||
* When attached to any datum, this component subscribes to COMSIG_PSI_CHECK_SENSITIVITY on behalf of its owner.
|
||||
* It provides a -1 modifier to Psi Sensitivity Checks.
|
||||
*/
|
||||
#define LOW_PSI_SENSITIVITY_COMPONENT /datum/component/psi_sensitivity/low
|
||||
/datum/component/psi_sensitivity/low
|
||||
sensitivity_modifier = -1
|
||||
|
||||
/**
|
||||
* Component that gets temporarily attached to someone who consumes excessive amounts of Wulumunusha.
|
||||
* When the Wulumunusha high wears off, the component deletes itself.
|
||||
*/
|
||||
#define WULU_OVERDOSE_COMPONENT /datum/component/psi_sensitivity/wulu_overdose
|
||||
/datum/component/psi_sensitivity/wulu_overdose
|
||||
sensitivity_modifier = 1
|
||||
@@ -0,0 +1,42 @@
|
||||
/**
|
||||
* Component used for the Psi-Suppression power.
|
||||
* Acts like a stronger Mind-shield/Mind-Blanker until toggled off.
|
||||
*/
|
||||
#define PSI_SUPPRESSION_COMPONENT /datum/component/psi_suppression
|
||||
/datum/component/psi_suppression
|
||||
|
||||
/**
|
||||
* The amount this component will modify its owner psi_sensitivity by when they are called by psychic phenomena to check.
|
||||
* See /proc/check_psi_sensitivity() for more information.
|
||||
*/
|
||||
var/sensitivity_modifier = -2
|
||||
|
||||
/datum/component/psi_suppression/Initialize()
|
||||
. = ..()
|
||||
if (!parent)
|
||||
return
|
||||
|
||||
RegisterSignal(parent, COMSIG_PSI_CHECK_SENSITIVITY, PROC_REF(modify_sensitivity), override = TRUE)
|
||||
RegisterSignal(parent, COMSIG_PSI_MIND_POWER, PROC_REF(cancel_power), override = TRUE)
|
||||
|
||||
/datum/component/psi_suppression/Destroy()
|
||||
. = ..()
|
||||
if (!parent)
|
||||
return
|
||||
|
||||
UnregisterSignal(parent, COMSIG_PSI_CHECK_SENSITIVITY)
|
||||
UnregisterSignal(parent, COMSIG_PSI_MIND_POWER)
|
||||
|
||||
/datum/component/psi_suppression/proc/modify_sensitivity(var/parent, var/effective_sensitivity)
|
||||
SIGNAL_HANDLER
|
||||
|
||||
*effective_sensitivity += sensitivity_modifier
|
||||
|
||||
/datum/component/psi_suppression/proc/cancel_power(var/parent, var/caster, var/cancelled, var/cancel_return, var/wide_field)
|
||||
SIGNAL_HANDLER
|
||||
|
||||
*cancelled = TRUE
|
||||
if (wide_field || parent == caster)
|
||||
return
|
||||
|
||||
to_chat(parent, SPAN_DANGER("You repulse an outside thought!"))
|
||||
@@ -35,6 +35,9 @@
|
||||
force = 0
|
||||
item_flags = ITEM_FLAG_NO_BLUDGEON
|
||||
light_system = MOVABLE_LIGHT
|
||||
pickup_sound = null
|
||||
drop_sound = null
|
||||
hitsound = null
|
||||
var/mob/living/carbon/human/owner
|
||||
var/obj/item/technomancer_core/core
|
||||
var/cast_methods = null // Controls how the spell is casted.
|
||||
|
||||
@@ -53,12 +53,13 @@
|
||||
SIGNAL_HANDLER
|
||||
*effective_sensitivity += sensitivity_modifier
|
||||
|
||||
/obj/item/implant/mindshield/proc/cancel_power(var/implantee, var/caster, var/cancelled)
|
||||
/obj/item/implant/mindshield/proc/cancel_power(var/implantee, var/caster, var/cancelled, var/cancel_return, var/wide_field)
|
||||
SIGNAL_HANDLER
|
||||
*cancelled = TRUE
|
||||
if(implantee == caster)
|
||||
if(wide_field || implantee == caster)
|
||||
return
|
||||
|
||||
*cancel_return = SPAN_DANGER("ACCESS DENIED: CONNECTION DROPPED.")
|
||||
to_chat(implantee, SPAN_DANGER("Your [name] buzzes angrily."))
|
||||
|
||||
/obj/item/implant/mindshield/emp_act(severity)
|
||||
|
||||
@@ -505,7 +505,7 @@
|
||||
desc = "A box of psionic receivers, which can be surgically implanted to act as a replacement for an underdeveloped or non-existent zona bovinae. This one has a large sticker on the side reading FOR RESEARCH USE ONLY."
|
||||
color = COLOR_PURPLE_GRAY
|
||||
illustration = "implant"
|
||||
starts_with = list(/obj/item/organ/internal/augment/psi = 4)
|
||||
starts_with = list(/obj/item/organ/internal/augment/bioaug/psi = 4)
|
||||
|
||||
/obj/item/storage/box/tethers
|
||||
name = "box of tethering devices"
|
||||
|
||||
@@ -163,8 +163,8 @@
|
||||
/datum/gear/augment/psiaug
|
||||
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_UNATHI, SPECIES_VAURCA_WORKER, SPECIES_VAURCA_WARRIOR, SPECIES_VAURCA_ATTENDANT, 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)
|
||||
path = /obj/item/organ/internal/augment/bioaug/psi
|
||||
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_ATTENDANT, SPECIES_VAURCA_BULWARK, SPECIES_VAURCA_BREEDER)
|
||||
flags = GEAR_HAS_NAME_SELECTION | GEAR_HAS_DESC_SELECTION
|
||||
|
||||
/datum/gear/augment/memory_inhibitor
|
||||
|
||||
@@ -133,3 +133,23 @@ BROKEN_DISABILITY(left_foot, "Left Foot", BP_L_FOOT)
|
||||
BROKEN_DISABILITY(right_foot, "Right Foot", BP_R_FOOT)
|
||||
|
||||
#undef BROKEN_DISABILITY
|
||||
|
||||
// Psi related traits. Not strictly disabilities, but also not positive traits either.
|
||||
/datum/character_disabilities/high_psi_sensitivity
|
||||
name = "High Psi-sensitivity"
|
||||
desc = "You are naturally more sensitive to psychic phenomena, roughly on par with having a psi-receiver implant." \
|
||||
+ "Though this does not grant any psychic abilities, a character with this trait is counted as being psychic for a variety of effects." \
|
||||
+ "For example, having the ability to distinguish the source of telepathic signals, but also taking bonus damage from anything that deals bonus damage to psychics."
|
||||
|
||||
/datum/character_disabilities/high_psi_sensitivity/apply_self(var/mob/living/carbon/human/H)
|
||||
H.AddComponent(HIGH_PSI_SENSITIVITY_COMPONENT)
|
||||
|
||||
/datum/character_disabilities/low_psi_sensitivity
|
||||
name = "Low Psi-sensitivity"
|
||||
desc = "Your Zona Bovinae is naturally under-developed, resulting in a lower than normal response to psychic phenomenon." \
|
||||
+ "Characters who are already psychic with this trait don't lose their powers, but they are also no longer counted as psychic for a variety of effects." \
|
||||
+ "For example, losing the ability to distinguish the source of telepathic signals, or taking brain damage when having their mind read." \
|
||||
+ "On the opposite end of the spectrum, anything that deals bonus damage to psychics will also deal reduced damage to you."
|
||||
|
||||
/datum/character_disabilities/low_psi_sensitivity/apply_self(var/mob/living/carbon/human/H)
|
||||
H.AddComponent(LOW_PSI_SENSITIVITY_COMPONENT)
|
||||
|
||||
@@ -31,13 +31,13 @@
|
||||
UnregisterSignal(owner, COMSIG_PSI_MIND_POWER)
|
||||
UnregisterSignal(owner, COMSIG_PSI_CHECK_SENSITIVITY)
|
||||
|
||||
/obj/item/organ/internal/augment/bioaug/mind_blanker/proc/cancel_power(var/implantee, var/caster, var/cancelled)
|
||||
/obj/item/organ/internal/augment/bioaug/mind_blanker/proc/cancel_power(var/implantee, var/caster, var/cancelled, var/cancel_return, var/wide_field)
|
||||
SIGNAL_HANDLER
|
||||
if(is_broken())
|
||||
return
|
||||
|
||||
*cancelled = TRUE
|
||||
if(implantee == caster)
|
||||
if(wide_field || implantee == caster)
|
||||
return
|
||||
|
||||
to_chat(implantee, SPAN_DANGER("Your mind wriggles as it repulses an outside thought."))
|
||||
@@ -82,13 +82,13 @@
|
||||
UnregisterSignal(owner, COMSIG_PSI_MIND_POWER)
|
||||
UnregisterSignal(owner, COMSIG_PSI_CHECK_SENSITIVITY)
|
||||
|
||||
/obj/item/organ/internal/augment/bioaug/mind_blanker_lethal/proc/cancel_power_lethal(var/mob/living/carbon/human/implantee, var/caster, var/cancelled)
|
||||
/obj/item/organ/internal/augment/bioaug/mind_blanker_lethal/proc/cancel_power_lethal(var/mob/living/carbon/human/implantee, var/caster, var/cancelled, var/cancel_return, var/wide_field)
|
||||
SIGNAL_HANDLER
|
||||
if(is_broken())
|
||||
return
|
||||
|
||||
*cancelled = TRUE
|
||||
if(implantee == caster)
|
||||
if(wide_field || implantee == caster)
|
||||
return
|
||||
|
||||
to_chat(implantee, SPAN_DANGER("Your mind wriggles as it repulses an outside thought."))
|
||||
@@ -96,7 +96,7 @@
|
||||
var/mob/living/victim = caster
|
||||
victim.adjustBrainLoss(20)
|
||||
victim.confused += 20
|
||||
to_chat(victim, SPAN_DANGER("Agony lances through my mind as [implantee.name]'s mind clamps down upon me!"))
|
||||
*cancel_return = SPAN_DANGER("Agony lances through my brain as their mind clamps down upon me!")
|
||||
|
||||
/obj/item/organ/internal/augment/bioaug/mind_blanker_lethal/proc/modify_sensitivity(var/implantee, var/effective_sensitivity)
|
||||
SIGNAL_HANDLER
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/obj/item/organ/internal/augment/psi
|
||||
/obj/item/organ/internal/augment/bioaug/psi
|
||||
name = "psionic receiver"
|
||||
desc = "A cybernetic implant that allows for the carrier of a receiver to be sensitive enough to accept and interpret psionic signals " \
|
||||
+ "Essentially an implanted and carefully encased cultured zona bovinae, these receivers are regularly found within dionae and vaurca who otherwise lack this specialized portion of the brain entirely." \
|
||||
@@ -6,30 +6,40 @@
|
||||
+ "Some psionically weak skrell will also implant themselves with a receiver in the same way a hearing aid is utilized."
|
||||
organ_tag = BP_AUG_PSI
|
||||
parent_organ = BP_HEAD
|
||||
species_restricted = list(
|
||||
SPECIES_HUMAN_OFFWORLD,
|
||||
SPECIES_HUMAN,
|
||||
SPECIES_SKRELL_AXIORI,
|
||||
SPECIES_SKRELL,
|
||||
SPECIES_TAJARA_MSAI,
|
||||
SPECIES_TAJARA_ZHAN,
|
||||
SPECIES_TAJARA,
|
||||
SPECIES_UNATHI,
|
||||
)
|
||||
var/sensitivity_modifier = 1
|
||||
|
||||
/obj/item/organ/internal/augment/psi/Initialize()
|
||||
/obj/item/organ/internal/augment/bioaug/psi/Initialize()
|
||||
. = ..()
|
||||
if(!owner)
|
||||
return
|
||||
|
||||
RegisterSignal(owner, COMSIG_PSI_CHECK_SENSITIVITY, PROC_REF(modify_sensitivity), override = TRUE)
|
||||
|
||||
/obj/item/organ/internal/augment/psi/replaced()
|
||||
/obj/item/organ/internal/augment/bioaug/psi/replaced()
|
||||
. = ..()
|
||||
if(!owner)
|
||||
return
|
||||
|
||||
RegisterSignal(owner, COMSIG_PSI_CHECK_SENSITIVITY, PROC_REF(modify_sensitivity), override = TRUE)
|
||||
|
||||
/obj/item/organ/internal/augment/psi/removed()
|
||||
/obj/item/organ/internal/augment/bioaug/psi/removed()
|
||||
. = ..()
|
||||
if(!owner)
|
||||
return
|
||||
|
||||
UnregisterSignal(owner, COMSIG_PSI_CHECK_SENSITIVITY)
|
||||
|
||||
/obj/item/organ/internal/augment/psi/proc/modify_sensitivity(var/implantee, var/effective_sensitivity)
|
||||
/obj/item/organ/internal/augment/bioaug/psi/proc/modify_sensitivity(var/implantee, var/effective_sensitivity)
|
||||
SIGNAL_HANDLER
|
||||
if(is_broken())
|
||||
return
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
name = "assay"
|
||||
desc = "Read someone's psionic potential."
|
||||
icon_state = "generic"
|
||||
item_icons = null
|
||||
cast_methods = CAST_MELEE|CAST_INNATE
|
||||
aspect = ASPECT_PSIONIC
|
||||
cooldown = 10
|
||||
@@ -53,7 +54,7 @@
|
||||
to_chat(user, SPAN_WARNING("Psionic power does not flow through a dead person."))
|
||||
return
|
||||
|
||||
var/psi_blocked = target.is_psi_blocked(user)
|
||||
var/psi_blocked = target.is_psi_blocked(user, FALSE)
|
||||
if(psi_blocked)
|
||||
to_chat(user, psi_blocked)
|
||||
return
|
||||
@@ -61,20 +62,14 @@
|
||||
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?"))
|
||||
var/target_psi_sensitivity = target.check_psi_sensitivity()
|
||||
|
||||
// Not using a switch case here because I need finer control of the domain than is permitted by TO statements.
|
||||
if (target_psi_sensitivity < 0)
|
||||
to_chat(user, SPAN_NOTICE("[target] has little to no ability to sense the fabric that weaves this universe."))
|
||||
else if (target_psi_sensitivity < PSI_RANK_SENSITIVE)
|
||||
to_chat(user, SPAN_NOTICE("[target] has only a limited perception of psionic signals, like a typical human. They can hear psionics, but have limited ability to interpret them."))
|
||||
else if (target_psi_sensitivity < PSI_RANK_HARMONIOUS)
|
||||
to_chat(user, SPAN_NOTICE("[target] is psionically sensitive, just like your typical skrell. They are capable of interpreting telepathic signals."))
|
||||
else
|
||||
to_chat(user, SPAN_NOTICE("[target] is exceptionally capable of handling and interpreting psionic messages, doing so trivially and intuitively."))
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
/obj/item/spell/barrier
|
||||
name = "psionic barrier"
|
||||
icon_state = "generic"
|
||||
item_icons = null
|
||||
cast_methods = CAST_USE
|
||||
aspect = ASPECT_PSIONIC
|
||||
cooldown = 20
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
/obj/item/spell/charge
|
||||
name = "charge"
|
||||
icon_state = "audible_deception"
|
||||
item_icons = null
|
||||
cast_methods = CAST_USE
|
||||
aspect = ASPECT_PSIONIC
|
||||
cooldown = 5
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
name = "commune"
|
||||
desc = "Déjà-vu."
|
||||
icon_state = "overload"
|
||||
item_icons = null
|
||||
cast_methods = CAST_RANGED|CAST_MELEE
|
||||
aspect = ASPECT_PSIONIC
|
||||
cooldown = 10
|
||||
@@ -36,12 +37,11 @@
|
||||
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(user)
|
||||
var/psi_blocked = target.is_psi_blocked(user, FALSE)
|
||||
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 = tgui_input_text(user, "What would you like to say?", "Commune", "", MAX_MESSAGE_LEN, TRUE)
|
||||
if(!text)
|
||||
return
|
||||
@@ -62,7 +62,16 @@
|
||||
to_chat(M, "<span class='notice'>[user] psionically says to [target]:</span> [text]")
|
||||
|
||||
var/mob/living/carbon/human/H = target
|
||||
if(H.check_psi_sensitivity() >= 1)
|
||||
var/target_sensitivity = H.check_psi_sensitivity()
|
||||
if(target_sensitivity >= 1)
|
||||
// Augmented case for anyone with enhancements to their psi-sensitivity.
|
||||
to_chat(H, SPAN_NOTICE("<i>[user] blinks, their eyes briefly developing an unnatural shine.</i>"))
|
||||
to_chat(H, SPAN_CULT("<b>You instinctively sense [user] passing a thought into your mind:</b> [text]"))
|
||||
else
|
||||
else if (target_sensitivity >= 0)
|
||||
// Standard case for most characters.
|
||||
to_chat(H, SPAN_ALIEN("<b>A thought from outside your consciousness slips into your mind:</b> [text]"))
|
||||
else
|
||||
// Negative sensitivity case, message arrives scrambled.
|
||||
// 25% of the message is scrambled per negative point of psi-sensitivity. Allowing fractional points.
|
||||
var/scrambled_message = stars(text, (abs(target_sensitivity) * 25))
|
||||
to_chat(H, SPAN_ALIEN("<b>A half-formed thought passes through your mind:</b> [scrambled_message]"))
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
/obj/item/spell/electrocute
|
||||
name = "electrocute"
|
||||
icon_state = "chain_lightning"
|
||||
item_icons = null
|
||||
cast_methods = CAST_MELEE
|
||||
aspect = ASPECT_PSIONIC
|
||||
cooldown = 10
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
name = "emotional suggestion"
|
||||
desc = "Suggest an emotion to someone."
|
||||
icon_state = "generic"
|
||||
item_icons = null
|
||||
cast_methods = CAST_RANGED|CAST_MELEE
|
||||
aspect = ASPECT_PSIONIC
|
||||
cooldown = 10
|
||||
@@ -35,12 +36,11 @@
|
||||
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(user)
|
||||
var/psi_blocked = target.is_psi_blocked(user, FALSE)
|
||||
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 = tgui_input_list(user, "Which emotion would you like to suggest?", "Emotional Suggestion", list("Calm", "Happiness", "Sadness", "Fear", "Anger", "Stress", "Confusion"))
|
||||
if(!text)
|
||||
return
|
||||
@@ -62,7 +62,16 @@
|
||||
to_chat(M, "<span class='notice'>[user] psionically suggests an emotion to [target]:</span> [text]")
|
||||
|
||||
var/mob/living/carbon/human/H = target
|
||||
if(H.check_psi_sensitivity() > 0)
|
||||
var/target_sensitivity = H.check_psi_sensitivity()
|
||||
if(target_sensitivity >= 1)
|
||||
// Augmented case for anyone with enhancements to their psi-sensitivity
|
||||
to_chat(H, SPAN_NOTICE("<i>[user] blinks, their eyes briefly developing an unnatural shine.</i>"))
|
||||
to_chat(H, SPAN_NOTICE("You sense [user]'s psyche link with your own, and an emotion of <b>[text]</b> washes through your mind."))
|
||||
else
|
||||
else if (target_sensitivity >= 0)
|
||||
// Standard case for most characters.
|
||||
to_chat(H, SPAN_NOTICE("An emotion from outside your consciousness slips into your mind: <b>[text]</b>."))
|
||||
else
|
||||
// Negative sensitivity case, message arrives scrambled.
|
||||
// 25% of the message is scrambled per negative point of psi-sensitivity. Allowing fractional points.
|
||||
var/scrambled_message = stars(text, (abs(target_sensitivity) * 25))
|
||||
to_chat(H, SPAN_NOTICE("A half-formed emotion passes through your mind: <b>[scrambled_message]</b>."))
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
name = "focus"
|
||||
desc = "Psionic drugs? No way."
|
||||
icon_state = "blink"
|
||||
item_icons = null
|
||||
cast_methods = CAST_USE
|
||||
aspect = ASPECT_PSIONIC
|
||||
cooldown = 50
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
name = "mend"
|
||||
desc = "Clear!"
|
||||
icon_state = "mend_wounds"
|
||||
item_icons = null
|
||||
cast_methods = CAST_MELEE
|
||||
aspect = ASPECT_PSIONIC
|
||||
cooldown = 50
|
||||
|
||||
@@ -41,7 +41,7 @@
|
||||
for(var/mob/living/L in GLOB.mob_list)
|
||||
if(L == user)
|
||||
continue
|
||||
if(!L.is_psi_blocked(user))
|
||||
if(!L.is_psi_blocked(user, TRUE))
|
||||
continue
|
||||
if(GET_Z(L) != GET_Z(user))
|
||||
continue
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
name = "psionic recovery"
|
||||
desc = "It's an aura recharge."
|
||||
icon_state = "generic"
|
||||
item_icons = null
|
||||
cast_methods = CAST_USE
|
||||
aspect = ASPECT_PSIONIC
|
||||
cooldown = 5
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
name = "psionic search"
|
||||
desc = "A psionic magnifying glass."
|
||||
icon_state = "generic"
|
||||
item_icons = null
|
||||
cast_methods = CAST_USE
|
||||
aspect = ASPECT_PSIONIC
|
||||
cooldown = 5
|
||||
@@ -30,9 +31,7 @@
|
||||
for(var/mob/living/carbon/human/H in GLOB.human_mob_list)
|
||||
if(H == L)
|
||||
continue
|
||||
if((GET_Z(H) == GET_Z(L)) && !H.is_psi_blocked(user))
|
||||
if(HAS_TRAIT(H, TRAIT_PSIONIC_SUPPRESSION))
|
||||
continue
|
||||
if((GET_Z(H) == GET_Z(L)) && !H.is_psi_blocked(user, TRUE))
|
||||
level_humans |= H
|
||||
if(H.psi)
|
||||
if(H.psi.get_rank() >= PSI_RANK_APEX)
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
name = "psi-stamina weave"
|
||||
desc = "Kind of like charging up your aura."
|
||||
icon_state = "generic"
|
||||
item_icons = null
|
||||
cast_methods = CAST_USE
|
||||
aspect = ASPECT_PSIONIC
|
||||
cooldown = 0
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/singleton/psionic_power/psi_suppression
|
||||
name = "Psionic Suppression"
|
||||
desc = "Hold in one of your hands to make yourself invisible to Psi-Search."
|
||||
desc = "Activate to toggle passive mind-shielding on yourself. While active, you cannot send or receive telepathic messages, and you are nearly impossible to detect as psychic."
|
||||
icon_state = "tech_shield"
|
||||
point_cost = 1
|
||||
ability_flags = PSI_FLAG_CANON
|
||||
@@ -9,19 +9,23 @@
|
||||
/obj/item/spell/psi_suppression
|
||||
name = "psionic suppression"
|
||||
icon_state = "generic"
|
||||
item_icons = null
|
||||
cast_methods = CAST_INNATE
|
||||
aspect = ASPECT_PSIONIC
|
||||
psi_cost = 5
|
||||
|
||||
/obj/item/spell/psi_suppression/Destroy()
|
||||
to_chat(owner, SPAN_NOTICE("You are no longer hidden from Psi-Search."))
|
||||
REMOVE_TRAIT(owner, TRAIT_PSIONIC_SUPPRESSION, TRAIT_SOURCE_PSIONICS)
|
||||
return ..()
|
||||
|
||||
/obj/item/spell/psi_suppression/on_innate_cast(mob/user)
|
||||
. = ..()
|
||||
if(!.)
|
||||
return
|
||||
|
||||
to_chat(user, SPAN_NOTICE("You are now hidden from Psi-Search."))
|
||||
ADD_TRAIT(user, TRAIT_PSIONIC_SUPPRESSION, TRAIT_SOURCE_PSIONICS)
|
||||
var/suppression_comp = user.GetComponent(PSI_SUPPRESSION_COMPONENT)
|
||||
if (suppression_comp)
|
||||
to_chat(user, SPAN_NOTICE("You are no longer suppressing your psi-signature!"))
|
||||
qdel(suppression_comp)
|
||||
qdel(src)
|
||||
return
|
||||
|
||||
to_chat(user, SPAN_NOTICE("You are now suppressing your psi-signature!"))
|
||||
user.AddComponent(PSI_SUPPRESSION_COMPONENT)
|
||||
qdel(src)
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
name = "read mind"
|
||||
desc = "Rip thoughts from someone's mind."
|
||||
icon_state = "generic"
|
||||
item_icons = null
|
||||
cast_methods = CAST_MELEE|CAST_USE
|
||||
aspect = ASPECT_PSIONIC
|
||||
cooldown = 10
|
||||
@@ -33,14 +34,15 @@
|
||||
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(user)
|
||||
var/psi_blocked = target.is_psi_blocked(user, FALSE)
|
||||
if(psi_blocked)
|
||||
to_chat(user, psi_blocked)
|
||||
return
|
||||
|
||||
var/safe_mode = FALSE
|
||||
var/target_sensitivity = target.check_psi_sensitivity()
|
||||
// Safe mode triggers if the caster's psi-sensitivity isn't 2 or more points greater than the receiver's sensitivity.
|
||||
if(user.check_psi_sensitivity() - target.check_psi_sensitivity() < PSI_RANK_HARMONIOUS)
|
||||
if(user.check_psi_sensitivity() - target_sensitivity < PSI_RANK_HARMONIOUS)
|
||||
safe_mode = TRUE
|
||||
|
||||
user.visible_message(SPAN_WARNING("[user] lays a palm on [hit_atom]'s forehead..."))
|
||||
@@ -62,7 +64,11 @@
|
||||
to_chat(user, SPAN_NOTICE("<b>You receive nothing useful from \the [target].</b>"))
|
||||
to_chat(target, SPAN_NOTICE("Your mind blanks out momentarily."))
|
||||
else
|
||||
if(safe_mode)
|
||||
if (target_sensitivity < 0)
|
||||
// Negative sensitivity (of target) case. Underdeveloped Zona Bovinae return a scrambled message.
|
||||
var/scrambled_message = stars(answer, (abs(target_sensitivity) * 25))
|
||||
to_chat(user, SPAN_NOTICE("<b>You tease a half-formed thought from [target]'s mind: <i>[scrambled_message]</i></b>"))
|
||||
else if(safe_mode)
|
||||
to_chat(user, SPAN_NOTICE("<b>You skim the first thoughts in [target]'s mind: <i>[answer]</i></b>"))
|
||||
else
|
||||
to_chat(user, SPAN_NOTICE("<b>You pry the answer to your question from [target]'s mind: <i>[answer]</i></b>"))
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
name = "rejuvenate"
|
||||
desc = "Blood bag who?"
|
||||
icon_state = "mend_life"
|
||||
item_icons = null
|
||||
cast_methods = CAST_MELEE
|
||||
aspect = ASPECT_PSIONIC
|
||||
cooldown = 50
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
name = "skinsight"
|
||||
desc = "A health analyzer, but cooler."
|
||||
icon_state = "blink"
|
||||
item_icons = null
|
||||
cast_methods = CAST_MELEE|CAST_USE
|
||||
aspect = ASPECT_PSIONIC
|
||||
cooldown = 10
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
name = "spasm"
|
||||
desc = "Made you drop your gun."
|
||||
icon_state = "control"
|
||||
item_icons = null
|
||||
cast_methods = CAST_RANGED
|
||||
aspect = ASPECT_PSIONIC
|
||||
cooldown = 100
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
edge = TRUE
|
||||
maintain_cost = 1
|
||||
icon_state = "psiblade_short"
|
||||
pickup_sound = 'sound/items/shield/energy/shield-start.ogg'
|
||||
hitsound = 'sound/weapons/psisword.ogg'
|
||||
|
||||
/obj/item/psychic_power/psiblade/Initialize()
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
return FALSE
|
||||
|
||||
/mob/living/carbon/has_psi_aug()
|
||||
var/obj/item/organ/internal/augment/psi/psiaug = internal_organs_by_name[BP_AUG_PSI]
|
||||
var/obj/item/organ/internal/augment/bioaug/psi/psiaug = internal_organs_by_name[BP_AUG_PSI]
|
||||
return psiaug && !psiaug.is_broken()
|
||||
|
||||
/**
|
||||
@@ -11,13 +11,19 @@
|
||||
* Traditionally, most organic life can in some way RECEIVE psionic messages via a Zona Bovinae, though some lack it.
|
||||
* Implants, drugs, and some psi powers may temporarily block RECEIVING.
|
||||
*
|
||||
* User should be the "Caster" of the power if possible.
|
||||
* Wide_Field should be set to TRUE for anything calling this inside For/While loops.
|
||||
* Basically if you're searching a list, declare it TRUE so that lethal mind blankers don't instagib you.
|
||||
* If it's single-target, keep it FALSE.
|
||||
*
|
||||
* This is NOT a check for "Can Receive?", if you need that go use check_psi_sensitivity().
|
||||
*/
|
||||
/atom/movable/proc/is_psi_blocked(mob/user)
|
||||
/atom/movable/proc/is_psi_blocked(mob/user, var/wide_field = FALSE)
|
||||
var/cancelled = FALSE
|
||||
SEND_SIGNAL(src, COMSIG_PSI_MIND_POWER, user, &cancelled)
|
||||
var/cancel_return = SPAN_WARNING("[src]'s mind is inaccessible, like hitting a brick wall.")
|
||||
SEND_SIGNAL(src, COMSIG_PSI_MIND_POWER, user, &cancelled, &cancel_return, wide_field)
|
||||
if(cancelled || (!has_zona_bovinae() && !has_psi_aug()))
|
||||
return SPAN_WARNING("[src]'s mind is inaccessible, like hitting a brick wall.")
|
||||
return cancel_return
|
||||
|
||||
/**
|
||||
* Check the "effective psi-sensitivity" of a mob. AKA: The target's RECEIVING statistic.
|
||||
@@ -35,7 +41,15 @@
|
||||
*/
|
||||
/atom/movable/proc/check_psi_sensitivity()
|
||||
var/effective_sensitivity = 0
|
||||
// effective_sensitivity is being sent as a Pointer by marking it with the Ampersand (&)
|
||||
// This means that components which have a RegisterSignal() associated with this will receive the memory address of the var/effective_sensitivity in this proc.
|
||||
// They are then allowed to add or subtract to this proc's var directly, without needing to return a number.
|
||||
// We have to do this with a pointer because it allows us to obtain a Sum of all psi-sensitivity modifiers.
|
||||
// If we instead relied on a Return, we would only be able to get the modifier of the first component to respond.
|
||||
SEND_SIGNAL(src, COMSIG_PSI_CHECK_SENSITIVITY, &effective_sensitivity)
|
||||
|
||||
// Pointers can be problematic if they're used to point to a value on a datum, since that can cause unintended hard deletes.
|
||||
// Here however, their use is acceptable because the pointer will cease to exist as soon as the proc reaches this return statement.
|
||||
return effective_sensitivity
|
||||
|
||||
/mob/living/check_psi_sensitivity()
|
||||
|
||||
@@ -476,11 +476,20 @@
|
||||
to_chat(M, SPAN_GOOD(pick("You can almost see the currents of air as they dance around you.", "You see the colours around you beginning to bleed together.", "You feel safe and comfortable.")))
|
||||
|
||||
/singleton/reagent/wulumunusha/overdose(mob/living/carbon/M, alien, removed = 0, scale = 1, datum/reagents/holder)
|
||||
M.AddComponent(WULU_OVERDOSE_COMPONENT)
|
||||
if(!M.psi || M.check_psi_sensitivity() < PSI_RANK_SENSITIVE)
|
||||
return
|
||||
|
||||
M.hallucination = max(M.hallucination, 10 * scale) //light hallucinations that afflict the psionically sensitive.
|
||||
|
||||
/singleton/reagent/wulumunusha/final_effect(mob/living/carbon/M, datum/reagents/holder)
|
||||
. = ..()
|
||||
var/wulu_overdose_comp = M.GetComponent(WULU_OVERDOSE_COMPONENT)
|
||||
if (!wulu_overdose_comp)
|
||||
return
|
||||
|
||||
qdel(wulu_overdose_comp)
|
||||
|
||||
/singleton/reagent/drugs/ambrosia_extract
|
||||
name = "Ambrosia Extract"
|
||||
description = "Ambrosia Extract is a fairly strong relaxant commonly found in Ambrosia plants. It's one of the most widely available drugs in human space."
|
||||
|
||||
@@ -30,7 +30,7 @@
|
||||
// get mobs
|
||||
var/list/affected_mobs = list()
|
||||
for(var/mob/living/carbon/human/mob_in_range in get_hearers_in_LOS(world.view, src))
|
||||
if((!mob_in_range.is_psi_blocked(src)) && ((mob_in_range.check_psi_sensitivity() > 0) || mob_in_range.has_zona_bovinae()))
|
||||
if((!mob_in_range.is_psi_blocked(src, TRUE)) && ((mob_in_range.check_psi_sensitivity() > 0) || mob_in_range.has_zona_bovinae()))
|
||||
affected_mobs += mob_in_range
|
||||
|
||||
// set up timer for delayed effects
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
author: Hellfirejag
|
||||
delete-after: True
|
||||
changes:
|
||||
- rscadd: "Added 2 new traits (which are temporarily in the disabilities tab) related to psi-sensitivity."
|
||||
- rscadd: "Magic powers of all kinds no longer by-default play the generic pickup and drop sounds. This includes psionic powers, which are now silent to equip."
|
||||
- rscadd: "Canonical psionic powers and some antag psi powers are now invisible when held."
|
||||
- rscadd: "Psi-Suppression is now a passively toggled ability which works like a stronger mindshield/mindblanker. It no longer requires you hold the power in hand."
|
||||
- bugfix: "Psi-protection sources like Mindshield, Mindblanker, and Psi-Suppression no longer play messages when they passively hide you from Psi-Search."
|
||||
- rscadd: "Assay no longer gives away antag status by telling you outright if someone is an antag psychic. It instead gives you hints as to the target's psi-sensitivity (which aren't conclusive of antags)."
|
||||
- rscadd: "Overdosing on Wulumunusha now temporarily increases psi-sensitivity until the high wears off."
|
||||
- rscadd: "Psi-receivers are now a Bioaug instead of a mechanical augment."
|
||||
- rscadd: "Having low psi-sensitivity now interferes with telepathic messages, such as from Commune, Emotional Suggestion, and Read Mind. Causing them to become distorted similarly to whispers from 2 tiles away."
|
||||
@@ -261,7 +261,7 @@
|
||||
/obj/item/organ/internal/augment/fuel_cell,
|
||||
/obj/item/organ/internal/augment/gustatorial/hand,
|
||||
/obj/item/organ/internal/augment/health_scanner,
|
||||
/obj/item/organ/internal/augment/psi,
|
||||
/obj/item/organ/internal/augment/bioaug/psi,
|
||||
/obj/item/organ/internal/augment/suspension,
|
||||
/obj/item/organ/internal/augment/tool/combitool,
|
||||
/obj/item/organ/internal/augment/tool/correctivelens/glare_dampener,
|
||||
|
||||
Reference in New Issue
Block a user