diff --git a/Assets/Scripts/ECS/Data/BattleComp.cs b/Assets/Scripts/ECS/Data/BattleComp.cs
index d923392..5c232aa 100644
--- a/Assets/Scripts/ECS/Data/BattleComp.cs
+++ b/Assets/Scripts/ECS/Data/BattleComp.cs
@@ -1,5 +1,6 @@
using Assets.Scripts.Data;
using Leopotam.EcsLite;
+using System.Collections.Generic;
namespace Assets.Scripts.ECS.Data
{
@@ -30,7 +31,19 @@ public struct HeroInstanceRefComp : IPackedWithWorldRef
{
public EcsPackedEntityWithWorld HeroInstancePackedEntity { get; internal set; }
public EcsPackedEntityWithWorld Packed => HeroInstancePackedEntity;
+ }
+ public struct HeroInstanceMapping
+ {
+ ///
+ /// Origin world entity packed used as a key, so when needed we can get a battle world entity by this key
+ ///
+ public Dictionary OriginToBattleMapping { get; internal set; }
+
+ ///
+ /// Battle world entity packed used as a key, so when needed we can get an origin world entity by this key
+ ///
+ public Dictionary BattleToOriginMapping { get; internal set; }
}
///
diff --git a/Assets/Scripts/ECS/Data/Relations.cs b/Assets/Scripts/ECS/Data/Relations.cs
index 29da7b7..ad6117a 100644
--- a/Assets/Scripts/ECS/Data/Relations.cs
+++ b/Assets/Scripts/ECS/Data/Relations.cs
@@ -13,15 +13,29 @@ public struct P2PRelationTag { }
/// Marks a value of current relation score between some parties
///
public struct RelationScoreTag { }
-
+
+ ///
+ /// For casting probability needs, we don't need any info about current effects, only their count
+ ///
+ public struct RelationEffectsCountTag { }
+
///
/// Marks a turn to process additional round queue manipulation to insert a hero after current turn
///
- public struct PrepareRevengeComp{
+ public struct PrepareRevengeComp {
public EcsPackedEntityWithWorld RevengeFor { get; set; }
public EcsPackedEntityWithWorld RevengeBy { get; set; }
}
+ ///
+ /// Marks a turn to affect targeting (aiming) system so all teammates will attack an effect's focus
+ ///
+ public struct PrepareTargetComp
+ {
+ public EcsPackedEntityWithWorld TargetFor { get; set; }
+ public EcsPackedEntityWithWorld TargetBy { get; set; }
+ }
+
///
/// Contains references to each score entity by hero instance entity,
/// so when event is spawned or we just need to check a score with some other guy
@@ -52,6 +66,11 @@ public struct EffectInstanceInfo
///
public EcsPackedEntityWithWorld EffectSource { get; set; }
+ ///
+ /// Score and effects count in the world of the relation origin
+ ///
+ public EcsPackedEntityWithWorld EffectP2PEntity { get; set; }
+
///
/// Applicable For:
/// - AlgoRevenge
@@ -76,6 +95,21 @@ public override string ToString()
public RelationEffectInfo EffectInfo { get; set; }
}
+ public struct RelEffectProbeComp
+ {
+ public EcsPackedEntityWithWorld TargetConfigRefPacked { get; internal set; }
+ public EcsPackedEntityWithWorld SourceOrigPacked { get; internal set; }
+ public EcsPackedEntityWithWorld TargetOrigPacked { get; internal set; }
+
+ ///
+ /// Score, current effects count (in the origin world), current effects info (in the battle wolrd
+ ///
+ public EcsPackedEntityWithWorld P2PEntityPacked { get; internal set; }
+
+ public EcsPackedEntity TurnEntity { get; internal set; }
+ public RelationSubjectState SubjectState { get; internal set; }
+ }
+
public struct RelationEffectsComp
{
private Dictionary currentEffects;
diff --git a/Assets/Scripts/ECS/Systems/Battle/BattleAssignRelationEffectsSystem.cs b/Assets/Scripts/ECS/Systems/Battle/BattleAssignRelationEffectsSystem.cs
index 8b67d76..4b376f6 100644
--- a/Assets/Scripts/ECS/Systems/Battle/BattleAssignRelationEffectsSystem.cs
+++ b/Assets/Scripts/ECS/Systems/Battle/BattleAssignRelationEffectsSystem.cs
@@ -1,13 +1,11 @@
using Assets.Scripts.Data;
using Assets.Scripts.ECS.Data;
-using Assets.Scripts.Services;
using Leopotam.EcsLite;
using Leopotam.EcsLite.Di;
-using System;
-using UnityEngine;
namespace Assets.Scripts.ECS.Systems
{
+
public class BattleAssignRelationEffectsSystem : IEcsRunSystem
where T : struct, IPackedWithWorldRef
{
@@ -17,20 +15,13 @@ public class BattleAssignRelationEffectsSystem : IEcsRunSystem
protected readonly EcsWorldInject ecsWorld;
protected readonly EcsPoolInject pool = default;
+ protected readonly EcsPoolInject relEffectProbePool = default;
protected readonly EcsPoolInject playerTeamTagPool = default;
protected readonly EcsPoolInject heroInstanceOriginRefPool = default;
protected readonly EcsPoolInject heroConfigRefPool = default;
- protected readonly EcsPoolInject relEffectsPool = default;
- protected readonly EcsPoolInject> updatePool = default;
- protected readonly EcsPoolInject attackerRefPool = default;
- protected readonly EcsPoolInject revengePool = default;
protected readonly EcsFilterInject> filter = default;
- protected readonly EcsCustomInject battleService = default;
-
- protected readonly EcsCustomInject heroLibraryService = default;
-
public void Run(IEcsSystems systems)
{
foreach (var entity in filter.Value)
@@ -42,8 +33,8 @@ public void Run(IEcsSystems systems)
if (!playerTeamTagPool.Value.Has(effectTargetEntity))
continue;
- ref var originRef = ref heroInstanceOriginRefPool.Value.Get(effectTargetEntity);
- if (!originRef.Packed.Unpack(out var origWorld, out var effectTargetOrig))
+ ref var effTargetOriginRef = ref heroInstanceOriginRefPool.Value.Get(effectTargetEntity);
+ if (!effTargetOriginRef.Packed.Unpack(out var origWorld, out var effectTargetOrig))
continue;
ref var heroConfigRef = ref heroConfigRefPool.Value.Get(effectTargetEntity);
@@ -57,142 +48,23 @@ public void Run(IEcsSystems systems)
foreach (var item in matrixComp.Matrix)
{
// matching only one side of the key to avoid duplicates
- if (!item.Key.Item1.EqualsTo(originRef.Packed))
+ if (!item.Key.Item1.EqualsTo(effTargetOriginRef.Packed))
continue;
- if (TryCastRelationEffect(heroConfigRef.Packed, item.Key.Item2, originRef.Packed, item.Value,
- out var effect))
- {
- // registering effect for the hero affected (in the battle world, to make it handy when needed)
- RelationEffectKey ruleKey = effect.Rule.Key;
- item.Key.Item2.Unpack(out _, out var effectSourceEntity);
-
- var affectedParty = effectTargetEntity;
-
- if (ruleKey.RelationsEffectType switch {
- RelationsEffectType.AlgoRevenge => true,
- RelationsEffectType.AlgoTarget => true,
- _ => false
- })
- {
- affectedParty = effectSourceEntity;
-
- ref var attackerRef = ref attackerRefPool.Value.Get(entity);
- effect.EffectFocus = attackerRef.Packed;
-
- var revengeEntity = ecsWorld.Value.NewEntity();
- ref var revengeComp = ref revengePool.Value.Add(revengeEntity);
- revengeComp.RevengeBy = ecsWorld.Value.PackEntityWithWorld(effectSourceEntity);
- revengeComp.RevengeFor = ecsWorld.Value.PackEntityWithWorld(effectTargetEntity);
- }
-
- // add info for UI
- var heroIconPool = origWorld.GetPool>();
- ref var heroIcon = ref heroIconPool.Get(effectSourceEntity);
- var info = effect.Rule.DraftEffectInfo(effect.Rule.GetHashCode(), heroIcon.Name);
- effect.EffectInfo = info;
-
- ref var relEffects = ref relEffectsPool.Value.Get(affectedParty);
- relEffects.SetEffect(ruleKey, effect);
-
- if (!updatePool.Value.Has(affectedParty))
- updatePool.Value.Add(affectedParty);
- }
-
+ var relEffectProbeEntity = ecsWorld.Value.NewEntity();
+ ref var probeComp = ref relEffectProbePool.Value.Add(relEffectProbeEntity);
+ probeComp.SourceOrigPacked = item.Key.Item1;
+ probeComp.TargetOrigPacked = item.Key.Item2;
+ probeComp.TargetConfigRefPacked = heroConfigRef.Packed;
+ probeComp.P2PEntityPacked = item.Value;
+ probeComp.SubjectState = SubjectState;
+ probeComp.TurnEntity = systems.GetWorld().PackEntity(entity);
}
}
}
}
- ///
- /// Will add relation effect if rules applied will allow to
- ///
- /// Entity of a hero to wich the effect will be casted (if any)
- /// EcsWorld to take relations from
- /// Hero Config Entity of the given hero
- /// Packed other guy entity in the origin world
- /// Packed this guy entity in the origin world
- /// Packed score entity for the given hero and the other guy
- /// true if new effect was casted
- protected bool TryCastRelationEffect(
- EcsPackedEntityWithWorld heroConfigPackedEntity,
- EcsPackedEntityWithWorld effectSource,
- EcsPackedEntityWithWorld effectTarget,
- EcsPackedEntityWithWorld scoreEntityPacked,
- out EffectInstanceInfo effect)
- {
- effect = default;
- if (!effectSource.Unpack(out var origWorld, out var otherGuyEntity))
- throw new Exception("Stale Other Guy Entity (probably dead already)");
-
- if (!scoreEntityPacked.Unpack(out _, out var scoreEntity))
- throw new Exception("Stale Score Entity");
-
- var relationsConfig = heroLibraryService.Value.HeroRelationsConfigProcessor();
-
- var score = origWorld.ReadIntValue(scoreEntity);
- var relationsState = relationsConfig.GetRelationState(score);
-
-
- if (!heroConfigPackedEntity.Unpack(out var libWorld, out var heroConfigEntity))
- throw new Exception("No Hero Config for current guy");
-
- var libHeroPool = libWorld.GetPool();
- ref var heroConfig = ref libHeroPool.Get(heroConfigEntity);
-
- var rulesCaseKey = new RelationEffectLibraryKey(
- heroConfig.Id, SubjectState, relationsState);
-
- var effectRules = heroLibraryService.Value.HeroRelationEffectsLibProcessor();
-
- if (!effectRules.SubjectStateEffectsIndex.TryGetValue(rulesCaseKey, out var scope))
- return false; // no effect for relation state, it's ok
-
- var origWorldConfigRefPool = origWorld.GetPool();
- ref var otherGuyConfigRef = ref origWorldConfigRefPool.Get(otherGuyEntity);
- if (!otherGuyConfigRef.Packed.Unpack(out _, out var otherGuyHeroConfigEntity))
- throw new Exception("No Hero Config for the other guy");
-
- ref var otherGuyHeroConfig = ref libHeroPool.Get(otherGuyHeroConfigEntity);
-
- var ruleType = scope.EffectRule.EffectType;
-
- if (ruleType.EffectClass() != RelationsEffectClass.Battle)
- return false; // this system process only battle effects
-
- var rule = (IBattleEffectRule)scope.EffectRule;
- ref var currentRound = ref battleService.Value.CurrentRound;
-
- Debug.Log($"Relations Effect of type {ruleType} was just spawned " +
- $"for {heroConfig.Name} in {scope.SelfState} due to {scope.RelationState} " +
- $"with {otherGuyHeroConfig.Name}");
-
- // 1. add component to the entity of the current score data;
- // 2. keep all spawned effects (EffectRules) in that component;
- // 3. count of already spawned effects used as a wheight for spawn rate (key for
- // AdditioinalEffectSpawnRate queries);
-
- var currentEffectsPool = origWorld.GetPool();
- // respect spawn rate from AdditionalEffectSpawnRate:
- ref var currentEffects = ref currentEffectsPool.Get(scoreEntity);
- if (!effectRules.TrySpawnAdditionalEffect(currentEffects.CurrentEffects.Count))
- return false;
-
- Debug.Log($"Spawned with respect of exisiting {currentEffects.CurrentEffects.Count} effects");
-
- effect = new EffectInstanceInfo()
- {
- StartRound = currentRound.Round,
- EndRound = currentRound.Round + rule.TurnsCount,
- UsageLeft = rule.TurnsCount,
- Rule = rule,
- EffectSource = effectSource,
- };
-
- currentEffects.SetEffect(rule.Key, effect); // effect focus (if any) is omitted here, but added for battle context.
-
- return true;
- }
+
}
}
diff --git a/Assets/Scripts/ECS/Systems/Battle/BattleDequeueExpiredRelationEffectsSystem.cs b/Assets/Scripts/ECS/Systems/Battle/BattleDequeueExpiredRelationEffectsSystem.cs
index f714955..78a2ce9 100644
--- a/Assets/Scripts/ECS/Systems/Battle/BattleDequeueExpiredRelationEffectsSystem.cs
+++ b/Assets/Scripts/ECS/Systems/Battle/BattleDequeueExpiredRelationEffectsSystem.cs
@@ -1,6 +1,5 @@
using Assets.Scripts.Data;
using Assets.Scripts.ECS.Data;
-using Assets.Scripts.Services;
using Leopotam.EcsLite;
using Leopotam.EcsLite.Di;
@@ -14,8 +13,6 @@ public class BattleDequeueExpiredRelationEffectsSystem : IEcsRunSystem
private readonly EcsFilterInject> currentEffectFilter = default;
private readonly EcsFilterInject> filter = default;
- private readonly EcsCustomInject raidService = default;
-
public void Run(IEcsSystems systems)
{
foreach (var entity in filter.Value)
@@ -25,14 +22,10 @@ public void Run(IEcsSystems systems)
// for both battle and raid worlds and remove expired effects:
DequeueRelationEffects(systems.GetWorld(), roundInfo.Round);
- if (raidService.Value.EcsWorld != null)
- DequeueRelationEffects(raidService.Value.EcsWorld, roundInfo.Round);
-
// enqueue view update to reflect changes (if any)
foreach (var effectsEntity in currentEffectFilter.Value)
if (!updatePool.Value.Has(effectsEntity))
- updatePool.Value.Add(effectsEntity);
-
+ updatePool.Value.Add(effectsEntity);
}
}
@@ -50,13 +43,18 @@ private void DequeueRelationEffects(EcsWorld world, int round)
buff.Add(item.Key);
foreach (var item in buff)
+ {
+ var effect = relEffect.CurrentEffects[item];
+ if (effect.EffectP2PEntity.Unpack(out var origWorld, out var p2pEntity))
+ origWorld.IncrementIntValue(-1, p2pEntity);
+
relEffect.CurrentEffects.Remove(item);
+ }
buff.Clear();
}
ListPool.Add(buff);
}
-
}
}
diff --git a/Assets/Scripts/ECS/Systems/Battle/BattleHeroesInitSystem.cs b/Assets/Scripts/ECS/Systems/Battle/BattleHeroesInitSystem.cs
index 1a64315..0c7e872 100644
--- a/Assets/Scripts/ECS/Systems/Battle/BattleHeroesInitSystem.cs
+++ b/Assets/Scripts/ECS/Systems/Battle/BattleHeroesInitSystem.cs
@@ -16,6 +16,7 @@ public class BattleHeroesInitSystem : IEcsRunSystem
private readonly EcsPoolInject heroInstanceOriginRefPool = default;
private readonly EcsPoolInject positionPool = default;
private readonly EcsPoolInject battleFieldPool = default;
+ private readonly EcsPoolInject heroInstanceMappingPool = default;
private readonly EcsFilterInject>> filter = default;
@@ -34,6 +35,7 @@ public void Run(IEcsSystems systems)
battleService.Value.NotifyBattleEventListeners(battleInfo);
ref var battleField = ref battleFieldPool.Value.Get(battleEntity);
+ ref var heroInstanceMappings = ref heroInstanceMappingPool.Value.Get(battleEntity);
#region Player team:
@@ -48,7 +50,7 @@ public void Run(IEcsSystems systems)
{
var sourcePosition = playerPosBuffer[0];
- AddHeroBattleInstance(battleWorld, packed, sourcePosition);
+ AddHeroBattleInstance(battleWorld, heroInstanceMappings, packed, sourcePosition);
playerPosBuffer.RemoveAt(0);
}
@@ -69,7 +71,7 @@ public void Run(IEcsSystems systems)
{
var sourcePosition = enemyPosBuffer[0];
- AddHeroBattleInstance(battleWorld, packed, sourcePosition);
+ AddHeroBattleInstance(battleWorld, heroInstanceMappings, packed, sourcePosition);
enemyPosBuffer.RemoveAt(0);
}
@@ -79,8 +81,11 @@ public void Run(IEcsSystems systems)
#endregion
}
- private void AddHeroBattleInstance(EcsWorld battleWorld,
- EcsPackedEntityWithWorld packed, HeroPosition sourcePosition)
+ private void AddHeroBattleInstance(
+ EcsWorld battleWorld,
+ HeroInstanceMapping heroInstanceMappings,
+ EcsPackedEntityWithWorld originHeroInstancePacked,
+ HeroPosition sourcePosition)
where T: struct
{
var entity = battleWorld.NewEntity();
@@ -94,16 +99,20 @@ private void AddHeroBattleInstance(EcsWorld battleWorld,
// remember hero instance origin (raid or library)
// to update HP and use bonuses from raid
- ref var origin = ref heroInstanceOriginRefPool.Value.Add(entity);
- origin.HeroInstancePackedEntity = packed;
+ ref var originRef = ref heroInstanceOriginRefPool.Value.Add(entity);
+ originRef.HeroInstancePackedEntity = originHeroInstancePacked;
// getting hero config ref from the origin
- if (!packed.Unpack(out var originWorld, out var originEntity))
+ if (!originHeroInstancePacked.Unpack(out var originWorld, out var originEntity))
throw new Exception("No Source Hero");
ref var originConfigRefComp = ref originWorld.GetPool().Get(originEntity);
ref var configRefComp = ref heroConfigRefPool.Value.Add(entity);
configRefComp.HeroConfigPackedEntity = originConfigRefComp.Packed;
+
+ var battleHeroInstancePacked = battleWorld.PackEntityWithWorld(entity);
+ heroInstanceMappings.OriginToBattleMapping.Add(originHeroInstancePacked, battleHeroInstancePacked);
+ heroInstanceMappings.BattleToOriginMapping.Add(battleHeroInstancePacked, originHeroInstancePacked);
}
}
}
diff --git a/Assets/Scripts/ECS/Systems/Battle/BattleInitSystem.cs b/Assets/Scripts/ECS/Systems/Battle/BattleInitSystem.cs
index 877b5d7..d8ad1cf 100644
--- a/Assets/Scripts/ECS/Systems/Battle/BattleInitSystem.cs
+++ b/Assets/Scripts/ECS/Systems/Battle/BattleInitSystem.cs
@@ -12,6 +12,7 @@ public class BattleInitSystem : IEcsInitSystem
private readonly EcsPoolInject battleInfoPool = default;
private readonly EcsPoolInject> draftTagPool = default;
+ private readonly EcsPoolInject heroInstanceMappingPool = default;
private readonly EcsCustomInject battleService = default;
private readonly EcsCustomInject libraryService = default;
@@ -39,6 +40,10 @@ public void Init(IEcsSystems systems)
battle.WinnerTeamId = -1;
+ ref var heroInstanceMapping = ref heroInstanceMappingPool.Value.Add(entity);
+ heroInstanceMapping.OriginToBattleMapping = new();
+ heroInstanceMapping.BattleToOriginMapping = new();
+
battleService.Value.BattleEntity = ecsWorld.Value.PackEntityWithWorld(entity);
}
diff --git a/Assets/Scripts/ECS/Systems/Battle/BattlePrepareRelEffectVisualSystem.cs b/Assets/Scripts/ECS/Systems/Battle/BattlePrepareRelEffectVisualSystem.cs
new file mode 100644
index 0000000..80b4190
--- /dev/null
+++ b/Assets/Scripts/ECS/Systems/Battle/BattlePrepareRelEffectVisualSystem.cs
@@ -0,0 +1,88 @@
+using Assets.Scripts.Data;
+using Assets.Scripts.ECS.Data;
+using Assets.Scripts.Services;
+using Leopotam.EcsLite;
+using Leopotam.EcsLite.Di;
+using System;
+
+namespace Assets.Scripts.ECS.Systems
+{
+ public partial class BattlePrepareRelEffectVisualSystem : IEcsRunSystem
+ {
+ private readonly EcsPoolInject mappingsPool = default;
+ private readonly EcsPoolInject pool = default;
+ private readonly EcsPoolInject probePool = default;
+ private readonly EcsPoolInject relEffectsPool = default;
+ private readonly EcsPoolInject> updatePool = default;
+
+ private readonly EcsFilterInject<
+ Inc<
+ DraftTag,
+ RelEffectProbeComp,
+ EffectInstanceInfo
+ >> filter = default;
+
+ private readonly EcsFilterInject<
+ Inc,
+ Exc
+ > playerTeamFilter = default;
+
+ private readonly EcsCustomInject battleManagementService = default;
+
+ public void Run(IEcsSystems systems)
+ {
+ if (!battleManagementService.Value.BattleEntity.Unpack(out var world, out var battleEntity))
+ throw new Exception("No battle!");
+
+ foreach (var entity in filter.Value)
+ {
+ ref var probe = ref probePool.Value.Get(entity);
+ ref var effect = ref pool.Value.Get(entity);
+ ref var mappings = ref mappingsPool.Value.Get(battleEntity);
+
+ var sourcePacked = mappings.OriginToBattleMapping[probe.SourceOrigPacked];
+ if (!sourcePacked.Unpack(out var battleWorld, out var sourceParty))
+ throw new Exception("Stale effect source entity");
+
+ var targetPacked = mappings.OriginToBattleMapping[probe.TargetOrigPacked];
+ if (!targetPacked.Unpack(out _, out var targetParty))
+ throw new Exception("Stale effect target entity");
+
+ switch (effect.Rule.Key.RelationsEffectType)
+ {
+ case RelationsEffectType.AlgoRevenge:
+ PrepareVisualForEffect(probe.TargetOrigPacked, sourceParty, ref effect);
+ break;
+ case RelationsEffectType.AlgoTarget:
+ {
+ // here we should add visual to all team mates as they are affected by the effect caster
+ foreach (var teammateEntity in playerTeamFilter.Value)
+ PrepareVisualForEffect(probe.SourceOrigPacked, teammateEntity, ref effect);
+ }
+ break;
+ default:
+ PrepareVisualForEffect(probe.SourceOrigPacked, targetParty, ref effect);
+ break;
+ }
+ }
+ }
+
+ private void PrepareVisualForEffect(EcsPackedEntityWithWorld origIconParty, int affectedParty, ref EffectInstanceInfo effect)
+ {
+ if (!origIconParty.Unpack(out var origWorld, out var iconEntity))
+ throw new Exception("Stale origin effect source!");
+
+ var heroIconPool = origWorld.GetPool>();
+ ref var heroIcon = ref heroIconPool.Get(iconEntity);
+ var info = effect.Rule.DraftEffectInfo(effect.Rule.GetHashCode(), heroIcon.Name);
+ effect.EffectInfo = info;
+
+ ref var relEffects = ref relEffectsPool.Value.Get(affectedParty);
+ relEffects.SetEffect(effect.Rule.Key, effect);
+
+ if (!updatePool.Value.Has(affectedParty))
+ updatePool.Value.Add(affectedParty);
+
+ }
+ }
+}
diff --git a/Assets/Scripts/ECS/Systems/Battle/BattlePrepareRelEffectVisualSystem.cs.meta b/Assets/Scripts/ECS/Systems/Battle/BattlePrepareRelEffectVisualSystem.cs.meta
new file mode 100644
index 0000000..1aa2ca7
--- /dev/null
+++ b/Assets/Scripts/ECS/Systems/Battle/BattlePrepareRelEffectVisualSystem.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: acb0d1c8b52d3ba41988b08d5e1374e5
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Scripts/ECS/Systems/Battle/BattlePrepareRevengeEffectSystem.cs b/Assets/Scripts/ECS/Systems/Battle/BattlePrepareRevengeEffectSystem.cs
new file mode 100644
index 0000000..d51e1fe
--- /dev/null
+++ b/Assets/Scripts/ECS/Systems/Battle/BattlePrepareRevengeEffectSystem.cs
@@ -0,0 +1,59 @@
+using Assets.Scripts.Data;
+using Assets.Scripts.ECS.Data;
+using Assets.Scripts.Services;
+using Leopotam.EcsLite;
+using Leopotam.EcsLite.Di;
+using System;
+
+namespace Assets.Scripts.ECS.Systems
+{
+
+ public class BattlePrepareRevengeEffectSystem : IEcsRunSystem
+ {
+ private readonly EcsWorldInject ecsWorld;
+
+ private readonly EcsPoolInject pool = default;
+ private readonly EcsPoolInject probePool = default;
+ private readonly EcsPoolInject attackerRefPool = default;
+ private readonly EcsPoolInject revengePool = default;
+ private readonly EcsPoolInject mappingsPool = default;
+
+ private readonly EcsFilterInject<
+ Inc<
+ DraftTag,
+ RelEffectProbeComp,
+ EffectInstanceInfo
+ >> filter = default;
+
+ private readonly EcsCustomInject battleManagementService = default;
+
+ public void Run(IEcsSystems systems)
+ {
+ if (!battleManagementService.Value.BattleEntity.Unpack(out _, out var battleEntity))
+ throw new Exception("No battle!");
+
+ foreach (var entity in filter.Value)
+ {
+ ref var effect = ref pool.Value.Get(entity);
+ ref var mappings = ref mappingsPool.Value.Get(battleEntity);
+
+ if (effect.Rule.Key.RelationsEffectType == RelationsEffectType.AlgoRevenge)
+ {
+ ref var probe = ref probePool.Value.Get(entity);
+
+ if (!probe.TurnEntity.Unpack(systems.GetWorld(), out var turnEntity))
+ throw new Exception("Stale Turn Entity");
+
+ // registering effect for the hero affected (in the battle world, to make it handy when needed)
+ ref var attackerRef = ref attackerRefPool.Value.Get(turnEntity);
+ effect.EffectFocus = attackerRef.Packed;
+
+ var revengeEntity = ecsWorld.Value.NewEntity();
+ ref var revengeComp = ref revengePool.Value.Add(revengeEntity);
+ revengeComp.RevengeBy = mappings.OriginToBattleMapping[probe.SourceOrigPacked];
+ revengeComp.RevengeFor = mappings.OriginToBattleMapping[probe.TargetOrigPacked];
+ }
+ }
+ }
+ }
+}
diff --git a/Assets/Scripts/ECS/Systems/Battle/BattlePrepareRevengeEffectSystem.cs.meta b/Assets/Scripts/ECS/Systems/Battle/BattlePrepareRevengeEffectSystem.cs.meta
new file mode 100644
index 0000000..5f30b63
--- /dev/null
+++ b/Assets/Scripts/ECS/Systems/Battle/BattlePrepareRevengeEffectSystem.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 08fc95a6e7b08d14aadd1bc06dc3e4d1
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Scripts/ECS/Systems/Battle/BattlePrepareTargetEffectSystem.cs b/Assets/Scripts/ECS/Systems/Battle/BattlePrepareTargetEffectSystem.cs
new file mode 100644
index 0000000..5f15376
--- /dev/null
+++ b/Assets/Scripts/ECS/Systems/Battle/BattlePrepareTargetEffectSystem.cs
@@ -0,0 +1,61 @@
+using Assets.Scripts.Data;
+using Assets.Scripts.ECS.Data;
+using Assets.Scripts.Services;
+using Leopotam.EcsLite;
+using Leopotam.EcsLite.Di;
+using System;
+
+namespace Assets.Scripts.ECS.Systems
+{
+ public class BattlePrepareTargetEffectSystem : IEcsRunSystem
+ {
+ private readonly EcsWorldInject ecsWorld;
+
+ private readonly EcsPoolInject pool = default;
+ private readonly EcsPoolInject probePool = default;
+ private readonly EcsPoolInject attackerRefPool = default;
+ private readonly EcsPoolInject targetPool = default;
+ private readonly EcsPoolInject mappingsPool = default;
+
+ private readonly EcsFilterInject<
+ Inc<
+ DraftTag,
+ RelEffectProbeComp,
+ EffectInstanceInfo
+ >> filter = default;
+
+ private readonly EcsCustomInject battleManagementService = default;
+
+ public void Run(IEcsSystems systems)
+ {
+ if (!battleManagementService.Value.BattleEntity.Unpack(out _, out var battleEntity))
+ throw new Exception("No battle!");
+
+ foreach (var entity in filter.Value)
+ {
+ ref var effect = ref pool.Value.Get(entity);
+ ref var mappings = ref mappingsPool.Value.Get(battleEntity);
+
+ if (effect.Rule.Key.RelationsEffectType == RelationsEffectType.AlgoTarget)
+ {
+ ref var probe = ref probePool.Value.Get(entity);
+
+ if (!probe.TurnEntity.Unpack(systems.GetWorld(), out var turnEntity))
+ throw new Exception("Stale Turn Entity");
+
+ // registering effect for the hero affected (in the battle world, to make it handy when needed)
+ probe.SourceOrigPacked.Unpack(out _, out var effectSourceEntity);
+ probe.TargetOrigPacked.Unpack(out _, out var effectTargetEntity);
+
+ ref var attackerRef = ref attackerRefPool.Value.Get(turnEntity);
+ effect.EffectFocus = attackerRef.Packed;
+
+ var targetEntity = ecsWorld.Value.NewEntity();
+ ref var targetComp = ref targetPool.Value.Add(targetEntity);
+ targetComp.TargetBy = mappings.OriginToBattleMapping[probe.SourceOrigPacked];
+ targetComp.TargetFor = mappings.OriginToBattleMapping[probe.TargetOrigPacked];
+ }
+ }
+ }
+ }
+}
diff --git a/Assets/Scripts/ECS/Systems/Battle/BattlePrepareTargetEffectSystem.cs.meta b/Assets/Scripts/ECS/Systems/Battle/BattlePrepareTargetEffectSystem.cs.meta
new file mode 100644
index 0000000..3c3f0b7
--- /dev/null
+++ b/Assets/Scripts/ECS/Systems/Battle/BattlePrepareTargetEffectSystem.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: f47ee94867ff0be478c77c9bd72088dd
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Scripts/ECS/Systems/Battle/BattleRelEffectProbeSystem.cs b/Assets/Scripts/ECS/Systems/Battle/BattleRelEffectProbeSystem.cs
new file mode 100644
index 0000000..b9d1bf9
--- /dev/null
+++ b/Assets/Scripts/ECS/Systems/Battle/BattleRelEffectProbeSystem.cs
@@ -0,0 +1,131 @@
+using Assets.Scripts.Data;
+using Assets.Scripts.ECS.Data;
+using Assets.Scripts.Services;
+using Leopotam.EcsLite;
+using Leopotam.EcsLite.Di;
+using System;
+using UnityEngine;
+
+namespace Assets.Scripts.ECS.Systems
+{
+ public class BattleRelEffectProbeSystem : IEcsRunSystem
+ {
+ private readonly EcsWorldInject ecsWorld;
+
+ private readonly EcsPoolInject pool = default;
+ private readonly EcsPoolInject effectsPool = default;
+ private readonly EcsPoolInject> draftTagPool = default;
+
+ private readonly EcsFilterInject> filter = default;
+
+ private readonly EcsCustomInject heroLibraryService = default;
+ private readonly EcsCustomInject battleService = default;
+
+ public void Run(IEcsSystems systems)
+ {
+ foreach (var entity in filter.Value)
+ {
+ ref var comp = ref pool.Value.Get(entity);
+ TryCastRelationEffect(
+ entity,
+ comp.TargetConfigRefPacked,
+ comp.SourceOrigPacked,
+ comp.TargetOrigPacked,
+ comp.P2PEntityPacked,
+ comp.SubjectState);
+ }
+
+ }
+
+ ///
+ /// Will add relation effect if rules applied will allow to
+ ///
+ /// Entity of a hero to wich the effect will be casted (if any)
+ /// EcsWorld to take relations from
+ /// Hero Config Entity of the given hero
+ /// Packed other guy entity in the origin world
+ /// Packed this guy entity in the origin world
+ /// Packed score entity for the given hero and the other guy
+ /// true if new effect was casted
+ private bool TryCastRelationEffect(
+ int effectProbeEntity,
+ EcsPackedEntityWithWorld targetConfigRefPacked,
+ EcsPackedEntityWithWorld effectSource,
+ EcsPackedEntityWithWorld effectTarget,
+ EcsPackedEntityWithWorld p2pEntityPacked,
+ RelationSubjectState SubjectState)
+ {
+ if (!effectSource.Unpack(out var origWorld, out var otherGuyEntity))
+ throw new Exception("Stale Other Guy Entity (probably dead already)");
+
+ if (!p2pEntityPacked.Unpack(out _, out var p2pEntity))
+ throw new Exception("Stale Score Entity");
+
+ var relationsConfig = heroLibraryService.Value.HeroRelationsConfigProcessor();
+ var effectRules = heroLibraryService.Value.HeroRelationEffectsLibProcessor();
+
+ var currentEffectsCount = origWorld.ReadIntValue(p2pEntity);
+ // respect spawn rate from AdditionalEffectSpawnRate:
+ if (!effectRules.TrySpawnAdditionalEffect(currentEffectsCount))
+ {
+ Debug.Log($"Spawn failed due to existing {currentEffectsCount} effects");
+ return false;
+ }
+
+ var score = origWorld.ReadIntValue(p2pEntity);
+ var relationsState = relationsConfig.GetRelationState(score);
+
+ if (!targetConfigRefPacked.Unpack(out var libWorld, out var heroConfigEntity))
+ throw new Exception("No Hero Config for current guy");
+
+ var libHeroPool = libWorld.GetPool();
+ ref var heroConfig = ref libHeroPool.Get(heroConfigEntity);
+
+ var rulesCaseKey = new RelationEffectLibraryKey(
+ heroConfig.Id, SubjectState, relationsState);
+
+ if (!effectRules.SubjectStateEffectsIndex.TryGetValue(rulesCaseKey, out var scope))
+ return false; // no effect for relation state, it's ok
+
+ var origWorldConfigRefPool = origWorld.GetPool();
+ ref var otherGuyConfigRef = ref origWorldConfigRefPool.Get(otherGuyEntity);
+ if (!otherGuyConfigRef.Packed.Unpack(out _, out var otherGuyHeroConfigEntity))
+ throw new Exception("No Hero Config for the other guy");
+
+ ref var otherGuyHeroConfig = ref libHeroPool.Get(otherGuyHeroConfigEntity);
+
+ var ruleType = scope.EffectRule.EffectType;
+
+ if (ruleType.EffectClass() != RelationsEffectClass.Battle)
+ return false; // this system process only battle effects
+
+ var rule = (IBattleEffectRule)scope.EffectRule;
+ ref var currentRound = ref battleService.Value.CurrentRound;
+
+ Debug.Log($"Relations Effect of type {ruleType} was just spawned " +
+ $"for {heroConfig.Name} in {scope.SelfState} due to {scope.RelationState} " +
+ $"with {otherGuyHeroConfig.Name}");
+
+ // 1. add component to the entity of the current score data;
+ // 2. keep all spawned effects (EffectRules) in that component;
+ // 3. count of already spawned effects used as a wheight for spawn rate (key for
+ // AdditioinalEffectSpawnRate queries);
+
+ draftTagPool.Value.Add(effectProbeEntity);
+
+ ref var effect = ref effectsPool.Value.Add(effectProbeEntity);
+ effect.StartRound = currentRound.Round;
+ effect.EndRound = currentRound.Round + rule.TurnsCount;
+ effect.UsageLeft = rule.TurnsCount;
+ effect.Rule = rule;
+ effect.EffectSource = effectSource;
+ effect.EffectP2PEntity = p2pEntityPacked;
+
+ Debug.Log($"Spawned with respect of exisiting {currentEffectsCount} effects");
+
+ origWorld.IncrementIntValue(1, p2pEntity);
+
+ return true;
+ }
+ }
+}
diff --git a/Assets/Scripts/ECS/Systems/Battle/BattleRelEffectProbeSystem.cs.meta b/Assets/Scripts/ECS/Systems/Battle/BattleRelEffectProbeSystem.cs.meta
new file mode 100644
index 0000000..035f566
--- /dev/null
+++ b/Assets/Scripts/ECS/Systems/Battle/BattleRelEffectProbeSystem.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: d899b8ef6777c054dbc5d734cc12b4aa
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Scripts/ECS/Systems/HeroLibrary/LibraryHandleHeroMoveSystem.cs b/Assets/Scripts/ECS/Systems/HeroLibrary/LibraryHandleHeroMoveSystem.cs
new file mode 100644
index 0000000..0cf81cd
--- /dev/null
+++ b/Assets/Scripts/ECS/Systems/HeroLibrary/LibraryHandleHeroMoveSystem.cs
@@ -0,0 +1,44 @@
+using Assets.Scripts.ECS.Data;
+using Assets.Scripts.Services;
+using Leopotam.EcsLite;
+using Leopotam.EcsLite.Di;
+
+namespace Assets.Scripts.ECS.Systems
+{
+ public class LibraryHandleHeroMoveSystem : IEcsRunSystem
+ {
+ private readonly EcsPoolInject positionPool = default;
+ private readonly EcsPoolInject playerTeamTagPool = default;
+ private readonly EcsPoolInject> updateTagPool = default;
+
+ private readonly EcsFilterInject<
+ Inc, PositionComp>> moveFilter = default;
+
+ private readonly EcsCustomInject libraryService = default;
+
+ public void Run(IEcsSystems systems)
+ {
+ foreach (var moveEntity in moveFilter.Value)
+ {
+ ref var position = ref positionPool.Value.Get(moveEntity);
+ var playerTeamId = libraryService.Value.PlayerTeam.Id;
+
+ if (position.Position.Team != position.PrevPosition.Team &&
+ (playerTeamId == position.Position.Team ||
+ playerTeamId == position.PrevPosition.Team))
+ {
+ if (playerTeamTagPool.Value.Has(moveEntity))
+ playerTeamTagPool.Value.Del(moveEntity);
+
+ if (position.Position.Team == playerTeamId)
+ playerTeamTagPool.Value.Add(moveEntity);
+
+ if (libraryService.Value.PlayerTeamEntity.Unpack(out _, out var playerTeamEntity) &&
+ !updateTagPool.Value.Has(playerTeamEntity))
+ updateTagPool.Value.Add(playerTeamEntity);
+ }
+ }
+ }
+ }
+}
+
diff --git a/Assets/Scripts/ECS/Systems/HeroLibrary/LibraryHandleHeroMoveSystem.cs.meta b/Assets/Scripts/ECS/Systems/HeroLibrary/LibraryHandleHeroMoveSystem.cs.meta
new file mode 100644
index 0000000..63ff280
--- /dev/null
+++ b/Assets/Scripts/ECS/Systems/HeroLibrary/LibraryHandleHeroMoveSystem.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 344ece6d59f382b489d8102291017c94
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Scripts/ECS/Systems/HeroLibrary/LibraryUpdatePlayerTeamRelationContextSystem.cs b/Assets/Scripts/ECS/Systems/HeroLibrary/LibraryUpdatePlayerTeamRelationContextSystem.cs
index 5421951..ba252b3 100644
--- a/Assets/Scripts/ECS/Systems/HeroLibrary/LibraryUpdatePlayerTeamRelationContextSystem.cs
+++ b/Assets/Scripts/ECS/Systems/HeroLibrary/LibraryUpdatePlayerTeamRelationContextSystem.cs
@@ -1,47 +1,11 @@
using Assets.Scripts.Data;
using Assets.Scripts.ECS.Data;
-using Assets.Scripts.Services;
using Leopotam.EcsLite;
using Leopotam.EcsLite.Di;
using System.Collections.Generic;
namespace Assets.Scripts.ECS.Systems
{
- public class LibraryHandleHeroMoveSystem : IEcsRunSystem
- {
- private readonly EcsPoolInject positionPool = default;
- private readonly EcsPoolInject playerTeamTagPool = default;
- private readonly EcsPoolInject> updateTagPool = default;
-
- private readonly EcsFilterInject<
- Inc, PositionComp>> moveFilter = default;
-
- private readonly EcsCustomInject libraryService = default;
-
- public void Run(IEcsSystems systems)
- {
- foreach (var moveEntity in moveFilter.Value)
- {
- ref var position = ref positionPool.Value.Get(moveEntity);
- var playerTeamId = libraryService.Value.PlayerTeam.Id;
-
- if (position.Position.Team != position.PrevPosition.Team &&
- (playerTeamId == position.Position.Team ||
- playerTeamId == position.PrevPosition.Team))
- {
- if (playerTeamTagPool.Value.Has(moveEntity))
- playerTeamTagPool.Value.Del(moveEntity);
-
- if (position.Position.Team == playerTeamId)
- playerTeamTagPool.Value.Add(moveEntity);
-
- if (libraryService.Value.PlayerTeamEntity.Unpack(out _, out var playerTeamEntity) &&
- !updateTagPool.Value.Has(playerTeamEntity))
- updateTagPool.Value.Add(playerTeamEntity);
- }
- }
- }
- }
public class LibraryUpdatePlayerTeamRelationContextSystem : IEcsRunSystem
{
@@ -49,18 +13,13 @@ public class LibraryUpdatePlayerTeamRelationContextSystem : IEcsRunSystem
private readonly EcsPoolInject pool = default;
private readonly EcsPoolInject> scorePool = default;
+ private readonly EcsPoolInject> countPool = default;
private readonly EcsPoolInject effectsPool = default;
private readonly EcsPoolInject matrixPool = default;
private readonly EcsFilterInject> matrixFilter = default;
private readonly EcsFilterInject> filter = default;
- private readonly EcsFilterInject<
- Inc> effectsFilter = default;
-
- private readonly EcsFilterInject<
- Inc>> scoreFilter = default;
-
private readonly EcsFilterInject<
Inc> teamMemberFilter = default;
@@ -77,13 +36,7 @@ public void Run(IEcsSystems systems)
ecsWorld.Value.DelEntity(matrixEntity);
foreach (var p2pEntity in filter.Value)
- pool.Value.Del(p2pEntity);
-
- foreach (var scoreEntity in scoreFilter.Value)
- scorePool.Value.Del(scoreEntity);
-
- foreach (var effectsEntity in effectsFilter.Value)
- effectsPool.Value.Del(effectsEntity);
+ ecsWorld.Value.DelEntity(p2pEntity);
// fill matrix
var matrix = new Dictionary();
@@ -124,6 +77,9 @@ public void Run(IEcsSystems systems)
ref var scoreComp = ref scorePool.Value.Add(p2pRelEntity);
scoreComp.Value = 0;
+
+ ref var countComp = ref countPool.Value.Add(p2pRelEntity);
+ countComp.Value = 0;
}
}
}
diff --git a/Assets/Scripts/ECS/Systems/Raid/PlayerTeamRelationScoresInitSystem.cs b/Assets/Scripts/ECS/Systems/Raid/PlayerTeamRelationScoresInitSystem.cs
index dfe2b19..13df7f0 100644
--- a/Assets/Scripts/ECS/Systems/Raid/PlayerTeamRelationScoresInitSystem.cs
+++ b/Assets/Scripts/ECS/Systems/Raid/PlayerTeamRelationScoresInitSystem.cs
@@ -6,14 +6,18 @@ namespace Assets.Scripts.ECS.Systems
{
public class PlayerTeamRelationScoresInitSystem : IEcsInitSystem
{
- private readonly EcsPoolInject> pool = default;
+ private readonly EcsPoolInject> pool = default;
+ private readonly EcsPoolInject> countPool = default;
private readonly EcsFilterInject> filter = default;
public void Init(IEcsSystems systems)
{
foreach (var entity in filter.Value)
+ {
pool.Value.Add(entity);
+ countPool.Value.Add(entity);
+ }
}
}
}
\ No newline at end of file
diff --git a/Assets/Scripts/Services/Battle/BattleManagementService+ECS.cs b/Assets/Scripts/Services/Battle/BattleManagementService+ECS.cs
index ed3cbdd..67044d6 100644
--- a/Assets/Scripts/Services/Battle/BattleManagementService+ECS.cs
+++ b/Assets/Scripts/Services/Battle/BattleManagementService+ECS.cs
@@ -63,6 +63,13 @@ public void StartEcsContext()
.Add(new BattleAssignTargetRelationEffectsSystem()) // if target is hero (not enemy)
// scans for relations and casts effects
// on active target
+ .Add(new BattleRelEffectProbeSystem()) //for all probes try cast a real effect
+ .Add(new BattlePrepareRevengeEffectSystem())
+ .Add(new BattlePrepareTargetEffectSystem()) //TODO: don't forget to reset this effect at some point
+ .Add(new BattlePrepareRelEffectVisualSystem())
+ .DelHere()
+ .DelHere>() //effects (if any were spawned) will survive
+
.Add(new BattleMarkTurnReadySystem()) // marks ready turns for autoplay
.DelHere()
.Add(new BattleAutoMakeTurnSystem())