using RobotAndDonkey.Game.Cards; using RobotAndDonkey.Game.Execution; using RobotAndDonkey.Game.Execution.Results; using RobotAndDonkey.Game.GameState; using RobotAndDonkey.Game.Intents; using RobotAndDonkey.Game.Pois; using RobotAndDonkey.Game.Utils; using Interact = RobotAndDonkey.Game.Intents.Interact; using Move = RobotAndDonkey.Game.Intents.Move; using Rest = RobotAndDonkey.Game.Intents.Rest; namespace RobotAndDonkey.Game.Modifiers; public record CorruptCellModifier(EModifierDuration Duration) : CorruptModifierBase(EModifierKind.Cell, Duration) { protected override CorruptCellModifier CreateInstance() => new(Duration); public override string ToolTip => "While in this area, instructions will have the opposite effect."; } public record CorruptCardModifier(EModifierDuration Duration) : CorruptModifierBase(EModifierKind.Card, Duration) { protected override CorruptCardModifier CreateInstance() => new(Duration); public override string ToolTip => "The instruction will have the opposite effect."; } public abstract record CorruptModifierBase(EModifierKind Kind, EModifierDuration Duration) : Modifier(Kind, EModifierId.Corrupt, Duration) { public override void Before(Guid requestId, ReadOnlySpan intents, CoreLoop coreLoop, Entity owner, List newIntents, List results) { if (coreLoop.RunPhase != ERunPhase.ExecuteProgram) return; foreach (var intent in intents) { switch (intent) { case Move m: { m.Direction = m.Direction.Opposite(); break; } case Turn t: { t.Delta = -t.Delta; break; } case Rest rest when owner is Card card: { rest.DebuffSources.Add(this); var board = coreLoop.Board; var avatarCell = board.Cells.First(c => c.Poi is Avatar); newIntents.Add(new Move(avatarCell, card, ((Avatar)avatarCell.Poi!).Direction.Opposite(), false, 1)); break; } case Interact interact: { var board = coreLoop.Board; var avatarCell = board.Cells.First(c => c.Poi is Avatar); var targetHex = avatarCell.Hex.GetNeighbour(interact.Direction); var cellIndex = board.FindCellIndex(targetHex); var cell = cellIndex >= 0 ? board.Cells[cellIndex] : null; if (cell != null) { interact.DebuffSources.Add(this); if (cell.Poi is Shed) { results.Add(new InvalidInstructionResult(requestId, EInvalidReason.NoTarget, owner as Card, cell)); newIntents.Add(new ModifyCurrency(new(-interact.EnergyCost, 0, 0, 0, 0, 0))); } else if (cell.Poi is Crate crate) { var carrying = coreLoop.Currency.Carry; newIntents.Add(new PickUp(cell, crate, -carrying, interact.EnergyCost)); } else if (cell.Poi == null && coreLoop.HasDonkey && owner is Card card) newIntents.Add(new DonkeyIntent(card, cell, interact.EnergyCost)); else if (cell.Poi is Tower tower) newIntents.Add(new TowerIntent(cell, tower, true, interact.EnergyCost)); else { results.Add(new InvalidInstructionResult(requestId, EInvalidReason.NoTarget, owner as Card, cell)); newIntents.Add(new ModifyCurrency(new(-interact.EnergyCost, 0, 0, 0, 0, 0))); } } break; } case ImmunizeCard { CanCorrupt: true } immunizeCard: { immunizeCard.DebuffState = false; break; } case TowerIntent tower: { tower.Active = true; break; } case ModifyCurrency { CanCorrupt: true, Delta: { } delta } modifyCurrency: { modifyCurrency.Delta = new(delta.Energy * -1, delta.MaxCarry * -1, delta.Carry * -1, delta.Delivery * -1, delta.TapeLength * -1, delta.HandSize * -1); break; } case DetoxiumPrime detoxiumPrime: { detoxiumPrime.Heal = false; break; } // #Next: handled in the cards that reference tape order (Repeat / Stabilize) } } } }