Фиксы некоторых моментов культа крови (#2503)

This commit is contained in:
iertis 2025-07-18 03:37:26 +05:00 committed by GitHub
parent 9b9cd5f0d5
commit d4148f3cea
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
18 changed files with 200 additions and 76 deletions

View file

@ -1,4 +1,5 @@
using Robust.Client.AutoGenerated;
using Content.Shared.Procedural.DungeonLayers;
using Robust.Client.AutoGenerated;
using Robust.Client.UserInterface.Controls;
using Robust.Client.UserInterface.CustomControls;
using Robust.Client.UserInterface.XAML;
@ -15,7 +16,7 @@ public partial class SummonCultistListWindow : DefaultWindow
RobustXamlLoader.Load(this);
}
public void PopulateList(List<int> items, List<string> labels)
public void PopulateList(List<int> items, List<string> labels, List<string> mobStates, List<string> distances)
{
ItemsContainer.RemoveAllChildren();
@ -26,7 +27,14 @@ public partial class SummonCultistListWindow : DefaultWindow
var item = items[i];
var button = new Button();
button.Text = labels[i];
var text = Loc.GetString(
"summon-button-label",
("label", labels[i]),
("mobState", mobStates[i]),
("distance", distances[i])
);
button.Text = text;
button.OnPressed += _ => ItemSelected?.Invoke(item, items.IndexOf(item));

View file

@ -1,4 +1,5 @@
using Content.Shared._Sunrise.BloodCult.UI;
using Robust.Client.UserInterface;
namespace Content.Client._Sunrise.BloodCult.UI.SummonCultistList;
@ -15,8 +16,7 @@ public sealed class SummonCultistListWindowBUI : BoundUserInterface
{
base.Open();
_window = new();
_window.OpenCentered();
_window = this.CreateWindow<SummonCultistListWindow>();
_window.OnClose += Close;
_window.ItemSelected += (item, index) =>
@ -36,7 +36,17 @@ public sealed class SummonCultistListWindowBUI : BoundUserInterface
if (state is SummonCultistListWindowBUIState newState)
{
_window?.PopulateList(newState.Items, newState.Label);
_window?.PopulateList(newState.Items, newState.Label, newState.MobStates, newState.Distances);
}
}
protected override void Dispose(bool disposing)
{
base.Dispose(disposing);
if (!disposing)
return;
_window?.Close();
}
}

View file

@ -15,7 +15,7 @@ public partial class TeleportRunesListWindow : DefaultWindow
RobustXamlLoader.Load(this);
}
public void PopulateList(List<int> items, List<string> labels)
public void PopulateList(List<int> items, List<string> labels, List<string> distances)
{
ItemsContainer.RemoveAllChildren();
@ -26,7 +26,13 @@ public partial class TeleportRunesListWindow : DefaultWindow
var item = items[i];
var button = new Button();
button.Text = labels[i];
var text = Loc.GetString(
"teleport-button-label",
("label", labels[i]),
("distance", distances[i])
);
button.Text = text;
button.OnPressed += _ => ItemSelected?.Invoke(item, items.IndexOf(item));

View file

@ -34,7 +34,7 @@ public sealed class TeleportRunesListWindowBUI : BoundUserInterface
if (state is TeleportRunesListWindowBUIState newState)
{
_window?.PopulateList(newState.Items, newState.Label);
_window?.PopulateList(newState.Items, newState.Label, newState.Distance);
}
}
}

View file

@ -36,6 +36,6 @@ public sealed class TeleportSpellEui : BaseEui
return;
_window.Clear();
_window.PopulateList(cast.Runes.Keys.ToList(), cast.Runes.Values.ToList());
_window.PopulateList(cast.Runes.Keys.ToList(), cast.Runes.Values.ToList(), cast.Distance);
}
}

View file

