From 60090e1acd2b470aaaec5d3bdb13f629b588fa8d Mon Sep 17 00:00:00 2001 From: Matt Atlas Date: Fri, 21 Jul 2023 20:05:38 +0200 Subject: [PATCH] With that smile, with that "I love you" You captivate everyone --- SQL/migrate/V081__psionics.sql | 5 + aurorastation.dme | 2 + code/__defines/species_languages.dm | 1 + code/__defines/traits.dm | 3 + .../preference_setup/general/07_psionics.dm | 125 ++++++++++++++++++ code/modules/client/preferences.dm | 2 + .../living/carbon/human/species/species.dm | 5 + .../human/species/station/skrell/skrell.dm | 8 +- code/modules/projectiles/projectile/beams.dm | 9 -- .../abilities/emotional_suggestion.dm | 2 +- code/modules/psionics/abilities/lightning.dm | 39 ++++++ .../psionics/abilities/psi_recovery.dm | 6 +- code/modules/psionics/abilities/psi_search.dm | 2 + .../psionics/abilities/psi_suppression.dm | 27 ++++ code/modules/psionics/complexus/complexus.dm | 2 +- .../psionics/complexus/complexus_process.dm | 1 + code/modules/psionics/interface/ui_hub.dm | 17 +-- 17 files changed, 224 insertions(+), 32 deletions(-) create mode 100644 SQL/migrate/V081__psionics.sql create mode 100644 code/modules/client/preference_setup/general/07_psionics.dm create mode 100644 code/modules/psionics/abilities/psi_suppression.dm diff --git a/SQL/migrate/V081__psionics.sql b/SQL/migrate/V081__psionics.sql new file mode 100644 index 00000000000..dcc27527fd1 --- /dev/null +++ b/SQL/migrate/V081__psionics.sql @@ -0,0 +1,5 @@ +-- +-- Adds psionic prefs +-- + +ALTER TABLE `ss13_characters` ADD COLUMN `psionics` VARCHAR(128) DEFAULT null AFTER `origin`; diff --git a/aurorastation.dme b/aurorastation.dme index 6682f7b80a3..5be141a2a91 100644 --- a/aurorastation.dme +++ b/aurorastation.dme @@ -1577,6 +1577,7 @@ #include "code\modules\client\preference_setup\general\04_equipment.dm" #include "code\modules\client\preference_setup\general\05_background.dm" #include "code\modules\client\preference_setup\general\06_flavor.dm" +#include "code\modules\client\preference_setup\general\07_psionics.dm" #include "code\modules\client\preference_setup\global\01_ui.dm" #include "code\modules\client\preference_setup\global\02_settings.dm" #include "code\modules\client\preference_setup\global\03_language.dm" @@ -2900,6 +2901,7 @@ #include "code\modules\psionics\abilities\psi_search.dm" #include "code\modules\psionics\abilities\psi_stamina.dm" #include "code\modules\psionics\abilities\psi_sunder.dm" +#include "code\modules\psionics\abilities\psi_suppression.dm" #include "code\modules\psionics\abilities\psi_sword.dm" #include "code\modules\psionics\abilities\psi_tool.dm" #include "code\modules\psionics\abilities\pull.dm" diff --git a/code/__defines/species_languages.dm b/code/__defines/species_languages.dm index f70deb13dfd..78309ae4c08 100644 --- a/code/__defines/species_languages.dm +++ b/code/__defines/species_languages.dm @@ -24,6 +24,7 @@ #define CAN_JOIN 0x2 // Species is selectable in chargen. #define IS_RESTRICTED 0x4 // Is not a core/normally playable species. (castes, mutantraces) #define NO_AGE_MINIMUM 0x8 // Doesn't respect minimum job age requirements. +#define HAS_PSIONICS 0x10 // Spawns with psionics. // Species appearance flags #define HAS_SKIN_TONE 0x1 // Skin tone selectable in chargen. (0-255) diff --git a/code/__defines/traits.dm b/code/__defines/traits.dm index 14b5d1261a4..814cea4743f 100644 --- a/code/__defines/traits.dm +++ b/code/__defines/traits.dm @@ -145,6 +145,9 @@ /// Mob is psionically deaf. #define TRAIT_PSIONICALLY_DEAF "psionically_deaf" +/// 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/modules/client/preference_setup/general/07_psionics.dm b/code/modules/client/preference_setup/general/07_psionics.dm new file mode 100644 index 00000000000..f5188d9bdd1 --- /dev/null +++ b/code/modules/client/preference_setup/general/07_psionics.dm @@ -0,0 +1,125 @@ +/datum/category_item/player_setup_item/general/psionics + name = "Psionics" + sort_order = 7 + + +/datum/category_item/player_setup_item/general/psionics/load_character(var/savefile/S) + var/psionics_json + S["psionics"] >> psionics_json + var/list/psionics = json_decode(psionics_json) + for(var/psi in psionics) + var/singleton/psionic_power/P = GET_SINGLETON(text2path(psi)) + if(!istype(P)) + continue + psionics |= P.type + pref.psionics = psionics + +/datum/category_item/player_setup_item/general/psionics/save_character(var/savefile/S) + var/list/psionics = pref.psionics + for(var/psi in psionics) + var/singleton/psionic_power/P = GET_SINGLETON(text2path(psi)) + if(!istype(P)) + continue + psionics |= P.type + S["psionics"] << json_encode(psionics) + +/datum/category_item/player_setup_item/general/psionics/gather_load_query() + return list( + "ss13_characters" = list( + "vars" = list( + "psionics" = "psionics", + ), + "args" = list("id") + ) + ) + +/datum/category_item/player_setup_item/general/psionics/gather_load_parameters() + return list("id" = pref.current_character) + + +/datum/category_item/player_setup_item/general/psionics/gather_save_query() + return list( + "ss13_characters" = list( + "psionics", + "id" = 1 + ) + ) + +/datum/category_item/player_setup_item/general/psionics/gather_save_parameters() + var/list/sanitized_psionics = list() + for(var/S in pref.psionics) + var/singleton/psionic_power/P = GET_SINGLETON(text2path(S)) + if(!istype(P)) + continue + sanitized_psionics |= "[P.type]" + return list( + "psionics" = json_encode(sanitized_psionics), + "char_id" = pref.current_character, + "ckey" = PREF_CLIENT_CKEY + ) + +/datum/category_item/player_setup_item/general/psionics/sanitize_character(var/sql_load = 0) + for(var/S in pref.psionics) + var/singleton/psionic_power/P = GET_SINGLETON(text2path(S)) + if(!istype(P)) + pref.psionics -= S + continue + else + if(!(P.ability_flags & PSI_FLAG_FOUNDATIONAL)) + pref.psionics -= S + continue + +/datum/category_item/player_setup_item/general/psionics/content(var/mob/user) + var/datum/species/mob_species = all_species[pref.species] + if(!(mob_species.spawn_flags & HAS_PSIONICS)) + return + var/list/bought_psionic_powers = list() + for(var/S in pref.psionics) + var/singleton/psionic_power/P = GET_SINGLETON(text2path(S)) + if(istype(P)) + bought_psionic_powers |= P + + var/list/dat = list( + "Psionics:
" + ) + for(var/singleton/psionic_power/P in bought_psionic_powers) + dat += "- [P.name] -
" + dat += "Add Psionic Power
" + . = dat.Join() + +/datum/category_item/player_setup_item/general/psionics/OnTopic(var/href,var/list/href_list, var/mob/user) + if(href_list["remove_psi_power"]) + var/power_to_remove = href_list["remove_psi_power"] + if(power_to_remove && (power_to_remove in pref.psionics)) + pref.psionics -= power_to_remove + return TOPIC_REFRESH + + else if(href_list["add_psi_power"]) + var/datum/species/mob_species = all_species[pref.species] + var/total_psi_points = mob_species.character_creation_psi_points + var/list/available_psionics = list() + var/list/psionic_map = list() + var/list/bought_psionic_powers = list() + + for(var/S in pref.psionics) + var/singleton/psionic_power/P = GET_SINGLETON(text2path(S)) + if(istype(P)) + bought_psionic_powers |= P + total_psi_points = max(0, total_psi_points - P.point_cost) + + for(var/singleton/psionic_power/P in GET_SINGLETON_SUBTYPE_LIST(/singleton/psionic_power)) + if((P.ability_flags & PSI_FLAG_CANON) && (P.point_cost <= total_psi_points) && !(P in bought_psionic_powers)) + available_psionics |= "[P.name]" + psionic_map[P.name] = P.type + + if(!length(available_psionics)) + to_chat(user, SPAN_WARNING("You ran out of points!")) + return + + var/new_power = input(user, "Choose a psionic power to add.", "Psionics") as null|anything in available_psionics + if(new_power) + var/singleton/psionic_power/P = GET_SINGLETON(psionic_map[new_power]) + if(istype(P)) + pref.psionics += "[P.type]" + return TOPIC_REFRESH + diff --git a/code/modules/client/preferences.dm b/code/modules/client/preferences.dm index dcfcaa18d2b..dbab18a4023 100644 --- a/code/modules/client/preferences.dm +++ b/code/modules/client/preferences.dm @@ -99,6 +99,8 @@ var/list/preferences_datums = list() var/culture var/origin + var/list/psionics = list() + var/list/char_render_holders //Should only be a key-value list of north/south/east/west = obj/screen. var/static/list/preview_screen_locs = list( "1" = "character_preview_map:1,5:-12", diff --git a/code/modules/mob/living/carbon/human/species/species.dm b/code/modules/mob/living/carbon/human/species/species.dm index e5337a801f2..559072f36dc 100644 --- a/code/modules/mob/living/carbon/human/species/species.dm +++ b/code/modules/mob/living/carbon/human/species/species.dm @@ -295,6 +295,9 @@ var/use_alt_hair_layer = FALSE + /// Number of psi points in character creation. + var/character_creation_psi_points = 0 + /datum/species/proc/get_eyes(var/mob/living/carbon/human/H) return @@ -470,6 +473,8 @@ if(!H.client || !H.client.prefs || !H.client.prefs.gender) H.gender = pick(default_genders) H.pronouns = H.gender + if(spawn_flags & HAS_PSIONICS) + H.set_psi_rank(PSI_RANK_SENSITIVE) /datum/species/proc/handle_death(var/mob/living/carbon/human/H, var/gibbed = 0) //Handles any species-specific death events (such as dionaea nymph spawns). return diff --git a/code/modules/mob/living/carbon/human/species/station/skrell/skrell.dm b/code/modules/mob/living/carbon/human/species/station/skrell/skrell.dm index 5317a1eec68..080c9064398 100644 --- a/code/modules/mob/living/carbon/human/species/station/skrell/skrell.dm +++ b/code/modules/mob/living/carbon/human/species/station/skrell/skrell.dm @@ -38,7 +38,7 @@ grab_mod = 2 resist_mod = 0.5 // LIKE BABBY - spawn_flags = CAN_JOIN | IS_WHITELISTED + spawn_flags = CAN_JOIN | IS_WHITELISTED | HAS_PSIONICS appearance_flags = HAS_HAIR_COLOR | HAS_LIPS | HAS_UNDERWEAR | HAS_SKIN_COLOR | HAS_SOCKS flags = NO_SLIP @@ -107,6 +107,8 @@ alterable_internal_organs = list(BP_HEART, BP_EYES, BP_LUNGS, BP_LIVER, BP_KIDNEYS, BP_STOMACH) + character_creation_psi_points = 4 + /datum/species/skrell/handle_trail(var/mob/living/carbon/human/H, var/turf/T) var/list/trail_info = ..() if(!length(trail_info) && !H.shoes) @@ -117,10 +119,6 @@ return trail_info -/datum/species/skrell/handle_post_spawn(mob/living/carbon/human/H) - ..() - H.set_psi_rank(PSI_RANK_SENSITIVE) - /datum/species/skrell/handle_strip(var/mob/user, var/mob/living/carbon/human/H, var/action) switch(action) if("headtail") diff --git a/code/modules/projectiles/projectile/beams.dm b/code/modules/projectiles/projectile/beams.dm index fe219b3dbd1..cd9e02e9f93 100644 --- a/code/modules/projectiles/projectile/beams.dm +++ b/code/modules/projectiles/projectile/beams.dm @@ -469,15 +469,6 @@ if(isliving(target)) tesla_zap(target, 5, 5000) -/obj/item/projectile/beam/tesla/master - damage = 15 - -/obj/item/projectile/beam/tesla/grandmaster - damage = 20 - -/obj/item/projectile/beam/tesla/paramount - damage = 25 - /obj/item/projectile/beam/freezer name = "freezing ray" icon_state = "bluelaser" diff --git a/code/modules/psionics/abilities/emotional_suggestion.dm b/code/modules/psionics/abilities/emotional_suggestion.dm index 18f4380e738..557f55142ec 100644 --- a/code/modules/psionics/abilities/emotional_suggestion.dm +++ b/code/modules/psionics/abilities/emotional_suggestion.dm @@ -2,7 +2,7 @@ name = "Emotional Suggestion" desc = "Allows you to psionically commune with the target." icon_state = "tech_gambit" - ability_flags = PSI_FLAG_CANON + ability_flags = PSI_FLAG_EVENT|PSI_FLAG_CANON spell_path = /obj/item/spell/emotional_suggestion /obj/item/spell/emotional_suggestion diff --git a/code/modules/psionics/abilities/lightning.dm b/code/modules/psionics/abilities/lightning.dm index e69de29bb2d..d6b368402ef 100644 --- a/code/modules/psionics/abilities/lightning.dm +++ b/code/modules/psionics/abilities/lightning.dm @@ -0,0 +1,39 @@ +/singleton/psionic_power/lightning + name = "Lightning" + desc = "Fire a concentrated lightning bolt. Activate this spell in hand to switch to a second mode that hits living beings in a 4x3 area in front of you." + icon_state = "tech_instabilitytapold" + point_cost = 0 + ability_flags = PSI_FLAG_APEX + spell_path = /obj/item/spell/projectile/psi_lightning + +/obj/item/spell/projectile/psi_lightning + name = "lightning" + icon_state = "chain_lightning" + cast_methods = CAST_RANGED|CAST_USE + aspect = ASPECT_PSIONIC + spell_projectile = /obj/item/projectile/beam/psi_lightning + fire_sound = 'sound/magic/LightningShock.ogg' + cooldown = 10 + psi_cost = 15 + var/mode = 0 + +/obj/item/spell/projectile/psi_lightning/on_use_cast(mob/user, bypass_psi_check) + . = ..(user, TRUE) + mode = !mode + if(mode) + to_chat(user, SPAN_NOTICE("You will now fire area-of-effect lightning in a 4x3 area in front of you.")) + else + to_chat(user, SPAN_NOTICE("You will now fire a normal lightning bolt.")) + +/obj/item/projectile/beam/psi_lightning + name = "psionic lightning" + damage = 30 + armor_penetration = 30 + damage_type = DAMAGE_BURN + pass_flags = PASSTABLE | PASSGRILLE | PASSRAILING + range = 40 + accuracy = 100 + + muzzle_type = /obj/effect/projectile/muzzle/tesla + tracer_type = /obj/effect/projectile/tracer/tesla + impact_type = /obj/effect/projectile/impact/tesla diff --git a/code/modules/psionics/abilities/psi_recovery.dm b/code/modules/psionics/abilities/psi_recovery.dm index 2e3deeac4ff..d9f4af7d7a0 100644 --- a/code/modules/psionics/abilities/psi_recovery.dm +++ b/code/modules/psionics/abilities/psi_recovery.dm @@ -25,9 +25,13 @@ var/mob/living/L = user L.visible_message(SPAN_NOTICE("[user] puts [user.get_pronoun("his")] hands together and focuses..."), SPAN_NOTICE("You put your hands together and begin focusing on recovering your psionic energy...")) + psi_recovery(user) + +/obj/item/spell/psi_recovery/proc/psi_recovery(mob/user) + var/mob/living/L = user if(do_after(user, 0.5 SECONDS)) L.psi.stamina = min(L.psi.max_stamina, L.psi.stamina + rand(1,3)) if(L.psi.stamina >= L.psi.max_stamina) to_chat(user, SPAN_NOTICE("You've recovered all your psionic energy.")) return TRUE - on_use_cast(user) + psi_recovery(user) diff --git a/code/modules/psionics/abilities/psi_search.dm b/code/modules/psionics/abilities/psi_search.dm index b44d784d463..d78ade8b122 100644 --- a/code/modules/psionics/abilities/psi_search.dm +++ b/code/modules/psionics/abilities/psi_search.dm @@ -29,6 +29,8 @@ var/found_apex = FALSE for(var/mob/living/carbon/human/H in human_mob_list) if(GET_Z(H) == GET_Z(H) && H.can_commune()) + if(HAS_TRAIT(H, TRAIT_PSIONIC_SUPPRESSION)) + continue level_humans |= H if(H.psi) if(H.psi.get_rank() >= PSI_RANK_APEX) diff --git a/code/modules/psionics/abilities/psi_suppression.dm b/code/modules/psionics/abilities/psi_suppression.dm new file mode 100644 index 00000000000..24465221c4e --- /dev/null +++ b/code/modules/psionics/abilities/psi_suppression.dm @@ -0,0 +1,27 @@ +/singleton/psionic_power/psi_suppression + name = "Psionic Suppression" + desc = "Hold in one of your hands to make yourself invisible to Psi-Search." + icon_state = "const_mend" + point_cost = 1 + ability_flags = PSI_FLAG_ANTAG + spell_path = /obj/item/spell/psi_suppression + +/obj/item/spell/psi_suppression + name = "psionic suppression" + icon_state = "generic" + 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) diff --git a/code/modules/psionics/complexus/complexus.dm b/code/modules/psionics/complexus/complexus.dm index 0acd358108d..9acfe6b1427 100644 --- a/code/modules/psionics/complexus/complexus.dm +++ b/code/modules/psionics/complexus/complexus.dm @@ -1,7 +1,7 @@ /datum/psi_complexus var/announced = FALSE // Whether or not we have been announced to our holder yet. - var/suppressed = TRUE // Whether or not we are suppressing our psi powers. + var/suppressed = FALSE // Whether or not we are suppressing our psi powers. var/use_psi_armor = TRUE // Whether or not we should automatically deflect/block incoming damage. var/cost_modifier = 1 // Multiplier for power use stamina costs. diff --git a/code/modules/psionics/complexus/complexus_process.dm b/code/modules/psionics/complexus/complexus_process.dm index a3ea6552414..32d37e93b99 100644 --- a/code/modules/psionics/complexus/complexus_process.dm +++ b/code/modules/psionics/complexus/complexus_process.dm @@ -78,6 +78,7 @@ update_hud = TRUE else to_chat(owner, SPAN_NOTICE("You have recovered your mental composure.")) + suppressed = FALSE update_hud = TRUE return diff --git a/code/modules/psionics/interface/ui_hub.dm b/code/modules/psionics/interface/ui_hub.dm index 7d2fd8a7550..6d200703d49 100644 --- a/code/modules/psionics/interface/ui_hub.dm +++ b/code/modules/psionics/interface/ui_hub.dm @@ -1,6 +1,6 @@ /obj/screen/psi/hub name = "Psi" - icon_state = "psi_suppressed" + icon_state = "psi_active" screen_loc = "EAST-1:28,CENTER-3:11" hidden = FALSE maptext_x = 6 @@ -13,7 +13,6 @@ START_PROCESSING(SSprocessing, src) /obj/screen/psi/hub/update_icon() - if(!owner.psi) return @@ -30,7 +29,7 @@ return if(!owner.psi) return - maptext = "[round((owner.psi.stamina/owner.psi.max_stamina)*100)]%" + maptext = SMALL_FONTS(7, "[round((owner.psi.stamina/owner.psi.max_stamina)*100)]%") update_icon() /obj/screen/psi/hub/Click(var/location, var/control, var/params) @@ -38,18 +37,6 @@ if(click_params["shift"]) ui_interact(owner) return - - if(owner.psi.suppressed && owner.psi.stun) - to_chat(owner, "You are dazed and reeling, and cannot muster enough focus to do that!") - return - - owner.psi.suppressed = !owner.psi.suppressed - to_chat(owner, "You are [owner.psi.suppressed ? "now suppressing" : "no longer suppressing"] your psi-power.") - if(owner.psi.suppressed) - owner.psi.hide_auras() - else - sound_to(owner, sound('sound/effects/psi/power_unlock.ogg')) - owner.psi.show_auras() update_icon() /obj/screen/psi/hub/ui_interact(mob/user, datum/tgui/ui)