using System; using System.Collections; using System.Collections.Generic; using System.Linq; using System.Linq.Expressions; using UnityEngine; public class LearningEngine : MonoBehaviour { private List<EnemyManager> activeEngagements = new List<EnemyManager>(); private Dictionary<EnemyManager, Engagement> engagements = new Dictionary<EnemyManager, Engagement>(); public LearningUI learningUI; public GameManager gameManager; // CONSTANT HEURISTICS DEFAULTS private int BAD_VERTICAL_CROSSHAIR_PLACEMENT = 6; private int BAD_HORIZONTAL_CROSSHAIR_PLACEMENT = 13; private int BAD_MISSED_HORIZONTAL_SHOTS = 0; private int BAD_MISSED_VERTICAL_SHOTS = 0; private int BAD_DAMAGE_SOURCES = 1; private float BAD_ACCURACY = 1; private float BAD_HEADSHOT = 1; private float BAD_TIME_TO_KILL = 0.9f; private float BAD_TIME_TO_DAMAGE = 0.6f; public bool ACCURACY_ENABLED; public bool HEADSHOT_ENABLED; public bool TTD_ENABLED; public bool TTK_ENABLED; public bool VC_ENABLED; public bool HC_ENABLED; public bool MISSES_ENABLED; public bool DS_ENABLED; public bool HEALTH_ENABLED; public bool TRACKING_ENABLED; private Color accuracyColor = Color.blue; private Color headshotColor = Color.red; private Color healthColor = Color.cyan; private Color ttdColor = Color.yellow; private Color ttkColor = Color.magenta; private Color trackingColor = Color.black; public void Start() { if (!PlayerPrefs.HasKey("playerAccuracy")) { PlayerPrefs.SetInt("playerAccuracyEnabled", 1); PlayerPrefs.SetFloat("playerAccuracy", BAD_ACCURACY); PlayerPrefs.SetInt("playerHeadshotEnabled", 1); PlayerPrefs.SetFloat("playerHeadshot", BAD_HEADSHOT); PlayerPrefs.SetInt("playerTtdEnabled", 1); PlayerPrefs.SetFloat("playerTtd", BAD_TIME_TO_DAMAGE); PlayerPrefs.SetInt("playerTtkEnabled", 1); PlayerPrefs.SetFloat("playerTtk", BAD_TIME_TO_KILL); PlayerPrefs.SetInt("playerVerticalCrosshairEnabled", 1); PlayerPrefs.SetFloat("playerVerticalCrosshair", BAD_VERTICAL_CROSSHAIR_PLACEMENT); PlayerPrefs.SetInt("playerHorizontalCrosshairEnabled", 1); PlayerPrefs.SetFloat("playerHorizontalCrosshair", BAD_HORIZONTAL_CROSSHAIR_PLACEMENT); PlayerPrefs.SetInt("playerMissesEnabled", 1); PlayerPrefs.SetFloat("playerMisses", BAD_MISSED_VERTICAL_SHOTS); PlayerPrefs.SetInt("playerDamageSourcesEnabled", 1); PlayerPrefs.SetFloat("playerDamageSources", BAD_DAMAGE_SOURCES); PlayerPrefs.SetInt("playerHealthLossEnabled", 1); } BAD_ACCURACY = PlayerPrefs.GetFloat("playerAccuracy"); BAD_HEADSHOT = PlayerPrefs.GetFloat("playerHeadshot"); BAD_TIME_TO_DAMAGE = PlayerPrefs.GetFloat("playerTtd"); BAD_TIME_TO_KILL = PlayerPrefs.GetFloat("playerTtk"); BAD_VERTICAL_CROSSHAIR_PLACEMENT = (int) PlayerPrefs.GetFloat("playerVerticalCrosshair"); BAD_HORIZONTAL_CROSSHAIR_PLACEMENT = (int) PlayerPrefs.GetFloat("playerHorizontalCrosshair"); BAD_MISSED_VERTICAL_SHOTS = (int) PlayerPrefs.GetFloat("playerMisses"); BAD_MISSED_HORIZONTAL_SHOTS = (int) PlayerPrefs.GetFloat("playerMisses"); BAD_DAMAGE_SOURCES = (int) PlayerPrefs.GetFloat("playerDamageSources"); ACCURACY_ENABLED = PlayerPrefs.GetInt("playerAccuracyEnabled") == 1; HEADSHOT_ENABLED = PlayerPrefs.GetInt("playerAccuracyEnabled") == 1; TTD_ENABLED = PlayerPrefs.GetInt("playerAccuracyEnabled") == 1; TTK_ENABLED = PlayerPrefs.GetInt("playerAccuracyEnabled") == 1; VC_ENABLED = PlayerPrefs.GetInt("playerAccuracyEnabled") == 1; HC_ENABLED = PlayerPrefs.GetInt("playerAccuracyEnabled") == 1; MISSES_ENABLED = PlayerPrefs.GetInt("playerAccuracyEnabled") == 1; DS_ENABLED = PlayerPrefs.GetInt("playerAccuracyEnabled") == 1; HEALTH_ENABLED = PlayerPrefs.GetInt("playerAccuracyEnabled") == 1; TRACKING_ENABLED = PlayerPrefs.GetInt("playerTrackingEnabled") == 1; } public void StartEngagement(EnemyManager enemy) { Debug.Log("starting engagement"); activeEngagements.Add(enemy); var eng = new Engagement(); eng.moving = enemy.moving; engagements.Add(enemy, eng); } public void EndEngagement(EnemyManager enemy) { if (!engagements.ContainsKey(enemy)) { return; } // detect which statistics are "bad" and of those pick the worst one // for the worst one pick an attribute they had that was bad and suggest improvement for it Debug.Log(JsonUtility.ToJson(engagements[enemy])); gameManager.results.engagements.Add(engagements[enemy]); var e = engagements[enemy]; var headshotPercentage = e.headshots / (double) e.hitshots; var accuracy = e.hitshots / (double) (e.hitshots + e.missedHorizontalShots.Count + e.missedVerticalShots.Count); var advised = false; if (e.ammoAtEngagement * 35 < enemy.health) { advised = true; learningUI.GuideAmmoManagement("Poor time to kill due to bad ammo management. Reloading before a fight will give you a lower time to kill.", ttkColor); } if (e.moving && TRACKING_ENABLED) { if (accuracy < BAD_ACCURACY && !advised && ACCURACY_ENABLED) { if (e.missedVerticalShots.Count > BAD_MISSED_VERTICAL_SHOTS && MISSES_ENABLED) { if (e.movementWhileShooting.Contains(true)) { advised = true; learningUI.GuideMovingWhileShooting( "Poor weapon accuracy due to moving while shooting. Come to a halt before firing so you don't miss any bullets.", trackingColor); } else if (e.missedHorizontalShots.Count > BAD_MISSED_HORIZONTAL_SHOTS || e.missedVerticalShots.Count > BAD_MISSED_VERTICAL_SHOTS) { advised = true; learningUI.GuideTracking("Missed shots due to poor tracking. Pay attention to the speed and direction the enemy is going so you can try and pre-emptively place your crosshair in the right position.", trackingColor); } } } } else { if (accuracy < BAD_ACCURACY && !advised && ACCURACY_ENABLED) { if (e.missedVerticalShots.Count > BAD_MISSED_VERTICAL_SHOTS && MISSES_ENABLED) { advised = true; if (e.movementWhileShooting.Contains(true)) { advised = true; learningUI.GuideMovingWhileShooting("Poor weapon accuracy due to moving while shooting. Come to a halt before firing so you don't miss any bullets.", accuracyColor); } else if (e.verticalCrosshairMovement > BAD_VERTICAL_CROSSHAIR_PLACEMENT && VC_ENABLED) { learningUI.GuideVerticalCrosshairPlacement("Poor weapon accuracy due to bad vertical crosshair placement. Aim at head height so your bullets hit the head fastest.", accuracyColor); } else { learningUI.GuideRecoil("Poor weapon accuracy due to bad recoil handling. Pull down your crosshair while shooting so it stays pointing at the enemy.", accuracyColor); } } else if (e.missedHorizontalShots.Count > BAD_MISSED_HORIZONTAL_SHOTS && MISSES_ENABLED) { advised = true; if (e.horizontalCrosshairMovement > BAD_HORIZONTAL_CROSSHAIR_PLACEMENT) { learningUI.GuideHorizontalCrosshairPlacement("Poor weapon accuracy due to bad horizontal crosshair placement. Line your crosshair up where you expect the enemy to be so your bullets hit them fastest.", accuracyColor); } else { learningUI.GuideRecoil("Poor weapon accuracy due to bad recoil handling. Pull down your crosshair while shooting so it stays pointing at the enemy.", accuracyColor); } } } if (headshotPercentage < BAD_HEADSHOT && !advised && HEADSHOT_ENABLED) { if (e.verticalCrosshairMovement > BAD_VERTICAL_CROSSHAIR_PLACEMENT && VC_ENABLED) { advised = true; learningUI.GuideVerticalCrosshairPlacement("Poor headshot% due to bad vertical crosshair placement. Placing your crosshair where you expect the enemies' heads to be lets you kill them faster once they come into view.", headshotColor); } else if (e.horizontalCrosshairMovement > BAD_HORIZONTAL_CROSSHAIR_PLACEMENT && HC_ENABLED) { advised = true; learningUI.GuideHorizontalCrosshairPlacement("Poor headshot% due to bad horizontal crosshair placement. Placing your crosshair where you expect the enemies' heads to be lets you kill them faster once they come into view.", headshotColor); } else if (e.movementWhileShooting.Contains(true)) { advised = true; learningUI.GuideMovingWhileShooting("Poor headshot% due to moving while shooting. Come to a halt before shooting so your bullets go where you are aiming.", headshotColor); } else if (e.missedVerticalShots.Count > BAD_MISSED_VERTICAL_SHOTS && MISSES_ENABLED) { advised = true; learningUI.GuideRecoil("Poor headshot% due to bad recoil control. Pull down when aiming to ensure your crosshair stays on the enemy.", headshotColor); } } if (e.healthLoss > enemy.damage && !advised && HEALTH_ENABLED) { if (e.noOfDamageSources.Count > BAD_DAMAGE_SOURCES && DS_ENABLED) { advised = true; learningUI.GuideOverpeeking("Lost more health than necessary due to overpeeking. Approach corners slowly so you can try and take fights one at a time.", healthColor); } } if (e.timeToDamage >= BAD_TIME_TO_DAMAGE && !advised && TTD_ENABLED) { if (e.verticalCrosshairMovement > BAD_VERTICAL_CROSSHAIR_PLACEMENT && VC_ENABLED) { advised = true; learningUI.GuideVerticalCrosshairPlacement("Poor time to damage due to bad vertical crosshair placement. Placing your crosshair at a height you expect the enemies to be will allow you to kill them faster, and lower your chances of taking damage.", ttdColor); } else if (e.horizontalCrosshairMovement > BAD_HORIZONTAL_CROSSHAIR_PLACEMENT && HC_ENABLED) { advised = true; learningUI.GuideHorizontalCrosshairPlacement("Poor time to damage due to bad horizontal crosshair placement. Placing your crosshair at a height you expect the enemies to be will allow you to kill them faster, and lower your chances of taking damage.", ttdColor); } else if (e.movementWhileShooting.Contains(true)) { advised = true; learningUI.GuideMovingWhileShooting("Poor time to damage due to moving while shooting. Come to a halt before shooting to make sure your bullets go where you are aiming.", ttdColor); } else if (e.missedVerticalShots.Count > BAD_MISSED_VERTICAL_SHOTS && MISSES_ENABLED) { advised = true; learningUI.GuideRecoil("Poor time to damage due to poor recoil control. Make sure you are aiming at the enemy before you start shooting, and pull down your crosshair to keep it on the enemy.", ttdColor); } else if (e.noOfDamageSources.Count > BAD_DAMAGE_SOURCES && DS_ENABLED) { advised = true; learningUI.GuideOverpeeking("Poor time to damage due to overpeeking. Try and approach corners slowly so you can take fights one at a time.", ttdColor); } } if (e.timeToKill >= BAD_TIME_TO_KILL && !advised && TTK_ENABLED) { if (e.verticalCrosshairMovement > BAD_VERTICAL_CROSSHAIR_PLACEMENT && VC_ENABLED) { advised = true; learningUI.GuideVerticalCrosshairPlacement("Poor time to kill due to bad vertical crosshair placement. Placing your crosshair at a height you expect the enemies to be will allow you to kill them faster, and lower your chances of taking damage.", ttkColor); } else if (e.horizontalCrosshairMovement > BAD_HORIZONTAL_CROSSHAIR_PLACEMENT && HC_ENABLED) { advised = true; learningUI.GuideHorizontalCrosshairPlacement("Poor time to kill due to bad horizontal crosshair placement. Placing your crosshair at a height you expect the enemies to be will allow you to kill them faster, and lower your chances of taking damage.", ttkColor); } else if (e.movementWhileShooting.Contains(true)) { advised = true; learningUI.GuideMovingWhileShooting("Poor time to kill due to moving while shooting. Come to a halt before shooting to make sure your bullets go where you are aiming.", ttkColor); } else if (e.missedVerticalShots.Count > BAD_MISSED_VERTICAL_SHOTS && MISSES_ENABLED) { advised = true; learningUI.GuideRecoil("Poor time to kill due to poor recoil control. Pull down your crosshair as you shoot to keep it on the enemy.", ttkColor); } else if (e.noOfDamageSources.Count > BAD_DAMAGE_SOURCES && DS_ENABLED) { advised = true; learningUI.GuideOverpeeking("Poor time to kill due to overpeeking. Try and approach corners slowly so you can take fights one at a time.", ttkColor); } } } if (!advised) { learningUI.GuideSuccess("Nothing was wrong there good skills", Color.green); } activeEngagements.Remove(enemy); engagements.Remove(enemy); } public void ReportMovingShot(bool moving) { foreach (EnemyManager engagement in activeEngagements) { engagements[engagement].movementWhileShooting.Add(moving); } } public void ReportCrosshairMovement(EnemyManager enemy, float xMovement, float yMovement) { if (engagements.ContainsKey(enemy)) { engagements[enemy].horizontalCrosshairMovement = xMovement; engagements[enemy].verticalCrosshairMovement = yMovement; } } public void ReportReload() { foreach (EnemyManager enemy in activeEngagements) { engagements[enemy].reloadsWhileEngaged += 1; } } public void ReportAmmo(int ammo) { foreach (var enemy in activeEngagements) { engagements[enemy].ammoAtEngagement = ammo; } } public void ReportDamageSource(EnemyManager enemy) { foreach (var engagement in activeEngagements) { // Debug.Log(engagements[engagement].noOfDamageSources.Count); // Debug.Log(enemy.id); if (!engagements[engagement].noOfDamageSources.Contains(enemy.id)) { // Debug.Log("doesnt contain so adding " + enemy.id); engagements[engagement].noOfDamageSources.Add(enemy.id); } } } public void ReportHeightDifference(EnemyManager enemy, float diff) { if (engagements.ContainsKey(enemy)) { engagements[enemy].verticalDistance = diff; } } public void ReportMissedShot(EnemyManager enemy, float xMovement, float yMovement) { if (engagements.ContainsKey(enemy)) { if (xMovement > yMovement) { engagements[enemy].missedHorizontalShots.Add(xMovement); } else { engagements[enemy].missedVerticalShots.Add(yMovement); } } } public void ReportHeadshot(bool headshot, EnemyManager enemy) { if (engagements.ContainsKey(enemy)) { engagements[enemy].hitshots += 1; engagements[enemy].headshots += headshot ? 1 : 0; } } public void ReportTimeToDamage(float time, EnemyManager enemy) { if (engagements.ContainsKey(enemy)) { engagements[enemy].timeToDamage = time; } } public void ReportTimeToKill(float time, EnemyManager enemy) { if (engagements.ContainsKey(enemy)) { engagements[enemy].timeToKill = time; } } public void ReportHealthLoss(EnemyManager enemy, int health) { if (engagements.ContainsKey(enemy)) { engagements[enemy].healthLoss += health; } } }