diff --git a/aurorastation.dme b/aurorastation.dme index 934ea706d8e..b4bbd4bc733 100644 --- a/aurorastation.dme +++ b/aurorastation.dme @@ -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" diff --git a/code/__DEFINES/traits.dm b/code/__DEFINES/traits.dm index cc61bc58d66..88b996ec376 100644 --- a/code/__DEFINES/traits.dm +++ b/code/__DEFINES/traits.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" diff --git a/code/datums/components/psionics/psi_sensitivity.dm b/code/datums/components/psionics/psi_sensitivity.dm new file mode 100644 index 00000000000..7d7c2cc0c68 --- /dev/null +++ b/code/datums/components/psionics/psi_sensitivity.dm @@ -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 diff --git a/code/datums/components/psionics/psi_suppression.dm b/code/datums/components/psionics/psi_suppression.dm new file mode 100644 index 00000000000..75150bd96c2 --- /dev/null +++ b/code/datums/components/psionics/psi_suppression.dm @@ -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!")) diff --git a/code/game/gamemodes/technomancer/spell_objs.dm b/code/game/gamemodes/technomancer/spell_objs.dm index f49c84dd63c..2ba34cb5912 100644 --- a/code/game/gamemodes/technomancer/spell_objs.dm +++ b/code/game/gamemodes/technomancer/spell_objs.dm @@ -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. diff --git a/code/game/objects/items/weapons/implants/implants/mindshield.dm b/code/game/objects/items/weapons/implants/implants/mindshield.dm index 9f6fe4257e6..d6d71228082 100644 --- a/code/game/objects/items/weapons/implants/implants/mindshield.dm +++ b/code/game/objects/items/weapons/implants/implants/mindshield.dm @@ -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) diff --git a/code/game/objects/items/weapons/storage/boxes.dm b/code/game/objects/items/weapons/storage/boxes.dm index 03a4e9fa227..66870ae7552 100644 --- a/code/game/objects/items/weapons/storage/boxes.dm +++ b/code/game/objects/items/weapons/storage/boxes.dm @@ -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" diff --git a/code/modules/client/preference_setup/loadout/items/augments.dm b/code/modules/client/preference_setup/loadout/items/augments.dm index ccdebb556d9..cc8c4c9d0b3 100644 --- a/code/modules/client/preference_setup/loadout/items/augments.dm +++ b/code/modules/client/preference_setup/loadout/items/augments.dm @@ -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 diff --git a/code/modules/mob/abstract/new_player/character_traits.dm b/code/modules/mob/abstract/new_player/character_traits.dm index a2988e9e929..986e90ae5c0 100644 --- a/code/modules/mob/abstract/new_player/character_traits.dm +++ b/code/modules/mob/abstract/new_player/character_traits.dm @@ -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) diff --git a/code/modules/organs/subtypes/augment/augments/mind_blanker.dm b/code/modules/organs/subtypes/augment/augments/mind_blanker.dm index 65c650842a4..79d799cadf9 100644 --- a/code/modules/organs/subtypes/augment/augments/mind_blanker.dm +++ b/code/modules/organs/subtypes/augment/augments/mind_blanker.dm @@ -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 diff --git a/code/modules/organs/subtypes/augment/augments/psi_receiver.dm b/code/modules/organs/subtypes/augment/augments/psi_receiver.dm index 152e0146f40..ca1be8afd74 100644 --- a/code/modules/organs/subtypes/augment/augments/psi_receiver.dm +++ b/code/modules/organs/subtypes/augment/augments/psi_receiver.dm @@ -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 diff --git a/code/modules/psionics/abilities/assay.dm b/code/modules/psionics/abilities/assay.dm index 8cbab06dd83..f91c7404451 100644 --- a/code/modules/psionics/abilities/assay.dm +++ b/code/modules/psionics/abilities/assay.dm @@ -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.")) diff --git a/code/modules/psionics/abilities/barrier.dm b/code/modules/psionics/abilities/barrier.dm index 6ef854302da..a097cba4ae3 100644 --- a/code/modules/psionics/abilities/barrier.dm +++ b/code/modules/psionics/abilities/barrier.dm @@ -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 diff --git a/code/modules/psionics/abilities/charge.dm b/code/modules/psionics/abilities/charge.dm index fab1a32235c..2ca1f772285 100644 --- a/code/modules/psionics/abilities/charge.dm +++ b/code/modules/psionics/abilities/charge.dm @@ -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 diff --git a/code/modules/psionics/abilities/commune.dm b/code/modules/psionics/abilities/commune.dm index 4a5b4e62aec..1064a0a1339 100644 --- a/code/modules/psionics/abilities/commune.dm +++ b/code/modules/psionics/abilities/commune.dm @@ -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("[user] blinks, their eyes briefly developing an unnatural shine.")) 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, "[user] psionically says to [target]: [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("[user] blinks, their eyes briefly developing an unnatural shine.")) to_chat(H, SPAN_CULT("You instinctively sense [user] passing a thought into your mind: [text]")) - else + else if (target_sensitivity >= 0) + // Standard case for most characters. to_chat(H, SPAN_ALIEN("A thought from outside your consciousness slips into your mind: [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("A half-formed thought passes through your mind: [scrambled_message]")) diff --git a/code/modules/psionics/abilities/electrocute.dm b/code/modules/psionics/abilities/electrocute.dm index c8fcbaa7dd6..108b8f0cab8 100644 --- a/code/modules/psionics/abilities/electrocute.dm +++ b/code/modules/psionics/abilities/electrocute.dm @@ -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 diff --git a/code/modules/psionics/abilities/emotional_suggestion.dm b/code/modules/psionics/abilities/emotional_suggestion.dm index df6dc7166bd..245e853243c 100644 --- a/code/modules/psionics/abilities/emotional_suggestion.dm +++ b/code/modules/psionics/abilities/emotional_suggestion.dm @@ -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("[user] blinks, their eyes briefly developing an unnatural shine.")) 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, "[user] psionically suggests an emotion to [target]: [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("[user] blinks, their eyes briefly developing an unnatural shine.")) to_chat(H, SPAN_NOTICE("You sense [user]'s psyche link with your own, and an emotion of [text] 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: [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_NOTICE("A half-formed emotion passes through your mind: [scrambled_message].")) diff --git a/code/modules/psionics/abilities/focus.dm b/code/modules/psionics/abilities/focus.dm index 3ffb245aef3..64331fc3cea 100644 --- a/code/modules/psionics/abilities/focus.dm +++ b/code/modules/psionics/abilities/focus.dm @@ -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 diff --git a/code/modules/psionics/abilities/mend.dm b/code/modules/psionics/abilities/mend.dm index 859b38db5cc..7132952de2b 100644 --- a/code/modules/psionics/abilities/mend.dm +++ b/code/modules/psionics/abilities/mend.dm @@ -10,6 +10,7 @@ name = "mend" desc = "Clear!" icon_state = "mend_wounds" + item_icons = null cast_methods = CAST_MELEE aspect = ASPECT_PSIONIC cooldown = 50 diff --git a/code/modules/psionics/abilities/nlom_eyes.dm b/code/modules/psionics/abilities/nlom_eyes.dm index cd265714f6f..69d2213864c 100644 --- a/code/modules/psionics/abilities/nlom_eyes.dm +++ b/code/modules/psionics/abilities/nlom_eyes.dm @@ -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 diff --git a/code/modules/psionics/abilities/psi_recovery.dm b/code/modules/psionics/abilities/psi_recovery.dm index d9f4af7d7a0..3a489ddc79b 100644 --- a/code/modules/psionics/abilities/psi_recovery.dm +++ b/code/modules/psionics/abilities/psi_recovery.dm @@ -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 diff --git a/code/modules/psionics/abilities/psi_search.dm b/code/modules/psionics/abilities/psi_search.dm index c97baed7d1f..446ae3fdd8b 100644 --- a/code/modules/psionics/abilities/psi_search.dm +++ b/code/modules/psionics/abilities/psi_search.dm @@ -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) diff --git a/code/modules/psionics/abilities/psi_stamina.dm b/code/modules/psionics/abilities/psi_stamina.dm index e8278b2fa47..3a7996ab612 100644 --- a/code/modules/psionics/abilities/psi_stamina.dm +++ b/code/modules/psionics/abilities/psi_stamina.dm @@ -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 diff --git a/code/modules/psionics/abilities/psi_suppression.dm b/code/modules/psionics/abilities/psi_suppression.dm index 758fa93811c..2023e0bf9ca 100644 --- a/code/modules/psionics/abilities/psi_suppression.dm +++ b/code/modules/psionics/abilities/psi_suppression.dm @@ -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) diff --git a/code/modules/psionics/abilities/read_mind.dm b/code/modules/psionics/abilities/read_mind.dm index 41b04147bd5..203764951e4 100644 --- a/code/modules/psionics/abilities/read_mind.dm +++ b/code/modules/psionics/abilities/read_mind.dm @@ -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("You receive nothing useful from \the [target].")) 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("You tease a half-formed thought from [target]'s mind: [scrambled_message]")) + else if(safe_mode) to_chat(user, SPAN_NOTICE("You skim the first thoughts in [target]'s mind: [answer]")) else to_chat(user, SPAN_NOTICE("You pry the answer to your question from [target]'s mind: [answer]")) diff --git a/code/modules/psionics/abilities/rejuvenate.dm b/code/modules/psionics/abilities/rejuvenate.dm index ab92f713ad9..ab576d4acb8 100644 --- a/code/modules/psionics/abilities/rejuvenate.dm +++ b/code/modules/psionics/abilities/rejuvenate.dm @@ -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 diff --git a/code/modules/psionics/abilities/skinsight.dm b/code/modules/psionics/abilities/skinsight.dm index 1966dbe4794..15298b05fa4 100644 --- a/code/modules/psionics/abilities/skinsight.dm +++ b/code/modules/psionics/abilities/skinsight.dm @@ -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 diff --git a/code/modules/psionics/abilities/spasm.dm b/code/modules/psionics/abilities/spasm.dm index 0cc7e961083..9b02e0fc01d 100644 --- a/code/modules/psionics/abilities/spasm.dm +++ b/code/modules/psionics/abilities/spasm.dm @@ -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 diff --git a/code/modules/psionics/equipment/psipower_blade.dm b/code/modules/psionics/equipment/psipower_blade.dm index 8167a83061b..752406c6cf6 100644 --- a/code/modules/psionics/equipment/psipower_blade.dm +++ b/code/modules/psionics/equipment/psipower_blade.dm @@ -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() diff --git a/code/modules/psionics/mob/mob_helpers.dm b/code/modules/psionics/mob/mob_helpers.dm index 6d5fa21d04b..91d31e6f2d6 100644 --- a/code/modules/psionics/mob/mob_helpers.dm +++ b/code/modules/psionics/mob/mob_helpers.dm @@ -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() diff --git a/code/modules/reagents/Chemistry-Reagents/Chemistry-Reagents-Drugs.dm b/code/modules/reagents/Chemistry-Reagents/Chemistry-Reagents-Drugs.dm index f712e54b12d..d0108be2878 100644 --- a/code/modules/reagents/Chemistry-Reagents/Chemistry-Reagents-Drugs.dm +++ b/code/modules/reagents/Chemistry-Reagents/Chemistry-Reagents-Drugs.dm @@ -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." diff --git a/code/modules/research/xenoarchaeology/artifact/artifact_crystal_madness.dm b/code/modules/research/xenoarchaeology/artifact/artifact_crystal_madness.dm index 5223a4e2e2b..3d2a09eb823 100644 --- a/code/modules/research/xenoarchaeology/artifact/artifact_crystal_madness.dm +++ b/code/modules/research/xenoarchaeology/artifact/artifact_crystal_madness.dm @@ -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 diff --git a/html/changelogs/hellfirejag-psi-rework-pt2.yml b/html/changelogs/hellfirejag-psi-rework-pt2.yml new file mode 100644 index 00000000000..f5c3ab81868 --- /dev/null +++ b/html/changelogs/hellfirejag-psi-rework-pt2.yml @@ -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." diff --git a/maps/away/ships/lone_spacer/lone_spacer_submaps.dmm b/maps/away/ships/lone_spacer/lone_spacer_submaps.dmm index c0667fed868..69c181898a4 100644 --- a/maps/away/ships/lone_spacer/lone_spacer_submaps.dmm +++ b/maps/away/ships/lone_spacer/lone_spacer_submaps.dmm @@ -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,