using RobotAndDonkey.Game.Board; using RobotAndDonkey.Game.Cards; using RobotAndDonkey.Game.Data; using RobotAndDonkey.Game.Execution; using RobotAndDonkey.Game.Execution.Results; using RobotAndDonkey.Game.GameState; using RobotAndDonkey.Game.Modifiers; using RobotAndDonkey.Game.Pois; using RobotAndDonkey.Game.Robots; using RobotAndDonkey.Game.Utils; namespace RobotAndDonkey.Game.Intents; public class RunProgram : Intent { public static IEnumerable<(Entity Entity, ECardLocation Location)> CollectEntities(CoreLoop coreLoop) { yield return (coreLoop.Robot, ECardLocation.Robot); foreach (var card in coreLoop.PatchDeck) yield return (card, ECardLocation.Deck); foreach (var card in coreLoop.Hand) yield return (card, ECardLocation.Hand); foreach (var card in coreLoop.Tape) yield return (card, ECardLocation.Tape); foreach (var card in coreLoop.Discard) yield return (card, ECardLocation.Discard); foreach (var card in coreLoop.Board.Cells) yield return (card, ECardLocation.Board); } public override void Run(Guid requestId, CoreLoop coreLoop, List newIntents, List results) { var board = coreLoop.Board; coreLoop.ProgramsExecuted += 1; results.Add(new ProgramResult(requestId, coreLoop.ProgramsExecuted)); var modifierStack = new ModifierStack(); modifierStack.Push(coreLoop.Robot); var tapeCards = coreLoop.GetTapeCards(); var minCount = Math.Min(tapeCards.Count, coreLoop.Currency.TapeLength); for (var i = 0; i < minCount; i++) { var card = tapeCards[i]; if (!card.Modifiers.Any(m => m is { Id: EModifierId.RaceCondition, DebuffSources.Count: 0 })) continue; if (coreLoop.Random.NextSingle() > Balancing.Instance.RaceConditionChance) continue; var targetIndex = CardExtensions.NextIndexConsideringCorruption(i, coreLoop); if (targetIndex >= 0 && targetIndex < tapeCards.Count) { results.Add(new ModifyCardResult(requestId, tapeCards[targetIndex].DeepClone(), EModifierId.RaceCondition, ECardLocation.Tape)); if (coreLoop.SwapTapeCards(i, targetIndex)) { (tapeCards[i], tapeCards[targetIndex]) = (tapeCards[targetIndex], tapeCards[i]); results.Add(new ProgramRowResult(requestId, coreLoop.ProgramRow.ToArray(), coreLoop.TapeCardIds)); results.Add(new TapeResult(requestId, tapeCards.ToArray())); } } } tapeCards = coreLoop.GetTapeCards(); minCount = Math.Min(tapeCards.Count, coreLoop.Currency.TapeLength); for (var i = 0; i < minCount; i++) { var card = tapeCards[i]; var avatarCell = board.Cells.Single(c => c.Poi is Avatar); modifierStack.Push(avatarCell); modifierStack.Push(card); results.Add(new RunCardResult(requestId, card)); var intents = new List(); card.CreateIntents(avatarCell, coreLoop, requestId, intents, results); modifierStack.Execute(requestId, coreLoop, intents, results, false, true); coreLoop.InstructionsUsed += 1; modifierStack.Pop(); modifierStack.Pop(); } modifierStack.Pop(); static IEnumerable<(Entity Owner, Modifier Modifier, ECardLocation Location)> CollectModifiers(CoreLoop coreLoop, EModifierDuration duration) { foreach (var (entity, location) in CollectEntities(coreLoop)) { foreach (var modifier in entity.Modifiers) { if (modifier.Duration == duration) yield return (entity, modifier, location); } } } void RemoveModifier(Entity entity, Modifier modifier, ECardLocation location) { entity.RemoveModifier(modifier, newIntents); if (entity is Cell cell) results.Add(new ModifyCellResult(requestId, new(coreLoop.Board), modifier.Id, cell.Hex)); if (entity is Card card) results.Add(new ModifyCardResult(requestId, card.DeepClone(), modifier.Id, location)); if (entity is Robot) results.Add(new ModifyRobotResult(requestId)); } foreach (var (entity, modifier, location) in CollectModifiers(coreLoop, EModifierDuration.ShortTerm).ToArray()) RemoveModifier(entity, modifier, location); tapeCards = coreLoop.GetTapeCards(); foreach (var card in tapeCards) { var isPersistent = card.Modifiers.Any(m => m is PersistentModifier && m.DebuffSources.Count == 0); if (!isPersistent) { coreLoop.Discard.Add(card); coreLoop.RemoveProgramCard(card); } } coreLoop.ClearTapeSelection(); coreLoop.ProgramCount -= 1; results.Add(new ProgramRowResult(requestId, coreLoop.ProgramRow.ToArray(), coreLoop.TapeCardIds)); results.Add(new CurrencyResult(requestId, coreLoop.Currency)); results.Add(new HandResult(requestId, coreLoop.Hand.ToArray())); results.Add(new DiscardResult(requestId, coreLoop.Discard.ToArray())); results.Add(new ProgramResult(requestId, coreLoop.ProgramCount)); results.Add(new TapeResult(requestId, coreLoop.Tape.ToArray())); results.Add(new DeckResult(requestId, coreLoop.PatchDeck.ToArray())); var victory = coreLoop.Board.Cells.Select(c => c.Poi as Shed).Where(s => s != null).Sum(s => s!.Remaining) == 0; if (coreLoop.ProgramCount == 0 || coreLoop.PatchDeck.Count == 0 || coreLoop.Currency.Energy <= 0 || victory) { coreLoop.Currency.Energy += Balancing.Instance.EndOfProgramEnergyReplenish; coreLoop.RunPhase = ERunPhase.Scoring; foreach (var (entity, modifier, location) in CollectModifiers(coreLoop, EModifierDuration.Temporary).ToArray()) { RemoveModifier(entity, modifier, location); } results.Add(new HandResult(requestId, coreLoop.Hand.ToArray())); results.Add(new DiscardResult(requestId, coreLoop.Discard.ToArray())); results.Add(new TapeResult(requestId, coreLoop.Tape.ToArray())); results.Add(new DeckResult(requestId, coreLoop.PatchDeck.ToArray())); results.Add(new RunPhaseResult(requestId, coreLoop.RunPhase)); } else { coreLoop.DrawHand(); } base.Run(requestId, coreLoop, newIntents, results); } public override bool IsValid(CoreLoop coreLoop) { if (!base.IsValid(coreLoop)) return false; return coreLoop.RunPhase == ERunPhase.ExecuteProgram; } public override bool Immune => true; public override string ToString() => "Run program, " + base.ToString(); }