Skip to content
This repository was archived by the owner on May 22, 2025. It is now read-only.
Closed
Show file tree
Hide file tree
Changes from 8 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 34 additions & 0 deletions code/__DEFINES/psi.dm
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
#define PSI_COERCION "coercion"

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

might be a bit confusing having dspawn psi and normal psi, psy could work beter tbh

#define PSI_PSYCHOKINESIS "psychokinesis"
#define PSI_REDACTION "redaction"
#define PSI_ENERGISTICS "energistics"

#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_IMPLANT_AUTOMATIC "Security Level Derived"
#define PSI_IMPLANT_SHOCK "Issue Neural Shock"
#define PSI_IMPLANT_WARN "Issue Reprimand"
#define PSI_IMPLANT_LOG "Log Incident"
#define PSI_IMPLANT_DISABLED "Disabled"

#define INVOKE_PSI_POWERS(holder, powers, target, return_on_invocation) \
if(holder && holder.psi && holder.psi.can_use()) { \
for(var/thing in powers) { \
var/datum/psionic_power/power = thing; \
var/obj/item/result = power.invoke(holder, target); \
Comment thread
nmajask marked this conversation as resolved.
Outdated
if(result) { \
power.handle_post_power(holder, target); \
if(istype(result)) { \
holder.playsound_local(soundin = 'sound/effects/psi/power_evoke.ogg'); \
LAZYADD(holder.psi.manifested_items, result); \
holder.put_in_hands(result); \
} \
return return_on_invocation; \
} \
} \
}
1 change: 1 addition & 0 deletions code/__DEFINES/{yogs_defines}/antagonists.dm
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
#define ANTAG_DATUM_VAMPIRE /datum/antagonist/vampire
#define ANTAG_DATUM_THRALL /datum/antagonist/thrall
#define ANTAG_DATUM_SHADOWTHRALL /datum/antagonist/thrall/shadowling
#define ANTAG_DATUM_SLING /datum/antagonist/shadowling
#define ANTAG_DATUM_DARKSPAWN /datum/antagonist/darkspawn
#define ANTAG_DATUM_VEIL /datum/antagonist/veil
Expand Down
2 changes: 2 additions & 0 deletions code/_onclick/hud/screen_objects.dm
Original file line number Diff line number Diff line change
Expand Up @@ -214,6 +214,8 @@
var/obj/item/I = hud.mymob.get_active_held_item()
if(I)
I.Click(location, control, params)
else
hud.mymob.attack_empty_hand(hud.mymob.active_hand_index)
else
hud.mymob.swap_hand(held_index)
return 1
Expand Down
16 changes: 14 additions & 2 deletions code/_onclick/other_mobs.dm
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
Otherwise pretty standard.
*/
/mob/living/carbon/human/UnarmedAttack(atom/A, proximity)
if(psi)
INVOKE_PSI_POWERS(src, psi.get_melee_powers(SSpsi.faculties_by_intent[a_intent]), A, FALSE)
if(HAS_TRAIT(A, TRAIT_NOINTERACT))
to_chat(A, span_notice("You can't touch things!"))
return
Expand Down Expand Up @@ -34,6 +36,15 @@
SEND_SIGNAL(src, COMSIG_HUMAN_MELEE_UNARMED_ATTACK, A)
A.attack_hand(src)

/mob/living/carbon/human/attack_empty_hand()
message_admins("A")
if(psi)
INVOKE_PSI_POWERS(src, psi.get_manifestations(), src, FALSE)

/mob/living/carbon/human/RangedAttack(atom/A, params)
if(psi)
INVOKE_PSI_POWERS(src, psi.get_ranged_powers(SSpsi.faculties_by_intent[a_intent]), A, TRUE)

//Return TRUE to cancel other attack hand effects that respect it.
/atom/proc/attack_hand(mob/user)
. = FALSE
Expand All @@ -44,6 +55,9 @@
if(interaction_flags_atom & INTERACT_ATOM_ATTACK_HAND)
. = _try_interact(user)

/mob/proc/attack_empty_hand(var/hand)
Comment thread
nmajask marked this conversation as resolved.
Outdated
return

//Return a non FALSE value to cancel whatever called this from propagating, if it respects it.
/atom/proc/_try_interact(mob/user)
if(IsAdminGhost(user)) //admin abuse
Expand Down Expand Up @@ -111,8 +125,6 @@
/*
Animals & All Unspecified
*/
/mob/living/UnarmedAttack(atom/A)
A.attack_animal(src)

/atom/proc/attack_animal(mob/user)
return
Expand Down
45 changes: 45 additions & 0 deletions code/controllers/subsystem/processing/psi.dm
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
var/global/list/psychic_ranks_to_strings = list("Latent", "Operant", "Masterclass", "Grandmasterclass", "Paramount")

PROCESSING_SUBSYSTEM_DEF(psi)
name = "Psychics"
// priority = SS_PRIORITY_PSYCHICS
flags = SS_POST_FIRE_TIMING | 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/armour_faculty_by_type = list()
var/list/faculties_by_intent = list()

