Skip to content

Commit

Permalink
Implement EjectPilotDie
Browse files Browse the repository at this point in the history
Determination between whether the unit is in the air or on the ground is still to be done
  • Loading branch information
charliefoxtwo authored and Tarcontar committed Feb 2, 2024
1 parent 9b93648 commit d225593
Show file tree
Hide file tree
Showing 6 changed files with 86 additions and 38 deletions.
12 changes: 6 additions & 6 deletions src/OpenSage.Game/Logic/Object/Behaviors/SlowDeathBehavior.cs
Original file line number Diff line number Diff line change
Expand Up @@ -38,9 +38,9 @@ internal bool IsApplicable(DeathType deathType, ObjectStatus? status) =>

private bool IsCorrectStatus(ObjectStatus? status)
{
var required = !_moduleData.RequiredStatus.AnyBitSet || // if nothing is required, we pass
var required = _moduleData.RequiredStatus == null || // if nothing is required, we pass
(status.HasValue && _moduleData.RequiredStatus.Get(status.Value)); // or if we are the one of the required statuses, we pass
var notExempt = !_moduleData.ExemptStatus.AnyBitSet || // if nothing is exempt, we pass
var notExempt = _moduleData.ExemptStatus == null || // if nothing is exempt, we pass
!status.HasValue || // if we don't have a status, we can't be exempt, so we pass
!_moduleData.ExemptStatus.Get(status.Value); // or if we are not one of the exempt statuses, we pass
return required && notExempt;
Expand Down Expand Up @@ -204,10 +204,10 @@ public class SlowDeathBehaviorModuleData : UpdateModuleData
{ "DoNotRandomizeMidpoint", (parser, x) => x.DoNotRandomizeMidpoint = parser.ParseBoolean() }
};

public BitArray<DeathType> DeathTypes { get; private set; }
public BitArray<ObjectStatus> RequiredStatus { get; private set; }
public BitArray<ObjectStatus> ExemptStatus { get; private set; }
public int ProbabilityModifier { get; private set; }
public BitArray<DeathType>? DeathTypes { get; private set; }
public BitArray<ObjectStatus>? RequiredStatus { get; private set; }
public BitArray<ObjectStatus>? ExemptStatus { get; private set; }
public int ProbabilityModifier { get; private set; } = 100;
public Percentage ModifierBonusPerOverkillPercent { get; private set; }
public float SinkRate { get; private set; }
public LogicFrameSpan SinkDelay { get; private set; }
Expand Down
11 changes: 7 additions & 4 deletions src/OpenSage.Game/Logic/Object/Die/DieModule.cs
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ internal override void Load(StatePersister reader)

internal sealed override void OnDie(BehaviorUpdateContext context, DeathType deathType, ObjectStatus? status)
{
if (!IsCorrectStatus(status))
if (!IsCorrectStatus(status) || !IsCorrectDeathType(deathType))
{
return;
}
Expand All @@ -41,6 +41,11 @@ private bool IsCorrectStatus(ObjectStatus? status)
return required && notExempt;
}

private bool IsCorrectDeathType(DeathType deathType)
{
return ModuleData.DeathTypes == null || ModuleData.DeathTypes.Get(deathType);
}

private protected virtual void Die(BehaviorUpdateContext context, DeathType deathType) { }
}

Expand All @@ -50,14 +55,12 @@ public abstract class DieModuleData : BehaviorModuleData

internal static readonly IniParseTable<DieModuleData> FieldParseTable = new IniParseTable<DieModuleData>
{
{ "VeterancyLevels", (parser, x) => x.VeterancyLevels = parser.ParseEnumBitArray<VeterancyLevel>() },
{ "DeathTypes", (parser, x) => x.DeathTypes = parser.ParseEnumBitArray<DeathType>() },
{ "ExemptStatus", (parser, x) => x.ExemptStatus = parser.ParseEnum<ObjectStatus>() },
{ "RequiredStatus", (parser, x) => x.RequiredStatus = parser.ParseEnum<ObjectStatus>() }
};

public BitArray<VeterancyLevel> VeterancyLevels { get; private set; }
public BitArray<DeathType> DeathTypes { get; private set; }
public BitArray<DeathType>? DeathTypes { get; private set; }
public ObjectStatus? ExemptStatus { get; private set; }
public ObjectStatus? RequiredStatus { get; private set; }
}
Expand Down
40 changes: 36 additions & 4 deletions src/OpenSage.Game/Logic/Object/Die/EjectPilotDie.cs
Original file line number Diff line number Diff line change
@@ -1,13 +1,38 @@
using OpenSage.Content;
using OpenSage.Content;
using OpenSage.Data.Ini;
using OpenSage.Mathematics;

