Add ambient music (#16829)

This commit is contained in:
metalgearsloth
2023-05-29 10:44:11 +10:00
committed by GitHub
parent f35fcff23f
commit 0c83642c5a
84 changed files with 1252 additions and 338 deletions

View File

@@ -0,0 +1,130 @@
using Content.Shared.Access;
using Content.Shared.Maps;
using Content.Shared.Whitelist;
using Robust.Shared.Prototypes;
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype.List;
namespace Content.Shared.Random;
/// <summary>
/// Rules-based item selection. Can be used for any sort of conditional selection
/// Every single condition needs to be true for this to be selected.
/// e.g. "choose maintenance audio if 90% of tiles nearby are maintenance tiles"
/// </summary>
[Prototype("rules")]
public sealed class RulesPrototype : IPrototype
{
[IdDataField] public string ID { get; } = string.Empty;
[DataField("rules", required: true)]
public List<RulesRule> Rules = new();
}
[ImplicitDataDefinitionForInheritors]
public abstract class RulesRule
{
}
/// <summary>
/// Returns true if the attached entity is in space.
/// </summary>
public sealed class InSpaceRule : RulesRule
{
}
/// <summary>
/// Checks for entities matching the whitelist in range.
/// This is more expensive than <see cref="NearbyComponentsRule"/> so prefer that!
/// </summary>
public sealed class NearbyEntitiesRule : RulesRule
{
/// <summary>
/// How many of the entity need to be nearby.
/// </summary>
[DataField("count")]
public int Count = 1;
[DataField("whitelist", required: true)]
public EntityWhitelist Whitelist = new();
[DataField("range")]
public float Range = 10f;
}
public sealed class NearbyTilesPercentRule : RulesRule
{
[DataField("percent", required: true)]
public float Percent;
[DataField("tiles", required: true, customTypeSerializer:typeof(PrototypeIdListSerializer<ContentTileDefinition>))]
public List<string> Tiles = new();
[DataField("range")]
public float Range = 10f;
}
/// <summary>
/// Always returns true. Used for fallbacks.
/// </summary>
public sealed class AlwaysTrueRule : RulesRule
{
}
/// <summary>
/// Returns true if on a grid or in range of one.
/// </summary>
public sealed class GridInRangeRule : RulesRule
{
[DataField("range")]
public float Range = 10f;
[DataField("inverted")]
public bool Inverted = false;
}
/// <summary>
/// Returns true if griduid and mapuid match (AKA on 'planet').
/// </summary>
public sealed class OnMapGridRule : RulesRule
{
}
/// <summary>
/// Checks for an entity nearby with the specified access.
/// </summary>
public sealed class NearbyAccessRule : RulesRule
{
// This exists because of doorelectronics contained inside doors.
/// <summary>
/// Does the access entity need to be anchored.
/// </summary>
[DataField("anchored")]
public bool Anchored = true;
/// <summary>
/// Count of entities that need to be nearby.
/// </summary>
[DataField("count")]
public int Count = 1;
[DataField("access", required: true, customTypeSerializer: typeof(PrototypeIdListSerializer<AccessLevelPrototype>))]
public List<string> Access = new();
[DataField("range")]
public float Range = 10f;
}
public sealed class NearbyComponentsRule : RulesRule
{
[DataField("count")] public int Count;
[DataField("components", required: true)]
public ComponentRegistry Components = default!;
[DataField("range")]
public float Range = 10f;
}

View File

@@ -0,0 +1,207 @@
using Content.Shared.Access.Components;
using Content.Shared.Access.Systems;
using Robust.Shared.Map;
using Robust.Shared.Map.Components;
namespace Content.Shared.Random;
public sealed class RulesSystem : EntitySystem
{
[Dependency] private readonly IMapManager _mapManager = default!;
[Dependency] private readonly ITileDefinitionManager _tileDef = default!;
[Dependency] private readonly AccessReaderSystem _reader = default!;
[Dependency] private readonly EntityLookupSystem _lookup = default!;
[Dependency] private readonly SharedTransformSystem _transform = default!;
public bool IsTrue(EntityUid uid, RulesPrototype rules)
{
foreach (var rule in rules.Rules)
{
switch (rule)
{
case AlwaysTrueRule:
break;
case GridInRangeRule griddy:
{
if (!TryComp<TransformComponent>(uid, out var xform))
{
return false;
}
if (xform.GridUid != null)
{
return !griddy.Inverted;
}
var worldPos = _transform.GetWorldPosition(xform);
foreach (var _ in _mapManager.FindGridsIntersecting(
xform.MapID,
new Box2(worldPos - griddy.Range, worldPos + griddy.Range)))
{
return !griddy.Inverted;
}
break;
}
case InSpaceRule:
{
if (!TryComp<TransformComponent>(uid, out var xform) ||
xform.GridUid != null)
{
return false;
}
break;
}
case NearbyAccessRule access:
{
var xformQuery = GetEntityQuery<TransformComponent>();
if (!xformQuery.TryGetComponent(uid, out var xform) ||
xform.MapUid == null)
{
return false;
}
var found = false;
var worldPos = _transform.GetWorldPosition(xform, xformQuery);
var count = 0;
// TODO: Update this when we get the callback version
foreach (var comp in _lookup.GetComponentsInRange<AccessReaderComponent>(xform.MapID,
worldPos, access.Range))
{
if (access.Anchored && !xformQuery.GetComponent(comp.Owner).Anchored ||
!_reader.AreAccessTagsAllowed(access.Access, comp))
{
continue;
}
count++;
if (count < access.Count)
continue;
found = true;
break;
}
if (!found)
return false;
break;
}
case NearbyComponentsRule nearbyComps:
{
if (!TryComp<TransformComponent>(uid, out var xform) ||
xform.MapUid == null)
{
return false;
}
var found = false;
var worldPos = _transform.GetWorldPosition(xform);
var count = 0;
foreach (var comp in nearbyComps.Components.Values)
{
// TODO: Update this when we get the callback version
foreach (var _ in _lookup.GetComponentsInRange(comp.Component.GetType(), xform.MapID,
worldPos, nearbyComps.Range))
{
count++;
if (count >= nearbyComps.Count)
{
found = true;
break;
}
}
if (found)
break;
}
if (!found)
return false;
break;
}
case NearbyEntitiesRule entity:
{
if (!TryComp<TransformComponent>(uid, out var xform) ||
xform.MapUid == null)
{
return false;
}
var found = false;
var worldPos = _transform.GetWorldPosition(xform);
var count = 0;
foreach (var ent in _lookup.GetEntitiesInRange(xform.MapID, worldPos, entity.Range))
{
if (!entity.Whitelist.IsValid(ent, EntityManager))
continue;
count++;
if (count < entity.Count)
continue;
found = true;
break;
}
if (!found)
return false;
break;
}
case NearbyTilesPercentRule tiles:
{
if (!TryComp<TransformComponent>(uid, out var xform) ||
!TryComp<MapGridComponent>(xform.GridUid, out var grid))
{
return false;
}
var tileCount = 0;
var matchingTileCount = 0;
foreach (var tile in grid.GetTilesIntersecting(new Circle(_transform.GetWorldPosition(xform),
tiles.Range)))
{
tileCount++;
if (!tiles.Tiles.Contains(_tileDef[tile.Tile.TypeId].ID))
continue;
matchingTileCount++;
}
if (matchingTileCount / (float) tileCount < tiles.Percent)
return false;
break;
}
case OnMapGridRule:
{
if (!TryComp<TransformComponent>(uid, out var xform) ||
xform.GridUid != xform.MapUid ||
xform.MapUid == null)
{
return false;
}
break;
}
default:
throw new NotImplementedException();
}
}
return true;
}
}