@ -1,4 +1,5 @@
using Content.Shared._Sunrise.BloodCult.Items;
using Robust.Client.UserInterface;
namespace Content.Client._Sunrise.BloodCult.UI.Torch;
@ -15,8 +16,7 @@ public sealed class TorchWindowBUI : BoundUserInterface
{
base.Open();
_window = new();
_window.OpenCentered();
_window = this.CreateWindow<TorchWindow>();
_window.OnClose += Close;
_window.ItemSelected += (uid, item) =>
@ -39,4 +39,14 @@ public sealed class TorchWindowBUI : BoundUserInterface
_window?.PopulateList(newState.Items);
}
}
protected override void Dispose(bool disposing)
{
base.Dispose(disposing);
if (!disposing)
return;
_window?.Close();
}
}

View file

@ -319,8 +319,7 @@ public sealed class BloodCultRuleSystem : GameRuleSystem<BloodCultRuleComponent>
var ev = new UpdateCultAppearance();
RaiseLocalEvent(ev);
EntityUid? actionId = null;
_actionsSystem.AddAction(uid, ref actionId, BloodCultistComponent.BloodMagicAction);
_actionsSystem.AddAction(uid, BloodCultistComponent.BloodMagicAction);
}
private void OnCultistComponentRemoved(EntityUid uid, BloodCultistComponent component, ComponentRemove args)

View file

