async Task BringerPushNInvaders(Space source, int countToPush, params TokenClass[] healthyInvaders)
    {
        // We can't track which original invader is was killed, so let the user choose.

//		TokenCountDictionary tokens = ctx.Target(source).Tokens;
        TokenCountDictionary tokens = ctx.GameState.Tokens[source];

        Token[] CalcInvaderTypes() => tokens.OfAnyType(healthyInvaders);

        var invaders = CalcInvaderTypes();

        while (0 < countToPush && 0 < invaders.Length)
        {
            var invader = await ctx.Decision(Select.TokenFrom1Space.TokenToPush(source, countToPush, invaders, Present.Always));

            if (invader == null)
            {
                break;
            }

            var destination = await ctx.Decision(new Select.Space(
                                                     "Push " + invader.ToString() + " to",
                                                     source.Adjacent.Where(s => ctx.Target(s).IsInPlay(Invader.Explorer))
                                                     , Present.Always
                                                     ));

            await tokens.MoveTo(invader, destination);

            --countToPush;
            invaders = CalcInvaderTypes();
        }
    }
示例#2
0
    public bool RunAfterGrowthResult => true;     // might receive additional presence

    public override async Task ActivateAsync(SelfCtx ctx)
    {
        var src = await ctx.Decision(Select.DeployedPresence.All("Move presence from:", ctx.Self, Present.Always));

        var dstOptions = src.Range(Range).Where(s => !s.IsOcean);
        var dst        = await ctx.Decision(Select.Space.ForAdjacent("Move preseence to:", src, Select.AdjacentDirection.Outgoing, dstOptions, Present.Always));

        ctx.Presence.Move(src, dst);
    }
示例#3
0
    public override async Task ActivateAsync(SelfCtx ctx)
    {
        var options = ctx.Self.Presence.Spaces.SelectMany(p => p.Range(2)).Distinct();
        var to      = await ctx.Decision(new Select.Space("Gather beast to", options, Present.Always));

        await ctx.Target(to).GatherUpTo(1, TokenType.Beast);
    }
    // ! Can't used normal PlacePresence, because it must be range-1, range 0 not allowed.
    public override async Task ActivateAsync(SelfCtx ctx)
    {
        var options = ctx.Self.Presence.Spaces.First().Adjacent;
        var space   = await ctx.Decision(new Select.Space("Add presence to", options, Present.Always));

        ctx.Presence.PlaceOn(space);
    }
    public override async Task ActivateAsync(SelfCtx ctx)
    {
        List <Space> gatherSpaces = ctx.Self.Presence.Spaces
                                    .Where(p => p.IsCoastal)
                                    .Select(p => p.Adjacent.Single(o => o.IsOcean))
                                    .Distinct()
                                    .ToList();

        while (0 < gatherSpaces.Count)
        {
            Space currentTarget = gatherSpaces[0];
            Space source        = await ctx.Decision(new Select.Space(
                                                         $"Select source of Presence to Gather into {currentTarget}"
                                                         , currentTarget.Adjacent
                                                         .Where(ctx.Self.Presence.Spaces.Contains)
                                                         .ToArray()
                                                         , Present.Always
                                                         ));

            // apply...
            ctx.Presence.Move(source, currentTarget);

            // next
            gatherSpaces.RemoveAt(0);
        }         // while
    }
示例#6
0
    public static async Task ActAsync(SelfCtx ctx)
    {
        // Your presence may count as badlands and beast.
        int PresenceAsToken(GameState _, Space space) => ctx.Self.Presence.CountOn(space);

        ctx.GameState.Tokens.RegisterDynamic(PresenceAsToken, TokenType.Badlands, false);
        ctx.GameState.Tokens.RegisterDynamic(PresenceAsToken, TokenType.Beast, false);
        // (Decide per presence, per action) ... Not doing this bit exactly, both are always present, but can't be destroyed.

        // your presence cannot move.
        // !!! not implemented

        // if you have 2 plant 3 animal:
        if (await ctx.YouHave("2 plant,3 animal"))
        {
            // 2 fear and
            ctx.AddFear(2);
            // 2 damamge in one of your lands.
            var space = await ctx.Decision(new Select.Space("2 damage", ctx.Self.Presence.Spaces, Present.Always));

            if (space != null)
            {
                await ctx.Target(space).DamageInvaders(2);
            }
        }
    }
示例#7
0
    public override async Task <object> GetTargetCtx(string powerName, SelfCtx ctx, TargettingFrom _)
    {
        Spirit target = ctx.GameState.Spirits.Length == 1 ? ctx.Self
                        : await ctx.Decision(new Select.Spirit(powerName, ctx.GameState.Spirits));

        return(ctx.TargetSpirit(target));
    }
