public IEnumerator TurnCycle(Team team, Team team2) { // AI calculations list of commands // yield return execute calculated commands and moves yield return(new WaitForSeconds(5)); Debug.Log("End Enemy turn"); /*stategies: * Scoring nearby slots based on utility. * n^2 n = around 20 = 400 per character * */ for (int i = 0; i < team.units.Count; i++) { Soldier unit = team.units[i]; //Generate data for all slots in move range and for soldiers in range that can be attacked. taken move slots are excluded. GridSlot[] slots = GridSlot.GetAvaliableSlotsInMoveRange(unit.curPositionSlot, unit.fullMovementRange); Soldier[] enemiesInRange = GridSlot.GetVisibleEnemySlots(unit, team2); AiSlotData[] moveData = new AiSlotData[slots.Length]; AiSlotData[] enemyData = new AiSlotData[enemiesInRange.Length]; moveScores = new int[moveData.Length]; enemyScores = new int[enemyData.Length]; for (int j = 0; j < slots.Length; j++) { moveData[j] = new AiSlotData(slots[j].id); } for (int j = 0; j < enemyData.Length; j++) { enemyData[j] = new AiSlotData(enemiesInRange[j].soldierId); } // Calculations have to be remade for every slots for every enemy. Not good. // Utility score. // + when enemies are on slot. +100 // + cover height +0 +50 +100 // - distance to enemy (gt dist, less) // /* how to choose to move vs choose to attack * just distance * */ // here we choose which actions will be prioritized, movement or shooting. int possibleMoveActions = 0; int attack = -1; if (enemiesInRange.Length == 0) { continue; } attack = 0; // shoot, when there are some enemies float dist = Vector3.Distance(enemiesInRange[0].transform.position, unit.transform.position); if (dist <= unit.movementRange1) { possibleMoveActions = 1; } if (enemiesInRange.Length == 0) { possibleMoveActions = 2; attack = -1; } int bestId = -1; int best = 0; // calculates scores for movement slots for (int j = 0; j < moveData.Length; j++) { moveData[j].score = (int)(ClampedReverseDist(unit, unit.fullMovementRange, slots, j) * MapGrid.CoverScoreMultiplier(slots[j])); if (moveData[j].score > best) { best = moveData[j].score; bestId = j; } moveScores[j] = moveData[j].score; } GameplayManager.m.moveScores = moveScores; int bestMoveDataId = bestId; GridSlot bestMove = slots[bestMoveDataId]; MapNode[] path = Pathfinding.FindPathAStar(unit.curPositionSlot.transform.position, bestMove.transform.position, MapGrid.wholeMap); yield return(unit.StartCoroutine(MoveToSlot(team, team2, bestMove, path))); if (attack != -1) { // calculates scores for enemies bestId = -1; for (int j = 0; j < enemyData.Length; j++) { enemyData[j].score = (int)(ClampedDist(enemiesInRange[j], 100, slots, j) * MapGrid.CoverScoreMultiplier(enemiesInRange[j].curPositionSlot)); if (enemyData[j].score > best) { best = enemyData[j].score; bestId = j; } enemyScores[j] = enemyData[j].score; } int bestEnemyDataId = bestId; if (bestEnemyDataId != -1) { Soldier bestEnemy = enemiesInRange[bestEnemyDataId]; unit.AttackSlot(bestEnemy.curPositionSlot); GameplayManager.m.enemyScores = enemyScores; } else { Debug.Log("No enemies in range"); } } team.ActiveSoldier.HandleCover(); SwapSoldier(team); } }