/datum/controller/subsystem/processing/psi/New()
NEW_SS_GLOBAL(SSpsi)

/datum/controller/subsystem/processing/psi/proc/get_faculty(faculty)
return faculties_by_name[faculty] || faculties_by_id[faculty]

/datum/controller/subsystem/processing/psi/Initialize()
. = ..()

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
Comment thread
nmajask marked this conversation as resolved.
Outdated

/datum/controller/subsystem/processing/psi/proc/report_failure(implant)
return // TODO

/datum/controller/subsystem/processing/psi/proc/report_violation(implant, stress)
return // TODO
7 changes: 7 additions & 0 deletions code/datums/mind.dm
Original file line number Diff line number Diff line change
Expand Up @@ -438,6 +438,13 @@
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"]))
message_admins("[key_name_admin(usr)] set [key_name(current)]'s [href_list["set_psi_faculty"]] faculty to [text2num(href_list["set_psi_faculty_rank"])].")
log_admin("[key_name_admin(usr)] set [key_name(current)]'s [href_list["set_psi_faculty"]] faculty to [text2num(href_list["set_psi_faculty_rank"])].")
return TRUE

var/self_antagging = usr == current

if(href_list["add_antag"])
Expand Down
30 changes: 30 additions & 0 deletions code/datums/thrall
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
/datum/antagonist/thrall
name = "Thrall"
id = MODE_THRALL
role_text = "Thrall"
role_text_plural = "Thralls"
bantype = "vampires"
feedback_tag = "thrall_objective"
restricted_jobs = list("AI", "Cyborg", "Chaplain")
protected_jobs = list()
restricted_species = list(
"Baseline Frame",
"Shell Frame",
"Hephaestus G1 Industrial Frame",
"Hephaestus G2 Industrial Frame",
"Xion Industrial Frame",
"Zeng-Hu Mobility Frame",
"Bishop Accessory Frame"
)
welcome_text = "You are a psionic operant's thrall: a pawn to be commanded by them at will."
flags = 0
antaghud_indicator = "hudthrall"

/datum/antagonist/thrall/New()
..()

thralls = src

/datum/antagonist/thrall/update_antag_mob(var/datum/mind/player)
..()
player.current.vampire_make_thrall()

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You fogot to add .dm to this file name

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

good catch, will fix soon

2 changes: 1 addition & 1 deletion code/datums/traits/negative.dm
Original file line number Diff line number Diff line change
Expand Up @@ -282,7 +282,7 @@

/datum/quirk/nyctophobia/on_process()
var/mob/living/carbon/human/H = quirk_holder
if((H.dna.species.id in list("shadow", "nightmare", "darkspawn")) || (H.mind && (H.mind.has_antag_datum(ANTAG_DATUM_THRALL) || H.mind.has_antag_datum(ANTAG_DATUM_SLING) || H.mind.has_antag_datum(ANTAG_DATUM_DARKSPAWN) || H.mind.has_antag_datum(ANTAG_DATUM_VEIL)))) //yogs - thrall & sling check
if((H.dna.species.id in list("shadow", "nightmare", "darkspawn")) || (H.mind && (H.mind.has_antag_datum(ANTAG_DATUM_SHADOWTHRALL) || H.mind.has_antag_datum(ANTAG_DATUM_SLING) || H.mind.has_antag_datum(ANTAG_DATUM_DARKSPAWN) || H.mind.has_antag_datum(ANTAG_DATUM_VEIL)))) //yogs - thrall & sling check
return //we're tied with the dark, so we don't get scared of it; don't cleanse outright to avoid cheese
var/turf/T = get_turf(quirk_holder)
var/lums = T.get_lumcount()
Expand Down
3 changes: 3 additions & 0 deletions code/game/atoms_movable.dm
Original file line number Diff line number Diff line change
Expand Up @@ -987,3 +987,6 @@
animate(I, alpha = 175, pixel_x = to_x, pixel_y = to_y, time = 0.3 SECONDS, transform = M, easing = CUBIC_EASING)
sleep(0.1 SECONDS)
animate(I, alpha = 0, transform = matrix(), time = 0.1 SECONDS)

/atom/movable/proc/do_simple_ranged_interaction(var/mob/user)
Comment thread
nmajask marked this conversation as resolved.
Outdated
return FALSE
8 changes: 8 additions & 0 deletions code/game/machinery/doors/door.dm
Original file line number Diff line number Diff line change
Expand Up @@ -181,6 +181,14 @@
return
..()

/obj/machinery/door/do_simple_ranged_interaction(var/mob/user)
Comment thread
nmajask marked this conversation as resolved.
Outdated
if(!requiresID() || allowed(null))
if(density)
open()
else
close()
return TRUE

