This commit is contained in:
DisposableCrewmember42 2026-05-10 11:43:47 +00:00 committed by GitHub
commit 4e24d95e90
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
17 changed files with 302 additions and 19 deletions

View File

@ -87,7 +87,7 @@ public sealed partial class AnomalySystem : SharedAnomalySystem
if (anomaly.Comp.CurrentBehavior is not null)
RemoveBehavior(anomaly, anomaly.Comp.CurrentBehavior.Value);
EndAnomaly(anomaly, spawnCore: false);
EndAnomaly(anomaly, spawnCore: false, forced: true);
}
private void OnStartCollide(Entity<AnomalyComponent> anomaly, ref StartCollideEvent args)
@ -143,7 +143,7 @@ public sealed partial class AnomalySystem : SharedAnomalySystem
return 0;
var multiplier = 1f;
if (component.Stability > component.GrowthThreshold)
if (component.AlwaysGrow || component.Stability > component.GrowthThreshold) // DeltaV - Add AlwaysGrow
multiplier = component.GrowingPointMultiplier; //more points for unstable
//penalty of up to 50% based on health
@ -253,7 +253,11 @@ public sealed partial class AnomalySystem : SharedAnomalySystem
else
{
string stateLoc;
if (anomalyComp.Stability < anomalyComp.DecayThreshold)
// DeltaV - Colossus Additions START
if (anomalyComp.AlwaysGrow)
stateLoc = Loc.GetString("anomaly-scanner-stability-high");
// DeltaV - Colossus Additions END
else if (anomalyComp.Stability < anomalyComp.DecayThreshold) // DeltaV - Add else
stateLoc = Loc.GetString("anomaly-scanner-stability-low");
else if (anomalyComp.Stability > anomalyComp.GrowthThreshold)
stateLoc = Loc.GetString("anomaly-scanner-stability-high");
@ -345,6 +349,15 @@ public sealed partial class AnomalySystem : SharedAnomalySystem
msg.AddMarkupOrThrow(Loc.GetString("anomaly-behavior-unknown"));
else
{
// DeltaV - Colossus Additions START
if (anomalyComp.AlwaysGrow)
{
msg.AddMarkupOrThrow("- " + Loc.GetString("anomaly-behavior-always-grow"));
if (anomalyComp.CurrentBehavior != null)
msg.PushNewline();
}
// DeltaV - Colossus Additions END
if (anomalyComp.CurrentBehavior != null)
{
var behavior = _prototype.Index(anomalyComp.CurrentBehavior.Value);
@ -354,7 +367,7 @@ public sealed partial class AnomalySystem : SharedAnomalySystem
var mod = Math.Floor((behavior.EarnPointModifier) * 100);
msg.AddMarkupOrThrow("- " + Loc.GetString("anomaly-behavior-point", ("mod", mod)));
}
else
else if(!anomalyComp.AlwaysGrow) // DeltaV - Add condition, previously regular else
{
msg.AddMarkupOrThrow(Loc.GetString("anomaly-behavior-balanced"));
}

View File

@ -1,15 +1,28 @@
using System.Numerics;
using Content.Server._DV.CosmicCult.Components;
using Content.Server.Actions;
using Content.Server.Chat.Managers;
using Content.Server.Objectives.Components;
using Content.Server.Objectives.Systems;
using Content.Server.Popups;
using Content.Shared._DV.CosmicCult;
using Content.Shared._DV.CosmicCult.Components;
using Content.Shared.Anomaly.Components;
using Content.Shared.Damage;
using Content.Shared.Damage.Components;
using Content.Shared.Damage.Systems;
using Content.Shared.Maps;
using Content.Shared.Mind;
using Content.Shared.Popups;
using Content.Shared.Warps;
using Content.Shared.Weapons.Melee;
using Robust.Server.Audio;
using Robust.Server.Player;
using Robust.Shared.Map;
using Robust.Shared.Map.Components;
using Robust.Shared.Player;
using Robust.Shared.Prototypes;
using Robust.Shared.Timing;
namespace Content.Server._DV.CosmicCult.Abilities;
@ -23,12 +36,110 @@ public sealed class CosmicEffigySystem : EntitySystem
[Dependency] private readonly SharedMapSystem _map = default!;
[Dependency] private readonly SharedMindSystem _mind = default!;
[Dependency] private readonly SharedTransformSystem _transform = default!;
[Dependency] private readonly DamageableSystem _damage = default!;
[Dependency] private readonly AudioSystem _audio = default!;
[Dependency] private readonly CosmicCultObjectiveSystem _cultObjective = default!;
[Dependency] private readonly IGameTiming _time = default!;
[Dependency] private readonly IPrototypeManager _proto = default!;
[Dependency] private readonly IChatManager _chat = default!;
[Dependency] private readonly IPlayerManager _player = default!;
public override void Initialize()
{
base.Initialize();
SubscribeLocalEvent<CosmicColossusComponent, EventCosmicColossusEffigy>(OnColossusEffigy);
SubscribeLocalEvent<CosmicEffigyComponent, AnomalySupercriticalEvent>(OnSupercritical);
SubscribeLocalEvent<CosmicEffigyComponent, AnomalyShutdownEvent>(OnAnomShutdown);
}
private void OnAnomShutdown(Entity<CosmicEffigyComponent> ent, ref AnomalyShutdownEvent args)
{
if (args.Forced || args.Supercritical || !Exists(ent.Comp.Colossus) || !TryComp<CosmicColossusComponent>(ent.Comp.Colossus, out var colossusComp))
return;
colossusComp.DeathTimer = _time.CurTime;
colossusComp.Timed = true;
}
private void OnSupercritical(Entity<CosmicEffigyComponent> ent, ref AnomalySupercriticalEvent args)
{
if (!Exists(ent.Comp.Colossus)
|| !TryComp<CosmicColossusComponent>(ent.Comp.Colossus, out var colossusComp)
|| !_mind.TryGetMind(ent.Comp.Colossus.Value, out _, out var mind))
return;
var colossus = ent.Comp.Colossus.Value;
if (TryComp<MeleeWeaponComponent>(colossus, out var weapon))
{
weapon.AttackRate *= ent.Comp.ColossusAttackRateMultiplier;
}
if (TryComp<CosmicCorruptingComponent>(colossus, out var corrupting))
{
corrupting.CorruptionSpeed *= ent.Comp.ColossusCorruptionSpeedMultiplier;
}
if (ent.Comp.ColossusHeal && TryComp<DamageableComponent>(colossus, out var damageable))
{
_damage.TryChangeDamage(ent.Comp.Colossus.Value, damageable.Damage / 2 * -1, true);
}
colossusComp.BonusDamage +=
new DamageSpecifier(_proto.Index(colossusComp.BonusDamageType), ent.Comp.ColossusBonusDamage);
var transform = Transform(ent.Comp.Colossus.Value);
Spawn(colossusComp.BuffVfx, transform.Coordinates);
if (colossusComp.CompletedEffigies == 0)
{
_audio.PlayStatic(colossusComp.ReawakenSfx,
Filter.BroadcastMap(transform.MapID),
transform.Coordinates,
true);
}
else
{
_audio.PlayPvs(colossusComp.ReawakenSfx, ent);
}
colossusComp.CompletedEffigies += 1;
if (colossusComp.CompletedEffigies >= colossusComp.MaxEffigies)
{
colossusComp.Timed = false;
_popup.PopupEntity(Loc.GetString("colossus-buff-final-popup"), colossus, PopupType.Large);
return;
}
_popup.PopupEntity(Loc.GetString("colossus-buff-popup"), colossus, PopupType.Large);
var objIndex = mind.Objectives.FindIndex(HasComp<CosmicEffigyConditionComponent>);
if (objIndex == -1 ||
!TryComp<CosmicEffigyConditionComponent>(mind.Objectives[objIndex], out var conditionComp))
{
Log.Error($"Failed to find effigy objective on {ToPrettyString(colossus)}!");
return;
}
var objective = mind.Objectives[objIndex];
if (_cultObjective.RandomizeEffigyTarget(objective, conditionComp, setDescription: true) is not {} nextTarget)
{
Log.Error("Failed to randomize effigy objective location!");
return;
}
if (mind.UserId is { } userId)
{
_chat.DispatchServerMessage(_player.GetSessionById(userId), Loc.GetString("colossus-next-target", ("location", nextTarget)));
}
_codeCondition.SetCompleted(objective, false);
colossusComp.EffigyPlaceActionEntity = _actions.AddAction(colossus, colossusComp.EffigyPlaceAction);
colossusComp.DeathTimer = _time.CurTime + colossusComp.DeathWaitEffigy;
colossusComp.Timed = true;
}
private void OnColossusEffigy(Entity<CosmicColossusComponent> ent, ref EventCosmicColossusEffigy args)
@ -38,8 +149,16 @@ public sealed class CosmicEffigySystem : EntitySystem
_actions.RemoveAction(ent.Owner, ent.Comp.EffigyPlaceActionEntity);
_codeCondition.SetCompleted(ent.Owner, ent.Comp.EffigyObjective);
Spawn(ent.Comp.EffigyPrototype, pos);
var effigy = Spawn(ent.Comp.EffigyPrototype, pos);
ent.Comp.Timed = false;
if (!TryComp<CosmicEffigyComponent>(effigy, out var effigyComp))
{
Log.Error("Colossus tried to place Effigy prototype missing CosmicEffigyComponent!");
return;
}
effigyComp.Colossus = ent.Owner;
}
private bool VerifyPlacement(Entity<CosmicColossusComponent> ent, out EntityCoordinates outPos)

View File

@ -1,3 +1,4 @@
using Content.Server._DV.CosmicCult.Abilities;
using Content.Server._DV.CosmicCult.EntitySystems;
using Content.Shared.Maps;
using Robust.Shared.Prototypes;
@ -5,7 +6,7 @@ using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom;
namespace Content.Server._DV.CosmicCult.Components;
[RegisterComponent, Access(typeof(CosmicCorruptingSystem))]
[RegisterComponent, Access(typeof(CosmicCorruptingSystem), typeof(CosmicEffigySystem))]
[AutoGenerateComponentPause]
public sealed partial class CosmicCorruptingComponent : Component
{

View File

@ -0,0 +1,22 @@
using Content.Shared.FixedPoint;
namespace Content.Server._DV.CosmicCult.Components;
[RegisterComponent]
public sealed partial class CosmicEffigyComponent : Component
{
[DataField]
public EntityUid? Colossus;
[DataField]
public float ColossusAttackRateMultiplier = 1.1f;
[DataField]
public float ColossusCorruptionSpeedMultiplier = 0.9f;
[DataField]
public FixedPoint2 ColossusBonusDamage = 10;
[DataField]
public bool ColossusHeal = true;
}

View File

@ -35,6 +35,12 @@ public sealed class CosmicCultObjectiveSystem : EntitySystem
if (args.Cancelled || !_roles.MindHasRole<CosmicColossusRoleComponent>(args.MindId))
return;
if (RandomizeEffigyTarget(uid, comp) is null)
args.Cancelled = true;
}
public string? RandomizeEffigyTarget(EntityUid uid, CosmicEffigyConditionComponent comp, bool setDescription = false)
{
var warps = new List<EntityUid>();
var query = EntityQueryEnumerator<WarpPointComponent>();
var effigyBlacklist = comp.Blacklist;
@ -51,10 +57,22 @@ public sealed class CosmicCultObjectiveSystem : EntitySystem
if (warps.Count <= 0)
{
args.Cancelled = true;
return;
return null;
}
comp.EffigyTarget = _random.Pick(warps);
var newWarp = _random.Pick(warps);
var warpComp = Comp<WarpPointComponent>(newWarp);
comp.EffigyTarget = newWarp;
if (setDescription)
{
_metaData.SetEntityDescription(uid,
warpComp.Location != null
? Loc.GetString("objective-condition-effigy", ("location", warpComp.Location))
: Loc.GetString("objective-condition-effigy-no-target"));
}
return warpComp.Location;
}
private void OnEffigyAfterAssign(EntityUid uid, CosmicEffigyConditionComponent comp, ref ObjectiveAfterAssignEvent args)

View File

@ -13,6 +13,7 @@ using Content.Shared.Popups;
using Content.Shared.Station.Components;
using Content.Shared.Throwing;
using Content.Shared.Warps;
using Content.Shared.Weapons.Melee.Events;
using Robust.Server.GameObjects;
using Robust.Shared.Audio.Systems;
using Robust.Shared.Physics.Components;
@ -41,6 +42,7 @@ public sealed class CosmicColossusSystem : EntitySystem
base.Initialize();
SubscribeLocalEvent<CosmicColossusComponent, ComponentInit>(OnSpawn);
SubscribeLocalEvent<CosmicColossusComponent, MobStateChangedEvent>(OnMobStateChanged);
SubscribeLocalEvent<CosmicColossusComponent, MeleeHitEvent>(OnMeleeHit);
}
public override void Update(float frameTime)
@ -82,7 +84,7 @@ public sealed class CosmicColossusSystem : EntitySystem
private void OnSpawn(Entity<CosmicColossusComponent> ent, ref ComponentInit args) // I WANT THIS BIG GUY HURLED TOWARDS THE STATION
{
ent.Comp.DeathTimer = _timing.CurTime + ent.Comp.DeathWait;
ent.Comp.DeathTimer = _timing.CurTime + ent.Comp.DeathWaitSpawn;
var station = _station.GetStationInMap(Transform(ent).MapID);
if (TryComp<StationDataComponent>(station, out var stationData))
{
@ -115,4 +117,9 @@ public sealed class CosmicColossusSystem : EntitySystem
RemComp<WarpPointComponent>(ent);
RemComp<CosmicCorruptingComponent>(ent);
}
private void OnMeleeHit(Entity<CosmicColossusComponent> colossus, ref MeleeHitEvent args)
{
args.BonusDamage += colossus.Comp.BonusDamage;
}
}

View File

@ -285,6 +285,11 @@ public sealed partial class AnomalyComponent : Component
[DataField]
public bool DeleteEntity = true;
// DeltaV - Colossus additions START
[DataField]
public bool AlwaysGrow;
// DeltaV - Colossus additions END
}
/// <summary>
@ -308,7 +313,7 @@ public readonly record struct AnomalySupercriticalEvent(EntityUid Anomaly, float
/// <param name="Anomaly">The anomaly being shut down.</param>
/// <param name="Supercritical">Whether or not the anomaly shut down passively or via a supercritical event.</param>
[ByRefEvent]
public readonly record struct AnomalyShutdownEvent(EntityUid Anomaly, bool Supercritical);
public readonly record struct AnomalyShutdownEvent(EntityUid Anomaly, bool Supercritical, bool Forced); // DeltaV - Add Forced
/// <summary>
/// Event broadcast when an anomaly's severity is changed.

View File

@ -84,7 +84,7 @@ public abstract partial class SharedAnomalySystem : EntitySystem // DeltaV - Mad
Log.Info($"Performing anomaly pulse. Entity: {ToPrettyString(uid)}");
// if we are above the growth threshold, then grow before the pulse
if (component.Stability > component.GrowthThreshold)
if (component.AlwaysGrow || component.Stability > component.GrowthThreshold) // DeltaV - Add AlwaysGrow
{
ChangeAnomalySeverity(uid, GetSeverityIncreaseFromGrowth(component), component);
}
@ -192,7 +192,8 @@ public abstract partial class SharedAnomalySystem : EntitySystem // DeltaV - Mad
/// <param name="supercritical">Whether or not the anomaly ended via supercritical event</param>
/// <param name="spawnCore">Create anomaly cores based on the result of completing an anomaly?</param>
/// <param name="logged">Whether or not the anomaly decaying/going supercritical is logged</param>
public void EndAnomaly(EntityUid uid, AnomalyComponent? component = null, bool supercritical = false, bool spawnCore = true, bool logged = false)
/// <param name="forced">Whether or not the anomaly shutdown was caused by component shutdown</param> // DeltaV - Add forced
public void EndAnomaly(EntityUid uid, AnomalyComponent? component = null, bool supercritical = false, bool spawnCore = true, bool logged = false, bool forced = false) // DeltaV - Add forced
{
if (logged)
{
@ -207,7 +208,7 @@ public abstract partial class SharedAnomalySystem : EntitySystem // DeltaV - Mad
if (!Resolve(uid, ref component))
return;
var ev = new AnomalyShutdownEvent(uid, supercritical);
var ev = new AnomalyShutdownEvent(uid, supercritical, forced); // DeltaV - Add forced
RaiseLocalEvent(uid, ref ev, true);
if (Terminating(uid) || _net.IsClient)
@ -345,7 +346,7 @@ public abstract partial class SharedAnomalySystem : EntitySystem // DeltaV - Mad
// if the stability is under the death threshold,
// update it every second to start killing it slowly.
if (anomaly.Stability < anomaly.DecayThreshold)
if (!anomaly.AlwaysGrow && anomaly.Stability < anomaly.DecayThreshold) // DeltaV - Add AlwaysGrow
{
ChangeAnomalyHealth(ent, anomaly.HealthChangePerSecond * frameTime, anomaly);
}
@ -479,6 +480,14 @@ public abstract partial class SharedAnomalySystem : EntitySystem // DeltaV - Mad
if (!Resolve(ent, ref ent.Comp, logMissing: false))
return false;
// DeltaV - Colossus Additions START
if (ent.Comp.AlwaysGrow)
{
visual = AnomalyStabilityVisuals.Growing;
return true;
}
// DeltaV - Colossus Additions END
visual = AnomalyStabilityVisuals.Stable;
if (ent.Comp.Stability <= ent.Comp.DecayThreshold)
{

View File

@ -1,3 +1,5 @@
using Content.Shared.Damage;
using Content.Shared.Damage.Prototypes;
using Robust.Shared.Audio;
using Robust.Shared.GameStates;
using Robust.Shared.Prototypes;
@ -36,6 +38,8 @@ public sealed partial class CosmicColossusComponent : Component
[DataField] public EntProtoId Attack1Vfx = "CosmicColossusAttack1Vfx";
[DataField] public EntProtoId BuffVfx = "ColossusBuffVfx";
[DataField] public EntProtoId TileDetonations = "MobTileDamageZone";
[DataField] public EntProtoId EffigyPrototype = "CosmicEffigy";
@ -52,13 +56,24 @@ public sealed partial class CosmicColossusComponent : Component
[DataField] public TimeSpan HibernationWait = TimeSpan.FromSeconds(30);
[DataField] public TimeSpan DeathWait = TimeSpan.FromMinutes(15);
[DataField] public TimeSpan DeathWaitSpawn = TimeSpan.FromMinutes(15);
[DataField] public TimeSpan DeathWaitEffigy = TimeSpan.FromMinutes(10);
[DataField] public bool Attacking;
[DataField] public bool Hibernating;
[DataField] public bool Timed;
[DataField] public short CompletedEffigies;
[DataField] public short MaxEffigies = 3;
[DataField] public DamageSpecifier BonusDamage = new();
[DataField] public ProtoId<DamageTypePrototype> BonusDamageType = "Blunt";
}
[Serializable, NetSerializable]

View File

@ -0,0 +1 @@
anomaly-behavior-always-grow = [color=red]Anomaly never stops growing.[/color]

View File

@ -0,0 +1,3 @@
colossus-buff-popup = You grow stronger. Another space calls for you.
colossus-buff-final-popup = You have grown strong enough. The curtains must fall.
colossus-next-target = {$location} calls for you. Beckon your next effigy there.

View File

@ -7,7 +7,7 @@ ghost-role-information-theunknown-rules = ...
# COLOSSUS
ghost-role-information-colossus-name = Entropic Colossus
ghost-role-information-colossus-description = Call upon an Effigy of Entropy to perpetuate your existence and accelerate the end of all things! You have 15 minutes to do so or your energies will be extinguished.
ghost-role-information-colossus-description = Call upon three Effigies of Entropy to grow in power and accelerate the end of all things, starting with the station! You have 15 minutes to place your first effigy. If you don't place one or your effigy decays, your energies will be extinguished.
ghost-role-information-colossus-rules = You are a [color={role-type-team-antagonist-color}][bold]{role-type-team-antagonist-name}[/bold][/color] with any cosmic cultists that may be present.
terror-colossus = Attention crew, it appears that someone on your station has drawn the attention of an enormous malign anomaly.

View File

@ -169,6 +169,36 @@
isLooped: true
reverseWhenFinished: true
- type: entity
categories: [ HideSpawnMenu ]
parent: BaseCosmicVFX
id: ColossusBuffVfx
components:
- type: TimedDespawn
lifetime: 0.8
- type: Sprite
layers:
- sprite: _DV/CosmicCult/Effects/colossus_buffvfx.rsi
state: vfx
shader: unshaded
- type: PointLight
color: "#a35d7b"
radius: 1.5
energy: 2.5
castShadows: false
- type: LightBehaviour
behaviours:
- !type:FadeBehaviour
interpolate: Linear
minDuration: 0.8
maxDuration: 0.8
startValue: 0.1
endValue: 2
property: Energy
enabled: true
isLooped: true
reverseWhenFinished: true
- type: entity
categories: [ HideSpawnMenu ]
parent: BaseCosmicVFX

View File

@ -23,6 +23,7 @@
- type: CosmicCultExamine
cultistText: cosmic-examine-text-culteffigy
othersText: cosmic-examine-text-effigy
- type: CosmicEffigy
- type: CosmicCorrupting
corruptionReduction: 0.02
enabled: true
@ -80,7 +81,7 @@
maxPulseLength: 80
minContituty: 0.4
maxContituty: 0.8
growthThreshold: 0.35
alwaysGrow: true
- type: EntitySpawnAnomaly
entries:
- settings:

View File

@ -6,7 +6,7 @@
weight: 4.5
earliestStart: 45
reoccurrenceDelay: 20
minimumPlayers: 25
minimumPlayers: 35
duration: null
- type: PrecognitionResult
message: psionic-power-precognition-colossus-spawn-result-message

View File

@ -0,0 +1,39 @@
{
"version": 1,
"license": "CC-BY-SA-3.0",
"copyright": "by DisposableCrewmember42 on GitHub",
"size": {
"x": 61,
"y": 118
},
"states": [
{
"name": "vfx",
"delays": [
[
0.04,
0.04,
0.04,
0.04,
0.04,
0.04,
0.04,
0.04,
0.04,
0.04,
0.04,
0.04,
0.04,
0.04,
0.04,
0.04,
0.04,
0.04,
0.04,
0.04,
0.04
]
]
}
]
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.6 KiB