@ -124,6 +124,7 @@ public sealed class CultBloodSpellSystem : EntitySystem
var orb = Spawn(component.BlodOrbSpawnId, _transformSystem.GetMapCoordinates(uid));
var bloodOrb = EnsureComp<CultBloodOrbComponent>(orb);
bloodOrb.BloodCharges = args.Count;
comp.BloodCharges -= args.Count; // По идее теперь забирает столько сколько потрачено на создание
}
private void OnRequestCreateOrb(EntityUid uid,

View file

@ -71,7 +71,7 @@ public sealed class VoidTeleportSystem : EntitySystem
EntityCoordinates coords = default;
var attempts = 10;
//Repeat until proper place for tp is found
while (attempts <= 10)
while (attempts > 0)
{
attempts--;
//Get coords to where tp
@ -83,8 +83,10 @@ public sealed class VoidTeleportSystem : EntitySystem
var tile = coords.GetTileRef();
//Check for walls
if (tile != null && _turf.IsTileBlocked(tile.Value, CollisionGroup.AllMask))
if (tile == null)
continue;
if (_turf.IsTileBlocked(tile.Value, CollisionGroup.AllMask))
continue;
break;

View file

@ -50,10 +50,7 @@ public sealed class PylonSystem : EntitySystem
private void OnAnchorStateChanged(EntityUid uid, SharedPylonComponent component, AnchorStateChangedEvent args)
{
if (args.Anchored)
return;
component.Activated = false;
component.Activated = args.Anchored;
UpdateAppearance(uid, component);
}

View file

@ -8,17 +8,22 @@ using Content.Server.Bible.Components;
using Content.Server.Body.Components;
using Content.Server.Chat.Systems;
using Content.Server.Chemistry.Components;
using Content.Server.Ghost.Roles.Components;
using Content.Server.Ghost.Roles.Raffles;
using Content.Server.Nutrition.Components;
using Content.Shared._Sunrise.BloodCult;
using Content.Shared._Sunrise.BloodCult.Components;
using Content.Shared._Sunrise.BloodCult.Items;
using Content.Shared._Sunrise.BloodCult.Runes;
using Content.Shared._Sunrise.BloodCult.UI;
using Content.Shared.Chemistry.Components.SolutionManager;
using Content.Shared.Coordinates;
using Content.Shared.Cuffs.Components;
using Content.Shared.Damage;
using Content.Shared.Damage.Prototypes;
using Content.Shared.DoAfter;
using Content.Shared.Examine;
using Content.Shared.Ghost.Roles.Raffles;
using Content.Shared.Humanoid;
using Content.Shared.Interaction;
using Content.Shared.Interaction.Events;
@ -32,8 +37,10 @@ using Content.Shared.Popups;
using Content.Shared.Projectiles;
using Content.Shared.Rejuvenate;
using Content.Shared.Verbs;
using Microsoft.EntityFrameworkCore;
using Robust.Shared.Audio;
using Robust.Shared.Map;
using Robust.Shared.Map.Components;
using Robust.Shared.Physics.Events;
using Robust.Shared.Player;
using Robust.Shared.Random;
@ -160,6 +167,9 @@ namespace Content.Server._Sunrise.BloodCult.Runes.Systems
{
var runePrototype = args.SelectedItem;
if (!IsCorrectLocation(args.Actor, out var coords))
return;
if (!TryComp<ActorComponent>(args.Actor, out var actorComponent))
return;
@ -199,7 +209,7 @@ namespace Content.Server._Sunrise.BloodCult.Runes.Systems
colorOverride: Color.Red);
}
if (!IsAllowedToDraw(whoCalled))
if (!IsAllowedToDraw(whoCalled))
return false;
var ev = new CultDrawEvent
@ -236,9 +246,11 @@ namespace Content.Server._Sunrise.BloodCult.Runes.Systems
return;
_bloodstreamSystem.TryModifyBloodLevel(user, howMuchBloodTake, bloodstreamComponent);
_audio.PlayPvs("/Audio/_Sunrise/BloodCult/blood.ogg", user, AudioParams.Default.WithMaxDistance(2f));
SpawnRune(user, rune);
_audio.PlayPvs("/Audio/_Sunrise/BloodCult/blood.ogg", user, AudioParams.Default.WithMaxDistance(2f));
}
private void OnChoose(EntityUid uid, CultRuneTeleportComponent component, NameSelectorMessage args)
@ -630,26 +642,25 @@ namespace Content.Server._Sunrise.BloodCult.Runes.Systems
private bool Teleport(EntityUid rune, EntityUid user)
{
var runes = EntityQuery<CultRuneTeleportComponent>();
var list = new List<int>();
var labels = new List<string>();
var distance = new List<string>();
foreach (var teleportRune in runes)
var query = EntityQueryEnumerator<CultRuneTeleportComponent, TransformComponent>();
while (query.MoveNext(out var uid, out var comp, out var xform))
{
if (!TryComp<CultRuneTeleportComponent>(teleportRune.Owner, out var teleportComponent))
if (comp.Label == null)
continue;
if (teleportComponent.Label == null)
if (uid == rune)
continue;
if (teleportRune.Owner == rune)
continue;
if (!int.TryParse(teleportRune.Owner.ToString(), out var intValue))
if (!int.TryParse(uid.ToString(), out var intValue))
continue;
list.Add(intValue);
labels.Add(teleportComponent.Label);
labels.Add(comp.Label);
distance.Add(GetDistance(rune, xform));
}
if (!TryComp<ActorComponent>(user, out var actorComponent))
@ -661,7 +672,7 @@ namespace Content.Server._Sunrise.BloodCult.Runes.Systems
return false;
}
_ui.SetUiState(rune, RuneTeleporterUiKey.Key, new TeleportRunesListWindowBUIState(list, labels));
_ui.SetUiState(rune, RuneTeleporterUiKey.Key, new TeleportRunesListWindowBUIState(list, labels, distance));
if (_ui.IsUiOpen(rune, RuneTeleporterUiKey.Key))
return false;
@ -868,6 +879,17 @@ namespace Content.Server._Sunrise.BloodCult.Runes.Systems
var result = Revive(victim.Value, args.User);
args.Result = result;
if (!_mindSystem.TryGetMind(victim.Value, out var mindid, out var mind))
{
EnsureComp<GhostRoleComponent>(victim.Value, out var ghost);
EnsureComp<GhostTakeoverAvailableComponent>(victim.Value);
ghost.RoleName = Loc.GetString("revived-cultist-name");
ghost.RoleDescription = Loc.GetString("revived-cultist-desc");
}
}
private bool Revive(EntityUid target, EntityUid user)
@ -937,9 +959,14 @@ namespace Content.Server._Sunrise.BloodCult.Runes.Systems
HashSet<EntityUid> cultistHashSet,
CultRuneSummoningComponent component)
{
var cultists = EntityQuery<BloodCultistComponent>();
if (!_entityManager.TryGetComponent<TransformComponent>(rune, out var runeTransform))
return false;
var list = new List<int>();
var labels = new List<string>();
var mobState = new List<string>();
var distance = new List<string>();
if (cultistHashSet.Count < component.SummonMinCount)
{
@ -947,19 +974,19 @@ namespace Content.Server._Sunrise.BloodCult.Runes.Systems
return false;
}
foreach (var cultist in cultists)
var query = EntityQueryEnumerator<BloodCultistComponent, MetaDataComponent, MobStateComponent, TransformComponent>();
while (query.MoveNext(out var uid, out var cultist, out var meta, out var state, out var xform))
{
if (!TryComp<MetaDataComponent>(cultist.Owner, out var meta))
if (cultistHashSet.Contains(uid))
continue;
if (cultistHashSet.Contains(cultist.Owner))
continue;
if (!int.TryParse(cultist.Owner.ToString(), out var intValue))
if (!int.TryParse(uid.ToString(), out var intValue))
continue;
list.Add(intValue);
labels.Add(meta.EntityName);
mobState.Add(GetStatus(state.CurrentState));
distance.Add(GetDistance(rune, xform));
}
if (!TryComp<ActorComponent>(user, out var actorComponent))
@ -974,7 +1001,7 @@ namespace Content.Server._Sunrise.BloodCult.Runes.Systems
_entityManager.EnsureComponent<CultRuneSummoningProviderComponent>(user, out var providerComponent);
providerComponent.BaseRune = rune;
_ui.SetUiState(user, SummonCultistUiKey.Key, new SummonCultistListWindowBUIState(list, labels));
_ui.SetUiState(user, SummonCultistUiKey.Key, new SummonCultistListWindowBUIState(list, labels, mobState, distance));
if (_ui.IsUiOpen(user, SummonCultistUiKey.Key))
return false;
@ -1216,9 +1243,8 @@ namespace Content.Server._Sunrise.BloodCult.Runes.Systems
private void SpawnRune(EntityUid uid, string? rune)
{
var transform = CompOrNull<TransformComponent>(uid)?.Coordinates;
if (transform == null)
if (!IsCorrectLocation(uid, out var coords))
return;
if (rune == null)
@ -1232,7 +1258,7 @@ namespace Content.Server._Sunrise.BloodCult.Runes.Systems
var damageSpecifier = new DamageSpecifier(_prototypeManager.Index<DamageTypePrototype>("Slash"), 10);
_damageableSystem.TryChangeDamage(uid, damageSpecifier, true, false);
_entityManager.SpawnEntity(rune, transform.Value);
_entityManager.SpawnEntity(rune, coords);
}
private bool SpawnShard(EntityUid target)
@ -1245,12 +1271,10 @@ namespace Content.Server._Sunrise.BloodCult.Runes.Systems
if (transform == null)
return false;
if (!mindComponent.Mind.HasValue)
return false;
var shard = _entityManager.SpawnEntity("SoulShardGhost", transform.Value);
var shard = _entityManager.SpawnEntity("SoulShard", transform.Value);
_mindSystem.TransferTo(mindComponent.Mind.Value, shard);
if (mindComponent.Mind.HasValue)
_mindSystem.TransferTo(mindComponent.Mind.Value, shard);
_bodySystem.GibBody(target);
@ -1287,6 +1311,62 @@ namespace Content.Server._Sunrise.BloodCult.Runes.Systems
_damageableSystem.TryChangeDamage(player, new DamageSpecifier(damageSpecifier2, -40));
}
private string GetStatus(MobState mobState)
{
return mobState switch
{
MobState.Alive => Loc.GetString("health-analyzer-window-entity-alive-text"),
MobState.Critical => Loc.GetString("health-analyzer-window-entity-critical-text"),
MobState.Dead => Loc.GetString("health-analyzer-window-entity-dead-text"),
_ => Loc.GetString("health-analyzer-window-entity-unknown-text"),
};
}
public string GetDistance(EntityUid uid, TransformComponent xform)
{
if (!_entityManager.TryGetComponent<TransformComponent>(uid, out var transform))
return string.Empty;
if (!transform.Coordinates.TryDistance(_entityManager, xform.Coordinates, out var dist))
return string.Empty;
var metres = dist.ToString("0.0");
return metres;
}
public bool IsCorrectLocation(EntityUid uid, out EntityCoordinates coords)
{
coords = default;
var transform = CompOrNull<TransformComponent>(uid);
if (transform == null)
return false;
var gridUid = transform.GridUid;
if (!TryComp<MapGridComponent>(gridUid, out var mapGrid))
return false;
var position = _map.TileIndicesFor(gridUid.Value, mapGrid, transform.Coordinates);
_intersectingEntities.Clear();
_lookup.GetLocalEntitiesIntersecting(gridUid.Value, position, _intersectingEntities, -0.05f, LookupFlags.Uncontained);
foreach (var ent in _intersectingEntities)
{
if (HasComp<CultRuneBaseComponent>(ent))
{
_popupSystem.PopupCursor(Loc.GetString("tile-has-rune"), uid, PopupType.MediumCaution);
return false;
}
}
coords = _map.GridTileToLocal(gridUid.Value, mapGrid, position);
return true;
}
/*
* Helpers End ----
*/

