/
romashov.z
/
PPAGame
Обзор
Документация
Войти
/
romashov.z
/
PPAGame
Код
Запросы
1
Задачи
Вики
Пакеты
0
Релизы
0
CI/CD
Аналитика
Безопасность
master
Core/Strategies/WideBridgeStrategy.cs
177 строк
8 KB
Zakhar Romashov
Добавили логику с бафами
29 апр 2026, 13:06
29 апр 2026, 13:06
7623dfb
Код
Авторство
О чём код?
using System; using System.Collections.Generic; namespace ArmyBattleGame { // Широкий мост (3 колонки): // - Рукопашный бой: 3 одновременные дуэли (по фронту каждой колонки). // - Активная армия бьёт первой волной, пассивная — контратакой. // - SA: для всех кроме фронтовиков, диагональная (соседние колонки ±1). class WideBridgeStrategy : FormationStrategyBase { public const string StrategyName = "WideBridge"; private const int Columns = 3; public override string Name => StrategyName; public override string DisplayName => "Широкий мост (колонна по трое)"; public override int ColumnCountFor(int unitCount) => Columns; public override void ExecuteMeleePhase(BattleField field, IBattleLogger logger) { var attackerArmy = field.IsArmy1Turn ? field.Army1 : field.Army2; var defenderArmy = field.IsArmy1Turn ? field.Army2 : field.Army1; // Волна 1: активная армия бьёт во всех 3 колонках одновременно. var wave1 = BuildMeleeWave(attackerArmy, defenderArmy); ApplyDamageWave(wave1, logger); attackerArmy.Compact(); defenderArmy.Compact(); if (!attackerArmy.HasAliveUnits || !defenderArmy.HasAliveUnits) return; // Волна 2: контратака (фронты могли поменяться - перебираем заново). var wave2 = BuildMeleeWave(defenderArmy, attackerArmy); ApplyDamageWave(wave2, logger); attackerArmy.Compact(); defenderArmy.Compact(); } private static List<(IUnit attacker, IUnit target, double damage)> BuildMeleeWave( Army attackerArmy, Army targetArmy) { var wave = new List<(IUnit, IUnit, double)>(); for (int col = 0; col < Columns; col++) { var a = attackerArmy.GetFront(col); var t = targetArmy.GetFront(col); if (a == null || t == null) continue; if (a.Damage <= 0) continue; double damage = a.Damage * 100 / (100 + t.Shield); wave.Add((a, t, damage)); } return wave; } public override void ExecuteSpecialsPhase(BattleField field, IBattleLogger logger) { var ctx1 = new BattleContext(field.Army1, field.Army2, this, logger); var ctx2 = new BattleContext(field.Army2, field.Army1, this, logger); int max = Math.Max(field.Army1.RowCount, field.Army2.RowCount); for (int row = 0; row < max; row++) { for (int col = 0; col < Columns; col++) { TryUseSpecial(ctx1, row, col); TryUseSpecial(ctx2, row, col); } } field.Army1.Compact(); field.Army2.Compact(); } private static void TryUseSpecial(BattleContext ctx, int row, int col) { var unit = ctx.OwnArmy.GetAt(row, col); if (unit is ISpecialAbility special && unit.IsAlive) { var pos = new UnitPosition(row, col); if (ctx.Strategy.CanUseSpecial(ctx.OwnArmy, pos)) special.UseSpecial(ctx, pos); } } public override bool CanUseSpecial(Army own, UnitPosition attackerPos) => CanUseSpecialIfNotFrontLine(own, attackerPos); // Цели лучника: в той же или соседних колонках (±1), на расстоянии range // от текущей строки. Возвращаем кандидатов в порядке: своя колонка → соседи. public override IEnumerable<(IUnit unit, UnitPosition pos)> GetEnemyTargets( Army own, Army enemy, UnitPosition attackerPos, int range) { // Целевая строка вычисляется как для NarrowBridge: range - attackerRow. int targetRow = range - attackerPos.Row; if (targetRow < 0) yield break; var preferredCols = new[] { attackerPos.Col, attackerPos.Col - 1, attackerPos.Col + 1 }; foreach (int col in preferredCols) { if (col < 0 || col >= Columns) continue; var direct = enemy.GetAt(targetRow, col); if (direct != null && direct.IsAlive) { yield return (direct, new UnitPosition(targetRow, col)); } } // Фолбэк: самый дальний живой в той же или соседней колонке. for (int r = enemy.RowCount - 1; r >= 0; r--) { foreach (int col in preferredCols) { if (col < 0 || col >= Columns) continue; var u = enemy.GetAt(r, col); if (u != null && u.IsAlive) { yield return (u, new UnitPosition(r, col)); yield break; } } } } // Союзники впереди: строки [attackerRow-range, attackerRow-1] во всех колонках, // кроме самого хилера. public override IEnumerable<(IUnit unit, UnitPosition pos)> GetForwardAllies( Army own, UnitPosition attackerPos, int range) { int rangeStart = Math.Max(0, attackerPos.Row - range); int rangeEnd = attackerPos.Row - 1; var self = own.GetAt(attackerPos.Row, attackerPos.Col); for (int r = rangeStart; r <= rangeEnd; r++) { for (int c = 0; c < Columns; c++) { var u = own.GetAt(r, c); if (u != null && u.IsAlive && !ReferenceEquals(u, self)) yield return (u, new UnitPosition(r, c)); } } } // Клон ставится в свободный слот в той же колонке перед магом // (если есть пустое место) или сдвигает мага назад. public override UnitPosition? PlaceClone(Army own, UnitPosition wizardPos, IUnit clone) { var flat = own.Flatten(); var wizard = own.GetAt(wizardPos.Row, wizardPos.Col); if (wizard == null) return null; int wizardIndex = -1; for (int i = 0; i < flat.Count; i++) { if (ReferenceEquals(flat[i], wizard)) { wizardIndex = i; break; } } if (wizardIndex < 0) return null; // Найти позицию вставки: чтобы клон встал перед магом в плоском списке. // После RebuildFromFlat с 3 колонками - пересчитаем позиции. flat.Insert(wizardIndex, clone); own.RebuildFromFlat(flat, Columns); own.NotifyUnitAdded(clone); // Найти где оказался клон. return own.FindPosition(clone); } } }