Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Псионика!!! #5195

Open
wants to merge 22 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 14 commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
d12b4ff
Basic
Microvolnovka19 Nov 24, 2024
d406401
Почти доделано(?)
Microvolnovka19 Nov 24, 2024
0adfc9c
Merge branch 'Fluffy-Frontier:master' into psyonics
Microvolnovka19 Nov 24, 2024
aab3c50
Добавить мед описание
Microvolnovka19 Nov 24, 2024
3de6d01
Иконка
Microvolnovka19 Nov 24, 2024
e5f5035
Мелкие правки
Microvolnovka19 Nov 25, 2024
138c440
Поменять название чтобы тест не ругался
Microvolnovka19 Nov 25, 2024
a209a46
Поднять повторяющиеся проки выше на уровень
Microvolnovka19 Dec 7, 2024
afbd361
Merge branch 'master' into psyonics
Microvolnovka19 Dec 7, 2024
ec9c4b6
Update tgstation.dme
Microvolnovka19 Dec 7, 2024
7c6ac64
Update tgstation.dme
Microvolnovka19 Dec 7, 2024
d2c9ec5
Японский истребитель...
Microvolnovka19 Dec 7, 2024
d62d142
Шапочка из фольги теперь защищает от школы внушения
Microvolnovka19 Dec 7, 2024
d318c01
Новый спелл
Microvolnovka19 Dec 7, 2024
caf8866
Merge branch 'master' into pr/5195
Iajret Dec 12, 2024
1d0f4d2
Patch №1
Microvolnovka19 Dec 13, 2024
6acc14b
Merge branch 'psyonics' of https://github.com/Microvolnovka19/FluffyS…
Microvolnovka19 Dec 13, 2024
047302a
Patch №2
Microvolnovka19 Dec 16, 2024
3924da0
Merge branch 'master' into pr/5195
Iajret Dec 19, 2024
7e82900
Update redaction.dm
Iajret Dec 19, 2024
55738eb
Лицензии
Microvolnovka19 Dec 22, 2024
6296ee4
fix
Microvolnovka19 Dec 22, 2024
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
193 changes: 193 additions & 0 deletions tff_modular/modules/psyonics/code/_psyonics.dm
Original file line number Diff line number Diff line change
@@ -0,0 +1,193 @@
// Тут хранятся некрасивые базовые классы и прочее. Не смотрите сюда.

/datum/action/cooldown/spell
// Сколько маны стоит кастануть спелл
var/mana_cost = 10
// Некоторые спеллы могут отнимать стамину
var/stamina_cost = 0
// Что написать жертве
var/target_msg
// Сила способности
var/cast_power = 0
// Вторичная школа. Может дать особые эффекты при комбинациях
var/secondary_school = 0

// Спеллы для призвания предмета
/datum/action/cooldown/spell/conjure_item/psyonic
delete_old = FALSE
delete_on_failure = TRUE
requires_hands = TRUE
// Псионические способности (в основном) не блокируются, но выводят особенные сообщения тем, кто это может
antimagic_flags = MAGIC_RESISTANCE_MIND
spell_requirements = NONE
cooldown_reduction_per_rank = 0 SECONDS

/datum/action/cooldown/spell/conjure_item/psyonic/New(Target, power, additional_school)
. = ..()
cast_power = power
secondary_school = additional_school

// Проверяем достаточно ли маны
/datum/action/cooldown/spell/proc/check_for_mana()
var/mob/living/carbon/human/caster = owner
var/datum/quirk/psyonic/quirk_holder = caster.get_quirk(/datum/quirk/psyonic)
if(quirk_holder && (quirk_holder.mana_level - mana_cost) >= 0)
Microvolnovka19 marked this conversation as resolved.
Show resolved Hide resolved
return TRUE
else
return FALSE

// Сосём ману у псионика
/datum/action/cooldown/spell/proc/drain_mana(forced = FALSE)
var/mob/living/carbon/human/caster = owner
var/datum/quirk/psyonic/quirk_holder = caster.get_quirk(/datum/quirk/psyonic)
caster.adjustStaminaLoss(stamina_cost, forced = TRUE)
if(quirk_holder && (quirk_holder.mana_level - mana_cost) >= 0)
quirk_holder.mana_level -= mana_cost
return TRUE
else if (forced)
quirk_holder.mana_level = 0
return TRUE
else
return FALSE

/datum/action/cooldown/spell/conjure_item/psyonic/can_cast_spell(feedback)
. = ..()
if(!.)
return FALSE