namespace OpenSage.Logic.Object
{
public sealed class EjectPilotDie : DieModule
{
// TODO
public EjectPilotDie(EjectPilotDieModuleData moduleData) : base(moduleData)
private readonly GameObject _gameObject;
private readonly GameContext _context;
private readonly EjectPilotDieModuleData _moduleData;

internal EjectPilotDie(GameObject gameObject, GameContext context, EjectPilotDieModuleData moduleData) : base(moduleData)
{
_gameObject = gameObject;
_context = context;
_moduleData = moduleData;
}

private protected override void Die(BehaviorUpdateContext context, DeathType deathType)
{
var veterancy = (VeterancyLevel)_gameObject.Rank;

if (!_moduleData.VeterancyLevels.Get(veterancy))
{
return;
}

var isOnGround = true; // todo: determine if unit is airborne
var creationList = isOnGround ? _moduleData.GroundCreationList : _moduleData.AirCreationList;
foreach (var gameObject in _context.ObjectCreationLists.Create(creationList.Value, context))
{
gameObject.Rank = _gameObject.Rank;
_context.AudioSystem.PlayAudioEvent(gameObject, _gameObject.Definition.UnitSpecificSounds.VoiceEject?.Value);
}
}

internal override void Load(StatePersister reader)
Expand All @@ -31,10 +56,17 @@ public sealed class EjectPilotDieModuleData : DieModuleData
.Concat(new IniParseTable<EjectPilotDieModuleData>
{
{ "GroundCreationList", (parser, x) => x.GroundCreationList = parser.ParseObjectCreationListReference() },
{ "AirCreationList", (parser, x) => x.AirCreationList = parser.ParseObjectCreationListReference() }
{ "AirCreationList", (parser, x) => x.AirCreationList = parser.ParseObjectCreationListReference() },
{ "VeterancyLevels", (parser, x) => x.VeterancyLevels = parser.ParseEnumBitArray<VeterancyLevel>() },
});

public LazyAssetReference<ObjectCreationList> GroundCreationList { get; private set; }
public LazyAssetReference<ObjectCreationList> AirCreationList { get; private set; }
public BitArray<VeterancyLevel> VeterancyLevels { get; private set; }

internal override BehaviorModule CreateModule(GameObject gameObject, GameContext context)
{
return new EjectPilotDie(gameObject, context, this);
}
}
}
50 changes: 29 additions & 21 deletions src/OpenSage.Game/Logic/Object/GameObject.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1203,34 +1203,42 @@ internal void Die(DeathType deathType)

if (!construction)
{
// If there are multiple SlowDeathBehavior modules,
// we need to use ProbabilityModifier to choose between them.
var slowDeathBehaviors = FindBehaviors<SlowDeathBehavior>()
.Where(x => x.IsApplicable(deathType, _status))
.ToList();
if (slowDeathBehaviors.Count > 1)
ExecuteRandomSlowDeathBehavior(deathType);
}

foreach (var module in _behaviorModules)
{
if (module is SlowDeathBehavior)
{
var sumProbabilityModifiers = slowDeathBehaviors.Sum(x => x.ProbabilityModifier);
var random = _gameContext.Random.Next(sumProbabilityModifiers);
var cumulative = 0;
foreach (var deathBehavior in slowDeathBehaviors)
{
cumulative += deathBehavior.ProbabilityModifier;
if (random < cumulative)
{
deathBehavior.OnDie(_behaviorUpdateContext, deathType, _status);
return;
}
}
throw new InvalidOperationException();
// this is handled above
continue;
}

module.OnDie(_behaviorUpdateContext, deathType, _status);
}

PlayDieSound(deathType);
}

foreach (var module in _behaviorModules)
private void ExecuteRandomSlowDeathBehavior(DeathType deathType)
{
// If there are multiple SlowDeathBehavior modules,
// we need to use ProbabilityModifier to choose between them.
var slowDeathBehaviors = FindBehaviors<SlowDeathBehavior>()
.Where(x => x.IsApplicable(deathType, _status))
.ToList();

var sumProbabilityModifiers = slowDeathBehaviors.Sum(x => x.ProbabilityModifier);
var random = _gameContext.Random.Next(sumProbabilityModifiers);
var cumulative = 0;
foreach (var deathBehavior in slowDeathBehaviors)
{
module.OnDie(_behaviorUpdateContext, deathType, _status);
cumulative += deathBehavior.ProbabilityModifier;
if (random < cumulative)
{
deathBehavior.OnDie(_behaviorUpdateContext, deathType, _status);
return;
}
}
}

Expand Down
10 changes: 7 additions & 3 deletions src/OpenSage.Game/Logic/Object/ObjectCreationList.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,16 @@ namespace OpenSage.Logic.Object
{
internal sealed class ObjectCreationListManager
{
public void Create(ObjectCreationList list, BehaviorUpdateContext context)
public IEnumerable<GameObject> Create(ObjectCreationList list, BehaviorUpdateContext context)
{
var objects = new List<GameObject>();

foreach (var item in list.Nuggets)
{
item.Execute(context);
objects.AddRange(item.Execute(context));
}

return objects;
}

public void CreateAtPosition(ObjectCreationList list, BehaviorUpdateContext context, Vector3 position)
Expand Down Expand Up @@ -225,7 +229,7 @@ public sealed class CreateObjectOCNugget : OCNugget

public LazyAssetReference<ObjectDefinition>[] ObjectNames { get; private set; }
public Vector3 Offset { get; private set; }
public int Count { get; private set; }
public int Count { get; private set; } = 1;
public bool SpreadFormation { get; private set; }
public float MinDistanceAFormation { get; private set; }
public float MinDistanceBFormation { get; private set; }
Expand Down
1 change: 1 addition & 0 deletions src/OpenSage.Game/Logic/Object/UnitSpecificSounds.cs
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ public sealed class UnitSpecificSounds : Dictionary<string, LazyAssetReference<B
public LazyAssetReference<BaseAudioEventInfo>? VoiceEnterHostile => TryGetValue("VoiceEnterHostile", out var sound) ? sound : null;
public LazyAssetReference<BaseAudioEventInfo>? VoiceGarrison => TryGetValue("VoiceGarrison", out var sound) ? sound : null;
public LazyAssetReference<BaseAudioEventInfo>? VoiceGetHealed => TryGetValue("VoiceGetHealed", out var sound) ? sound : null;
public LazyAssetReference<BaseAudioEventInfo>? VoiceEject => TryGetValue("VoiceEject", out var sound) ? sound : null;

internal static UnitSpecificSounds Parse(IniParser parser)
{
Expand Down

0 comments on commit d225593

Please sign in to comment.