Skip to content

Commit

Permalink
Merge pull request OpenSAGE#837 from charliefoxtwo/feature/special-po…
Browse files Browse the repository at this point in the history
…wer-timers

Implement Special Power timers
  • Loading branch information
Tarcontar authored Feb 5, 2024
2 parents 4c2fd94 + 02cd5c5 commit 4ab2763
Show file tree
Hide file tree
Showing 15 changed files with 265 additions and 62 deletions.
5 changes: 5 additions & 0 deletions src/OpenSage.Game/Logic/Object/BehaviorModule.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,11 @@ internal virtual void OnDie(BehaviorUpdateContext context, DeathType deathType,

internal virtual void OnDamageStateChanged(BehaviorUpdateContext context, BodyDamageType fromDamage, BodyDamageType toDamage) { }

protected static uint FramesForMs(int ms)
{
return (uint)(Game.LogicFramesPerSecond * (ms / 1000f));
}

internal override void Load(StatePersister reader)
{
reader.PersistVersion(1);
Expand Down
25 changes: 24 additions & 1 deletion src/OpenSage.Game/Logic/Object/Create/SpecialPowerCreate.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,37 @@

namespace OpenSage.Logic.Object
{
public class SpecialPowerCreate : CreateModule
{
private readonly GameObject _gameObject;

public SpecialPowerCreate(GameObject gameObject)
{
_gameObject = gameObject;
}

protected override void OnBuildCompleteImpl()
{
foreach (var specialPowerModule in _gameObject.FindBehaviors<SpecialPowerModule>())
{
specialPowerModule.ResetCountdown();
}
}
}

/// <summary>
/// Forces the object's SpecialPower to start charging upon creation of the object. Required
/// Forces the object's SpecialPower to start charging upon creation of the object. Required
/// by special powers that have <see cref="SpecialPower.PublicTimer"/> set to <code>true</code>.
/// </summary>
public sealed class SpecialPowerCreateModuleData : CreateModuleData
{
internal static SpecialPowerCreateModuleData Parse(IniParser parser) => parser.ParseBlock(FieldParseTable);

private static readonly IniParseTable<SpecialPowerCreateModuleData> FieldParseTable = new IniParseTable<SpecialPowerCreateModuleData>();

internal override SpecialPowerCreate CreateModule(GameObject gameObject, GameContext context)
{
return new SpecialPowerCreate(gameObject);
}
}
}
9 changes: 3 additions & 6 deletions src/OpenSage.Game/Logic/Object/GameObject.cs
Original file line number Diff line number Diff line change
Expand Up @@ -797,7 +797,7 @@ public T FindBehavior<T>()
return _firstBehaviorCache!.TryGetValue(typeof(T), out var behavior) ? (T)behavior : default;
}

internal IEnumerable<T> FindBehaviors<T>()
public IEnumerable<T> FindBehaviors<T>()
{
if (_behaviorCache == null)
{
Expand Down Expand Up @@ -1155,12 +1155,9 @@ internal void UpdateUpgradeableModules()
{
var completedUpgrades = GetUpgradesCompleted();

foreach (var module in _modules)
foreach (var upgradeableModule in FindBehaviors<IUpgradeableModule>())
{
if (module is IUpgradeableModule upgradeableModule)
{
upgradeableModule.TryUpgrade(completedUpgrades);
}
upgradeableModule.TryUpgrade(completedUpgrades);
}
}

Expand Down
11 changes: 7 additions & 4 deletions src/OpenSage.Game/Logic/Object/SpecialPower.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
using System;
using System;
using OpenSage.Audio;
using OpenSage.Content;
using OpenSage.Data.Ini;
Expand All @@ -18,7 +18,7 @@ internal static SpecialPower Parse(IniParser parser)
private static readonly IniParseTable<SpecialPower> FieldParseTable = new()
{
{ "Enum", (parser, x) => x.Type = parser.ParseEnum<SpecialPowerType>() },
{ "ReloadTime", (parser, x) => x.ReloadTime = parser.ParseLong() },
{ "ReloadTime", (parser, x) => x.ReloadTime = parser.ParseInteger() },
{ "RequiredScience", (parser, x) => x.RequiredSciences = new[] { parser.ParseScienceReference() } },
{ "PublicTimer", (parser, x) => x.PublicTimer = parser.ParseBoolean() },
{ "SharedSyncedTimer", (parser, x) => x.SharedSyncedTimer = parser.ParseBoolean() },
Expand All @@ -45,7 +45,10 @@ internal static SpecialPower Parse(IniParser parser)
};

public SpecialPowerType Type { get; private set; }
public long ReloadTime { get; private set; }
/// <summary>
/// The time for the special power to reload, in ms.
/// </summary>
public int ReloadTime { get; private set; }
public bool PublicTimer { get; private set; }
public bool SharedSyncedTimer { get; private set; }
public LazyAssetReference<BaseAudioEventInfo> InitiateSound { get; private set; }
Expand Down Expand Up @@ -79,7 +82,7 @@ internal static SpecialPower Parse(IniParser parser)
public int ForbiddenObjectRange { get; private set; }

[AddedIn(SageGame.Bfme2)]
public LazyAssetReference<Science>[] RequiredSciences { get; private set; }
public LazyAssetReference<Science>[] RequiredSciences { get; private set; } = [];

[AddedIn(SageGame.Bfme2)]
public string UnitSpecificSoundToUseAsInitiateIntendToDoVoice { get; private set; }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,10 @@ namespace OpenSage.Logic.Object
{
public sealed class CashBountyPower : SpecialPowerModule
{
internal CashBountyPower(GameObject gameObject, GameContext context, CashBountyPowerModuleData moduleData) : base(gameObject, context, moduleData)
{
}

internal override void Load(StatePersister reader)
{
reader.PersistVersion(1);
Expand All @@ -25,9 +29,9 @@ public sealed class CashBountyPowerModuleData : SpecialPowerModuleData

public Percentage Bounty { get; private set; }

internal override BehaviorModule CreateModule(GameObject gameObject, GameContext context)
internal override CashBountyPower CreateModule(GameObject gameObject, GameContext context)
{
return new CashBountyPower();
return new CashBountyPower(gameObject, context, this);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,10 @@ namespace OpenSage.Logic.Object
{
public sealed class CashHackSpecialPower : SpecialPowerModule
{
internal CashHackSpecialPower(GameObject gameObject, GameContext context, CashHackSpecialPowerModuleData moduleData) : base(gameObject, context, moduleData)
{
}

internal override void Load(StatePersister reader)
{
reader.PersistVersion(1);
Expand Down Expand Up @@ -37,9 +41,9 @@ public sealed class CashHackSpecialPowerModuleData : SpecialPowerModuleData
/// </summary>
public int MoneyAmount { get; private set; }

internal override BehaviorModule CreateModule(GameObject gameObject, GameContext context)
internal override CashHackSpecialPower CreateModule(GameObject gameObject, GameContext context)
{
return new CashHackSpecialPower();
return new CashHackSpecialPower(gameObject, context, this);
}
}

Expand Down
10 changes: 7 additions & 3 deletions src/OpenSage.Game/Logic/Object/SpecialPower/CleanupAreaPower.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,12 @@

namespace OpenSage.Logic.Object
{
public sealed class CleanupAreaPower : BehaviorModule
public sealed class CleanupAreaPower : SpecialPowerModule
{
internal CleanupAreaPower(GameObject gameObject, GameContext context, CleanupAreaPowerModuleData moduleData) : base(gameObject, context, moduleData)
{
}

internal override void Load(StatePersister reader)
{
reader.PersistVersion(1);
Expand Down Expand Up @@ -36,9 +40,9 @@ public sealed class CleanupAreaPowerModuleData : SpecialPowerModuleData

public float MaxMoveDistanceFromLocation { get; private set; }

internal override BehaviorModule CreateModule(GameObject gameObject, GameContext context)
internal override CleanupAreaPower CreateModule(GameObject gameObject, GameContext context)
{
return new CleanupAreaPower();
return new CleanupAreaPower(gameObject, context, this);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,10 @@ namespace OpenSage.Logic.Object
{
public sealed class DefectorSpecialPower : SpecialPowerModule
{
internal DefectorSpecialPower(GameObject gameObject, GameContext context, DefectorSpecialPowerModuleData moduleData) : base(gameObject, context, moduleData)
{
}

internal override void Load(StatePersister reader)
{
reader.PersistVersion(1);
Expand All @@ -15,7 +19,7 @@ internal override void Load(StatePersister reader)
}

/// <summary>
/// When used in junction with the SPECIAL_DEFECTOR special power, the unit will defect to
/// When used in junction with the SPECIAL_DEFECTOR special power, the unit will defect to
/// your side.
/// </summary>
public sealed class DefectorSpecialPowerModuleData : SpecialPowerModuleData
Expand All @@ -25,9 +29,9 @@ public sealed class DefectorSpecialPowerModuleData : SpecialPowerModuleData
private static new readonly IniParseTable<DefectorSpecialPowerModuleData> FieldParseTable = SpecialPowerModuleData.FieldParseTable
.Concat(new IniParseTable<DefectorSpecialPowerModuleData>());

internal override BehaviorModule CreateModule(GameObject gameObject, GameContext context)
internal override DefectorSpecialPower CreateModule(GameObject gameObject, GameContext context)
{
return new DefectorSpecialPower();
return new DefectorSpecialPower(gameObject, context, this);
}
}
}
15 changes: 4 additions & 11 deletions src/OpenSage.Game/Logic/Object/SpecialPower/OCLSpecialPower.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,23 +9,19 @@ namespace OpenSage.Logic.Object
public class OCLSpecialPowerModule : SpecialPowerModule
{
private readonly OCLSpecialPowerModuleData _moduleData;
private readonly GameObject _gameObject;
private readonly GameContext _context;
private bool _activated = false;
private Vector3 _position;

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

internal override void Update(BehaviorUpdateContext context)
{
if (_activated)
{
_context.ObjectCreationLists.CreateAtPosition(_moduleData.OCL.Value, context, _position);
Context.ObjectCreationLists.CreateAtPosition(_moduleData.OCL.Value, context, _position);
_activated = false;
}
}
Expand All @@ -34,11 +30,8 @@ internal override void Activate(Vector3 position)
{
_position = position;
_activated = true;
}

internal bool Matches(SpecialPower specialPower)
{
return _moduleData.SpecialPower.Value == specialPower;
base.Activate(position);
}

internal override void Load(StatePersister reader)
Expand Down Expand Up @@ -99,7 +92,7 @@ public sealed class OCLSpecialPowerModuleData : SpecialPowerModuleData
[AddedIn(SageGame.Bfme2)]
public WeatherType ChangeWeather { get; private set; }

internal override BehaviorModule CreateModule(GameObject gameObject, GameContext context)
internal override OCLSpecialPowerModule CreateModule(GameObject gameObject, GameContext context)
{
return new OCLSpecialPowerModule(gameObject, context, this);
}
Expand Down
8 changes: 6 additions & 2 deletions src/OpenSage.Game/Logic/Object/SpecialPower/SpecialAbility.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,10 @@ public sealed class SpecialAbilityModule : SpecialPowerModule
{
// TODO

internal SpecialAbilityModule(GameObject gameObject, GameContext context, SpecialAbilityModuleData moduleData) : base(gameObject, context, moduleData)
{
}

internal override void Load(StatePersister reader)
{
reader.PersistVersion(1);
Expand All @@ -23,9 +27,9 @@ public sealed class SpecialAbilityModuleData : SpecialPowerModuleData
private static new readonly IniParseTable<SpecialAbilityModuleData> FieldParseTable = SpecialPowerModuleData.FieldParseTable
.Concat(new IniParseTable<SpecialAbilityModuleData>());

internal override BehaviorModule CreateModule(GameObject gameObject, GameContext context)
internal override SpecialAbilityModule CreateModule(GameObject gameObject, GameContext context)
{
return new SpecialAbilityModule();
return new SpecialAbilityModule(gameObject, context, this);
}
}
}
Loading

0 comments on commit 4ab2763

Please sign in to comment.