public override void ProcessExternalInputWhileHeld(Vector3 inputPosition) { base.ProcessExternalInputWhileHeld(inputPosition); TorpedoAttack.Target target = new TorpedoAttack.Target(); Board board = Battle.main.defender.board; Vector3Int flatTileCoordinate = grid.GetFlatTileCoordinateAtPosition(inputPosition); if (!grid.GetTileAtPosition(inputPosition)) { if (flatTileCoordinate.x >= 0 && flatTileCoordinate.x < board.tiles.GetLength(0)) { target.torpedoDropPoint = board.tiles[flatTileCoordinate.x, flatTileCoordinate.z > 0 ? board.tiles.GetLength(1) - 1 : 0]; target.torpedoHeading = Vector2Int.up * (flatTileCoordinate.z > 0 ? -1 : 1); } else if (flatTileCoordinate.z >= 0 && flatTileCoordinate.z < board.tiles.GetLength(1)) { target.torpedoDropPoint = board.tiles[flatTileCoordinate.x > 0 ? board.tiles.GetLength(0) - 1 : 0, flatTileCoordinate.z]; target.torpedoHeading = Vector2Int.right * (flatTileCoordinate.x > 0 ? -1 : 1); } } if (effect == null) { if (target.torpedoDropPoint != null && target.torpedoHeading != Vector2Int.zero) { effect = Effect.CreateEffect(typeof(TorpedoAttack)); effect.visibleTo = Battle.main.attacker; effect.targetedPlayer = Battle.main.defender; } else { hookedPosition = Utilities.GetPositionOnElevationFromPerspective(inputPosition, Camera.main.transform.position, pickupPosition.y).projectedPosition; } } if (effect != null) { TorpedoAttack attack = effect as TorpedoAttack; if (target.torpedoDropPoint != null && target.torpedoHeading != Vector2Int.zero) { if (target != attack.target) { attack.target = target; RefreshEffectRepresentation(); } } else { Destroy(attack.gameObject); effect = null; } } }
static void FightFor(Player player) { Player attacked_player = Battle.main.attacker == player ? Battle.main.defender : Battle.main.attacker; Map map = new Map(attacked_player.board); float[,] priority_map = map.ratings.Normalize(); float advantage = player.board.ships.Sum(x => x.health) / (float)attacked_player.board.ships.Sum(x => x.health > 0 ? x.maxHealth : 0); int prefered_torpedocount = Mathf.FloorToInt(Mathf.Clamp(player.arsenal.torpedoes, 0, player.arsenal.loadedTorpedoCap) * ((Mathf.Cos(advantage * Mathf.PI) + 1.0f) / 2.0f)); int gun_targetcount = player.arsenal.guns; int torpedo_targetcount = player.arsenal.loadedTorpedoes >= prefered_torpedocount || player.arsenal.loadedTorpedoes == player.arsenal.torpedoes ? prefered_torpedocount : 0; int aircraft_targetcount = Mathf.CeilToInt(Mathf.Clamp(player.arsenal.aircraft - Battle.main.effects.Count(x => x is AircraftRecon && x.visibleTo == player), 0, int.MaxValue) * priority_map.Average()); int cyclone_size = Battle.main.effects.Exists(x => x is Cyclone) ? (Battle.main.effects.Find(x => x is Cyclone) as Cyclone).maximumTileSpacingToTakeEffect * 2 : 0; for (int ti = 0; ti < gun_targetcount; ti++) { Vector2Int target = priority_map.Max(); ArtilleryAttack attack = Effect.CreateEffect(typeof(ArtilleryAttack)) as ArtilleryAttack; attack.target = attacked_player.board.tiles[target.x, target.y]; attack.visibleTo = player; attack.targetedPlayer = attacked_player; Effect.AddToStack(attack); if (cyclone_size > 0) { priority_map = priority_map.AddHeat(target, dist => dist <= cyclone_size ? 0.1f : 1.0f, (original, function) => original * function); } else { priority_map = priority_map.AddHeat(target, dist => 1 - Mathf.Pow(0.5f, dist), (original, function) => original * function); } } for (int ti = 0; ti < torpedo_targetcount; ti++) { float best_lane_rating = Mathf.NegativeInfinity; TorpedoAttack.Target best_target = new TorpedoAttack.Target(); for (int i = 0; i < 4; i++) { for (int a = 0; a < priority_map.GetLength(i % 2); a++) { float rating = 0; for (int b = 0; b < priority_map.GetLength((i + 1) % 2) / 2; b++) { int x = i % 2 == 0 ? a : (i == 1 ? b : priority_map.GetLength(0) - b - 1); int y = i % 2 == 1 ? a : (i == 0 ? b : priority_map.GetLength(1) - b - 1); rating += priority_map[x, y]; } if (rating > best_lane_rating) { best_lane_rating = rating; best_target.torpedoDropPoint = attacked_player.board.tiles[i % 2 == 0 ? a : (i == 1 ? 0 : (priority_map.GetLength(0) - 1)), i % 2 == 1 ? a : (i == 0 ? 0 : (priority_map.GetLength(1) - 1))]; best_target.torpedoHeading = new Vector2Int((2 - i) % 2, (1 - i) % 2); } } } TorpedoAttack attack = Effect.CreateEffect(typeof(TorpedoAttack)) as TorpedoAttack; attack.target = best_target; attack.visibleTo = player; attack.targetedPlayer = attacked_player; Effect.AddToStack(attack); float average = priority_map.Average(); priority_map = priority_map.AddHeat(best_target.torpedoDropPoint.coordinates, dist => 1 - Mathf.Pow(0.5f, dist), (original, function) => original * function); } for (int ti = 0; ti < aircraft_targetcount; ti++) { float best_line_rating = Mathf.NegativeInfinity; int best_line = 0; int line_count = attacked_player.board.tiles.GetLength(0) + attacked_player.board.tiles.GetLength(1) - 2; for (int line = 0; line < line_count; line++) { int line_position = line % (attacked_player.board.tiles.GetLength(0) - 1); bool lineVertical = line_position == line; float line_rating = 0; for (int a = 0; a < 2; a++) { for (int b = 0; b < attacked_player.board.tiles.GetLength(lineVertical ? 1 : 0); b++) { int x = lineVertical ? a + line_position : b; int y = lineVertical ? b : a + line_position; line_rating += priority_map[x, y]; } } if (line_rating > best_line_rating) { best_line = line; best_line_rating = line_rating; } } AircraftRecon recon = Effect.CreateEffect(typeof(AircraftRecon)) as AircraftRecon; recon.target = best_line; recon.visibleTo = player; recon.targetedPlayer = attacked_player; Effect.AddToStack(recon); bool line_vertical = best_line < attacked_player.board.tiles.GetLength(0); best_line %= attacked_player.board.tiles.GetLength(0) - 1; for (int a = 0; a < 2; a++) { for (int b = 0; b < attacked_player.board.tiles.GetLength(line_vertical ? 1 : 0); b++) { int x = line_vertical ? a + best_line : b; int y = line_vertical ? b : a + best_line; priority_map[x, y] = 0; } } } }