示例#8
0
    public async Task <(Space, Space)> PushUpTo1()
    {
        // Select source
        var source = await ctx.Decision(Select.DeployedPresence.ToPush(ctx.Self));

        if (source == null)
        {
            return(null, null);
        }
        var sourceCtx = ctx.Target(source);
        // Select destination
        var destination = await sourceCtx.Decision(Select.Space.PushPresence(sourceCtx.Space, sourceCtx.Adjacent, Present.Always));

        Move(source, destination);
        return(source, destination);
    }
    public override async Task ActivateAsync(SelfCtx ctx)
    {
        var gameState = ctx.GameState;
        var options   = gameState.Island.AllSpaces.Where(space => gameState.Tokens[space].Beasts.Any);
        var space     = await ctx.Decision(new Select.Space("Add presence to", options, Present.Always));

        ctx.Presence.PlaceOn(space);
    }
示例#10
0
    static public async Task ActAsync(SelfCtx ctx)
    {
        if (ctx.Self is not FracturedDaysSplitTheSky frac)
        {
            return;
        }
        // Cost to Use: 3 Time
        if (frac.Time < 3)
        {
            return;
        }
        await frac.SpendTime(3);

        // Move 1 of your presence to a different land with your presence.
        var src = await ctx.Decision(Select.DeployedPresence.All("Move presence from:", ctx.Self, Present.Always));

        var dstOptions = ctx.Self.Presence.Spaces.Where(s => s != src);
        var dst        = await ctx.Decision(Select.Space.ForAdjacent("Move preseence to:", src, Select.AdjacentDirection.Outgoing, dstOptions, Present.Always));

        ctx.Presence.Move(src, dst);

        if (src.Board == dst.Board)
        {
            return;
        }

        // On the board moved from: During the Invader Phase, Resolve Invader and "Each board / Each land..." Actions one fewer time.
        foreach (var space in src.Board.Spaces)
        {
            ctx.GameState.Skip1Build(space);
            ctx.GameState.SkipExplore(space);
            ctx.GameState.SkipRavage(space);
        }

        // On the board moved to: During the Invader Phase, Resolve Invader and "Each board / Each Land..." Actions one more time.
        foreach (var space in src.Board.Spaces)
        {
            ctx.GameState.Add1Build(space);
            ctx.GameState.AddExplore(space);
            ctx.GameState.AddRavage(space);
        }
    }
    public bool RunAfterGrowthResult => true;     // depends on Presence location which might change during growth

    public override async Task ActivateAsync(SelfCtx ctx)
    {
        var dahanOptions = ctx.Self.Presence.Spaces
                           .SelectMany(space => ctx.Target(space).Dahan.Keys.Select(t => new SpaceToken(space, t)));
        var source = await ctx.Decision(new Select.TokenFromManySpaces("Select dahan to push from land", dahanOptions, Present.Done));

        if (source == null)
        {
            return;
        }

        await new TokenPusher(ctx.Target(source.Space)).PushToken(source.Token);
    }
    static public async Task ActAsync(SelfCtx ctx)
    {
        if (ctx.Self is not FracturedDaysSplitTheSky frac)
        {
            return;
        }

        // Cost to Use: N Time, and Spirits jointly pay N Energy (where N = # of players).
        int cost = ctx.GameState.Spirits.Length;

        if (frac.Time < cost)
        {
            return;
        }

        // !!! Implementing this as 1 spirit, but once we have >1 player, switch to all spirits can pay
        if (frac.Energy < cost)
        {
            return;
        }

        frac.Energy -= cost;
        await frac.SpendTime(cost);

        // Swap the top card of the Invader Deck with a card in the Invader discard that is withing 1 Invader Stage of it.
        var deck           = ctx.GameState.InvaderDeck;
        var newCard        = deck.Explore.First();
        int stageOfTopCard = newCard.InvaderStage;
        var options        = deck.Discards.Where(d => System.Math.Abs(d.InvaderStage - stageOfTopCard) <= 1).ToArray();

        // You can't swap cards that don't exist.
        if (options.Length == 0)
        {
            return;
        }

        var oldCard = await ctx.Decision(new Select.TypedDecision <IInvaderCard>(
                                             "Select card to return to top of Invader deck", options, Present.Always
                                             ));

        // Replace New with Old
        deck.Explore[0] = oldCard;
        // Replace Old with New
        deck.Discards.Remove(oldCard);
        deck.Discards.Add(newCard);           // face down

        // The Discarded card stays face-down.
        // !!! deck / card has no knowledge of face-up/face-down, if spirit plays this card again, they will see the 'face-down' card
    }
