Skip to content

Commit

Permalink
Merge pull request impstation#1138 from honeyed-lemons/supermatter
Browse files Browse the repository at this point in the history
Supermatter Engine Port
  • Loading branch information
Darkmajia authored Dec 28, 2024
2 parents 3c6b2de + dbc10ca commit 990fce4
Show file tree
Hide file tree
Showing 42 changed files with 1,473 additions and 19 deletions.

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
@@ -0,0 +1,210 @@
using Content.Server.AlertLevel;
using Content.Server.Atmos.EntitySystems;
using Content.Server.Chat.Systems;
using Content.Server.DoAfter;
using Content.Server.Explosion.EntitySystems;
using Content.Server.Kitchen.Components;
using Content.Server.Lightning;
using Content.Server.Popups;
using Content.Server.Station.Systems;
using Content.Shared._EinsteinEngines.Supermatter.Components;
using Content.Shared.Atmos;
using Content.Shared.Audio;
using Content.Shared.DoAfter;
using Content.Shared.Examine;
using Content.Shared.Interaction;
using Content.Shared.Mobs.Components;
using Content.Shared.Projectiles;
using Robust.Server.GameObjects;
using Robust.Shared.Audio.Systems;
using Robust.Shared.Configuration;
using Robust.Shared.Containers;
using Robust.Shared.Physics;
using Robust.Shared.Physics.Events;

namespace Content.Server._EinsteinEngines.Supermatter.Systems;

public sealed partial class SupermatterSystem : EntitySystem
{
[Dependency] private readonly AtmosphereSystem _atmosphere = default!;
[Dependency] private readonly ChatSystem _chat = default!;
[Dependency] private readonly SharedContainerSystem _container = default!;
[Dependency] private readonly ExplosionSystem _explosion = default!;
[Dependency] private readonly TransformSystem _xform = default!;
[Dependency] private readonly SharedAudioSystem _audio = default!;
[Dependency] private readonly SharedAmbientSoundSystem _ambient = default!;
[Dependency] private readonly LightningSystem _lightning = default!;
[Dependency] private readonly AlertLevelSystem _alert = default!;
[Dependency] private readonly StationSystem _station = default!;
[Dependency] private readonly DoAfterSystem _doAfter = default!;
[Dependency] private readonly SharedTransformSystem _transform = default!;
[Dependency] private readonly PopupSystem _popup = default!;
[Dependency] private readonly IConfigurationManager _config = default!;


public override void Initialize()
{
base.Initialize();

SubscribeLocalEvent<SupermatterComponent, MapInitEvent>(OnMapInit);

SubscribeLocalEvent<SupermatterComponent, StartCollideEvent>(OnCollideEvent);
SubscribeLocalEvent<SupermatterComponent, InteractHandEvent>(OnHandInteract);
SubscribeLocalEvent<SupermatterComponent, InteractUsingEvent>(OnItemInteract);
SubscribeLocalEvent<SupermatterComponent, ExaminedEvent>(OnExamine);
SubscribeLocalEvent<SupermatterComponent, SupermatterDoAfterEvent>(OnGetSliver);
}


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

foreach (var sm in EntityManager.EntityQuery<SupermatterComponent>())
{
if (!sm.Activated)
return;

var uid = sm.Owner;
sm.UpdateAccumulator += frameTime;

if (sm.UpdateAccumulator >= sm.UpdateTimer)
{
sm.UpdateAccumulator -= sm.UpdateTimer;
Cycle(uid, sm);
}
}
}


public void Cycle(EntityUid uid, SupermatterComponent sm)
{
sm.ZapAccumulator++;
sm.YellAccumulator++;

ProcessAtmos(uid, sm);
HandleDamage(uid, sm);

if (sm.Damage >= sm.DamageDelaminationPoint || sm.Delamming)
HandleDelamination(uid, sm);

HandleSoundLoop(uid, sm);

if (sm.ZapAccumulator >= sm.ZapTimer)
{
sm.ZapAccumulator -= sm.ZapTimer;
SupermatterZap(uid, sm);
}

if (sm.YellAccumulator >= sm.YellTimer)
{
sm.YellAccumulator -= sm.YellTimer;
AnnounceCoreDamage(uid, sm);
}
}

