Files
LuaCsForBarotraumaEP/Barotrauma/BarotraumaShared/SharedSource/Characters/Talents/Abilities/CharacterAbility.cs
T
2024-04-24 18:09:05 +03:00

139 lines
5.6 KiB
C#

using System;
using System.Reflection;
namespace Barotrauma.Abilities
{
abstract class CharacterAbility
{
public CharacterAbilityGroup CharacterAbilityGroup { get; }
public CharacterTalent CharacterTalent { get; }
public Character Character { get; }
public bool RequiresAlive { get; }
public virtual bool AllowClientSimulation => false;
public virtual bool AppliesEffectOnIntervalUpdate => false;
private const float DefaultEffectTime = 1.0f;
// currently resets if the character dies. would need to be stored in a dictionary of sorts to maintain through death
/// <summary>
/// Used primarily for StatusEffects. Default to constant outside interval abilities.
/// </summary>
protected float EffectDeltaTime => CharacterAbilityGroup is CharacterAbilityGroupInterval abilityGroupInterval ? abilityGroupInterval.TimeSinceLastUpdate : DefaultEffectTime;
public CharacterAbility(CharacterAbilityGroup characterAbilityGroup, ContentXElement abilityElement)
{
CharacterAbilityGroup = characterAbilityGroup ?? throw new ArgumentNullException(nameof(characterAbilityGroup));
CharacterTalent = characterAbilityGroup.CharacterTalent;
Character = CharacterTalent.Character;
RequiresAlive = abilityElement.GetAttributeBool("requiresalive", true);
}
public bool IsViable()
{
if (!AllowClientSimulation && GameMain.NetworkMember is { IsClient: true }) { return false; }
if (RequiresAlive && Character.IsDead) { return false; }
return true;
}
public virtual void InitializeAbility(bool addingFirstTime) { }
public virtual void UpdateCharacterAbility(bool conditionsMatched, float timeSinceLastUpdate)
{
// may need a separate Update for changing state on non-interval-based abilities
if (AppliesEffectOnIntervalUpdate)
{
if (conditionsMatched)
{
ApplyEffect();
}
}
else
{
VerifyState(conditionsMatched, timeSinceLastUpdate);
}
}
protected virtual void VerifyState(bool conditionsMatched, float timeSinceLastUpdate)
{
DebugConsole.ThrowError($"Error in talent {CharacterTalent.DebugIdentifier}: Ability {this} does not have an implementation for VerifyState! This ability does not work in interval ability groups.",
contentPackage: CharacterTalent.Prefab.ContentPackage);
}
public void ApplyAbilityEffect(AbilityObject abilityObject)
{
if (abilityObject is null)
{
ApplyEffect();
}
else
{
ApplyEffect(abilityObject);
}
}
protected virtual void ApplyEffect()
{
DebugConsole.AddWarning($"Ability {this} used improperly! This ability does not have a definition for ApplyEffect in talent {CharacterTalent.DebugIdentifier}",
CharacterTalent.Prefab.ContentPackage);
}
protected virtual void ApplyEffect(AbilityObject abilityObject)
{
DebugConsole.AddWarning($"Ability {this} used improperly! This ability does not take a parameter for ApplyEffect in talent {CharacterTalent.DebugIdentifier}",
CharacterTalent.Prefab.ContentPackage);
}
protected void LogAbilityObjectMismatch()
{
DebugConsole.ThrowError($"Incompatible ability! Ability {this} is incompatitible with this type of ability effect type in talent {CharacterTalent.DebugIdentifier}",
contentPackage: CharacterTalent.Prefab.ContentPackage);
}
// XML
public static CharacterAbility Load(ContentXElement abilityElement, CharacterAbilityGroup characterAbilityGroup, bool errorMessages = true)
{
Type abilityType;
string type = abilityElement.Name.ToString().ToLowerInvariant();
try
{
abilityType = ReflectionUtils.GetTypeWithBackwardsCompatibility("Barotrauma.Abilities", type, false, true);
if (abilityType == null)
{
if (errorMessages) DebugConsole.ThrowError("Could not find the CharacterAbility \"" + type + "\" (" + characterAbilityGroup.CharacterTalent.DebugIdentifier + ")",
contentPackage: abilityElement.ContentPackage);
return null;
}
}
catch (Exception e)
{
if (errorMessages)
{
DebugConsole.ThrowError("Could not find the CharacterAbility \"" + type + "\" (" + characterAbilityGroup.CharacterTalent.DebugIdentifier + ")", e,
contentPackage: abilityElement.ContentPackage);
}
return null;
}
object[] args = { characterAbilityGroup, abilityElement };
CharacterAbility characterAbility;
try
{
characterAbility = (CharacterAbility)Activator.CreateInstance(abilityType, args);
}
catch (TargetInvocationException e)
{
DebugConsole.ThrowError("Error while creating an instance of a CharacterAbility of the type " + abilityType + ".", e.InnerException,
contentPackage: abilityElement.ContentPackage);
return null;
}
return characterAbility;
}
}
}