Skip to content

Усиление зомби - #401

Open
JustGiveMeALaserSword4 wants to merge 6 commits into
MetalSage:masterfrom
JustGiveMeALaserSword4:Zombie-buff_Just
Open

Усиление зомби#401
JustGiveMeALaserSword4 wants to merge 6 commits into
MetalSage:masterfrom
JustGiveMeALaserSword4:Zombie-buff_Just

Conversation

@JustGiveMeALaserSword4

@JustGiveMeALaserSword4 JustGiveMeALaserSword4 commented Jun 13, 2026

Copy link
Copy Markdown
Contributor

О PR

Данный ПР усиливает зомби, добавляя им три новые способности:
Чутьё - позволяет узнать есть ли не зомби в радиусе 15-ти тайлов
Рывок - рывок на два тайла в направлении взгляда
Спячка - усыпление на минуту с усилением регенерации

Так же был добавлен видимый эффект от насильного усыпления

Почему / Баланс

Реализация предложки https://discord.com/channels/1111698541841240164/1506183558899957851
Зомби - достаточно слабый антагонист (пару цитат из дискорда)

"страж в соло может толпу захреначить своими способками"
"без саботажа химки зомби автоматически проигрывают"

Новые способности должны сделать зомби более опасным врагом

Технические детали

Предисловие: я не силён в C#, поэтому написанный мною код может показаться вам странным/костыльным, и если вы так считаете - прошу указать это мне. Все имеют право учиться, ведь так?

        // Stories-Start
        if (HasComp<CanHostGuardianComponent>(target) && TryComp(target, out ActionsComponent? actionsComp)) // CanHostGuardianComponent is present on MobMonkey, MobKobold, STMobShadowling and BaseSpeciesMob (playable races)
        {
            if (!HasComp<JumpAbilityComponent>(target))
            {
                var jumpComp = AddComp<JumpAbilityComponent>(target);
                jumpComp.Action = ZombieGravityJumpAction;
                _actions.RemoveAction(target, jumpComp.ActionEntity);
                jumpComp.ActionEntity = _actions.AddAction(target, jumpComp.Action);
                jumpComp.CanCollide = true;
                jumpComp.JumpDistance = 2;
                Dirty(target, jumpComp);
            }
            _actions.AddAction(target, ZombieLookUpAction);
            _actions.AddAction(target, ZombieRegenerativeSleepAction);
        }
        // Stories-End

Код проверяет наличие у цели CanHostGuardianComponent и ActionsComponent. Первым обозначаются сущности которые могут иметь эти способности, было бы странно если бы мышь могла прыгать на два тайла, второй компонент же отвечает за возможность хранить и использовать какие либо способности в принципе, не думаю что без проверки на его наличие что-нибудь сломалось бы, но я видел как другая система делала так же
При удовлетворении первых двух условий, добавляются способности ZombieLookUpAction и ZombieRegenerativeSleepAction - "Чутьё" и "Спячка" соответственно. Дальше идет проверка на наличие JumpAbilityComponent - отсеиваивание вульп, которые и без того могут прыгать, даже лучше. В случае отсутствия компонента - он добавляется с указанными сразу ниже значениями.
Отдельно хочу выделить взаимодействие с полем ActionEntity, при добавлении компонента JumpAbilityComponent, сразу же добавляется указанная в его поле Action способность и привязывается к полю ActionEntity. Я долго пытался изменить поле Action до добавления способности, но ничего не вышло, поэтому код удаляет способность указанную в поле ActionEntity, после чего добавляет и привязывает к нему новую способность из изменённого поля Action.

        // Stories-Start
        private void OnLookUp(EntityUid uid, ZombieComponent component, ZombieLookUpActionEvent args)
        {
            var allMobs  = _lookup.GetEntitiesInRange<MobThresholdsComponent>(_transform.GetMapCoordinates(uid), args.Range);
            int mobsCount = allMobs.Count;

            var allZombieMobs  = _lookup.GetEntitiesInRange<ZombieComponent>(_transform.GetMapCoordinates(uid), args.Range);
            int zombieMobsCount = allZombieMobs.Count;
    
            int notZombieMobsCount = mobsCount - zombieMobsCount;

            if (notZombieMobsCount == 0)
                _popup.PopupEntity(Loc.GetString("stories-no-not-zombie-mobs"), uid, uid);
            else if (notZombieMobsCount == 1)
                _popup.PopupEntity(Loc.GetString("stories-one-not-zombie-mob"), uid, uid);
            else if (notZombieMobsCount >= 2 && notZombieMobsCount <= 5)
                _popup.PopupEntity(Loc.GetString("stories-some-not-zombie-mobs"), uid, uid);
            else if (notZombieMobsCount >= 6)
                _popup.PopupEntity(Loc.GetString("stories-many-not-zombie-mobs"), uid, uid);
            else
                _popup.PopupEntity(Loc.GetString("stories-invalid-count-not-zombie-mobs"), uid, uid);

            args.Handled = true;
        }