private void OnMapInit(EntityUid uid, SupermatterComponent sm, MapInitEvent args)
{
// Set the Sound
_ambient.SetAmbience(uid, true);

// Add Air to the initialized SM in the Map so it doesn't delam on its' own
var mix = _atmosphere.GetContainingMixture(uid, true, true);
mix?.AdjustMoles(Gas.Oxygen, Atmospherics.OxygenMolesStandard);
mix?.AdjustMoles(Gas.Nitrogen, Atmospherics.NitrogenMolesStandard);
}

private void OnCollideEvent(EntityUid uid, SupermatterComponent sm, ref StartCollideEvent args)
{
if (!sm.Activated)
sm.Activated = true;

var target = args.OtherEntity;
if (args.OtherBody.BodyType == BodyType.Static
|| HasComp<SupermatterImmuneComponent>(target)
|| _container.IsEntityInContainer(uid))
return;

if (!HasComp<ProjectileComponent>(target))
{
EntityManager.SpawnEntity(sm.CollisionResultPrototype, Transform(target).Coordinates);
_audio.PlayPvs(sm.DustSound, uid);
sm.Power += args.OtherBody.Mass;
}

EntityManager.QueueDeleteEntity(target);

if (TryComp<SupermatterFoodComponent>(target, out var food))
sm.Power += food.Energy;
else if (TryComp<ProjectileComponent>(target, out var projectile))
sm.Power += (float) projectile.Damage.GetTotal();
else
sm.Power++;

sm.MatterPower += HasComp<MobStateComponent>(target) ? 200 : 0;
}

private void OnHandInteract(EntityUid uid, SupermatterComponent sm, ref InteractHandEvent args)
{
if (!sm.Activated)
sm.Activated = true;

var target = args.User;

if (HasComp<SupermatterImmuneComponent>(target))
return;

sm.MatterPower += 200;

EntityManager.SpawnEntity(sm.CollisionResultPrototype, Transform(target).Coordinates);
_audio.PlayPvs(sm.DustSound, uid);
EntityManager.QueueDeleteEntity(target);
}

private void OnItemInteract(EntityUid uid, SupermatterComponent sm, ref InteractUsingEvent args)
{
if (!sm.Activated)
sm.Activated = true;

if (sm.SliverRemoved)
return;

if (!HasComp<SharpComponent>(args.Used))
return;

var dae = new DoAfterArgs(EntityManager, args.User, 30f, new SupermatterDoAfterEvent(), args.Target)
{
BreakOnDamage = true,
BreakOnHandChange = false,
BreakOnWeightlessMove = false,
NeedHand = true,
RequireCanInteract = true,
};

_doAfter.TryStartDoAfter(dae);
_popup.PopupClient(Loc.GetString("supermatter-tamper-begin"), uid, args.User);
}

private void OnGetSliver(EntityUid uid, SupermatterComponent sm, ref SupermatterDoAfterEvent args)
{
if (args.Cancelled)
return;

// Your criminal actions will not go unnoticed
sm.Damage += sm.DamageDelaminationPoint / 10;

var integrity = GetIntegrity(sm).ToString("0.00");
SendSupermatterAnnouncement(uid, Loc.GetString("supermatter-announcement-cc-tamper", ("integrity", integrity)), true, "Central Command");

Spawn(sm.SliverPrototype, _transform.GetMapCoordinates(args.User));
_popup.PopupClient(Loc.GetString("supermatter-tamper-end"), uid, args.User);

sm.DelamTimer /= 2;
}

private void OnExamine(EntityUid uid, SupermatterComponent sm, ref ExaminedEvent args)
{
if (args.IsInDetailsRange)
args.PushMarkup(Loc.GetString("supermatter-examine-integrity", ("integrity", GetIntegrity(sm).ToString("0.00"))));
}
}
148 changes: 148 additions & 0 deletions Content.Shared/CCVar/CCVars.cs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
using Content.Shared._EinsteinEngines.Supermatter.Components;
using Robust.Shared;
using Robust.Shared.Configuration;

Expand All @@ -20,6 +21,153 @@ public sealed partial class CCVars : CVars
public static readonly CVarDef<bool> DebugOptionVisualizerTest =
CVarDef.Create("debug.option_visualizer_test", false, CVar.CLIENTONLY);

/// DELTA-V CCVARS
/*
* Glimmer
*/

/// <summary>
/// Whether glimmer is enabled.
/// </summary>
public static readonly CVarDef<bool> GlimmerEnabled =
CVarDef.Create("glimmer.enabled", true, CVar.REPLICATED);

/// <summary>
/// Passive glimmer drain per second.
/// Note that this is randomized and this is an average value.
/// </summary>
public static readonly CVarDef<float> GlimmerLostPerSecond =
CVarDef.Create("glimmer.passive_drain_per_second", 0.1f, CVar.SERVERONLY);

/// <summary>
/// Whether random rolls for psionics are allowed.
/// Guaranteed psionics will still go through.
/// </summary>
public static readonly CVarDef<bool> PsionicRollsEnabled =
CVarDef.Create("psionics.rolls_enabled", true, CVar.SERVERONLY);

/// <summary>
/// Whether height & width sliders adjust a character's Fixture Component
/// </summary>
public static readonly CVarDef<bool> HeightAdjustModifiesHitbox =
CVarDef.Create("heightadjust.modifies_hitbox", true, CVar.SERVERONLY);

/// <summary>
/// Whether height & width sliders adjust a player's max view distance
/// </summary>
public static readonly CVarDef<bool> HeightAdjustModifiesZoom =
CVarDef.Create("heightadjust.modifies_zoom", false, CVar.SERVERONLY);

/// <summary>
/// Enables station goals
/// </summary>
public static readonly CVarDef<bool> StationGoalsEnabled =
CVarDef.Create("game.station_goals", true, CVar.SERVERONLY);

/// <summary>
/// Chance for a station goal to be sent
/// </summary>
public static readonly CVarDef<float> StationGoalsChance =
CVarDef.Create("game.station_goals_chance", 0.1f, CVar.SERVERONLY);

#region Contests System

/// <summary>
/// The MASTER TOGGLE for the entire Contests System.
/// ALL CONTESTS BELOW, regardless of type or setting will output 1f when false.
/// </summary>
public static readonly CVarDef<bool> DoContestsSystem =
CVarDef.Create("contests.do_contests_system", true, CVar.REPLICATED | CVar.SERVER);

/// <summary>
/// Contest functions normally include an optional override to bypass the clamp set by max_percentage.
/// This CVar disables the bypass when false, forcing all implementations to comply with max_percentage.
/// </summary>
public static readonly CVarDef<bool> AllowClampOverride =
CVarDef.Create("contests.allow_clamp_override", true, CVar.REPLICATED | CVar.SERVER);

/// <summary>
/// Toggles all MassContest functions. All mass contests output 1f when false
/// </summary>
public static readonly CVarDef<bool> DoMassContests =
CVarDef.Create("contests.do_mass_contests", true, CVar.REPLICATED | CVar.SERVER);

/// <summary>
/// Toggles all StaminaContest functions. All stamina contests output 1f when false
/// </summary>
public static readonly CVarDef<bool> DoStaminaContests =
CVarDef.Create("contests.do_stamina_contests", true, CVar.REPLICATED | CVar.SERVER);

/// <summary>
/// Toggles all HealthContest functions. All health contests output 1f when false
/// </summary>
public static readonly CVarDef<bool> DoHealthContests =
CVarDef.Create("contests.do_health_contests", true, CVar.REPLICATED | CVar.SERVER);

/// <summary>
/// Toggles all MindContest functions. All mind contests output 1f when false.
/// MindContests are not currently implemented, and are awaiting completion of the Psionic Refactor
/// </summary>
public static readonly CVarDef<bool> DoMindContests =
CVarDef.Create("contests.do_mind_contests", true, CVar.REPLICATED | CVar.SERVER);

