S7-03 + S7-04 + S7-05
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
using GeometryTD.Definition;
|
||||
using GeometryTD.Entity.EntityData;
|
||||
using GeometryTD;
|
||||
using GeometryTD.Entity;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Components
|
||||
@@ -76,6 +77,9 @@ namespace Components
|
||||
{
|
||||
BaseDamage = _attackDamage,
|
||||
AttackPropertyType = attackPropertyType,
|
||||
SourceEntityId = ResolveSourceEntityId(),
|
||||
ProjectileEntityId = bulletEntityId,
|
||||
OriginPosition = spawnPoint.position,
|
||||
TagRuntimes = CloneTagRuntimes(_tagRuntimes)
|
||||
};
|
||||
BulletData bulletData = new BulletData(
|
||||
@@ -114,5 +118,11 @@ namespace Components
|
||||
|
||||
return cloned;
|
||||
}
|
||||
|
||||
private int ResolveSourceEntityId()
|
||||
{
|
||||
TowerEntity towerEntity = GetComponentInParent<TowerEntity>();
|
||||
return towerEntity != null ? towerEntity.Id : 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using System;
|
||||
using GeometryTD.CustomUtility;
|
||||
using UnityEngine;
|
||||
|
||||
namespace GeometryTD.Definition
|
||||
{
|
||||
@@ -8,6 +9,9 @@ namespace GeometryTD.Definition
|
||||
{
|
||||
public int BaseDamage { get; set; }
|
||||
public AttackPropertyType AttackPropertyType { get; set; }
|
||||
public int SourceEntityId { get; set; }
|
||||
public int ProjectileEntityId { get; set; }
|
||||
public Vector3 OriginPosition { get; set; }
|
||||
public TagRuntimeData[] TagRuntimes { get; set; } = Array.Empty<TagRuntimeData>();
|
||||
|
||||
public AttackPayload Clone()
|
||||
@@ -16,6 +20,9 @@ namespace GeometryTD.Definition
|
||||
{
|
||||
BaseDamage = BaseDamage,
|
||||
AttackPropertyType = AttackPropertyType,
|
||||
SourceEntityId = SourceEntityId,
|
||||
ProjectileEntityId = ProjectileEntityId,
|
||||
OriginPosition = OriginPosition,
|
||||
TagRuntimes = InventoryCloneUtility.CloneTagRuntimes(TagRuntimes)
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,7 +1,26 @@
|
||||
using System;
|
||||
using GeometryTD.Entity;
|
||||
using UnityEngine;
|
||||
|
||||
namespace GeometryTD.Definition
|
||||
{
|
||||
[Serializable]
|
||||
public sealed class HitStatusModifierContext
|
||||
{
|
||||
public float BonusBurnDurationSeconds { get; set; }
|
||||
public float BonusBurnDamagePerSecond { get; set; }
|
||||
public float BonusSlowDurationSeconds { get; set; }
|
||||
public float BonusSlowRatio { get; set; }
|
||||
|
||||
public void Reset()
|
||||
{
|
||||
BonusBurnDurationSeconds = 0f;
|
||||
BonusBurnDamagePerSecond = 0f;
|
||||
BonusSlowDurationSeconds = 0f;
|
||||
BonusSlowRatio = 0f;
|
||||
}
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
public sealed class HitContext
|
||||
{
|
||||
@@ -9,5 +28,35 @@ namespace GeometryTD.Definition
|
||||
public int FinalDamage { get; set; }
|
||||
public bool IsCriticalHit { get; set; }
|
||||
public bool IsKilled { get; set; }
|
||||
public int TargetEntityId { get; set; }
|
||||
public Vector3 TargetPosition { get; set; }
|
||||
public int TargetCurrentHealthBeforeHit { get; set; }
|
||||
public int TargetCurrentHealthAfterHit { get; set; }
|
||||
public int TargetMaxHealth { get; set; }
|
||||
public float TargetMoveSpeedMultiplierBeforeHit { get; set; } = 1f;
|
||||
public TagType[] TargetStatusTagsBeforeHit { get; set; } = Array.Empty<TagType>();
|
||||
public EnemyTagStatusRuntime TargetStatusRuntime { get; set; }
|
||||
public float? CritRoll { get; set; }
|
||||
public HitStatusModifierContext StatusModifierContext { get; set; } = new HitStatusModifierContext();
|
||||
|
||||
public bool HasTargetStatus(TagType tagType)
|
||||
{
|
||||
if (tagType == TagType.None || TargetStatusTagsBeforeHit == null || TargetStatusTagsBeforeHit.Length <= 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
for (int i = 0; i < TargetStatusTagsBeforeHit.Length; i++)
|
||||
{
|
||||
if (TargetStatusTagsBeforeHit[i] == tagType)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public bool HasSlowStatusBeforeHit => TargetMoveSpeedMultiplierBeforeHit < 0.999f || HasTargetStatus(TagType.Ice);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,12 +4,7 @@ namespace GeometryTD.Definition
|
||||
{
|
||||
public static class NumericTagEffectHandler
|
||||
{
|
||||
public static void ApplyBeforeHit(
|
||||
HitContext hitContext,
|
||||
int targetCurrentHealth,
|
||||
int targetMaxHealth,
|
||||
bool targetHasSlowStatus,
|
||||
float? critRoll = null)
|
||||
public static void ApplyBeforeHit(HitContext hitContext)
|
||||
{
|
||||
if (hitContext == null || hitContext.AttackPayload == null)
|
||||
{
|
||||
@@ -42,21 +37,22 @@ namespace GeometryTD.Definition
|
||||
switch (runtime.TagType)
|
||||
{
|
||||
case TagType.Crit:
|
||||
ApplyCrit(hitContext, runtime.TotalStack, definition.Config as CritTagConfig, critRoll);
|
||||
ApplyCrit(hitContext, runtime.TotalStack, definition.Config as CritTagConfig);
|
||||
break;
|
||||
case TagType.Execution:
|
||||
ApplyExecution(hitContext, runtime.TotalStack, targetCurrentHealth, targetMaxHealth, definition.Config as ExecutionTagConfig);
|
||||
ApplyExecution(hitContext, runtime.TotalStack, definition.Config as ExecutionTagConfig);
|
||||
break;
|
||||
case TagType.Shatter:
|
||||
ApplyShatter(hitContext, runtime.TotalStack, targetHasSlowStatus, definition.Config as ShatterTagConfig);
|
||||
ApplyShatter(hitContext, runtime.TotalStack, definition.Config as ShatterTagConfig);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
hitContext.IsKilled = targetCurrentHealth > 0 && hitContext.FinalDamage >= targetCurrentHealth;
|
||||
hitContext.IsKilled = hitContext.TargetCurrentHealthBeforeHit > 0 &&
|
||||
hitContext.FinalDamage >= hitContext.TargetCurrentHealthBeforeHit;
|
||||
}
|
||||
|
||||
private static void ApplyCrit(HitContext hitContext, int stack, CritTagConfig config, float? critRoll)
|
||||
private static void ApplyCrit(HitContext hitContext, int stack, CritTagConfig config)
|
||||
{
|
||||
if (config == null || !config.IsImplemented || stack <= 0)
|
||||
{
|
||||
@@ -64,7 +60,7 @@ namespace GeometryTD.Definition
|
||||
}
|
||||
|
||||
float chance = Mathf.Clamp01(stack * config.CritChancePerStack);
|
||||
float resolvedCritRoll = critRoll ?? Random.value;
|
||||
float resolvedCritRoll = hitContext.CritRoll ?? Random.value;
|
||||
if (resolvedCritRoll > chance)
|
||||
{
|
||||
return;
|
||||
@@ -77,16 +73,14 @@ namespace GeometryTD.Definition
|
||||
private static void ApplyExecution(
|
||||
HitContext hitContext,
|
||||
int stack,
|
||||
int targetCurrentHealth,
|
||||
int targetMaxHealth,
|
||||
ExecutionTagConfig config)
|
||||
{
|
||||
if (config == null || !config.IsImplemented || stack <= 0 || targetMaxHealth <= 0)
|
||||
if (config == null || !config.IsImplemented || stack <= 0 || hitContext.TargetMaxHealth <= 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
float healthRatio = Mathf.Clamp01((float)Mathf.Max(0, targetCurrentHealth) / targetMaxHealth);
|
||||
float healthRatio = Mathf.Clamp01((float)Mathf.Max(0, hitContext.TargetCurrentHealthBeforeHit) / hitContext.TargetMaxHealth);
|
||||
if (healthRatio > config.TargetHealthThreshold)
|
||||
{
|
||||
return;
|
||||
@@ -96,14 +90,14 @@ namespace GeometryTD.Definition
|
||||
hitContext.FinalDamage = Mathf.Max(0, Mathf.RoundToInt(hitContext.FinalDamage * multiplier));
|
||||
}
|
||||
|
||||
private static void ApplyShatter(HitContext hitContext, int stack, bool targetHasSlowStatus, ShatterTagConfig config)
|
||||
private static void ApplyShatter(HitContext hitContext, int stack, ShatterTagConfig config)
|
||||
{
|
||||
if (config == null || !config.IsImplemented || stack <= 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (config.RequiresSlowedTarget && !targetHasSlowStatus)
|
||||
if (config.RequiresSlowedTarget && !hitContext.HasSlowStatusBeforeHit)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
+3
-5
@@ -7,11 +7,9 @@ namespace GeometryTD.Definition
|
||||
{
|
||||
public abstract TagType TagType { get; }
|
||||
|
||||
public virtual void Apply(AttackPayload attackPayload, EnemyTagStatusRuntime runtime,
|
||||
TagRuntimeData runtimeData)
|
||||
public virtual void Apply(HitContext hitContext, TagRuntimeData runtimeData)
|
||||
{
|
||||
_ = attackPayload;
|
||||
_ = runtime;
|
||||
_ = hitContext;
|
||||
_ = runtimeData;
|
||||
}
|
||||
|
||||
@@ -29,4 +27,4 @@ namespace GeometryTD.Definition
|
||||
return 1f;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,10 +8,11 @@ namespace GeometryTD.Definition
|
||||
{
|
||||
public override TagType TagType => TagType.Fire;
|
||||
|
||||
public override void Apply(AttackPayload attackPayload, EnemyTagStatusRuntime runtime,
|
||||
TagRuntimeData runtimeData)
|
||||
public override void Apply(HitContext hitContext, TagRuntimeData runtimeData)
|
||||
{
|
||||
Debug.Assert(TagDefinitionRegistry.TryGetDefinition(TagType, out TagDefinition definition));
|
||||
Debug.Assert(hitContext != null);
|
||||
Debug.Assert(hitContext.TargetStatusRuntime != null);
|
||||
|
||||
FireTagConfig config = definition.Config as FireTagConfig;
|
||||
Debug.Assert(config != null);
|
||||
@@ -20,11 +21,13 @@ namespace GeometryTD.Definition
|
||||
return;
|
||||
}
|
||||
|
||||
EnemyTagStatusRuntime runtime = hitContext.TargetStatusRuntime;
|
||||
FireTagState state = runtime.GetOrCreateState<FireTagState>(TagType);
|
||||
int infernoStack = TagEffectResolver.GetTagStack(attackPayload?.TagRuntimes, TagType.Inferno);
|
||||
int effectiveStack = Mathf.Max(0, Mathf.Min(runtimeData.TotalStack, config.MaxEffectiveStack));
|
||||
HitStatusModifierContext modifierContext = hitContext.StatusModifierContext ?? new HitStatusModifierContext();
|
||||
float burnDamagePerSecond = Mathf.Max(
|
||||
0f,
|
||||
config.BurnDamagePerSecondPerStack * runtimeData.TotalStack + GetInfernoBonusDamagePerSecond(infernoStack));
|
||||
config.BurnDamagePerSecondPerStack * effectiveStack + modifierContext.BonusBurnDamagePerSecond);
|
||||
|
||||
if (burnDamagePerSecond <= 0f)
|
||||
{
|
||||
@@ -33,7 +36,7 @@ namespace GeometryTD.Definition
|
||||
|
||||
state.RemainingDuration = Mathf.Max(
|
||||
state.RemainingDuration,
|
||||
config.BurnDurationSeconds + GetInfernoBonusDuration(infernoStack));
|
||||
config.BurnDurationSeconds + modifierContext.BonusBurnDurationSeconds);
|
||||
state.DamagePerSecond = Mathf.Max(state.DamagePerSecond, burnDamagePerSecond);
|
||||
runtime.Activate(TagType);
|
||||
}
|
||||
@@ -68,39 +71,5 @@ namespace GeometryTD.Definition
|
||||
state.PendingDamage = 0f;
|
||||
return false;
|
||||
}
|
||||
|
||||
private static float GetInfernoBonusDuration(int infernoStack)
|
||||
{
|
||||
if (infernoStack <= 0 ||
|
||||
!TagDefinitionRegistry.TryGetDefinition(TagType.Inferno, out TagDefinition definition))
|
||||
{
|
||||
return 0f;
|
||||
}
|
||||
|
||||
InfernoTagConfig infernoConfig = definition.Config as InfernoTagConfig;
|
||||
if (infernoConfig == null || !infernoConfig.IsImplemented)
|
||||
{
|
||||
return 0f;
|
||||
}
|
||||
|
||||
return infernoStack * infernoConfig.BonusBurnDurationSeconds;
|
||||
}
|
||||
|
||||
private static float GetInfernoBonusDamagePerSecond(int infernoStack)
|
||||
{
|
||||
if (infernoStack <= 0 ||
|
||||
!TagDefinitionRegistry.TryGetDefinition(TagType.Inferno, out TagDefinition definition))
|
||||
{
|
||||
return 0f;
|
||||
}
|
||||
|
||||
InfernoTagConfig infernoConfig = definition.Config as InfernoTagConfig;
|
||||
if (infernoConfig == null || !infernoConfig.IsImplemented)
|
||||
{
|
||||
return 0f;
|
||||
}
|
||||
|
||||
return infernoStack * infernoConfig.BonusBurnDamagePerSecondPerStack;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+2
-2
@@ -6,8 +6,8 @@ namespace GeometryTD.Definition
|
||||
public interface IEnemyStatusTagEffect
|
||||
{
|
||||
TagType TagType { get; }
|
||||
void Apply(AttackPayload attackPayload, EnemyTagStatusRuntime runtime, TagRuntimeData runtimeData);
|
||||
void Apply(HitContext hitContext, TagRuntimeData runtimeData);
|
||||
bool Tick(EnemyTagStatusRuntime runtime, float deltaTime, Action<int> applyDamage);
|
||||
float GetMoveSpeedMultiplier(EnemyTagStatusRuntime runtime);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,10 +8,10 @@ namespace GeometryTD.Definition
|
||||
{
|
||||
public override TagType TagType => TagType.Ice;
|
||||
|
||||
public override void Apply(AttackPayload attackPayload, EnemyTagStatusRuntime runtime,
|
||||
TagRuntimeData runtimeData)
|
||||
public override void Apply(HitContext hitContext, TagRuntimeData runtimeData)
|
||||
{
|
||||
_ = attackPayload;
|
||||
Debug.Assert(hitContext != null);
|
||||
Debug.Assert(hitContext.TargetStatusRuntime != null);
|
||||
Debug.Assert(runtimeData != null);
|
||||
Debug.Assert(runtimeData.TotalStack > 0);
|
||||
Debug.Assert(TagDefinitionRegistry.TryGetDefinition(TagType, out TagDefinition definition));
|
||||
@@ -23,13 +23,14 @@ namespace GeometryTD.Definition
|
||||
return;
|
||||
}
|
||||
|
||||
EnemyTagStatusRuntime runtime = hitContext.TargetStatusRuntime;
|
||||
IceTagState state = runtime.GetOrCreateState<IceTagState>(TagType);
|
||||
int absoluteZeroStack = TagEffectResolver.GetTagStack(attackPayload?.TagRuntimes, TagType.AbsoluteZero);
|
||||
float slowRatio = runtimeData.TotalStack * config.SlowRatioPerStack + GetAbsoluteZeroBonusSlowRatio(absoluteZeroStack);
|
||||
HitStatusModifierContext modifierContext = hitContext.StatusModifierContext ?? new HitStatusModifierContext();
|
||||
float slowRatio = runtimeData.TotalStack * config.SlowRatioPerStack + modifierContext.BonusSlowRatio;
|
||||
float slowMultiplier = Mathf.Max(config.MinMoveSpeedMultiplier, 1f - slowRatio);
|
||||
state.RemainingDuration = Mathf.Max(
|
||||
state.RemainingDuration,
|
||||
config.SlowDurationSeconds + GetAbsoluteZeroBonusDuration(absoluteZeroStack));
|
||||
config.SlowDurationSeconds + modifierContext.BonusSlowDurationSeconds);
|
||||
state.SlowMultiplier = Mathf.Min(state.SlowMultiplier, slowMultiplier);
|
||||
runtime.Activate(TagType);
|
||||
}
|
||||
@@ -49,39 +50,5 @@ namespace GeometryTD.Definition
|
||||
IceTagState state = runtime.GetState<IceTagState>(TagType);
|
||||
return state == null ? 1f : state.SlowMultiplier;
|
||||
}
|
||||
|
||||
private static float GetAbsoluteZeroBonusDuration(int absoluteZeroStack)
|
||||
{
|
||||
if (absoluteZeroStack <= 0 ||
|
||||
!TagDefinitionRegistry.TryGetDefinition(TagType.AbsoluteZero, out TagDefinition definition))
|
||||
{
|
||||
return 0f;
|
||||
}
|
||||
|
||||
AbsoluteZeroTagConfig absoluteZeroConfig = definition.Config as AbsoluteZeroTagConfig;
|
||||
if (absoluteZeroConfig == null || !absoluteZeroConfig.IsImplemented)
|
||||
{
|
||||
return 0f;
|
||||
}
|
||||
|
||||
return absoluteZeroStack * absoluteZeroConfig.BonusSlowDurationSeconds;
|
||||
}
|
||||
|
||||
private static float GetAbsoluteZeroBonusSlowRatio(int absoluteZeroStack)
|
||||
{
|
||||
if (absoluteZeroStack <= 0 ||
|
||||
!TagDefinitionRegistry.TryGetDefinition(TagType.AbsoluteZero, out TagDefinition definition))
|
||||
{
|
||||
return 0f;
|
||||
}
|
||||
|
||||
AbsoluteZeroTagConfig absoluteZeroConfig = definition.Config as AbsoluteZeroTagConfig;
|
||||
if (absoluteZeroConfig == null || !absoluteZeroConfig.IsImplemented)
|
||||
{
|
||||
return 0f;
|
||||
}
|
||||
|
||||
return absoluteZeroStack * absoluteZeroConfig.BonusSlowRatioPerStack;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,37 +5,58 @@ namespace GeometryTD.Definition
|
||||
{
|
||||
public static class TagEffectResolver
|
||||
{
|
||||
public static HitContext ResolveBeforeHit(
|
||||
AttackPayload attackPayload,
|
||||
int targetCurrentHealth,
|
||||
int targetMaxHealth,
|
||||
bool targetHasSlowStatus,
|
||||
float? critRoll = null)
|
||||
private static readonly HitStatusModifierContext EmptyStatusModifierContext = new HitStatusModifierContext();
|
||||
|
||||
public static HitContext ResolveBeforeHit(HitContext hitContext)
|
||||
{
|
||||
_ = targetHasSlowStatus;
|
||||
AttackPayload resolvedPayload = attackPayload?.Clone() ?? new AttackPayload();
|
||||
HitContext hitContext = new HitContext
|
||||
if (hitContext == null)
|
||||
{
|
||||
return new HitContext
|
||||
{
|
||||
AttackPayload = new AttackPayload()
|
||||
};
|
||||
}
|
||||
|
||||
AttackPayload resolvedPayload = hitContext.AttackPayload?.Clone() ?? new AttackPayload();
|
||||
HitContext resolvedContext = new HitContext
|
||||
{
|
||||
AttackPayload = resolvedPayload,
|
||||
FinalDamage = Mathf.Max(0, resolvedPayload.BaseDamage),
|
||||
IsCriticalHit = false,
|
||||
IsKilled = targetCurrentHealth > 0 && resolvedPayload.BaseDamage >= targetCurrentHealth
|
||||
IsKilled = hitContext.TargetCurrentHealthBeforeHit > 0 &&
|
||||
resolvedPayload.BaseDamage >= hitContext.TargetCurrentHealthBeforeHit,
|
||||
TargetEntityId = hitContext.TargetEntityId,
|
||||
TargetPosition = hitContext.TargetPosition,
|
||||
TargetCurrentHealthBeforeHit = hitContext.TargetCurrentHealthBeforeHit,
|
||||
TargetCurrentHealthAfterHit = hitContext.TargetCurrentHealthAfterHit,
|
||||
TargetMaxHealth = hitContext.TargetMaxHealth,
|
||||
TargetMoveSpeedMultiplierBeforeHit = hitContext.TargetMoveSpeedMultiplierBeforeHit,
|
||||
TargetStatusTagsBeforeHit = hitContext.TargetStatusTagsBeforeHit ?? System.Array.Empty<TagType>(),
|
||||
TargetStatusRuntime = hitContext.TargetStatusRuntime,
|
||||
CritRoll = hitContext.CritRoll,
|
||||
StatusModifierContext = new HitStatusModifierContext()
|
||||
};
|
||||
|
||||
NumericTagEffectHandler.ApplyBeforeHit(
|
||||
hitContext,
|
||||
targetCurrentHealth,
|
||||
targetMaxHealth,
|
||||
targetHasSlowStatus,
|
||||
critRoll);
|
||||
return hitContext;
|
||||
NumericTagEffectHandler.ApplyBeforeHit(resolvedContext);
|
||||
return resolvedContext;
|
||||
}
|
||||
|
||||
public static void ApplyAfterHit(AttackPayload attackPayload, EnemyTagStatusRuntime targetStatusRuntime)
|
||||
public static void ApplyAfterHit(HitContext hitContext)
|
||||
{
|
||||
if (attackPayload != null && targetStatusRuntime != null)
|
||||
if (hitContext?.StatusModifierContext == null)
|
||||
{
|
||||
TagRuntimeData[] tagRuntimes = attackPayload.TagRuntimes;
|
||||
if (hitContext != null)
|
||||
{
|
||||
hitContext.StatusModifierContext = new HitStatusModifierContext();
|
||||
}
|
||||
}
|
||||
|
||||
hitContext?.StatusModifierContext?.Reset();
|
||||
ApplyStatusModifiers(hitContext);
|
||||
|
||||
if (hitContext?.AttackPayload != null && hitContext.TargetStatusRuntime != null)
|
||||
{
|
||||
TagRuntimeData[] tagRuntimes = hitContext.AttackPayload.TagRuntimes;
|
||||
if (tagRuntimes != null && tagRuntimes.Length > 0)
|
||||
{
|
||||
foreach (var tag in tagRuntimes)
|
||||
@@ -55,15 +76,12 @@ namespace GeometryTD.Definition
|
||||
continue;
|
||||
}
|
||||
|
||||
effect.Apply(attackPayload, targetStatusRuntime, tag);
|
||||
effect.Apply(hitContext, tag);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
AttackShapeTagEffectHandler.Apply(new HitContext
|
||||
{
|
||||
AttackPayload = attackPayload
|
||||
}, TagTriggerPhase.OnAfterHit);
|
||||
AttackShapeTagEffectHandler.Apply(hitContext, TagTriggerPhase.OnAfterHit);
|
||||
}
|
||||
|
||||
public static void ApplyOnHit(HitContext hitContext)
|
||||
@@ -95,5 +113,65 @@ namespace GeometryTD.Definition
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
private static void ApplyStatusModifiers(HitContext hitContext)
|
||||
{
|
||||
if (hitContext?.AttackPayload?.TagRuntimes == null || hitContext.AttackPayload.TagRuntimes.Length <= 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
HitStatusModifierContext modifierContext = hitContext.StatusModifierContext ?? EmptyStatusModifierContext;
|
||||
for (int i = 0; i < hitContext.AttackPayload.TagRuntimes.Length; i++)
|
||||
{
|
||||
TagRuntimeData runtime = hitContext.AttackPayload.TagRuntimes[i];
|
||||
if (runtime == null || runtime.TotalStack <= 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!TagDefinitionRegistry.TryGetDefinition(runtime.TagType, out TagDefinition definition) ||
|
||||
definition == null ||
|
||||
definition.Category != TagCategory.StatusModifier ||
|
||||
definition.TriggerPhase != TagTriggerPhase.OnAfterHit ||
|
||||
definition.Config == null ||
|
||||
!definition.Config.IsImplemented)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
switch (runtime.TagType)
|
||||
{
|
||||
case TagType.Inferno:
|
||||
ApplyInfernoModifier(runtime.TotalStack, definition.Config as InfernoTagConfig, modifierContext);
|
||||
break;
|
||||
case TagType.AbsoluteZero:
|
||||
ApplyAbsoluteZeroModifier(runtime.TotalStack, definition.Config as AbsoluteZeroTagConfig, modifierContext);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void ApplyInfernoModifier(int stack, InfernoTagConfig config, HitStatusModifierContext modifierContext)
|
||||
{
|
||||
if (config == null || stack <= 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
modifierContext.BonusBurnDurationSeconds += stack * config.BonusBurnDurationSeconds;
|
||||
modifierContext.BonusBurnDamagePerSecond += stack * config.BonusBurnDamagePerSecondPerStack;
|
||||
}
|
||||
|
||||
private static void ApplyAbsoluteZeroModifier(int stack, AbsoluteZeroTagConfig config, HitStatusModifierContext modifierContext)
|
||||
{
|
||||
if (config == null || stack <= 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
modifierContext.BonusSlowDurationSeconds += stack * config.BonusSlowDurationSeconds;
|
||||
modifierContext.BonusSlowRatio += stack * config.BonusSlowRatioPerStack;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,8 +8,5 @@ namespace GeometryTD.Definition
|
||||
public BurnSpreadTagConfig(bool isImplemented) : base(isImplemented)
|
||||
{
|
||||
}
|
||||
|
||||
public float SpreadRadius { get; set; } = 0f;
|
||||
public float SpreadDamageRate { get; set; } = 0f;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,7 +8,5 @@ namespace GeometryTD.Definition
|
||||
public FreezeMaskTagConfig(bool isImplemented) : base(isImplemented)
|
||||
{
|
||||
}
|
||||
|
||||
public float FreezeBuildUpPerStack { get; set; } = 0f;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,8 +8,5 @@ namespace GeometryTD.Definition
|
||||
public IgniteBurstTagConfig(bool isImplemented) : base(isImplemented)
|
||||
{
|
||||
}
|
||||
|
||||
public float BurstRadius { get; set; } = 0f;
|
||||
public float BurstDamageRate { get; set; } = 0f;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,8 +8,5 @@ namespace GeometryTD.Definition
|
||||
public OverpenetrateTagConfig(bool isImplemented) : base(isImplemented)
|
||||
{
|
||||
}
|
||||
|
||||
public int ExtraPenetrationCount { get; set; } = 0;
|
||||
public float RemainingDamageRate { get; set; } = 0f;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,7 +8,5 @@ namespace GeometryTD.Definition
|
||||
public PierceTagConfig(bool isImplemented) : base(isImplemented)
|
||||
{
|
||||
}
|
||||
|
||||
public int ExtraPierceCount { get; set; } = 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -69,16 +69,16 @@ namespace GeometryTD.Definition
|
||||
return new Dictionary<TagType, TagDefinition>
|
||||
{
|
||||
[TagType.Fire] = CreateDefinition(TagType.Fire, TagCategory.Status, TagTriggerPhase.OnAfterHit, new FireTagConfig(true)),
|
||||
[TagType.BurnSpread] = CreateDefinition(TagType.BurnSpread, TagCategory.AttackShape, TagTriggerPhase.OnKill, new BurnSpreadTagConfig(false)),
|
||||
[TagType.IgniteBurst] = CreateDefinition(TagType.IgniteBurst, TagCategory.AttackShape, TagTriggerPhase.OnKill, new IgniteBurstTagConfig(false)),
|
||||
[TagType.BurnSpread] = CreateDefinition(TagType.BurnSpread, TagCategory.AttackShape, TagTriggerPhase.None, new BurnSpreadTagConfig(false)),
|
||||
[TagType.IgniteBurst] = CreateDefinition(TagType.IgniteBurst, TagCategory.AttackShape, TagTriggerPhase.None, new IgniteBurstTagConfig(false)),
|
||||
[TagType.Inferno] = CreateDefinition(TagType.Inferno, TagCategory.StatusModifier, TagTriggerPhase.OnAfterHit, new InfernoTagConfig(true)),
|
||||
[TagType.Ice] = CreateDefinition(TagType.Ice, TagCategory.Status, TagTriggerPhase.OnAfterHit, new IceTagConfig(true)),
|
||||
[TagType.FreezeMask] = CreateDefinition(TagType.FreezeMask, TagCategory.AttackShape, TagTriggerPhase.OnAfterHit, new FreezeMaskTagConfig(false)),
|
||||
[TagType.FreezeMask] = CreateDefinition(TagType.FreezeMask, TagCategory.AttackShape, TagTriggerPhase.None, new FreezeMaskTagConfig(false)),
|
||||
[TagType.Shatter] = CreateDefinition(TagType.Shatter, TagCategory.NumericModifier, TagTriggerPhase.OnBeforeHit, new ShatterTagConfig(true)),
|
||||
[TagType.AbsoluteZero] = CreateDefinition(TagType.AbsoluteZero, TagCategory.StatusModifier, TagTriggerPhase.OnAfterHit, new AbsoluteZeroTagConfig(true)),
|
||||
[TagType.Pierce] = CreateDefinition(TagType.Pierce, TagCategory.AttackShape, TagTriggerPhase.OnHit, new PierceTagConfig(false)),
|
||||
[TagType.Pierce] = CreateDefinition(TagType.Pierce, TagCategory.AttackShape, TagTriggerPhase.None, new PierceTagConfig(false)),
|
||||
[TagType.Crit] = CreateDefinition(TagType.Crit, TagCategory.NumericModifier, TagTriggerPhase.OnBeforeHit, new CritTagConfig(true)),
|
||||
[TagType.Overpenetrate] = CreateDefinition(TagType.Overpenetrate, TagCategory.AttackShape, TagTriggerPhase.OnHit, new OverpenetrateTagConfig(false)),
|
||||
[TagType.Overpenetrate] = CreateDefinition(TagType.Overpenetrate, TagCategory.AttackShape, TagTriggerPhase.None, new OverpenetrateTagConfig(false)),
|
||||
[TagType.Execution] = CreateDefinition(TagType.Execution, TagCategory.NumericModifier, TagTriggerPhase.OnBeforeHit, new ExecutionTagConfig(true))
|
||||
};
|
||||
}
|
||||
|
||||
@@ -115,14 +115,23 @@ namespace GeometryTD.Entity
|
||||
return;
|
||||
}
|
||||
|
||||
HitContext hitContext = TagEffectResolver.ResolveBeforeHit(
|
||||
attackPayload,
|
||||
_currentHealth,
|
||||
_maxHealth,
|
||||
HasSlowStatus);
|
||||
HitContext hitContext = TagEffectResolver.ResolveBeforeHit(new HitContext
|
||||
{
|
||||
AttackPayload = attackPayload,
|
||||
TargetEntityId = Id,
|
||||
TargetPosition = CachedTransform.position,
|
||||
TargetCurrentHealthBeforeHit = _currentHealth,
|
||||
TargetCurrentHealthAfterHit = _currentHealth,
|
||||
TargetMaxHealth = _maxHealth,
|
||||
TargetMoveSpeedMultiplierBeforeHit = _tagStatusRuntime.GetMoveSpeedMultiplier(),
|
||||
TargetStatusTagsBeforeHit = _tagStatusRuntime.GetActiveTagSnapshot(),
|
||||
TargetStatusRuntime = _tagStatusRuntime
|
||||
});
|
||||
ApplyDirectDamage(hitContext.FinalDamage);
|
||||
hitContext.TargetCurrentHealthAfterHit = _currentHealth;
|
||||
hitContext.IsKilled = _currentHealth <= 0;
|
||||
TagEffectResolver.ApplyOnHit(hitContext);
|
||||
TagEffectResolver.ApplyAfterHit(hitContext.AttackPayload, _tagStatusRuntime);
|
||||
TagEffectResolver.ApplyAfterHit(hitContext);
|
||||
if (hitContext.IsKilled)
|
||||
{
|
||||
TagEffectResolver.ApplyOnKill(hitContext);
|
||||
|
||||
@@ -15,6 +15,16 @@ namespace GeometryTD.Entity
|
||||
return _statesByTag.ContainsKey(tagType);
|
||||
}
|
||||
|
||||
public TagType[] GetActiveTagSnapshot()
|
||||
{
|
||||
if (_activeTags.Count <= 0)
|
||||
{
|
||||
return Array.Empty<TagType>();
|
||||
}
|
||||
|
||||
return _activeTags.ToArray();
|
||||
}
|
||||
|
||||
public void Reset()
|
||||
{
|
||||
_statesByTag.Clear();
|
||||
|
||||
Reference in New Issue
Block a user