Код получает количество сущностей имеющих компонент MobThresholdsComponent (здесь это маркер всех сущностей, являющихся мобами), после чего получает количество сущностей имеющих уже компонент ZombieComponent (маркер зомбифицированных мобов), и вычитывает из первого второе, фактически получая количество всех ещё не зомбифицированных мобов. Затем, в зависимости количества не зомбифицированных мобов, выводит одно из попуп сообщений. На всякий случай указан вариант, когда переменная будет равна не предусмотренному значению, например, будет отрицательна, что бы игроку не казалось будто способность сломалась

        private void OnSleep(EntityUid uid, ZombieComponent component, ZombieRegenerativeSleepEvent args)
        {
            TryComp<PassiveDamageComponent>(uid, out var oldComp);
            var oldHeal = oldComp?.Damage;

            EnsureComp<PassiveDamageComponent>(uid).Damage = new()
            {
                DamageDict = args.PassiveHeal,
            };

            _statusEffects.TrySetStatusEffectDuration(uid, ForcedSleepingStatusEffect, args.Duration);

            Timer.Spawn(args.Duration, () =>
            {
                if (Exists(uid))
                {
                    if (oldHeal != null)
                        EnsureComp<PassiveDamageComponent>(uid).Damage = oldHeal;
                    else
                        RemComp<PassiveDamageComponent>(uid);
                }
            });

            args.Handled = true;
        }
        // TODO: переделать ZombieRegenerativeSleepEvent в обобщённой форме и вынести от сюда, использовать можно для регенеративного транса стража клинка
        // Stories-End

Код получает значение поля Damage из текущего компонента PassiveDamageComponent применившей способность сущности и записывает его в переменную oldHeal. После чего код изменяет значение этого поля на значение, указанное в поле PassiveHeal в ZombieRegenerativeSleepEvent и добавляет эффект ForcedSleepingStatusEffect на время, указанное в поле Duration в том же ивенте. Через время, указанное в поле Duration (то есть фактически по истечению времени действия эффекта ForcedSleepingStatusEffect), проверяет не равен ли oldHeal null - компонент PassiveDamageComponent отсутствовал у сущности, и если это так, то убирает у сущности добавленный ранее компонент, в противном случае (если oldHeal не равен null) - задает значение его поля Damage переменной oldHeal, в которую он ранее записывал изначальное значение поля Damage

Добавлены все соответствующие прототипы способностей, текстуры для них и локализация

Медиа

  • Я добавил к этому PR скриншоты/видео, демонстрирующие его изменения в игре, или этот PR не требует демонстрации в игре
Screenshot_447 Screenshot_448 Screenshot_449 Screenshot_450 Screenshot_451

Эффект усыпления:
Screenshot_452
Screenshot_453

Changelog
@JustGiveMeALaserSword4

  • add: Новые способности для зомби: Чутьё - позволяет узнать есть ли не зомби в радиусе 15-ти тайлов; Рывок - рывок на два тайла в направлении взгляда; Спячка - усыпление на минуту с усилением регенерации
  • tweak: Теперь эффект принудительного сна отображается в правой части экрана

Данный коммит усиливает зомби, добавляя им три новые способности:
Чутьё - позволяет узнать есть ли не зомби в радиусе 15-ти тайлов
Рывок - рывок на два тайла в направлении взгляда
Спячка - усыпление на минуту с усилением регенерации

Так же был добавлен видимый эффект от насильного усыпления
Теперь система добавления новых способностей зомби проверяет наличие CanHostGuardianComponent и ActionsComponent, исправлен баг при котором не добавлялась способность ZombieGravityJumpAction
@github-actions github-actions Bot added size/M S: Needs Review Ожидайте рассмотрения своего PR. S: Untriaged Changes: Sprites and removed S: Untriaged labels Jun 13, 2026
@github-actions

github-actions Bot commented Jun 13, 2026

Copy link
Copy Markdown
Contributor

RSI Diff Bot; head commit c87a98e merging into a2574fb
This PR makes changes to 1 or more RSIs. Here is a summary of all changes:

Resources/Textures/_Stories/Actions/zombie.rsi

State Old New Status
jump Added
scent Added
sleep Added

Edit: diff updated after c87a98e

@github-actions

Copy link
Copy Markdown
Contributor

This pull request has conflicts, please resolve those before we can evaluate the pull request.

@github-actions github-actions Bot added the S: Merge Conflict Исправьте конфликты слияния в своём PR. label Jun 14, 2026
# Conflicts:
#	Content.Server/Zombies/ZombieSystem.cs
@github-actions github-actions Bot removed the S: Merge Conflict Исправьте конфликты слияния в своём PR. label Jun 14, 2026

@MetalSage MetalSage left a comment

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

Комментарии принадлежности кода к даунстриму сториса написаны плохо, в коде есть лишние комментарии, незаконченные TODO, которые никогда видимо не будут закончены.


_statusEffects.TrySetStatusEffectDuration(uid, ForcedSleepingStatusEffect, args.Duration);

Timer.Spawn(args.Duration, () =>

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

Лучше использовать статус эффекты, ибо может быть много багов.

}

// Stories-ZombieAbilities Start
private void OnLookUp(EntityUid uid, ZombieComponent component, ZombieLookUpActionEvent args)

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

Плохие, тяжёлые проверки.

_tag.AddTag(target, CannotSuicideTag);

// Stories-ZombieAbilities Start
if (HasComp<CanHostGuardianComponent>(target) && TryComp(target, out ActionsComponent? actionsComp)) // CanHostGuardianComponent is present on MobMonkey, MobKobold, STMobShadowling and BaseSpeciesMob (playable races)

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

Очень странная проверка на странный компонент.

/// The basic action prototype is "ActionGravityJump".
/// </summary>
[RegisterComponent, NetworkedComponent, AutoGenerateComponentState, Access(typeof(SharedJumpAbilitySystem))]
[RegisterComponent, NetworkedComponent, AutoGenerateComponentState] // Removed "Access(typeof(SharedJumpAbilitySystem))" - Stories-ZombieAbilities

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

Редактировать компоненты в несвязных с ним напрямую системах является плохим тоном, используй методы системы JumpAbilitySystem.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Changes: Sprites S: Needs Review Ожидайте рассмотрения своего PR. size/M

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants