Skip to content
Draft

Mono #472

Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ protected override void Cycle(EntityUid uid, BallisticAmmoProviderComponent comp
Containers.Remove(existing, component.Container);
EnsureShootable(existing);
}
else if (component.UnspawnedCount > 0)
else if (component.UnspawnedCount > 0 && !component.InfiniteUnspawned)
{
component.UnspawnedCount--;
ent = Spawn(component.Proto, coordinates);
Expand Down
63 changes: 62 additions & 1 deletion Content.Client/_Mono/FireControl/UI/FireControlWindow.xaml.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
// Copyright Rane (elijahrane@gmail.com) 2025
// All rights reserved. Relicensed under AGPL with permission

using System.Linq;
using Content.Client.UserInterface.Controls;
using Content.Shared._Mono.FireControl;
using Content.Shared._Mono.ShipGuns;
Expand All @@ -27,6 +28,8 @@ public sealed partial class FireControlWindow : FancyWindow
// Dictionary to store weapon entity to type mapping
private readonly Dictionary<NetEntity, ShipGunType> _weaponTypes = new();

private FireControlConsoleBoundInterfaceState? _currentState;

public FireControlWindow()
{
RobustXamlLoader.Load(this);
Expand All @@ -48,6 +51,8 @@ private void SelectAllWeapons(BaseButton.ButtonEventArgs args)
}

OnWeaponSelectionChanged?.Invoke();

UpdateAllWeaponButtonTexts();
}

private void UnselectAllWeapons(BaseButton.ButtonEventArgs args)
Expand All @@ -58,6 +63,8 @@ private void UnselectAllWeapons(BaseButton.ButtonEventArgs args)
}

OnWeaponSelectionChanged?.Invoke();

UpdateAllWeaponButtonTexts();
}

private void SelectBallisticWeapons(BaseButton.ButtonEventArgs args)
Expand All @@ -81,6 +88,7 @@ private void SelectBallisticWeapons(BaseButton.ButtonEventArgs args)
}

OnWeaponSelectionChanged?.Invoke();
UpdateAllWeaponButtonTexts();
}

private void SelectEnergyWeapons(BaseButton.ButtonEventArgs args)
Expand All @@ -104,6 +112,7 @@ private void SelectEnergyWeapons(BaseButton.ButtonEventArgs args)
}

OnWeaponSelectionChanged?.Invoke();
UpdateAllWeaponButtonTexts();
}

private void SelectMissileWeapons(BaseButton.ButtonEventArgs args)
Expand All @@ -127,6 +136,48 @@ private void SelectMissileWeapons(BaseButton.ButtonEventArgs args)
}

OnWeaponSelectionChanged?.Invoke();
UpdateAllWeaponButtonTexts();
}

/// <summary>
/// Updates the text of a weapon button based on its selection state and manual reload status.
/// </summary>
private void UpdateWeaponButtonText(Button button, FireControllableEntry controllable)
{
if (button.Pressed && controllable.HasManualReload && controllable.AmmoCount.HasValue)
{
button.Text = Loc.GetString("gunnery-gun-select-ammo", ("name", controllable.Name), ("ammo", controllable.AmmoCount.Value));

if (controllable.AmmoCount.Value == 0)
{
button.ModulateSelfOverride = Color.Red;
}
else
{
button.ModulateSelfOverride = null;
}
}
else
{
button.Text = Loc.GetString("gunnery-gun-select", ("name", controllable.Name));
button.ModulateSelfOverride = null;
}
}

/// <summary>
/// Updates all weapon button texts based on current selection state.
/// </summary>
private void UpdateAllWeaponButtonTexts()
{
foreach (var (netEntity, button) in WeaponsList)
{
var controllable = _currentState?.FireControllables?.FirstOrDefault(c => c.NetEntity == netEntity);

if (controllable.HasValue)
{
UpdateWeaponButtonText(button, controllable.Value);
}
}
}

private void SelectMiningWeapons(BaseButton.ButtonEventArgs args)
Expand All @@ -151,6 +202,7 @@ private void SelectMiningWeapons(BaseButton.ButtonEventArgs args)

public void UpdateStatus(FireControlConsoleBoundInterfaceState state)
{
_currentState = state;
NavRadar.UpdateState(state.NavState);

if (state.Connected)
Expand All @@ -167,6 +219,8 @@ public void UpdateStatus(FireControlConsoleBoundInterfaceState state)

UpdateWeaponsList(state);

UpdateAllWeaponButtonTexts();

// Update the category buttons state based on whether weapons of that type are available
bool hasBallisticWeapons = false;
bool hasEnergyWeapons = false;
Expand Down Expand Up @@ -226,6 +280,7 @@ private void UpdateWeaponsList(FireControlConsoleBoundInterfaceState state)
if (WeaponsList.TryGetValue(controllable.NetEntity, out var existingButton))
{
toRemove.Remove(controllable.NetEntity);
UpdateWeaponButtonText(existingButton, controllable);
}
else
{
Expand All @@ -238,10 +293,16 @@ private void UpdateWeaponsList(FireControlConsoleBoundInterfaceState state)
Margin = new Thickness(4, 1)
};

button.OnToggled += _ => OnWeaponSelectionChanged?.Invoke();
button.OnToggled += _ =>
{
OnWeaponSelectionChanged?.Invoke();
UpdateAllWeaponButtonTexts();
};

ControllablesBox.AddChild(button);
WeaponsList.Add(controllable.NetEntity, button);

UpdateWeaponButtonText(button, controllable);
}
}

Expand Down
33 changes: 31 additions & 2 deletions Content.Server/Lightning/LightningSystem.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
using Content.Server.Lightning.Components;
using Content.Shared.Lightning;
using Robust.Server.GameObjects;
using Robust.Shared.Prototypes; // Mono
using Robust.Shared.Random;

namespace Content.Server.Lightning;
Expand All @@ -19,6 +20,7 @@ namespace Content.Server.Lightning;
public sealed class LightningSystem : SharedLightningSystem
{
[Dependency] private readonly BeamSystem _beam = default!;
[Dependency] private readonly IPrototypeManager _proto = default!; // Mono
[Dependency] private readonly IRobustRandom _random = default!;
[Dependency] private readonly EntityLookupSystem _lookup = default!;
[Dependency] private readonly TransformSystem _transform = default!;
Expand Down Expand Up @@ -48,6 +50,18 @@ private void OnRemove(EntityUid uid, LightningComponent component, ComponentRemo
/// <param name="lightningPrototype">The prototype for the lightning to be created</param>
/// <param name="triggerLightningEvents">if the lightnings being fired should trigger lightning events.</param>
public void ShootLightning(EntityUid user, EntityUid target, string lightningPrototype = "Lightning", bool triggerLightningEvents = true)
{
// Mono
EntProtoId? spawnOnHit = null;
var proto = _proto.Index(lightningPrototype);
if (proto.TryGetComponent<LightningComponent>(out var lightningComp, EntityManager.ComponentFactory))
spawnOnHit = lightningComp.SpawnOnHit;

ShootLightning(user, target, lightningPrototype, triggerLightningEvents);
}

// Mono - for optimisation purposes
private void ShootLightning(EntityUid user, EntityUid target, EntProtoId? spawnOnHit, string lightningPrototype = "Lightning", bool triggerLightningEvents = true)
{
var spriteState = LightningRandomizer();
_beam.TryCreateBeam(user, target, lightningPrototype, spriteState);
Expand All @@ -57,6 +71,9 @@ public void ShootLightning(EntityUid user, EntityUid target, string lightningPro
var ev = new HitByLightningEvent(user, target);
RaiseLocalEvent(target, ref ev);
}

if (spawnOnHit != null)
Spawn(spawnOnHit.Value, _transform.GetMapCoordinates(target));
}


Expand All @@ -70,6 +87,18 @@ public void ShootLightning(EntityUid user, EntityUid target, string lightningPro
/// <param name="arcDepth">how many times to recursively fire lightning bolts from the target points of the first shot.</param>
/// <param name="triggerLightningEvents">if the lightnings being fired should trigger lightning events.</param>
public void ShootRandomLightnings(EntityUid user, float range, int boltCount, string lightningPrototype = "Lightning", int arcDepth = 0, bool triggerLightningEvents = true)
{
// Mono
EntProtoId? spawnOnHit = null;
var proto = _proto.Index(lightningPrototype);
if (proto.TryGetComponent<LightningComponent>(out var lightningComp, EntityManager.ComponentFactory))
spawnOnHit = lightningComp.SpawnOnHit;

ShootRandomLightnings(user, range, boltCount, spawnOnHit, lightningPrototype, arcDepth, triggerLightningEvents);
}

// Mono - for optimisation purposes
private void ShootRandomLightnings(EntityUid user, float range, int boltCount, EntProtoId? spawnOnHit, string lightningPrototype = "Lightning", int arcDepth = 0, bool triggerLightningEvents = true)
{
//TODO: add support to different priority target tablem for different lightning types
//TODO: Remove Hardcode LightningTargetComponent (this should be a parameter of the SharedLightningComponent)
Expand All @@ -92,10 +121,10 @@ public void ShootRandomLightnings(EntityUid user, float range, int boltCount, st
if (!_random.Prob(curTarget.Comp.HitProbability)) //Chance to ignore target
continue;

ShootLightning(user, targets[count].Owner, lightningPrototype, triggerLightningEvents);
ShootLightning(user, targets[count].Owner, spawnOnHit, lightningPrototype, triggerLightningEvents);
if (arcDepth - targets[count].Comp.LightningResistance > 0)
{
ShootRandomLightnings(targets[count].Owner, range, 1, lightningPrototype, arcDepth - targets[count].Comp.LightningResistance, triggerLightningEvents);
ShootRandomLightnings(targets[count].Owner, range, 1, spawnOnHit, lightningPrototype, arcDepth - targets[count].Comp.LightningResistance, triggerLightningEvents);
}
shootedCount++;
}
Expand Down
13 changes: 12 additions & 1 deletion Content.Server/Weapons/Ranged/Systems/GunSystem.Ballistic.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,16 @@ namespace Content.Server.Weapons.Ranged.Systems;

public sealed partial class GunSystem
{
/// <summary>
/// Adds ammo to a ballistic ammo provider by incrementing UnspawnedCount.
/// </summary>
public void AddBallisticAmmo(EntityUid uid, BallisticAmmoProviderComponent component, int amount = 1)
{
component.UnspawnedCount += amount;

DirtyField(uid, component, nameof(BallisticAmmoProviderComponent.UnspawnedCount));
}

protected override void Cycle(EntityUid uid, BallisticAmmoProviderComponent component, MapCoordinates coordinates)
{
EntityUid? ent = null;
Expand All @@ -18,9 +28,10 @@ protected override void Cycle(EntityUid uid, BallisticAmmoProviderComponent comp
DirtyField(uid, component, nameof(BallisticAmmoProviderComponent.Entities));

Containers.Remove(existing, component.Container);
ent = existing; //Mono: Sound bugfix
EnsureShootable(existing);
}
else if (component.UnspawnedCount > 0)
else if (component.UnspawnedCount > 0 && !component.InfiniteUnspawned) // Mono - no ammo generator
{
component.UnspawnedCount--;
DirtyField(uid, component, nameof(BallisticAmmoProviderComponent.UnspawnedCount));
Expand Down
2 changes: 1 addition & 1 deletion Content.Server/Weapons/Ranged/Systems/GunSystem.cs
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ public override void Initialize()

private void OnBallisticPrice(EntityUid uid, BallisticAmmoProviderComponent component, ref PriceCalculationEvent args)
{
if (string.IsNullOrEmpty(component.Proto) || component.UnspawnedCount == 0)
if (string.IsNullOrEmpty(component.Proto) || component.UnspawnedCount == 0 || component.InfiniteUnspawned) // Mono
return;

if (!ProtoManager.TryIndex<EntityPrototype>(component.Proto, out var proto))
Expand Down
Loading
Loading