if(!check_for_mana())
return FALSE
else
return TRUE

/datum/action/cooldown/spell/conjure_item/psyonic/cast(atom/cast_on)
drain_mana()
return ..()

// Для спеллов которые применяются на себя тыком кнопки a.k.a. выдача генов
/datum/action/cooldown/spell/psyonic
// Псионические способности (в основном) не блокируются, но выводят особенные сообщения тем, кто это может
antimagic_flags = MAGIC_RESISTANCE_MIND

school = SCHOOL_UNSET
invocation_type = INVOCATION_NONE
spell_requirements = NONE
cooldown_reduction_per_rank = 0 SECONDS

/datum/action/cooldown/spell/psyonic/New(Target, power, additional_school)
. = ..()
cast_power = power
secondary_school = additional_school

/datum/action/cooldown/spell/psyonic/can_cast_spell(feedback)
. = ..()
if(!.)
return FALSE

if(!check_for_mana())
return FALSE
else
return TRUE

// Спеллы для пострелушек
/datum/action/cooldown/spell/pointed/projectile/psyonic
// Псионические способности (в основном) не блокируются, но выводят особенные сообщения тем, кто это может
antimagic_flags = MAGIC_RESISTANCE_MIND

school = SCHOOL_UNSET
invocation_type = INVOCATION_NONE
spell_requirements = NONE
cooldown_reduction_per_rank = 0 SECONDS

/datum/action/cooldown/spell/pointed/projectile/psyonic/New(Target, power, additional_school)
. = ..()
cast_power = power
secondary_school = additional_school

/datum/action/cooldown/spell/pointed/projectile/psyonic/can_cast_spell(feedback)
. = ..()
if(!.)
return FALSE

if(!check_for_mana())
return FALSE
else
return TRUE

// Направленные спеллы a.k.a. псионик выбирают цель на дистанции
/datum/action/cooldown/spell/pointed/psyonic
// Псионические способности (в основном) не блокируются, но выводят особенные сообщения тем, кто это может
antimagic_flags = MAGIC_RESISTANCE_MIND
school = SCHOOL_UNSET
invocation_type = INVOCATION_NONE
spell_requirements = NONE
cooldown_reduction_per_rank = 0 SECONDS

/datum/action/cooldown/spell/pointed/psyonic/New(Target, power, additional_school)
. = ..()
cast_power = power
secondary_school = additional_school

/datum/action/cooldown/spell/pointed/psyonic/can_cast_spell(feedback)
. = ..()
if(!.)
return FALSE

if(!check_for_mana())
return FALSE
else
return TRUE

// Спеллы которыми надо каснуться чего либо
/datum/action/cooldown/spell/touch/psyonic
// Псионические способности (в основном) не блокируются, но выводят особенные сообщения тем, кто это может
antimagic_flags = MAGIC_RESISTANCE_MIND
school = SCHOOL_UNSET
invocation_type = INVOCATION_NONE
spell_requirements = NONE

/datum/action/cooldown/spell/touch/psyonic/New(Target, power, additional_school)
. = ..()
cast_power = power
secondary_school = additional_school

/datum/action/cooldown/spell/touch/psyonic/can_cast_spell(feedback)
. = ..()
if(!.)
return FALSE

if(!check_for_mana())
return FALSE
else
return TRUE

/datum/action/cooldown/spell/touch/psyonic/create_hand(mob/living/carbon/cast_on)
. = ..()
if(!.)
return .
var/obj/item/bodypart/transfer_limb = cast_on.get_active_hand()
if(IS_ROBOTIC_LIMB(transfer_limb))
to_chat(cast_on, span_notice("You fail to channel your psyonic powers through your inorganic hand."))
return FALSE

return TRUE

/particles/droplets/psyonic
icon = 'icons/effects/particles/generic.dmi'
icon_state = list("dot"=2,"drop"=1)
width = 32
height = 36
count = 20
spawning = 0.2
lifespan = 1.5 SECONDS
fade = 0.5 SECONDS
color = "#00a2ff"
position = generator(GEN_BOX, list(-9,-9,0), list(9,18,0), NORMAL_RAND)
scale = generator(GEN_VECTOR, list(0.9,0.9), list(1.1,1.1), NORMAL_RAND)
gravity = list(0, 0.95)