View file

@ -50,6 +50,7 @@ namespace Content.Server._Sunrise.BloodCult.Runes.Systems
[Dependency] private readonly ContainerSystem _containerSystem = default!;
[Dependency] private readonly CuffableSystem _cuffable = default!;
[Dependency] private readonly DamageableSystem _damageableSystem = default!;
[Dependency] private readonly SharedMapSystem _map = default!;
[Dependency] private readonly DoAfterSystem _doAfterSystem = default!;
[Dependency] private readonly EmpSystem _empSystem = default!;
[Dependency] private readonly EntityManager _entityManager = default!;
@ -125,6 +126,8 @@ namespace Content.Server._Sunrise.BloodCult.Runes.Systems
private EntityUid? _playingStream;
private HashSet<EntityUid> _intersectingEntities = new();
private float _timeToDraw;
public override void Initialize()

View file

@ -1,4 +1,5 @@
using Content.Server._Sunrise.BloodCult.Runes.Comps;
using Content.Server._Sunrise.BloodCult.Runes.Systems;
using Content.Server.EUI;
using Content.Server.Popups;
using Content.Shared._Sunrise.BloodCult.Actions;
@ -6,6 +7,7 @@ using Content.Shared._Sunrise.BloodCult.Components;
using Content.Shared._Sunrise.BloodCult.UI;
using Content.Shared.Eui;
using Content.Shared.Popups;
using Microsoft.EntityFrameworkCore.Metadata.Builders;
using Robust.Server.Audio;
using Robust.Shared.Audio;
using Robust.Shared.Audio.Systems;
@ -29,7 +31,7 @@ public sealed class TeleportSpellEui : BaseEui
private EntityUid _target;
private SharedTransformSystem _transformSystem;
private SharedAudioSystem _audio;
private BloodCultSystem _bloodCult;
private bool _used;
@ -41,6 +43,7 @@ public sealed class TeleportSpellEui : BaseEui
_transformSystem = _entityManager.System<SharedTransformSystem>();
_audio = _entityManager.System<SharedAudioSystem>();
_popupSystem = _entityManager.System<PopupSystem>();
_bloodCult = _entityManager.System<BloodCultSystem>();
_performer = performer;
_target = target;
@ -50,12 +53,13 @@ public sealed class TeleportSpellEui : BaseEui
public override EuiStateBase GetNewState()
{
var runes = _entityManager.EntityQuery<CultRuneTeleportComponent>();
var state = new TeleportSpellEuiState();
foreach (var rune in runes)
var query = _entityManager.EntityQueryEnumerator<CultRuneTeleportComponent, TransformComponent>();
while (query.MoveNext(out var uid, out var comp, out var xform))
{
state.Runes.Add((int)rune.Owner, rune.Label!);
state.Runes.Add((int)uid, comp.Label!);
state.Distance.Add(_bloodCult.GetDistance(_performer, xform));
}
return state;

View file

@ -1,4 +1,6 @@
using System.Linq;
using Content.Shared.Maps;
using Content.Shared.Physics;
using JetBrains.Annotations;
using Robust.Shared.Map;
@ -15,7 +17,9 @@ public sealed partial class TileNotBlocked : IConstructionCondition
public bool Condition(EntityUid user, EntityCoordinates location, Direction direction)
{
var tileRef = location.GetTileRef();
var entManager = IoCManager.Resolve<IEntityManager>();
var sysMan = entManager.EntitySysManager;
var lookupSys = sysMan.GetEntitySystem<EntityLookupSystem>();
if (tileRef == null)
{
return false;
@ -30,8 +34,10 @@ public sealed partial class TileNotBlocked : IConstructionCondition
{
return false;
}
return !tileRef.Value.IsBlockedTurf(_filterMobs);
// Sunrise-start, Временное решение. У оффов много что поломано с методом IsTileBlocked
// return !tileRef.Value.IsBlockedTurf(_filterMobs);
return !lookupSys.GetEntitiesIntersecting(location, LookupFlags.Static).Any();
// Sunrise-end
}
public ConstructionGuideEntry GenerateGuideEntry()

View file

@ -1,4 +1,5 @@
using Robust.Shared.Serialization;
using Content.Shared.Store;
using Robust.Shared.Serialization;
namespace Content.Shared._Sunrise.BloodCult.UI;
@ -58,16 +59,11 @@ public class TeleportRuneChangeNameMessage : BoundUserInterfaceMessage
}
[Serializable, NetSerializable]
public class TeleportRunesListWindowBUIState : BoundUserInterfaceState
public sealed class TeleportRunesListWindowBUIState(List<int> items, List<string> labels, List<string> distance) : BoundUserInterfaceState
{
public TeleportRunesListWindowBUIState(List<int> items, List<string> labels)
{
Items = items;
Label = labels;
}
public List<int> Items { get; set; }
public List<string> Label { get; set; }
public List<int> Items = items;
public List<string> Label = labels;
public List<string> Distance = distance;
}
[NetSerializable, Serializable]
@ -90,16 +86,12 @@ public class SummonCultistListWindowItemSelectedMessage : BoundUserInterfaceMess
}
[Serializable, NetSerializable]
public class SummonCultistListWindowBUIState : BoundUserInterfaceState
public sealed class SummonCultistListWindowBUIState(List<int> items, List<string> labels, List<string> mobState, List<string> distance) : BoundUserInterfaceState
{
public SummonCultistListWindowBUIState(List<int> items, List<string> labels)
{
Items = items;
Label = labels;
}
public List<int> Items { get; set; }
public List<string> Label { get; set; }
public List<int> Items = items;
public List<string> Label = labels;
public List<string> MobStates = mobState;
public List<string> Distances = distance;
}
[Serializable, NetSerializable]

View file

@ -7,6 +7,8 @@ namespace Content.Shared._Sunrise.BloodCult.UI;
public sealed class TeleportSpellEuiState : EuiStateBase
{
public Dictionary<int, string> Runes = new();
public List<string> Distance = new();
}
[Serializable, NetSerializable]

View file

@ -1,4 +1,4 @@
ent-OfferingRune = руна предпонесения
ent-OfferingRune = руна преподнесения
ent-BuffRune = руна усиления
ent-EmpoweringRune = руна могущества
ent-TeleportRune = руна телепортации

View file

@ -51,3 +51,7 @@ objective-condition-cult-kill-target = { $targetName } ({ CAPITALIZE($job) }) -
objective-condition-cult-kill-title =
Жертвы:
{ $targets }
summon-button-label = {$label} ({$mobState}; {$distance} м)
teleport-button-label = {$label} ({$distance} м)
revived-cultist-desc = Культист крови, душа которого сгинула в вечном мраке.
tile-has-rune = На этом тайле уже есть руна!