/obj/machinery/door/proc/try_to_activate_door(mob/user)
add_fingerprint(user)
if(operating || (obj_flags & EMAGGED))
Expand Down
5 changes: 5 additions & 0 deletions code/game/objects/items.dm
Original file line number Diff line number Diff line change
Expand Up @@ -402,6 +402,11 @@ GLOBAL_DATUM_INIT(welding_sparks, /mutable_appearance, mutable_appearance('icons
R.activate_module(src)
R.hud_used.update_robot_modules_display()

/obj/item/do_simple_ranged_interaction(var/mob/user)
Comment thread
nmajask marked this conversation as resolved.
Outdated
if(user)
attack_self(user)
return TRUE

/obj/item/proc/GetDeconstructableContents()
return GetAllContents() - src

Expand Down
113 changes: 113 additions & 0 deletions code/game/objects/items/implants/implant_psi.dm
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
/obj/item/implant/psi_control
name = "psi dampener implant"
desc = "A safety implant for registered psi-operants."
implant_color = "n"
activated = FALSE

var/overload = 0
var/max_overload = 100
var/psi_mode = PSI_IMPLANT_AUTOMATIC

/obj/item/implant/psi_control/get_data()
var/dat = {"<b>Implant Specifications:</b><BR>
<b>Name:</b> Nanotrasen Psionic Mitigation Implant<BR>
<b>Life:</b> Ten years.<BR>
<b>Important Notes:</b> Psionic personel injected with this device can have their psionic potental di.<BR>
<HR>
<b>Implant Details:</b><BR>
<b>Function:</b> Contains a small pod of nanobots that protects the host's mental functions from manipulation.<BR>
<b>Special Features:</b> Will prevent and cure most forms of brainwashing.<BR>
<b>Integrity:</b> Implant will last so long as the nanobots are inside the bloodstream."}
return dat

/obj/item/implant/psi_control/Initialize()
. = ..()
SSpsi.psi_dampeners += src

/obj/item/implant/psi_control/Destroy()
SSpsi.psi_dampeners -= src
. = ..()

/obj/item/implant/psi_control/disrupts_psionics()
var/use_psi_mode = get_psi_mode()
return ((use_psi_mode == PSI_IMPLANT_SHOCK || use_psi_mode == PSI_IMPLANT_WARN)) ? src : FALSE

/obj/item/implant/psi_control/removed()
var/mob/living/M = imp_in
if(disrupts_psionics() && istype(M) && M.psi)
to_chat(M, span_notice("You feel the chilly shackles around your psionic faculties fade away."))
. = ..()

/obj/item/implant/psi_control/proc/update_functionality(var/silent)
Comment thread
nmajask marked this conversation as resolved.
Outdated
var/mob/living/M = imp_in
if(silent || !M || !M.psi)
return
if(get_psi_mode() == PSI_IMPLANT_DISABLED)
to_chat(M, span_notice("You feel the chilly shackles around your psionic faculties fade away."))
else
to_chat(M, span_notice("Bands of hollow ice close themselves around your psionic faculties."))

/obj/item/implant/psi_control/proc/meltdown()
overload = 100
if(imp_in)
SSpsi.report_failure(src)
psi_mode = PSI_IMPLANT_DISABLED
update_functionality()

/obj/item/implant/psi_control/proc/get_psi_mode()
if(psi_mode == PSI_IMPLANT_AUTOMATIC)
switch(get_security_level())
if("green")
return PSI_IMPLANT_SHOCK
if("blue")
return PSI_IMPLANT_WARN
else
return PSI_IMPLANT_DISABLED

return psi_mode

/obj/item/implant/psi_control/withstand_psi_stress(var/stress, var/atom/source)
Comment thread
nmajask marked this conversation as resolved.
Outdated

var/use_psi_mode = get_psi_mode()

if(use_psi_mode == PSI_IMPLANT_DISABLED)
return stress

. = 0

if(stress > 0)
Comment thread
nmajask marked this conversation as resolved.
Outdated

// If we're disrupting psionic attempts at the moment, we might overload.
if(disrupts_psionics())
var/overload_amount = FLOOR(stress, 10)
if(overload_amount > 0)
Comment thread
nmajask marked this conversation as resolved.
Outdated
overload += overload_amount
if(overload >= 100)
if(imp_in)
to_chat(imp_in, span_danger("Your psi dampener overloads violently!"))
meltdown()
update_functionality()
return
if(imp_in)
if(overload >= 75 && overload < 100)
to_chat(imp_in, span_danger("Your psi dampener is searing hot!"))
else if(overload >= 50 && overload < 75)
to_chat(imp_in, span_warning("Your psi dampener is uncomfortably hot..."))
else if(overload >= 25 && overload < 50)
to_chat(imp_in, span_warning("You feel your psi dampener heating up..."))

// If all we're doing is logging the incident then just pass back stress without changing it.
if(source && source == imp_in)
SSpsi.report_violation(src, stress)
if(use_psi_mode == PSI_IMPLANT_LOG)
return stress
else if(use_psi_mode == PSI_IMPLANT_SHOCK)
to_chat(imp_in, span_danger("Your psi dampener punishes you with a violent neural shock!"))
imp_in.electrocute_act(5, src)
if(isliving(imp_in))
var/mob/living/M = imp_in
if(M.psi) M.psi.stunned(5)
else if(use_psi_mode == PSI_IMPLANT_WARN)
to_chat(imp_in, span_warning("Your psi dampener primly informs you it has reported this violation."))

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

switch

// /obj/item/implant/nullglass
Loading