Skip to content

Commit

Permalink
[UPDATE Xeno and litle FIX] (#912)
Browse files Browse the repository at this point in the history
## Описание PR
 Обновление Ксеноморфов и мелкий фикс священника.

## Техническая  информация
Если прочитать код, то вроде все понятно.
В компоненте XenoQueen (Серверный) можно изменять некоторые параметры и
отключать то или иное.
~~Очки королевы не показываются и только в компоненте можно посмотреть
их количество.~~
Очки королевы показываются как иконка ниндзя костюма. (Типа цистерна
крови. Не обязуйте). Максимум 140. Каждая полоска = 20 очкам.
Причиной этого является отсутствие спрайтов и идей другой кастомизации.
Из плюсов можно выделить то, что недостающие очки пишутся при попытке
вызвать кого либо.

## Медиа

![image](https://github.com/user-attachments/assets/4e363d2b-c443-4769-8c8a-cd0fd65eb117)

## Требования
- [x] Я прочитал(а) и следую [Руководство по созданию пулл
реквестов](https://docs.spacestation14.com/en/general-development/codebase-info/pull-request-guidelines.html).
Я понимаю, что в противном случае мой ПР может быть закрыт по усмотрению
мейнтейнера.
- [x] Я добавил скриншоты/видео к этому пулл реквесту, демонстрирующие
его изменения в игре, **или** этот пулл реквест не требует демонстрации
в игре

**Чейнджлог**
:cl: NameLunar, при поддержке FaDeOkbo
- add: Ксеноморфы вновь эволюционируют! Их чешуйчатая броня крепка как
сталь, но очень уязвима к теплу.
- fix: Потерянный священник вновь верует в богов!
- tweak: Теперь Королеве ксеноморфов требуются очки для спавна других
ксенов. (Не получится призвать 999 мобов сразу😢)
- tweak: Штурмовой борг синдиката стал настоящим смертоносным оружием,
как и цена на него.

---------

Co-authored-by: Schrödinger <[email protected]>
  • Loading branch information
NameLunar and Schrodinger71 authored Jan 9, 2025
1 parent 00f3f68 commit 5ead783
Show file tree
Hide file tree
Showing 24 changed files with 538 additions and 138 deletions.
29 changes: 0 additions & 29 deletions Content.Server/ADT/Abilities/XenoQeen/XenoQeenComponent.cs

This file was deleted.

66 changes: 0 additions & 66 deletions Content.Server/ADT/Abilities/XenoQeen/XenoQeenSystem.cs

This file was deleted.

54 changes: 54 additions & 0 deletions Content.Server/ADT/Abilities/XenoQueen/XenoQueenComponent.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
using Content.Shared.FixedPoint;
using Robust.Shared.Prototypes;
using Content.Shared.Alert;
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype;

namespace Content.Server.ADT.Abilities.XenoQueen
{
/// <summary>
/// Lets its owner entity use mime powers, like placing invisible walls.
/// </summary>
[RegisterComponent]
public sealed partial class XenoQueenComponent : Component
{
[DataField]
public bool XenoCreatTurretEnabled = true;

//
[DataField]
public string XenoTurret = "WeaponTurretXeno";
public string? XenoTurretAction = "ActionXenoQueenTurret";

// Призывы
public EntityUid? XenoTurretActionEntity;
public EntityUid? ActionSpawnXenoBurrower;
public EntityUid? ActionSpawnXenoDrone;
public EntityUid? ActionSpawnXenoRunner;
public EntityUid? ActionSpawnXenoSpitter;
public EntityUid? ActionSpawnXenoPraetorian;
public EntityUid? ActionSpawnXenoRavager;
public EntityUid? ActionSpawnXenoQueen;

// Регенрация очков
[DataField]
public bool Regenetarion = true; // Можно ли регенерировать очки.

[DataField]
public float RegenDelay = 60f; // Секунды до регена. Используется в счетчике

[ViewVariables]
public float Accumulator = 0f; // Сам счетчик 0.000000

[DataField]
public FixedPoint2 BloobCount = 20; // Очки. Начальные очки равны 20

[DataField]
public FixedPoint2 MaxBloobCount = 140; // Максимальыне количество очков

[DataField]
public int RegenBloobCount = 5; // Реген очков в минуту

// Иконка
public ProtoId<AlertPrototype> Alert = "XenoQueenBloobCount";
}
}
167 changes: 167 additions & 0 deletions Content.Server/ADT/Abilities/XenoQueen/XenoQueenSystem.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,167 @@
using Content.Server.Popups;
using Content.Shared.Actions;
using Content.Shared.Actions.Events;
using Content.Shared.Maps;
using Content.Shared.Coordinates.Helpers;
using Content.Shared.Magic.Events;
using Content.Shared.Physics;
using Robust.Shared.Containers;
using Robust.Shared.Prototypes;
using Robust.Shared.Map;
using Content.Shared.ADT.Events;
using Content.Shared.Alert;
using Content.Shared.Magic;
using Content.Shared.FixedPoint;

namespace Content.Server.ADT.Abilities.XenoQueen
{
public sealed class XenoQueenSystem : EntitySystem
{
[Dependency] private readonly PopupSystem _popupSystem = default!;
[Dependency] private readonly SharedActionsSystem _actionsSystem = default!;
[Dependency] private readonly IPrototypeManager _proto = default!;
[Dependency] private readonly TurfSystem _turf = default!;
[Dependency] private readonly IMapManager _mapMan = default!;
[Dependency] private readonly AlertsSystem _alerts = default!;
[Dependency] private readonly SharedContainerSystem _container = default!;

public override void Initialize()
{
base.Initialize();
SubscribeLocalEvent<XenoQueenComponent, MapInitEvent>(OnMapInit);
SubscribeLocalEvent<XenoQueenComponent, ComponentStartup>(OnStartup);
SubscribeLocalEvent<XenoQueenComponent, ComponentShutdown>(OnShutdown);
SubscribeLocalEvent<XenoQueenComponent, EmptyXenoActionEvent>(OnCreateTurret);
SubscribeLocalEvent<XenoQueenComponent, SpawnXenoQueenEvent>(OnWorldSpawn);
}

public override void Update(float frameTime)
{
base.Update(frameTime);

var query = EntityQueryEnumerator<XenoQueenComponent>();
while (query.MoveNext(out var uid, out var component) && component.Regenetarion) // Костыль, но супер рабочий)
{
if (component.BloobCount >= component.MaxBloobCount)
{
component.Accumulator = 0f;
continue;
}

component.Accumulator += frameTime; // 0.000001

if (component.Accumulator <= component.RegenDelay)
continue;

component.Accumulator -= component.RegenDelay; // component.Accumulator = 0f;
if (component.BloobCount < component.MaxBloobCount)
{
ChangePowerAmount(uid, component.RegenBloobCount, component);
}
}
}
private void OnStartup(EntityUid uid, XenoQueenComponent component, ComponentStartup args)
{
//update the icon
UpdateAlertShow(uid, component);
}
public void ChangePowerAmount(EntityUid uid, FixedPoint2 amount, XenoQueenComponent? component = null)
{
if (!Resolve(uid, ref component))
return;

if (component.BloobCount + amount < 0)
return;

component.BloobCount += amount;
UpdateAlertShow(uid, component);
}
private void OnMapInit(EntityUid uid, XenoQueenComponent component, MapInitEvent args)
{
_actionsSystem.AddAction(uid, ref component.XenoTurretActionEntity, component.XenoTurretAction, uid);
_actionsSystem.AddAction(uid, ref component.ActionSpawnXenoBurrower, "ActionSpawnMobXenoBurrower");
_actionsSystem.AddAction(uid, ref component.ActionSpawnXenoDrone, "ActionSpawnMobXenoDrone");
_actionsSystem.AddAction(uid, ref component.ActionSpawnXenoRunner, "ActionSpawnMobXenoRunner");
_actionsSystem.AddAction(uid, ref component.ActionSpawnXenoSpitter, "ActionSpawnMobXenoSpitter");
_actionsSystem.AddAction(uid, ref component.ActionSpawnXenoPraetorian, "ActionSpawnMobXenoPraetorian");
_actionsSystem.AddAction(uid, ref component.ActionSpawnXenoRavager, "ActionSpawnMobXenoRavager");
_actionsSystem.AddAction(uid, ref component.ActionSpawnXenoQueen, "ActionSpawnMobXenoQueen");
}
private void OnShutdown(EntityUid uid, XenoQueenComponent component, ComponentShutdown args)
{
_actionsSystem.RemoveAction(uid, component.XenoTurretActionEntity);
_actionsSystem.RemoveAction(uid, component.ActionSpawnXenoBurrower);
_actionsSystem.RemoveAction(uid, component.ActionSpawnXenoDrone);
_actionsSystem.RemoveAction(uid, component.ActionSpawnXenoRunner);
_actionsSystem.RemoveAction(uid, component.ActionSpawnXenoSpitter);
_actionsSystem.RemoveAction(uid, component.ActionSpawnXenoPraetorian);
_actionsSystem.RemoveAction(uid, component.ActionSpawnXenoRavager);
_actionsSystem.RemoveAction(uid, component.ActionSpawnXenoQueen);
}
private void OnCreateTurret(EntityUid uid, XenoQueenComponent component, EmptyXenoActionEvent args)
{
if (!component.XenoCreatTurretEnabled)
return;

if (_container.IsEntityOrParentInContainer(uid))
return;
if (component.BloobCount >= args.Cost)
{
component.BloobCount -= args.Cost.Value;
var xform = Transform(uid);
// Get the tile in front of the Queen
var offsetValue = xform.LocalRotation.ToWorldVec();
var coords = xform.Coordinates.Offset(offsetValue).SnapToGrid(EntityManager, _mapMan);
var tile = coords.GetTileRef(EntityManager, _mapMan);
if (tile == null)
return;

// Check if the tile is blocked by a wall or mob, and don't create the wall if so
if (_turf.IsTileBlocked(tile.Value, CollisionGroup.Impassable | CollisionGroup.Opaque))
{
_popupSystem.PopupEntity(Loc.GetString("create-turret-failed"), uid, uid);
return;
}

_popupSystem.PopupEntity(Loc.GetString("create-turret"), uid);
// Make sure we set the xeno turret to despawn properly
Spawn(component.XenoTurret, _turf.GetTileCenter(tile.Value));
// Handle args so cooldown works
args.Handled = true;
}
else
{
_popupSystem.PopupEntity(Loc.GetString("queen-no-bloob-count", ("CountBloob", args.Cost.GetValueOrDefault() - component.BloobCount)), uid); // Заменю в будущем
}
UpdateAlertShow(uid, component);
}
// Spawn Tipo
private void OnWorldSpawn(EntityUid uid, XenoQueenComponent component, SpawnXenoQueenEvent args) // SpawnXenoQueenEvent
{
if (component.BloobCount > args.Cost)
{
component.BloobCount -= args.Cost.Value;
Spawn(args.Prototypes[0].PrototypeId, Transform(uid).Coordinates);
Speak(args);
args.Handled = true;
}
else
{
_popupSystem.PopupEntity(Loc.GetString("queen-no-bloob-count", ("CountBloob", args.Cost.GetValueOrDefault() - component.BloobCount)), uid);
}
UpdateAlertShow(uid, component);
}
private void Speak(BaseActionEvent args)
{
if (args is not ISpeakSpell speak || string.IsNullOrWhiteSpace(speak.Speech))
return;

var ev = new SpeakSpellEvent(args.Performer, speak.Speech);
RaiseLocalEvent(ref ev);
}
private void UpdateAlertShow(EntityUid uid, XenoQueenComponent component)
{
_alerts.ShowAlert(uid, _proto.Index(component.Alert), (short)Math.Clamp(Math.Round(component.BloobCount.Float() / 20), 0, 7)); // Почему ": 20" ? Все просто. 140 / 20 = 7.... Ну и все.
}
}
}
10 changes: 10 additions & 0 deletions Content.Shared/ADT/Actions/EmptyXenoActionEvent.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
using Content.Shared.Actions;

namespace Content.Shared.ADT.Events;

[DataDefinition]
public sealed partial class EmptyXenoActionEvent : InstantActionEvent
{
[DataField]
public int? Cost { get; private set; }
}
18 changes: 18 additions & 0 deletions Content.Shared/ADT/Actions/SpawnXenoQueenEvent.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
using Content.Shared.Actions;
using Content.Shared.Storage;

namespace Content.Shared.ADT.Events;

// TODO: This class needs combining with InstantSpawnSpellEvent
[DataDefinition]
public sealed partial class SpawnXenoQueenEvent : WorldTargetActionEvent
{
[DataField]
public List<EntitySpawnEntry> Prototypes = new();

[DataField]
public string? Speech { get; private set; }

[DataField]
public int? Cost { get; private set; }
}
16 changes: 0 additions & 16 deletions Resources/Locale/ru-RU/ADT/prototypes/Actions/XenoQeen.ftl

This file was deleted.

21 changes: 21 additions & 0 deletions Resources/Locale/ru-RU/ADT/prototypes/Actions/XenoQueen.ftl
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
ent-ActionXenoQueenTurret = Создать ксено турель. [color=green]25[/color]
.desc = Создаёт перед вами ксену турель, если хватает места.
create-turret-failed = Найдите другое место.
create-turret = Арргхсс. Шшшшш!
ent-ActionSpawnMobXenoSpitter = Призвать Плевальщик [color=green]20[/color]
.desc = Родите Плевальщика, который будет плеваться!
ent-ActionSpawnMobXenoPraetorian = Призвать Преторианеца [color=green]50[/color]
.desc = Родите Преторианеца, который будет сражаться за вас!
ent-ActionSpawnMobXenoDrone = Просто Дрон [color=green]30[/color]. Кому он нужен?
.desc = Родите рабочего, Дрон.
ent-ActionSpawnMobXenoRavager = Призвать Разрушителя [color=green]80[/color]
.desc = Родите [color=red]смерть[/color] во плоти!
ent-ActionSpawnMobXenoRunner = Призвать Бегуна [color=green]40[/color]
.desc = Родите самую быструю личинку!
ent-ActionSpawnMobXenoBurrower = Призвать рабочего [color=green]10[/color]
.desc = Стандартный ксено.
ent-ActionSpawnMobXenoQueen = Призвать [color=violet]Королеву[/color] [color=green]100[/color]
.desc = [color=red]Новое потомство! Новое поколение! Эволюция![/color]
queen-no-bloob-count = Недостаточно {$CountBloob} очков.
alerts-xeno-queen-bloob-count-name = [color=green]Bloob Canister[/color]
alerts-xeno-queen-bloob-count-desc = Кто то скажет, что это батарея, а я отвечу - канистра крови.
Loading

0 comments on commit 5ead783

Please sign in to comment.