示例#13
0
class Setup_PlacePresenceOnMountain : GrowthActionFactory { // Similar to SharpFang initialization
    public override async Task ActivateAsync(SelfCtx ctx)
    {
        // Put 1 presence on your starting board in a mountain of your choice.
        var options = ctx.AllSpaces.Where(space => space.IsMountain);
        var space   = await ctx.Decision(new Select.Space("Add presence to", options, Present.Always));

        ctx.Presence.PlaceOn(space);

        // Push all dahan from that land.
        var targetCtx = ctx.Target(space);

        if (targetCtx.Dahan.Any)
        {
            await targetCtx.PushDahan(targetCtx.Dahan.Count);
        }
    }
    static async Task DistributeTokens(SelfCtx ctx, Space space, Space other, GameState gs)
    {
        // Distribute Tokens (All of them are considered moved.)
        // !!! not counting unmoved tokens as moved li
        var srcTokens = gs.Tokens[space];

        while (srcTokens.Keys.Any())
        {
            var tokenToMove = await ctx.Decision(Select.TokenFrom1Space.TokenToPush(space, 100, srcTokens.Keys.ToArray(), Present.Done));

            if (tokenToMove == null)
            {
                break;
            }
            await srcTokens.MoveTo(tokenToMove, other);
        }
    }
    static async Task TakeActionInUpToNLands(SelfCtx ctx, int adjCount, IEnumerable <Space> spaces, ActionOption <TargetSpaceCtx> action)
    {
        List <Space> options = spaces.ToList();

        while (adjCount-- > 0 && options.Count > 0)
        {
            var space = await ctx.Decision(new Select.Space($"{action.Description} ({adjCount + 1} remaining)", options, Present.Done));

            if (space == null)
            {
                break;
            }
            await action.Execute(ctx.Target(space));

            options.Remove(space);
        }
    }
示例#16
0
    public override async Task ActivateAsync(SelfCtx ctx)
    {
        if (ctx.Self.Presence.Placed.Count == 1)
        {
            return;                                           // don't let them switch their last presence to a beast
        }
        var options = ctx.Self.Presence.Spaces;
        var space   = await ctx.Decision(new Select.DeployedPresence("Select presence to replace with beast", options, Present.Done));     // let them change their minds

        if (space == null)
        {
            return;
        }

        await ctx.Presence.RemoveFrom(space);

        await ctx.GameState.Tokens[space].Beasts.Add(1);
    }
示例#17
0
    public override async Task ActivateAsync(SelfCtx ctx)
    {
        List <Space> pushSpaces = ctx.Self.Presence.Spaces
                                  .Where(p => p.IsOcean)
                                  .Distinct()
                                  .ToList();

        while (0 < pushSpaces.Count)
        {
            var currentSource = pushSpaces[0];

            // #pushpresence
            var destination = await ctx.Decision(Select.Space.PushPresence(currentSource, currentSource.Adjacent, Present.Always));

            // apply...
            ctx.Presence.Move(currentSource, destination);

            // next
            pushSpaces.RemoveAt(0);
        }
    }
示例#18
0
    static async Task PushExplorerIntoSpaceWithMoreTownsOrCities(SelfCtx ctx, Dictionary <Space, int> buildingCounts)
    {
        Space[] GetNeighborWithMoreBuildings(Space s) => s.Adjacent.Where(n => buildingCounts[n] > buildingCounts[s]).ToArray();
        bool HasNeighborWithMoreBuildings(Space s) => GetNeighborWithMoreBuildings(s).Any();

        // Select Source
        var sourceOptions = ctx.GameState.Island.AllSpaces
                            .Where(s => ctx.GameState.Tokens[s].Has(Invader.Explorer) && HasNeighborWithMoreBuildings(s))
                            .ToArray();

        if (sourceOptions.Length == 0)
        {
            return;
        }

        Space source = await ctx.Decision(new Select.Space("Fear: Select land to push explorer from into more towns/cities", sourceOptions, Present.Done));

        if (source == null)
        {
            return;                      // continue => next spirit, break/return => no more spirits
        }
        // Push
        await ctx.Target(source).PushUpTo(1, Invader.Explorer);
    }
    public override async Task ActivateAsync(SelfCtx ctx)
    {
        var space = await ctx.Decision(new Select.Space("Select land to apply 2 Damage.", ctx.Self.Presence.Spaces, Present.Always));

        await ctx.Target(space).DamageInvaders(2);
    }