// Проверка на то, есть ли квирк псионики у хумана
/mob/living/carbon/human/proc/ispsyonic()
if(has_quirk(/datum/quirk/psyonic))
return TRUE
return FALSE
186 changes: 186 additions & 0 deletions tff_modular/modules/psyonics/code/_quirk.dm
Original file line number Diff line number Diff line change
@@ -0,0 +1,186 @@
#define TRAIT_PSYONIC_USER "psyonicuser"
#define TRAIT_NO_PSYONICS "no_psyonics"
#define TRAIT_PRO_PSYONICS "pro_psyonics"

#define LATENT_PSYONIC 0
#define OPERANT_PSYONIC 1
#define MASTER_PSYONIC 2
#define GRANDMASTER_PSYONIC 3
#define PARAMOUNT_PSYONIC 4

GLOBAL_LIST_INIT(psyonic_schools, list(
"Redaction",
"Coercion",
"Psychokinesis",
"Energistics",
))

/datum/quirk/psyonic
name = "Psyonic Abilities"
desc = "Either you were born like this or gained powers from implants/training or other events - you are a psyonic. \
Your mind can access the world that lies beyond our mortal plane. One day voices from within had pierced your skull \
like a tide wave turns a sailboat over in open sea, but you withstanded it and received abilities your father haven't \
even dreamed of. From now on a special type of energy is stored in your mind, body and soul and you have control over it. \
Every psyonic is a follower of a certain school: \
Redaction - school of mending and curing bodies and souls; \
Coercion - school of trickery and controlling others; \
Psychokinesis - school of object manipulation; \
Energistics - school of elecricity, fire and light; \
You can select the school, but it's power will be randomised every round."
value = 12 // Отдадите за псионику жопу, чтобы потом вам Рэнди Рандом всегда слал наименьший уровень силы
medical_record_text = "Patient possesses connection to an another plain of reality."
quirk_flags = QUIRK_HIDE_FROM_SCAN|QUIRK_HUMAN_ONLY|QUIRK_PROCESSES // Сканеры не видят псиоников. Только псионик школы принуждения может точно определить, является ли живое существо псиоником
gain_text = span_cyan("You mind feels uneasy, but... so powerful.")
lose_text = span_warning("You lost something, that kept your connection with other realms.")
icon = "fa-star"
mob_trait = TRAIT_PSYONIC_USER
veteran_only = TRUE
allow_for_donator = TRUE
// Текущий уровень маны
var/mana_level = 0
// Максимально возможный уровень маны
var/max_mana = 10
// Уровень псионических способностей
var/psyonic_level = 0
// Строка для описания уровня
var/psyonic_level_string = "Latent"
// Первичная школа псионики
var/school
// Вторичная школа псионики
var/secondary_school

/datum/quirk/psyonic/add(client/client_source)
school = client_source?.prefs?.read_preference(/datum/preference/choiced/psyonic_school)
if(!school)
school = pick(GLOB.psyonic_schools)
secondary_school = client_source?.prefs?.read_preference(/datum/preference/choiced/psyonic_school_secondary)
if(!secondary_school)
secondary_school = pick(GLOB.psyonic_schools)
var/fluff_1 = rand(0,1)
var/fluff_2 = rand(0,1)
var/fluff_3 = rand(0,1)
var/fluff_4 = rand(0,1)
psyonic_level = fluff_1 + fluff_2 + fluff_3 + fluff_4
switch(psyonic_level)
if(LATENT_PSYONIC)
psyonic_level_string = "Pi"
if(OPERANT_PSYONIC)
psyonic_level_string = "Omicron"
if(MASTER_PSYONIC)
psyonic_level_string = "Lambda"
if(GRANDMASTER_PSYONIC)
psyonic_level_string = "Theta"
if(PARAMOUNT_PSYONIC)
psyonic_level_string = "Epsilon"
max_mana = (psyonic_level + 1) * 20 // Минимальный - 20, максимальный - 100
RegisterSignal(quirk_holder, COMSIG_MOB_GET_STATUS_TAB_ITEMS, PROC_REF(get_status_tab_item))
var/mob/living/carbon/human/whom_to_give = quirk_holder
if(school == secondary_school)
psyonic_level += 1 // Если вторичка совпадает с первой - добавляем один уровень, но не меняем описание
switch(school)
if("Redaction")
whom_to_give.try_add_redaction_school(psyonic_level, secondary_school)
if("Coercion")
whom_to_give.try_add_coercion_school(psyonic_level, secondary_school)
if("Psychokinesis")
whom_to_give.try_add_psychokinesis_school(psyonic_level, secondary_school)
if("Energistics")
whom_to_give.try_add_energistics_school(psyonic_level, secondary_school)