/// <summary>
/// The maximum amount that Mass Contests can modify a physics multiplier, given as a +/- percentage
/// Default of 0.25f outputs between * 0.75f and 1.25f
/// </summary>
public static readonly CVarDef<float> MassContestsMaxPercentage =
CVarDef.Create("contests.max_percentage", 0.25f, CVar.REPLICATED | CVar.SERVER);

#endregion

#region Supermatter System

/// <summary>
/// With completely default supermatter values, Singuloose delamination will occur if engineers inject at least 900 moles of coolant per tile
/// in the crystal chamber. For reference, a gas canister contains 1800 moles of air. This Cvar directly multiplies the amount of moles required to singuloose.
/// </summary>
public static readonly CVarDef<float> SupermatterSingulooseMolesModifier =
CVarDef.Create("supermatter.singuloose_moles_modifier", 1f, CVar.SERVER);

/// <summary>
/// Toggles whether or not Singuloose delaminations can occur. If both Singuloose and Tesloose are disabled, it will always delam into a Nuke.
/// </summary>
public static readonly CVarDef<bool> SupermatterDoSingulooseDelam =
CVarDef.Create("supermatter.do_singuloose", true, CVar.SERVER);

/// <summary>
/// By default, Supermatter will "Tesloose" if the conditions for Singuloose are not met, and the core's power is at least 4000.
/// The actual reasons for being at least this amount vary by how the core was screwed up, but traditionally it's caused by "The core is on fire".
/// This Cvar multiplies said power threshold for the purpose of determining if the delam is a Tesloose.
/// </summary>
public static readonly CVarDef<float> SupermatterTesloosePowerModifier =
CVarDef.Create("supermatter.tesloose_power_modifier", 1f, CVar.SERVER);

/// <summary>
/// Toggles whether or not Tesloose delaminations can occur. If both Singuloose and Tesloose are disabled, it will always delam into a Nuke.
/// </summary>
public static readonly CVarDef<bool> SupermatterDoTeslooseDelam =
CVarDef.Create("supermatter.do_tesloose", true, CVar.SERVER);

/// <summary>
/// When true, bypass the normal checks to determine delam type, and instead use the type chosen by supermatter.forced_delam_type
/// </summary>
public static readonly CVarDef<bool> SupermatterDoForceDelam =
CVarDef.Create("supermatter.do_force_delam", false, CVar.SERVER);

/// <summary>
/// If supermatter.do_force_delam is true, this determines the delamination type, bypassing the normal checks.
/// </summary>
public static readonly CVarDef<DelamType> SupermatterForcedDelamType =
CVarDef.Create("supermatter.forced_delam_type", DelamType.Singulo, CVar.SERVER);

/// <summary>
/// Directly multiplies the amount of rads put out by the supermatter. Be VERY conservative with this.
/// </summary>
public static readonly CVarDef<float> SupermatterRadsModifier =
CVarDef.Create("supermatter.rads_modifier", 1f, CVar.SERVER);

#endregion
/// <summary>
/// Set to true to disable parallel processing in the pow3r solver.
/// </summary>
Expand Down
3 changes: 2 additions & 1 deletion Content.Shared/DoAfter/SharedDoAfterSystem.cs
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,8 @@ private void OnDamage(EntityUid uid, DoAfterComponent component, DamageChangedEv
{
// If we're applying state then let the server state handle the do_after prediction.
// This is to avoid scenarios where a do_after is erroneously cancelled on the final tick.
if (!args.InterruptsDoAfters || !args.DamageIncreased || args.DamageDelta == null || GameTiming.ApplyingState)
if (!args.InterruptsDoAfters || !args.DamageIncreased || args.DamageDelta == null || GameTiming.ApplyingState
|| args.DamageDelta.DamageDict.ContainsKey("Radiation")) //Sanity check so people can crowbar doors open to flee from Lord Singuloth
return;

var delta = args.DamageDelta.GetTotal();
Expand Down
Loading

0 comments on commit 990fce4

Please sign in to comment.