G4XIS2NEM4WHRP2775YBCLFDT7JZZS52CMEHY3PA43QSXL45XNDAC
QOAVQCDV2MRAPUX62ZLDTUB6AXYSAGEEWIEZIG4TGIQKCLP5T5GAC
HUULCHM5GFGZ7GKLCULFHC333LQ3LBI62VKII3YL5O4C5CDGCT4AC
2SLVO3SYIJQOEV2YNSD73BSUSWQNZVROQCGHJCPCDSMCCNKZTQFQC
FNS4LRFQNFM4BCB23CYHOWA2N4MG2DEUMNK6D55BQ26TX6OJLIBQC
XF52N4U7HWXOF4PDSCR7LCUENLTSXLWEZGS2IJ6562KYI567Z2GAC
WKHLLZ3K732M7VJ5KWDSLRWZUARDNDP6ODAXD6SW43CHCT5DX5SAC
LAFCS4AAOMBOBURWXRZEDUI4J5QGBP7CJQXIPLKXEDXNBCVE7SLQC
RZAMG2H2NY73KZJIV4VXLJHJVSRGJDRWWZJERAI6O7AVDW64JEQQC
IDXWT3DH3C3X7PP4VVKUZTCGDALW6NH7KREI4E2VFQVMCBJKDMTAC
MHN2B5YZ2Y4G3O7UOZJKFQ3SSP5HTNJCXFKCO3KYY46I2GHM3TIQC
I33Z5QD6JHPO7W7G3EHGBIXQABW6ZOC2W4NJP6L5ENDPFRORUFNAC
6UYO5OFJ5JDP3ANPDJ3NG66EQHMTBAAP6K4LPRG3DH34R2S4VZUAC
VPXUP5WZTVC3OVD73TNKPK43IAGFXGUGCEJT56JM4IT4APYQXUHAC
DTKCWM4J7PFNWAAES3RZHQGDA6PTDNX4TZVOXAKF5V7LCZBI3XUAC
OXMN3LHBNH7CWHEZRPSZTN244O3ACTOEKZEAKQNKFXQ7VQSM26YQC
L2SE4UCTEU4R7JSHG2J5H6RZPRN4SGBMXK3WCRED2HARX5JEN2AQC
R475KN7MR3OG7EBLVNOO7QRIKXDGY2PIDXXV3HW4KBD5QM7B5OJQC
IFN4UDLTN7TD26CPONDCRHW4G3DJEXEYV62ZHZC4QD7DKJ76JAEQC
CD5FF75KTOBTMVMTMCKMR6F5DFKOF26I5K43ITNHGBI3ZAZHA4RAC
HXTSBPAP75A7EC4RKWYQMVPPHPNZFPHUORBZWDHGEB6MPAGI7G7AC
6ET6RCSSOEHFM5GPIG7LDITMTLL2VHNENY2IEHKXQNQJI7VG6EEAC
public void AddCurrentModifier<TResource, TUnitType>(TResource resource, Unit<TUnitType> value) where TResource : Resource<TUnitType> where TUnitType : IUnitType {
var modifier = new PermanentStatModifier<TUnitType> {
Amount = value
};
CancellationToken _cancellationToken = CancellationToken.None;
public void AddCapacityModifier<TResource, TUnitType>(TResource resource, Unit<TUnitType> value) where TResource : Resource<TUnitType> where TUnitType : IUnitType {
var modifier = new PermanentStatModifier<TUnitType> {
Amount = value
};
resource.AddPermanentCapacityModifier(modifier);
public StatModifierAccessor(CancellationToken cancellationToken) {
_cancellationToken = cancellationToken;
public void AddPermanentCapacityModifier(PermanentStatModifier<TUnitType> modifier) {
_capacity.AddPermanentModifier(modifier);
OnChanged?.Invoke(this, (OnChangeArgs)this);
public void AddCapacityModifier(StatModifier<TUnitType> modifier, CancellationToken cancelToken) {
AddModifier(modifier, _capacity, cancelToken);
public void AddPermanentCurrentModifier(PermanentStatModifier<TUnitType> modifier) {
_current.AddPermanentModifier(modifier);
OnChanged?.Invoke(this, (OnChangeArgs)this);
public void AddCurrentModifier(StatModifier<TUnitType> modifier, CancellationToken cancelToken) {
AddModifier(modifier, _current, cancelToken);
if (stat.AddTransientModifier(modifier)) {
StartCoroutine(ExpireModifiers(modifier.ExpiryTime, stat));
}
cancelToken.Register(() => {
OnResourceChanged((ResourceChangeArgs)this);
});
Debug.Log($"AddTransientModifier {transform.name}.{GetType().Name}.{typeof(TStatType).Name}");
OnChanged?.Invoke(this, (OnChangeArgs)this);
}
stat.AddModifier(modifier, cancelToken);
protected IEnumerator ExpireModifiers<TStatType>(double expiryTime, Stat<TStatType> stat)
where TStatType : IStatType {
var timeToWait = (float)(expiryTime - Time.timeAsDouble);
yield return new WaitForSeconds(timeToWait);
Debug.Log($"AddModifier {transform.name}.{GetType().Name}.{typeof(TStatType).Name}");
OnResourceChanged((ResourceChangeArgs)this);
}
Debug.Log($"Retiring modifiers of {transform.name}.{GetType().Name}.{typeof(TStatType).Name} with expiry < {expiryTime}");
stat.Retire(expiryTime);
OnChanged?.Invoke(this, (OnChangeArgs)this);
public event EventHandler<ResourceChangeArgs> ResourceChanged;
public static explicit operator ResourceChangeArgs(Resource<TUnitType> resource) {
return new((int)resource.GetCurrent(), (int)resource.GetCapacity(), resource.transform);
public event EventHandler<OnChangeArgs> OnChanged;
public static explicit operator OnChangeArgs(Resource<TUnitType> resource) {
return new((int)resource.GetCurrent(), (int)resource.GetCapacity(), resource.transform);
void OnResourceChanged(ResourceChangeArgs e) {
ResourceChanged?.Invoke(this, e);
/// <Summary>
/// Adds a new permanent modifier to the stat. Taken into account in <paramref name="Base"/> property.
/// </Summary>
public void AddPermanentModifier(PermanentStatModifier<TUnitType> modifier) {
Base += modifier.Amount;
public Unit<TUnitType> Modified {
get;
private set;
/// <Summary>
/// Adds a new transient modifier to the stat. Taken into account in <paramref name="Modified"/> and <paramref name="Value"/> properties.
/// </Summary>
/// <returns>
/// True when a transient modifier with a new expiry time is inserted.
/// False when a transient modifier with the same expiry time is already present.
/// </returns>
public bool AddTransientModifier(TransientStatModifier<TUnitType> modifier) {
_modifiers.Add(modifier);
return _expiry.Add(modifier.ExpiryTime);
public Unit<TUnitType> Total => Base + Modified;
public void AddModifier(StatModifier<TUnitType> modifier, CancellationToken cancelToken) {
if (cancelToken == CancellationToken.None) {
Base += modifier.Amount;
}
else {
AddTransientModifier(modifier, cancelToken);
}
public void Retire(double expiryTime) {
_modifiers = _modifiers.Where(modifier => modifier.ExpiryTime > expiryTime).ToList();
_expiry.Remove(expiryTime);
void AddTransientModifier(StatModifier<TUnitType> modifier, CancellationToken cancelToken) {
LinkedListNode<StatModifier<TUnitType>> node = new(modifier);
_modifiers.AddFirst(node);
Modified += modifier.Amount;
cancelToken.Register(() => {
_modifiers.Remove(node);
Modified -= modifier.Amount;
});
fileFormatVersion: 2
guid: 75d3569cf2cac3942ace199d3f57185a
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
using System.Collections;
using TagFighter.Effects.Triggers;
using TagFighter.Resources;
using UnityEngine;
namespace TagFighter.Effects
{
public class PawnCondition : MonoBehaviour
{
public void Apply() {
Debug.Log("Apply a new condition");
Debug.Log($"Origin: {Origin} Caster: {Context.Caster} Target: {Context.EffectLocation}");
Trigger.Register(this);
StartCoroutine(SelfDestruct());
}
public void OnTrigger() {
EffectInput data = new(Context, Context.GetAffectedUnits(), new PermanentStatModifierAccessor());
foreach (var effect in Context.EffectsToTrigger) {
effect.DelayedAction(data);
}
Destroy(this);
}
}
}
}
protected void OnDestroy() {
Trigger.UnRegister();
}
yield return new WaitForSeconds((float)Duration);
IEnumerator SelfDestruct() {
double _duration;
Transform _origin;
EffectContext _context;
ITrigger _trigger;
public double Duration { get => _duration; set => _duration = value; }
public Transform Origin { get => _origin; set => _origin = value; }
public EffectContext Context { get => _context; set => _context = value; }
public ITrigger Trigger { get => _trigger; set => _trigger = value; }
fileFormatVersion: 2
guid: 0ed9a99045057be48bae44742b4d2a00
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
fileFormatVersion: 2
guid: 83af9b93e6ef2a24a964511656caa8e5
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
using System.Threading;
namespace TagFighter.Effects
{
public class TransientPawnCondition : PawnCondition
{
CancellationTokenSource _cancellationSource;
protected override void SetStatModifier() {
_cancellationSource = new();
StatModifier = new(_cancellationSource.Token);
}
protected override void OnDestroySpecific() {
_cancellationSource.Cancel();
_cancellationSource.Dispose();
}
}
}
fileFormatVersion: 2
guid: 75d3569cf2cac3942ace199d3f57185a
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
using TagFighter.Effects.Triggers;
using TagFighter.Resources;
using UnityEngine;
namespace TagFighter.Effects
{
public class PawnCondition : MonoBehaviour
{
public Transform Origin { get; set; }
public EffectContext Context { get; set; }
public ITrigger ApplyTrigger { get; set; }
public ITrigger EndTrigger { get; set; }
protected StatModifierAccessor StatModifier;
public void Apply() {
Debug.Log("Apply a new condition");
Debug.Log($"Origin: {Origin} Caster: {Context.Caster} Target: {Context.EffectLocation}");
SetStatModifier();
ApplyTrigger.Register(this);
ApplyTrigger.TriggerConditionMet += ApplyTrigger_OnTriggerConditionMet;
EndTrigger.Register(this);
EndTrigger.TriggerConditionMet += EndTrigger_OnTriggerConditionMet;
}
protected virtual void SetStatModifier() {
StatModifier = StatModifierAccessor.Permanent;
}
void EndTrigger_OnTriggerConditionMet(object sender, ConditionTriggerArgs e) {
Debug.Log($"{nameof(EndTrigger_OnTriggerConditionMet)}");
Destroy(this);
}
void ApplyTrigger_OnTriggerConditionMet(object sender, ConditionTriggerArgs e) {
Debug.Log($"{nameof(ApplyTrigger_OnTriggerConditionMet)}");
EffectInput data = new(Context, Context.GetAffectedUnits(), StatModifier);
foreach (var effect in Context.EffectsToTrigger) {
effect.DelayedAction(data);
}
}
protected void OnDestroy() {
ApplyTrigger.TriggerConditionMet -= ApplyTrigger_OnTriggerConditionMet;
ApplyTrigger.UnRegister();
EndTrigger.TriggerConditionMet -= EndTrigger_OnTriggerConditionMet;
EndTrigger.UnRegister();
OnDestroySpecific();
}
protected virtual void OnDestroySpecific() {
}
}
}
protected override void Trigger(int current, int before, int threshold) {
if (current > before + threshold) {
Condition.OnTrigger();
}
protected override bool ShouldTrigger(int current, int before, int threshold) {
return current > before + threshold;
protected override void Trigger(int current, int before, int threshold) {
if (current < before - threshold) {
Condition.OnTrigger();
}
protected override bool ShouldTrigger(int current, int before, int threshold) {
return current < before - threshold;
public class TransientWeave : IImmediateEffect
{
public ResourceInfoGet<IResourceTypeAccessor, ResourceLocationAccessors.Get.Context> Duration;
public void ImmediateAction(EffectContext context, IEffect effect) {
EffectInput data = new(context, context.GetAffectedUnits(), new PermanentStatModifierAccessor());
if (effect != null) {
effect.Apply(data);
data.Affected = context.GetAffectedUnits();
}
/// Currently Duration is Context getter so there's only a single value in the iterator.
/// To support get from pawns, requires somekind of aggregation operator from <see cref="IResourceOperator"/>
/// to be included in this
var duration = Duration.Get(data).First();
data.StatAccessor = new TransientStatModifierAccessor(duration);
Materialize(data);
}
void Materialize(EffectInput data) {
foreach (var effect in data.Context.EffectsToTrigger) {
effect.DelayedAction(data);
}
data.Context.EffectsToTrigger.Clear();
}
}
[Serializable]
/// Currently Duration is Context getter so there's only a single value in the iterator.
/// To support get from pawns, requires somekind of aggregation operator from <see cref="IResourceOperator"/>
/// to be included in this
var duration = Duration.Get(data).First();
duration = Math.Clamp(duration, MinFrequency, MaxDuration);
var condition = affectedPawn.gameObject.AddComponent<PawnCondition>();
condition.Duration = duration;
condition.Trigger = Trigger.ShallowCopy();
var condition = IsPermanent ? affectedPawn.gameObject.AddComponent<PawnCondition>() : affectedPawn.gameObject.AddComponent<TransientPawnCondition>();
condition.EndTrigger = EndTrigger.ShallowCopy();
condition.ApplyTrigger = ApplyTrigger.ShallowCopy();
- rid: 4320157394915295262
type: {class: Capacity, ns: TagFighter.Effects.ResourceLocationAccessors.PawnProperties,
asm: Assembly-CSharp}
- rid: 4320157623323459588
type: {class: OnTimePass, ns: TagFighter.Effects.Triggers, asm: Assembly-CSharp}
data:
_frequency: 5
- rid: 4320157394915295239
type: {class: OnResourceIncrease, ns: TagFighter.Effects.Triggers, asm: Assembly-CSharp}
data:
Resource:
rid: 4320157394915295240
Stat:
rid: 4320157394915295263
Threshold: 0
- rid: 4320157394915295240
type: {class: Pain, ns: TagFighter.Effects.ResourceTypeAccessors, asm: Assembly-CSharp}