diff --git a/Assets/GWConquest/Prefabs/ArmyGui.prefab b/Assets/GWConquest/Prefabs/ArmyGui.prefab index 83490fe..45dbe83 100644 --- a/Assets/GWConquest/Prefabs/ArmyGui.prefab +++ b/Assets/GWConquest/Prefabs/ArmyGui.prefab @@ -64,7 +64,7 @@ MonoBehaviour: m_OnCullStateChanged: m_PersistentCalls: m_Calls: [] - m_Sprite: {fileID: 0} + m_Sprite: {fileID: 21300000, guid: f2fa446b698637a48bfe48e7cc582cbb, type: 3} m_Type: 3 m_PreserveAspect: 0 m_FillCenter: 1 @@ -1355,7 +1355,9 @@ MonoBehaviour: m_Name: m_EditorClassIdentifier: FormationsTransform: {fileID: 77748483683952273} + FormationsPanelTransform: {fileID: 7794718298833807266} SelectedUnitNameText: {fileID: 77748482107769389} + SelectedUnitHealthBar: {fileID: 77748481860671164} IsOwnPlayer: 1 FormationUIPrefab: {fileID: 790083374931814115, guid: 5b96168d30f6b44428827c365006875b, type: 3} diff --git a/Assets/GWConquest/Prefabs/BattleUnitIcon.prefab b/Assets/GWConquest/Prefabs/BattleUnitIcon.prefab index a2a3574..33c24a0 100644 --- a/Assets/GWConquest/Prefabs/BattleUnitIcon.prefab +++ b/Assets/GWConquest/Prefabs/BattleUnitIcon.prefab @@ -297,6 +297,7 @@ MonoBehaviour: mediumColor: {r: 1, g: 0.7411765, b: 0, a: 0.8784314} criticalColor: {r: 0.8980392, g: 0.15686275, b: 0.15686275, a: 0.8784314} HitSoundDelay: 0.25 + IsDraggable: 1 --- !u!95 &2103027038577876570 Animator: serializedVersion: 3 diff --git a/Assets/GWConquest/Scenes/GalaxyMap.unity b/Assets/GWConquest/Scenes/GalaxyMap.unity index 2bbcda1..ec13132 100644 --- a/Assets/GWConquest/Scenes/GalaxyMap.unity +++ b/Assets/GWConquest/Scenes/GalaxyMap.unity @@ -24806,6 +24806,7 @@ MonoBehaviour: GroundTransitionLengthFactor: 30 SpaceTransitionLengthFactor: 1 BattleTurnLength: 30 + BattleTurnDeviation: 10 MoveToFlankCooldown: 15 MoveToReserveCooldown: 15 SpawnAIPlayer: 1 diff --git a/Assets/GWConquest/Scripts/Battle.cs b/Assets/GWConquest/Scripts/Battle.cs index c19d21d..687be79 100644 --- a/Assets/GWConquest/Scripts/Battle.cs +++ b/Assets/GWConquest/Scripts/Battle.cs @@ -12,26 +12,22 @@ namespace GWConquest get => FormationList.Select((f,i) => f.GetComponent().Player).Distinct(); } - private float LastTurnTime = 0f; - private int BattleTurn = 0; + public IEnumerable AllUnits { + get => FormationList.SelectMany(e => e.GetComponent().Units); + } private List UnitActions = new List(); [System.Serializable] private class UnitAction { public Unit Unit; + public BattleFlank BattleFlank; + public int WeaponIndex; public float ActionTime; - } - - private Dictionary TargetingPools = new Dictionary(); - private TargetingPool GetTargetingPoolForPlayer(Player player) - { - if(!TargetingPools.ContainsKey(player)) - { - TargetingPools[player] = new TargetingPool(); + public WeaponStats Weapon { + get => Unit.Class.WeaponStatsArray[WeaponIndex]; } - return TargetingPools[player]; } public int FlankCount { @@ -133,73 +129,26 @@ namespace GWConquest base.SimulateOwner(); var gm = GameManager.Instance; - var time = Time.time; - - if(time > LastTurnTime + gm.BattleTurnLength) - { - LastTurnTime = time; - BattleTurn++; - BoltLog.Info("Starting turn {0} on battle {1}", BattleTurn, this); - - StartNewTurn(time); - } SimulateTurn(); } - private void StartNewTurn(float time) - { - var allUnits = FormationList.SelectMany((e, i) => e.GetComponent().Units); - - var actions = allUnits.Select((u,i) => { - return new UnitAction() { - Unit = u, - ActionTime = Random.value - }; - }).ToList(); - - actions.Sort((a,b) => (int) Mathf.Sign(a.ActionTime - b.ActionTime)); - - foreach(var action in actions) - { - action.ActionTime *= GameManager.Instance.BattleTurnLength; - action.ActionTime += time; - } - - UnitActions = actions; - - var allPlayers = AllPlayers; - foreach(Player p in allPlayers) - { - var pool = GetTargetingPoolForPlayer(p); - pool.Clear(); - - var attackableUnits = allUnits.Where((u,i) => u.Player != p); - - foreach(Unit u in attackableUnits) - { - if(!u.IsDead) - { - pool.Add(u, u.Class.Size); - } - } - } - } - private void SimulateTurn() { - var time = Time.time; + var time = Time.fixedTime; bool hasChanges = false; - while(UnitActions.Count > 0 && UnitActions[0].ActionTime <= time) + foreach(UnitAction action in UnitActions.ToList()) { + if(action.ActionTime <= time) + { + SimulateUnitAction(action); - var unit = UnitActions[0].Unit; - - SimulateUnitAction(unit); - - UnitActions.RemoveAt(0); + RenewUnitAction(action); hasChanges = true; + } + + } if(hasChanges) @@ -221,48 +170,131 @@ namespace GWConquest } } - private void SimulateUnitAction(Unit unit) + private void AddCombatActions(Unit unit) { - BoltLog.Info("Simulating action for unit {0} on turn {1}", unit, BattleTurn); + float time = Time.fixedTime; + if(unit.CurrentFlank != null && !unit.IsDead) + { + var weapons = unit.Class.WeaponStatsArray; + for(int i = 0; i < weapons.Length; i++) + { + var action = new UnitAction() { + Unit = unit, + BattleFlank = unit.CurrentFlank, + WeaponIndex = i + }; + RenewUnitAction(action); + UnitActions.Add(action); + } + } + } + + private void RenewUnitAction(UnitAction action) + { + var attackCount = action.Weapon.AttackCount; + var gm = GameManager.Instance; + + float attackDelay = Random.Range(gm.BattleTurnLength - gm.BattleTurnDeviation, gm.BattleTurnLength + gm.BattleTurnDeviation); + attackDelay /= attackCount; - var pool = GetTargetingPoolForPlayer(unit.Player); + action.ActionTime = Time.fixedTime + attackDelay; + } - if(pool.IsEmpty()) - return; + private void RemoveUnitActions(Unit unit) + { + UnitActions.RemoveAll(a => a.Unit == unit); + } + + private void SimulateUnitAction(UnitAction action) + { + var unit = action.Unit; + var flank = action.BattleFlank; + BoltLog.Info("Simulating action for unit {0} on flank {1}", unit, flank); - var weapons = unit.Class.WeaponStatsArray; + var weapon = action.Weapon; - foreach(var weapon in weapons) + var target = FindTargetForCombat(action); + + if(target == null) { - for(int i = 0; i < weapon.AttackCount; i++) - { - if(pool.IsEmpty()) - return; + return; + } + + if(!Check(weapon.Accuracy)) + return; - if(!Check(weapon.Accuracy)) - continue; + if(Check(target.Class.Evasion)) + return; - var target = pool.GetRandomUnit(); + int damage = weapon.Damage; + float modifier = GetArmourModifier(target.Class.Armour, weapon.Penetration); - if(Check(target.Class.Evasion)) - continue; + damage = Mathf.RoundToInt(damage * modifier); + + if(damage <= 0) + return; - int damage = weapon.Damage; - float modifier = GetArmourModifier(target.Class.Armour, weapon.Penetration); + BoltLog.Info("Dealing {0} HP damage to unit {1} from unit {2}", damage, target, unit); + + target.TakeDamage(damage); + + } + + private Unit FindTargetForCombat(UnitAction action) + { + IEnumerable targets; + + if(action.BattleFlank != null) + { + targets = action.BattleFlank.OpposingFlank.Units; + } + else { + throw new System.NotImplementedException(); + } - damage = Mathf.RoundToInt(damage * modifier); + targets = targets.Where(u => !u.IsDead); - if(damage <= 0) - continue; + if(targets.FirstOrDefault() == null) + { + return null; + } - BoltLog.Info("Dealing {0} HP damage to unit {1} from unit {2}", damage, target, unit); + float penetration = action.Unit.Class.WeaponStatsArray[action.WeaponIndex].Penetration; - target.TakeDamage(damage); - if(target.IsDead){ - pool.RemoveUnit(target); - } + IEnumerable penTargets = null;; + for(float p = penetration; p >= 0; p--) + { + penTargets = targets.Where(u => u.Armour <= p && u.Armour > p - 1); + if(penTargets.FirstOrDefault() != null) + { + break; } } + + if(penTargets == null || penTargets.FirstOrDefault() == null) + { + penTargets = targets; + } + + var tList = penTargets.ToList(); + int randomInd = Random.Range(0, tList.Count); + + return tList[randomInd]; + } + + public void OnBattleStateChanged(Unit unit) + { + RemoveUnitActions(unit); + + if(unit.BattleState == BattleUnitState.OnFlank) + { + AddCombatActions(unit); + } + } + + public void OnUnitDead(Unit unit) + { + RemoveUnitActions(unit); } public void MoveUnitToFlank(Unit unit, BattleFlank flank, int flankIndex) @@ -286,11 +318,19 @@ namespace GWConquest float movement = unit.Class.Movement <= 0 ? 1f : unit.Class.Movement; unit.SetActionCooldown(GameManager.Instance.MoveToFlankCooldown / movement); flank.SetUnit(flankIndex, unit); + unit.CurrentFlank = flank; //SetUIDirty(updatePositions: true); } } + public void MoveUnitToReserve(Unit unit) + { + unit.BattleState = BattleUnitState.MovingToReserve; + float movement = unit.Class.Movement <= 0 ? 1f : unit.Class.Movement; + unit.SetActionCooldown(GameManager.Instance.MoveToReserveCooldown / movement); + } + private static bool Check(float chance) { return Random.Range(0f, 1f) <= chance; } diff --git a/Assets/GWConquest/Scripts/BattleFlank.cs b/Assets/GWConquest/Scripts/BattleFlank.cs index ed2905d..668e9bd 100644 --- a/Assets/GWConquest/Scripts/BattleFlank.cs +++ b/Assets/GWConquest/Scripts/BattleFlank.cs @@ -1,4 +1,5 @@ -using UnityEngine; +using System.Collections.Generic; +using System.Linq; namespace GWConquest { @@ -32,6 +33,33 @@ namespace GWConquest { { state.Units[index] = unit?.entity; } + + public int GetUnitIndex(Unit unit) + { + for(int i = 0; i < state.MaxUnitCount; i++) + { + if(state.Units[i] == unit.entity) + { + return i; + } + } + return -1; + } + + public void RemoveUnit(Unit unit) + { + int index = GetUnitIndex(unit); + if(index != -1) + { + SetUnit(index, null); + } + } + + public IEnumerable Units { + get { + return state.Units.Where(e => e != null).Select((e,i) => e.GetComponent()); + } + } } } \ No newline at end of file diff --git a/Assets/GWConquest/Scripts/GameManager.cs b/Assets/GWConquest/Scripts/GameManager.cs index dffeadf..4710618 100644 --- a/Assets/GWConquest/Scripts/GameManager.cs +++ b/Assets/GWConquest/Scripts/GameManager.cs @@ -13,6 +13,7 @@ namespace GWConquest public float SpaceTransitionLengthFactor; public float BattleTurnLength; + public float BattleTurnDeviation; public float MoveToFlankCooldown; public float MoveToReserveCooldown; diff --git a/Assets/GWConquest/Scripts/ServerCallbacks.cs b/Assets/GWConquest/Scripts/ServerCallbacks.cs index 28741d2..9540db8 100644 --- a/Assets/GWConquest/Scripts/ServerCallbacks.cs +++ b/Assets/GWConquest/Scripts/ServerCallbacks.cs @@ -74,5 +74,14 @@ namespace GWConquest var flank = evnt.Flank.GetComponent(); flank.Battle.MoveUnitToFlank(evnt.Unit.GetComponent(), flank, evnt.FlankIndex); } + + public override void OnEvent(MoveUnitToReserveEvent evnt) + { + var unit = evnt.Unit.GetComponent(); + if(unit.CurrentBattle != null) + { + unit.CurrentBattle.MoveUnitToReserve(unit); + } + } } } \ No newline at end of file diff --git a/Assets/GWConquest/Scripts/UI/BattleArmyPanel.cs b/Assets/GWConquest/Scripts/UI/BattleArmyPanel.cs index f6f7d43..036d7a0 100644 --- a/Assets/GWConquest/Scripts/UI/BattleArmyPanel.cs +++ b/Assets/GWConquest/Scripts/UI/BattleArmyPanel.cs @@ -8,7 +8,10 @@ namespace GWConquest { public RectTransform FormationsTransform; + public RectTransform FormationsPanelTransform; + public Text SelectedUnitNameText; + public Image SelectedUnitHealthBar; public bool IsOwnPlayer; @@ -16,6 +19,8 @@ namespace GWConquest { public GameObject Buttons; + + public BattleUI BattleUI; public Battle Battle { get => BattleUI.Battle; @@ -127,6 +132,7 @@ namespace GWConquest { { Buttons.SetActive(true); SelectedUnitNameText.text = SelectedUnit.Class.FullName; + SelectedUnitHealthBar.fillAmount = (float) SelectedUnit.Hitpoints / SelectedUnit.Class.Hitpoints; } else { diff --git a/Assets/GWConquest/Scripts/UI/BattleFlankUI.cs b/Assets/GWConquest/Scripts/UI/BattleFlankUI.cs index 935f6e3..b97f2c6 100644 --- a/Assets/GWConquest/Scripts/UI/BattleFlankUI.cs +++ b/Assets/GWConquest/Scripts/UI/BattleFlankUI.cs @@ -61,6 +61,16 @@ namespace GWConquest { } } + public void OnIconDraggedToPanel(BattleUnitIcon icon, BattleArmyPanel panel) + { + if(icon.Unit.BattleState == BattleUnitState.OnFlank) + { + MoveUnitToReserveEvent ev = MoveUnitToReserveEvent.Create(Bolt.GlobalTargets.OnlyServer); + ev.Unit = icon.Unit.entity; + ev.Send(); + } + } + } } \ No newline at end of file diff --git a/Assets/GWConquest/Scripts/UI/BattleUnitIcon.cs b/Assets/GWConquest/Scripts/UI/BattleUnitIcon.cs index a2be9ad..7103570 100644 --- a/Assets/GWConquest/Scripts/UI/BattleUnitIcon.cs +++ b/Assets/GWConquest/Scripts/UI/BattleUnitIcon.cs @@ -20,6 +20,8 @@ namespace GWConquest { [System.NonSerialized] public Unit Unit; + public bool IsDraggable = true; + private RectTransform ImageTransform; public static int Compare(Unit a, Unit b) @@ -51,7 +53,20 @@ namespace GWConquest { } public void OnClick(){ - GetComponentInParent()?.OnIconClicked(this); + if(Unit != null) + { + var battleUI = GetComponentInParent(); + BattleArmyPanel panel; + if(Unit.Player == Player.CurrentPlayer) + { + panel = battleUI.PlayerPanel; + } + else { + panel = battleUI.EnemyPanel; + } + + panel.OnIconClicked(this); + } } public void UpdateIcon() @@ -107,22 +122,45 @@ namespace GWConquest { { if(Unit != null) { - foreach(BattleUnitIcon icon in FindObjectsOfType()) + var armyPanel = GetComponentInParent(); + var flankUI = GetComponentInParent(); + if (armyPanel != null) { - var iconRT = icon.GetComponent(); - Vector3 mousePos = Input.mousePosition; - if(RectTransformUtility.RectangleContainsScreenPoint(iconRT, mousePos)) + foreach (BattleUnitIcon icon in FindObjectsOfType()) + { + var iconRT = icon.GetComponent(); + Vector3 mousePos = Input.mousePosition; + if (RectTransformUtility.RectangleContainsScreenPoint(iconRT, mousePos)) + { + armyPanel.OnIconDragged(this, icon); + break; + } + } + } + else if(flankUI != null){ + foreach(BattleArmyPanel panel in FindObjectsOfType()) { - GetComponentInParent()?.OnIconDragged(this, icon); - break; + var panelRT = panel.FormationsPanelTransform; + Vector3 mousePos = Input.mousePosition; + if (RectTransformUtility.RectangleContainsScreenPoint(panelRT, mousePos)) + { + flankUI.OnIconDraggedToPanel(this, panel); + break; + } } } + } return true; } + public override bool CanDrag() + { + return IsDraggable && Unit != null; + } + } } \ No newline at end of file diff --git a/Assets/GWConquest/Scripts/UI/DragDropElement.cs b/Assets/GWConquest/Scripts/UI/DragDropElement.cs index c3c58fb..2d926a0 100644 --- a/Assets/GWConquest/Scripts/UI/DragDropElement.cs +++ b/Assets/GWConquest/Scripts/UI/DragDropElement.cs @@ -20,7 +20,7 @@ namespace GWConquest private void Update() { - if(!isDragging & Input.GetButtonDown("Left Click")) + if(!isDragging & Input.GetButtonDown("Left Click") && CanDrag()) { Vector3 mousePos = Input.mousePosition; if(RectTransformUtility.RectangleContainsScreenPoint(rectTransform, mousePos)) @@ -80,5 +80,10 @@ namespace GWConquest { } + + public virtual bool CanDrag() + { + return true; + } } } \ No newline at end of file diff --git a/Assets/GWConquest/Scripts/UI/IngameUI.cs b/Assets/GWConquest/Scripts/UI/IngameUI.cs index b7a895a..6f3106c 100644 --- a/Assets/GWConquest/Scripts/UI/IngameUI.cs +++ b/Assets/GWConquest/Scripts/UI/IngameUI.cs @@ -40,6 +40,10 @@ namespace GWConquest Instance = this; } + private void Start() { + DisablePlanetView(); + } + private void Update() { if (Input.GetButtonDown("Left Click")) @@ -67,13 +71,17 @@ namespace GWConquest if(Input.GetButtonDown("Cancel")) { - if(PlanetViewEnabled && PlanetView.BattleUI.isActiveAndEnabled) + if(PlanetViewEnabled) { - PlanetView.HideBattleUI(); - } - else { - DisablePlanetView(); + if(PlanetView.BattleUI.isActiveAndEnabled) + { + PlanetView.HideBattleUI(); + } + else { + DisablePlanetView(); + } } + } } @@ -236,32 +244,31 @@ namespace GWConquest private void DisablePlanetView() { - if(PlanetViewEnabled) - { - PlanetView.HideUI(); - PlanetView.gameObject.SetActive(false); - foreach(Planet p in Planet.AllPlanets) + PlanetView.HideUI(); + PlanetView.gameObject.SetActive(false); + + foreach(Planet p in Planet.AllPlanets) + { + foreach (Renderer r in p.GetComponentsInChildren()) { - foreach (Renderer r in p.GetComponentsInChildren()) - { - r.enabled = true; - } + r.enabled = true; } + } - GWCamera camera = FindObjectOfType(); - camera.ResetCameraTransform(); + GWCamera camera = FindObjectOfType(); + camera.ResetCameraTransform(); - Camera.main.orthographic = true; + Camera.main.orthographic = true; - viewedPlanet.GetComponent().enabled = true; - PlanetHud.gameObject.SetActive(true); - PlanetNames.SetActive(true); - PlanetConnections.SetActive(true); + viewedPlanet.GetComponent().enabled = true; + PlanetHud.gameObject.SetActive(true); + PlanetNames.SetActive(true); + PlanetConnections.SetActive(true); + + viewedPlanet = null; + PlanetViewEnabled = false; - viewedPlanet = null; - PlanetViewEnabled = false; - } } diff --git a/Assets/GWConquest/Scripts/Unit.cs b/Assets/GWConquest/Scripts/Unit.cs index 58022fd..8c581a0 100644 --- a/Assets/GWConquest/Scripts/Unit.cs +++ b/Assets/GWConquest/Scripts/Unit.cs @@ -31,6 +31,14 @@ namespace GWConquest set => state.Hitpoints = value; } + public float Armour { + get => Class.Armour; + } + + public float Evasion { + get => Class.Evasion; + } + public bool IsDead { get => Hitpoints <= 0; } @@ -41,7 +49,16 @@ namespace GWConquest public BattleUnitState BattleState { get => (BattleUnitState) state.BattleState; - set => state.BattleState = (int) value; + set { + state.BattleState = (int) value; + if(BoltNetwork.IsServer) + { + if(CurrentBattle != null) + { + CurrentBattle.OnBattleStateChanged(this); + } + } + } } public RevealState RevealState { @@ -66,6 +83,13 @@ namespace GWConquest [System.NonSerialized] public BattleUnitIcon CurrentIcon; + [System.NonSerialized] + public BattleFlank CurrentFlank; + + public Battle CurrentBattle { + get => Formation.currentZone.CurrentBattle; + } + public override void Attached() { state.AddCallback("Formation", () => @@ -110,6 +134,11 @@ namespace GWConquest { CurrentIcon.PlayHitAnim(); } + + if(Hitpoints <= 0) + { + CurrentBattle.OnUnitDead(this); + } } public override void SimulateOwner() @@ -122,6 +151,12 @@ namespace GWConquest { BattleState = BattleUnitState.OnFlank; } + else if (BattleState == BattleUnitState.MovingToReserve) + { + BattleState = BattleUnitState.InReserve; + CurrentFlank.RemoveUnit(this); + CurrentFlank = null; + } } else { @@ -130,7 +165,14 @@ namespace GWConquest } - + public bool IsInReserve { + get { + return BattleState == BattleUnitState.InReserve || + BattleState == BattleUnitState.Arriving || + BattleState == BattleUnitState.Departing || + BattleState == BattleUnitState.MovingToReserve; + } + }