public async Task <CommandResult> Bet(CommandContext context) { if (context.Message.MessageSource != MessageSource.Chat) { return new CommandResult { Response = "you may only bet through chat" } } ; IBettingPeriod <User>?bettingPeriod = _bettingPeriodProvider(); if (bettingPeriod == null) { return new CommandResult { Response = "betting not available right now" } } ; if (!bettingPeriod.IsBettingOpen) { return new CommandResult { Response = "betting is already closed" } } ; (var amountOptions, Side side) = await context.ParseArgs <OneOf <PositiveInt, Pokeyen, Percentage>, Side>(); int amount; if (amountOptions.Item1.IsPresent) { amount = amountOptions.Item1.Value; } else if (amountOptions.Item2.IsPresent) { amount = amountOptions.Item2.Value; } else { amount = (int)Math.Ceiling(amountOptions.Item3.Value.AsDecimal * context.Message.User.Pokeyen); } PlaceBetFailure?failure = await bettingPeriod.BettingShop.PlaceBet(context.Message.User, side, amount); if (failure != null) { return(new CommandResult { Response = failure switch { PlaceBetFailure.BetTooHigh betTooHigh => $"must bet at most {betTooHigh.MaxBet}", PlaceBetFailure.BetTooLow betTooLow => $"must bet at least {betTooLow.MinBet}", PlaceBetFailure.CannotChangeSide cannotChangeSide => $"already bet on {cannotChangeSide.SideBetOn}", PlaceBetFailure.CannotLowerBet cannotLowerBet => $"cannot lower existing bet of {cannotLowerBet.ExistingBet}", PlaceBetFailure.InsufficientFunds insufficientFunds => $"insufficient funds, you only have {insufficientFunds.AvailableMoney} pokeyen available", _ => $"{failure} (missing text, tell the devs to fix this)" } });
private async Task Loop(CancellationToken cancellationToken) { var teams = new Teams { Blue = ImmutableList.Create(MatchTesting.TestVenonatForOverlay), Red = ImmutableList.Create(MatchTesting.TestVenonatForOverlay), }; await Task.Delay(TimeSpan.FromSeconds(3), cancellationToken); await ResetBalances(); //ensure everyone has money to bet before the betting period const int matchId = -1; // TODO IBettingShop<User> bettingShop = new DefaultBettingShop<User>( async user => await _pokeyenBank.GetAvailableMoney(user)); bettingShop.BetPlaced += (_, args) => TaskToVoidSafely(_logger, () => _overlayConnection.Send(new MatchPokeyenBetUpdateEvent { MatchId = matchId, DefaultAction = "", NewBet = new Bet { Amount = args.Amount, Team = args.Side, BetBonus = 0 }, NewBetUser = args.User, Odds = bettingShop.GetOdds() }, cancellationToken)); _bettingPeriod = new BettingPeriod<User>(_pokeyenBank, bettingShop); _bettingPeriod.Start(); IMatchCycle match = new CoinflipMatchCycle(_loggerFactory.CreateLogger<CoinflipMatchCycle>()); Task setupTask = match.SetUp(new MatchInfo(teams.Blue, teams.Red), cancellationToken); await _overlayConnection.Send(new MatchCreatedEvent(), cancellationToken); await _overlayConnection.Send(new MatchBettingEvent(), cancellationToken); await _overlayConnection.Send(new MatchModesChosenEvent(), cancellationToken); // TODO await _overlayConnection.Send(new MatchSettingUpEvent { MatchId = 1234, Teams = teams, BettingDuration = _matchmodeConfig.DefaultBettingDuration.TotalSeconds, RevealDuration = 0, Gimmick = "speed", Switching = SwitchingPolicy.Never, BattleStyle = BattleStyle.Singles, InputOptions = new InputOptions { Moves = new MovesInputOptions { Policy = MoveSelectingPolicy.Always, Permitted = ImmutableList.Create("a", "b", "c", "d") }, Switches = new SwitchesInputOptions { Policy = SwitchingPolicy.Never, Permitted = ImmutableList<string>.Empty, RandomChance = 0 }, Targets = new TargetsInputOptions { Policy = TargetingPolicy.Disabled, Permitted = ImmutableList<string>.Empty, AllyHitChance = 0 }, }, BetBonus = 35, BetBonusType = "bet", }, cancellationToken); Duration bettingBeforeWarning = _matchmodeConfig.DefaultBettingDuration - _matchmodeConfig.WarningDuration; await Task.Delay(bettingBeforeWarning.ToTimeSpan(), cancellationToken); await _overlayConnection.Send(new MatchWarningEvent(), cancellationToken); await Task.Delay(_matchmodeConfig.WarningDuration.ToTimeSpan(), cancellationToken); await setupTask; _bettingPeriod.Close(); Task<MatchResult> performTask = match.Perform(cancellationToken); await _overlayConnection.Send(new MatchPerformingEvent { Teams = teams }, cancellationToken); MatchResult result = await performTask; await _overlayConnection.Send(new MatchOverEvent { MatchResult = result }, cancellationToken); // TODO log matches Dictionary<User, long> changes = await _bettingPeriod.Resolve(matchId, result, cancellationToken); await _overlayConnection.Send( new MatchResultsEvent { PokeyenResults = new PokeyenResults { Transactions = changes.ToImmutableDictionary(kvp => kvp.Key.Id, kvp => new Transaction { Change = kvp.Value, NewBalance = kvp.Key.Pokeyen }) } }, cancellationToken); await Task.Delay(_matchmodeConfig.ResultDuration.ToTimeSpan(), cancellationToken); await _overlayConnection.Send(new ResultsFinishedEvent(), cancellationToken); }