if(secondary_school != school) // Если школы разные, добавить способность нулевого уровня вторичной школы
switch(secondary_school)
if("Redaction")
whom_to_give.try_add_redaction_school(0, 0)
if("Coercion")
whom_to_give.try_add_coercion_school(0, 0)
if("Psychokinesis")
whom_to_give.try_add_psychokinesis_school(0, 0)
if("Energistics")
whom_to_give.try_add_energistics_school(0, 0)

var/fluff_text = span_cyan("Current psionic factors:") + "<br>" + \
"[fluff_1 ? "Current star position is aligned to your soul." : "The stars do not precede luck to you."]" + "<br>" + \
"[fluff_2 ? "Other realms are unusually active this shift." : "Other realms are quiet today."]" + "<br>" + \
"[fluff_3 ? "Time-bluespace continuum seems to be stable today." : "Time-bluespace continuum is not giving you energy today."]" + "<br>" + \
"[fluff_4 ? "Your mind is clearly open to otherwordly energy." : "Something clouds your connection to otherworld energy."]"
to_chat(quirk_holder, examine_block(span_infoplain(jointext(fluff_text, "\n&bull; "))))
psyonic_level -= 1 // Обязаловка, иначе выдаст спеллы которые нельзя кастануть

/datum/quirk/psyonic/remove()
UnregisterSignal(quirk_holder, COMSIG_MOB_GET_STATUS_TAB_ITEMS)

// Показывает текущее кол-во псионической энергии
/datum/quirk/psyonic/proc/get_status_tab_item(mob/living/source, list/items)
SIGNAL_HANDLER

items += "Psyonic School: [school]"
items += "Secondary School: [secondary_school]"
items += "Psyonic Tier: [psyonic_level_string]"
items += "Current psyonic energy: [mana_level]/[max_mana]"

/datum/quirk/psyonic/process(seconds_per_tick)
if(HAS_TRAIT(quirk_holder, TRAIT_NO_PSYONICS)) // Имплант подавления регена
return

var/additional_mana = 1
if(quirk_holder.has_status_effect(/datum/status_effect/drugginess)) // Наркота даёт бафф к генерации маны
additional_mana *= 1.5

if(HAS_TRAIT(quirk_holder, TRAIT_PRO_PSYONICS)) // Если есть имплант для увеличения регена маны
additional_mana *= 2

if(mana_level <= max_mana)
mana_level += seconds_per_tick * 0.5 * additional_mana
mana_level = clamp(mana_level, 0, max_mana)

/datum/quirk_constant_data/psyonic_school
associated_typepath = /datum/quirk/psyonic
customization_options = list(/datum/preference/choiced/psyonic_school, /datum/preference/choiced/psyonic_school_secondary)

/datum/preference/choiced/psyonic_school
category = PREFERENCE_CATEGORY_MANUALLY_RENDERED
savefile_key = "psyonic_school"
savefile_identifier = PREFERENCE_CHARACTER

/datum/preference/choiced/psyonic_school/create_default_value()
return "Redaction"

/datum/preference/choiced/psyonic_school/init_possible_values()
return GLOB.psyonic_schools

/datum/preference/choiced/psyonic_school/is_accessible(datum/preferences/preferences)
. = ..()
if (!.)
return FALSE

return "Psyonic Abilities" in preferences.all_quirks

/datum/preference/choiced/psyonic_school/apply_to_human(mob/living/carbon/human/target, value)
return

/datum/preference/choiced/psyonic_school_secondary
category = PREFERENCE_CATEGORY_MANUALLY_RENDERED
savefile_key = "psyonic_school_secondary"
savefile_identifier = PREFERENCE_CHARACTER

/datum/preference/choiced/psyonic_school_secondary/create_default_value()
return "Redaction"

/datum/preference/choiced/psyonic_school_secondary/init_possible_values()
return GLOB.psyonic_schools

/datum/preference/choiced/psyonic_school_secondary/is_accessible(datum/preferences/preferences)
. = ..()
if (!.)
return FALSE

return "Psyonic Abilities" in preferences.all_quirks

/datum/preference/choiced/psyonic_school_secondary/apply_to_human(mob/living/carbon/human/target, value)
return

#undef LATENT_PSYONIC
#undef OPERANT_PSYONIC
#undef MASTER_PSYONIC
#undef GRANDMASTER_PSYONIC
#undef PARAMOUNT_PSYONIC
Loading
Loading