コード例 #1
0
ファイル: BaseDialog.cs プロジェクト: davidlfox/DrugBot
        protected User GetUser(IDialogContext context)
        {
            var userId = context.UserData.Get <int>(StateKeys.UserId);
            var db     = new DrugBotDataContext();

            return(db.Users.FirstOrDefault(x => x.UserId == userId));
        }
コード例 #2
0
        private static string DoDrugSpikeDown(int userId, DrugBotDataContext db, IDialogContext context)
        {
            // randomize the drug to spike
            var drugs = db.GetDrugs().ToList();
            var drug  = drugs.ElementAt(rand.Next(0, drugs.Count()));

            // todo: put these bounds somewhere static or configurable
            // adjust drug price, % of the min
            var spikeRate  = GetRandomDoubleBetween(0.20, 0.40);
            var minPrice   = drug.MinPrice;
            var spikePrice = (int)(minPrice * spikeRate);

            if (spikePrice <= 0)
            {
                spikePrice = 1;
            }

            var drugPrices = context.UserData.Get <Dictionary <int, int> >(StateKeys.DrugPrices);

            drugPrices[drug.DrugId] = spikePrice;
            context.UserData.SetValue(StateKeys.DrugPrices, drugPrices);

            var spikeText = RandomDownSpikeText();

            return($"{spikeText} {drug.Name} prices have bottomed out!");
        }
コード例 #3
0
ファイル: BaseDialog.cs プロジェクト: davidlfox/DrugBot
        protected Location GetLocation(IDialogContext context)
        {
            var locationId = context.UserData.Get <int>(StateKeys.LocationId);
            var db         = new DrugBotDataContext();

            return(db.Locations.Single(x => x.LocationId == locationId));
        }
コード例 #4
0
ファイル: SellDialog.cs プロジェクト: davidlfox/DrugBot
        public async Task StartAsync(IDialogContext context)
        {
            var db = new DrugBotDataContext();

            // check inventory to see if they have anything to sell
            var userId = context.UserData.Get <int>(StateKeys.UserId);
            var user   = db.Users.Single(x => x.UserId == userId);

            if (!user.Inventory.Any(x => x.Quantity > 0))
            {
                await context.PostAsync("You don't have anything to sell...");

                this.Done(context);
            }
            else
            {
                var buttons = this.GetDrugButtons(context);

                this.AddCancelButton(buttons);

                await context.PostAsync(this.SetupHeroResponse(context, buttons, "What do you want to sell?"));

                context.Wait(MessageReceivedAsync);
            }
        }
コード例 #5
0
ファイル: BaseDialog.cs プロジェクト: davidlfox/DrugBot
        protected Gun GetRandomGun(int dayOfGame)
        {
            var db   = new DrugBotDataContext();
            var guns = db.Guns.Where(x => x.MinimumDayOfGame <= dayOfGame).ToList();

            return(guns.ElementAt(RandomEvent.GetRandomNumberBetween(0, guns.Count)));
        }
コード例 #6
0
        public override bool IsValid(object value)
        {
            var proposedName = value.ToString();

            var db = new DrugBotDataContext();

            return(!db.Users.Any(x => x.Name == proposedName));
        }
コード例 #7
0
ファイル: SellDialog.cs プロジェクト: davidlfox/DrugBot
        private async Task MessageReceivedAsync(IDialogContext context, IAwaitable <IMessageActivity> result)
        {
            var message = await result;

            if (message.Text.ToLower() == "cancel")
            {
                this.Done(context);
            }
            else
            {
                var db = new DrugBotDataContext();

                var drugs = db.GetDrugs().ToList()
                            .Select(x => new
                {
                    Name   = x.Name.ToLower(),
                    DrugId = x.DrugId,
                });

                var drugPrices = this.GetDrugPrices(context);

                if (drugs.Any(x => x.Name == message.Text.ToLower()))
                {
                    var drug = drugs.Single(x => x.Name == message.Text.ToLower());

                    var user      = this.GetUser(context);
                    var inventory = user.Inventory.FirstOrDefault(x => x.DrugId == drug.DrugId);

                    if (inventory != null && inventory.Quantity > 0)
                    {
                        if (drugPrices.Any(x => x.Key == drug.DrugId))
                        {
                            context.UserData.SetValue(StateKeys.DrugToSell, drug.Name);

                            // get inventory
                            var qty = user.Inventory.Single(x => x.DrugId == drug.DrugId).Quantity;

                            // prompt for quantity
                            PromptDialog.Number(context, SellQuantityAsync, $"You have {qty:n0}. How much do you want to sell?");
                        }
                    }
                    else
                    {
                        await context.PostAsync("You don't have any of that. Type CANCEL if you don't want to sell anything.");

                        context.Wait(MessageReceivedAsync);
                    }
                }
                else
                {
                    await context.PostAsync("You can't sell that...Type CANCEL if you don't want to sell anything.");

                    context.Wait(MessageReceivedAsync);
                }
            }
        }
コード例 #8
0
ファイル: BaseDialog.cs プロジェクト: davidlfox/DrugBot
        protected void SetupLoan(IDialogContext context, int amount, double rate)
        {
            var db     = new DrugBotDataContext();
            var userId = context.UserData.Get <int>(StateKeys.UserId);
            var user   = db.Users.FirstOrDefault(x => x.UserId == userId);

            user.LoanDebt = amount;
            user.LoanRate = rate;
            user.Wallet   = user.Wallet + amount;

            db.Commit();
        }
コード例 #9
0
        public static EventInfo Get(IDialogContext context, int userId)
        {
            var eventText = string.Empty;

            // random weighted event
            var eventOdd = rand.Next(1, 7);

            System.Diagnostics.Debug.WriteLine($"eventOdd: {eventOdd}");

            // todo: some kind of weighted dictionary/enum/whatevs to handle this randomization

            var db = new DrugBotDataContext();

            switch (eventOdd)
            {
            // event: mugging
            case 1:
                eventText = DoMugging(userId, db);
                break;

            // event: police raid
            case 2:
                eventText = DoDrugSpike(userId, db, context);
                break;

            // event: drug spike down
            case 3:
                eventText = DoDrugSpikeDown(userId, db, context);
                break;

            // event: found a trenchcoat
            case 4:
                eventText = DoTrenchcoat(userId, db);
                break;

            // event: option to buy a gun, handled later
            case 5:
                return(new EventInfo {
                    IsGunEvent = true
                });

            // event: cops!
            case 6:
                return(new EventInfo {
                    IsCombatEvent = true
                });
            }

            return(new EventInfo {
                EventText = eventText
            });
        }
コード例 #10
0
ファイル: BaseDialog.cs プロジェクト: davidlfox/DrugBot
        protected async Task ShowLeaderboard(IDialogContext context)
        {
            var db = new DrugBotDataContext();

            // show leaderboard
            var leaders = db.GetLeaderboard();

            var sb = new StringBuilder("Leaderboard:\n\n");

            foreach (var leader in leaders)
            {
                sb.Append($"{leader.User.Name}: {leader.Score:C0}\n\n");
            }

            await context.PostAsync(sb.ToString());
        }
コード例 #11
0
        private static string DoMugging(int userId, DrugBotDataContext db)
        {
            var user = db.Users.Single(x => x.UserId == userId);

            // get current wallet
            var wallet = user.Wallet;

            // todo: put bounds somewhere static or configurable
            var lossRate    = GetRandomDoubleBetween(0.05, 0.10);
            var moneyLost   = (int)(wallet * lossRate);
            var muggingText = RandomMuggingText();

            user.Wallet = user.Wallet - moneyLost;
            db.Commit();

            return($"{muggingText} You lost {moneyLost:C0}!");
        }
コード例 #12
0
ファイル: SetupNameDialog.cs プロジェクト: davidlfox/DrugBot
        private async Task MessageReceivedAsync(IDialogContext context, IAwaitable <IMessageActivity> result)
        {
            var message      = await result;
            var proposedName = message.Text;

            var db = new DrugBotDataContext();

            this.BotUserId = message.Conversation.Id;

            var validationError = db.ValidateUser(this.BotUserId, proposedName);

            // hack: check specifically for a unique name
            if (db.Users.Any(x => x.Name == proposedName))
            {
                validationError = "Your name must be unique...try again.";
            }

            // validate username, etc
            if (string.IsNullOrWhiteSpace(validationError))
            {
                var user    = db.AddUser(this.BotUserId, proposedName);
                var records = db.Commit();

                this.Name = proposedName;

                context.UserData.SetValue <int>(StateKeys.UserId, user.UserId);

                await context.PostAsync($"Thanks {this.Name}...let's make some money!");

                // start in washington, dc
                context.UserData.SetValue <int>(StateKeys.LocationId, 1);

                // go back
                this.Done(context, new GameState {
                    IsNameReady = true
                });
            }
            else
            {
                await context.PostAsync(validationError);

                // loop
                context.Wait(MessageReceivedAsync);
            }
        }
コード例 #13
0
ファイル: CombatDialog.cs プロジェクト: davidlfox/DrugBot
        private async Task PlayerDead(IDialogContext context)
        {
            context.UserData.RemoveValue(StateKeys.CombatContext);

            var           lostInventory  = string.Empty;
            var           lostWallet     = 0;
            InventoryItem stolenDrug     = null;
            var           stolenQuantity = 0;

            var db     = new DrugBotDataContext();
            var userId = context.UserData.Get <int>(StateKeys.UserId);
            var user   = db.Users.Single(x => x.UserId == userId);

            // randomize some losses
            if (user.Wallet > 0)
            {
                var lossRate = RandomEvent.GetRandomDoubleBetween(0.05, 0.10);
                lostWallet  = (int)(user.Wallet * lossRate);
                user.Wallet = user.Wallet - lostWallet;
            }

            if (user.Inventory.Any(x => x.Quantity > 0))
            {
                var availableInventory = db.InventoryItems
                                         .Where(x => x.UserId == userId && x.Quantity > 0);
                var count     = availableInventory.Count();
                var drugIndex = RandomEvent.GetRandomNumberBetween(0, count);

                stolenDrug = availableInventory.ToList().ElementAt(drugIndex);
                var stealRate = RandomEvent.GetRandomDoubleBetween(0.05, 0.10);
                stolenQuantity      = (int)(stolenDrug.Quantity * stealRate);
                stolenDrug.Quantity = stolenDrug.Quantity - stolenQuantity;
            }

            db.Commit();

            lostInventory = $"{(lostWallet > 0 ? $"{lostWallet:C0} from your wallet" : string.Empty)}" +
                            $"{(lostWallet > 0 && stolenQuantity > 0 ? " and " : string.Empty)}" +
                            $"{(stolenQuantity > 0 ? $"{stolenQuantity} {stolenDrug.Drug.Name} from you" : string.Empty)}";

            await context.PostAsync($"They beat you unconscious and took {lostInventory}.");

            this.Done(context);
        }
コード例 #14
0
ファイル: GameDialog.cs プロジェクト: davidlfox/DrugBot
        public virtual async Task MessageReceivedAsync(IDialogContext context, IAwaitable <IMessageActivity> result)
        {
            var message = await result;

            this.BotUserId = message.Conversation.Id;

            if (message.Text.ToLower() == "play")
            {
                var db   = new DrugBotDataContext();
                var user = db.FindUser(this.BotUserId);

                // start in washington, dc
                context.UserData.SetValue <int>(StateKeys.LocationId, 1);
                db.Commit();

                if (user == null)
                {
                    // first time playing, create user, prompt for name...
                    context.Call(new SetupNameDialog(), BackToSetupNameAsync);
                }
                else
                {
                    // todo: greet user
                    await context.PostAsync("I know you...");

                    context.UserData.SetValue <int>(StateKeys.UserId, user.UserId);
                    context.Call(new MainMenuDialog(), BackToSetupNameAsync);
                }
            }
            else if (message.Text.ToLower() == "leaderboard")
            {
                await this.ShowLeaderboard(context);

                context.Wait(MessageReceivedAsync);
            }
            else
            {
                // tell them to trigger the game start
                await context.PostAsync("You should probably type PLAY to start the game...");

                context.Wait(MessageReceivedAsync);
            }
        }
コード例 #15
0
ファイル: BuyDialog.cs プロジェクト: davidlfox/DrugBot
        private async Task MessageReceivedAsync(IDialogContext context, IAwaitable <IMessageActivity> result)
        {
            var message = await result;

            if (message.Text.ToLower() == "cancel")
            {
                this.Done(context);
            }
            else
            {
                var db    = new DrugBotDataContext();
                var drugs = db.GetDrugs().ToList()
                            .Select(x => new
                {
                    DrugId = x.DrugId,
                    Name   = x.Name.ToLower(),
                });

                if (drugs.Any(x => x.Name == message.Text.ToLower()))
                {
                    // send intended drug to state
                    // confirm db record matches, so we store a good drug name to bot state
                    var drug = drugs.Single(x => x.Name == message.Text.ToLower());
                    context.UserData.SetValue(StateKeys.DrugToBuy, drug.Name);

                    // get affordability
                    var user      = this.GetUser(context);
                    var drugPrice = this.GetDrugPrices(context).Single(x => x.Key == drug.DrugId).Value;
                    var canAfford = user.Wallet / drugPrice;
                    var canHold   = user.InventorySize - user.Inventory.Sum(x => x.Quantity);

                    // prompt for quantity
                    PromptDialog.Number(context, BuyQuantityAsync, $"You can afford {canAfford:n0} and hold {canHold}. How much do you want to buy?");
                }
                else
                {
                    await context.PostAsync("You can't buy that...Type CANCEL if you don't want to buy anything.");

                    context.Wait(MessageReceivedAsync);
                }
            }
        }
コード例 #16
0
        private static string DoTrenchcoat(int userId, DrugBotDataContext db)
        {
            var user = db.Users.Single(x => x.UserId == userId);

            // get storage
            var currentSpace = user.InventorySize;

            // get increase rate
            // todo: make static/configurable
            var newSpaceRate = GetRandomDoubleBetween(0.30, 0.50);
            var newSpace     = (int)(currentSpace * newSpaceRate);

            // commit to user
            user.InventorySize = user.InventorySize + newSpace;
            db.Commit();

            var trenchcoatText = RandomTrenchcoatText();

            return($"{trenchcoatText} You can hold {newSpace} more drugs!");
        }
コード例 #17
0
ファイル: BaseDialog.cs プロジェクト: davidlfox/DrugBot
        protected bool PayLoan(IDialogContext context)
        {
            var db     = new DrugBotDataContext();
            var userId = context.UserData.Get <int>(StateKeys.UserId);
            var user   = db.Users.FirstOrDefault(x => x.UserId == userId);

            if (user.Wallet >= user.LoanDebt)
            {
                user.Wallet   = user.Wallet - user.LoanDebt;
                user.LoanDebt = 0;
                user.LoanRate = 0.0;
                db.Commit();

                context.UserData.SetValue <double>(StateKeys.LoanRate, 0.0);

                return(true);
            }

            return(false);
        }
コード例 #18
0
ファイル: BaseDialog.cs プロジェクト: davidlfox/DrugBot
        protected int TravelUser(int userId, int locationId)
        {
            var db   = new DrugBotDataContext();
            var user = db.Users.FirstOrDefault(x => x.UserId == userId);

            if (user != null)
            {
                user.LocationId = locationId;
                user.DayOfGame  = user.DayOfGame + 1;
                if (user.LoanDebt > 0)
                {
                    user.LoanDebt = user.LoanDebt + (int)(user.LoanDebt * user.LoanRate);
                }

                db.Commit();

                return(user.DayOfGame);
            }

            return(0);
        }
コード例 #19
0
        private static string DoDrugSpike(int userId, DrugBotDataContext db, IDialogContext context)
        {
            // randomize the drug to spike
            var drugs = db.GetDrugs().ToList();
            var drug  = drugs.ElementAt(rand.Next(0, drugs.Count()));

            // todo: put these bounds somewhere static or configurable
            // adjust drug price, 50% to 400% over the max
            var spikeRate  = GetRandomDoubleBetween(0.50, 4.0);
            var maxPrice   = drug.MaxPrice;
            var spikePrice = (int)(maxPrice + (maxPrice * spikeRate));

            var drugPrices = context.UserData.Get <Dictionary <int, int> >(StateKeys.DrugPrices);

            drugPrices[drug.DrugId] = spikePrice;
            context.UserData.SetValue(StateKeys.DrugPrices, drugPrices);

            var spikeText = RandomSpikeText();

            return($"{spikeText} {drug.Name} prices have gone through the roof!");
        }
コード例 #20
0
ファイル: BaseDialog.cs プロジェクト: davidlfox/DrugBot
        protected BuyGunInfo BuyGun(IDialogContext context)
        {
            var db     = new DrugBotDataContext();
            var gun    = context.UserData.Get <Gun>(StateKeys.GunToBuy);
            var userId = context.UserData.Get <int>(StateKeys.UserId);
            var user   = db.Users.FirstOrDefault(x => x.UserId == userId);

            if (user.Wallet >= gun.Cost)
            {
                user.Wallet = user.Wallet - gun.Cost;
                user.GunId  = gun.GunId;
                db.Commit();

                return(new BuyGunInfo {
                    IsSuccessful = true
                });
            }

            return(new BuyGunInfo {
                IsSuccessful = false, ReasonText = "You ain't got the cash for this piece."
            });
        }
コード例 #21
0
ファイル: BaseDialog.cs プロジェクト: davidlfox/DrugBot
        protected Dictionary <int, int> GetDrugPrices(IDialogContext context, bool newPrices = false)
        {
            var drugPrices = new Dictionary <int, int>();

            var db    = new DrugBotDataContext();
            var drugs = db.GetDrugs().ToList();

            if (!context.UserData.TryGetValue(StateKeys.DrugPrices, out drugPrices) || newPrices)
            {
                drugPrices = new Dictionary <int, int>();

                foreach (var drug in drugs)
                {
                    var price = rand.Next(drug.MinPrice, drug.MaxPrice);
                    drugPrices.Add(drug.DrugId, price);
                }

                // store to state
                context.UserData.SetValue(StateKeys.DrugPrices, drugPrices);
            }

            return(drugPrices);
        }
コード例 #22
0
ファイル: BaseDialog.cs プロジェクト: davidlfox/DrugBot
        protected void ResetUser(IDialogContext context)
        {
            var db     = new DrugBotDataContext();
            var userId = context.UserData.Get <int>(StateKeys.UserId);
            var user   = db.Users.FirstOrDefault(x => x.UserId == userId);

            var money = user.Wallet;

            user.Wallet        = Defaults.StartingMoney;
            user.DayOfGame     = Defaults.GameStartDay;
            user.LocationId    = Defaults.LocationId;
            user.LoanDebt      = 0;
            user.LoanRate      = 0.0;
            user.GunId         = null;
            user.InventorySize = Defaults.InventorySize;

            // clear out inventory
            db.InventoryItems.RemoveRange(user.Inventory);

            // regenerate drug prices for this user
            this.GetDrugPrices(context, true);

            db.Commit();
        }
コード例 #23
0
ファイル: BaseDialog.cs プロジェクト: davidlfox/DrugBot
        protected IQueryable <Location> GetLocations()
        {
            var db = new DrugBotDataContext();

            return(db.Locations);
        }
コード例 #24
0
ファイル: BaseDialog.cs プロジェクト: davidlfox/DrugBot
        protected IQueryable <Drug> GetDrugs()
        {
            var db = new DrugBotDataContext();

            return(db.Drugs);
        }
コード例 #25
0
ファイル: SellDialog.cs プロジェクト: davidlfox/DrugBot
        private async Task SellQuantityAsync(IDialogContext context, IAwaitable <long> result)
        {
            var qty = await result;

            if (qty < 1)
            {
                await context.PostAsync("Looks like you don't want to sell any--thanks for wasting my time");

                this.Done(context);
            }
            else
            {
                // yeah, i know this could truncate
                var quantity = Convert.ToInt32(qty);
                var db       = new DrugBotDataContext();

                var userId = context.UserData.Get <int>(StateKeys.UserId);
                var user   = db.Users.Single(x => x.UserId == userId);

                var drugs = db.GetDrugs().ToList()
                            .Select(x => new
                {
                    Name      = x.Name,
                    NameLower = x.Name.ToLower(),
                    DrugId    = x.DrugId,
                });

                // determine drug price
                var drugPrices = this.GetDrugPrices(context);
                var drugToSell = context.UserData.Get <string>(StateKeys.DrugToSell);
                var drug       = drugs.Single(x => x.NameLower == drugToSell);

                if (user.Inventory.Any(x => x.DrugId == drug.DrugId && x.Quantity >= quantity))
                {
                    var price = drugPrices[drug.DrugId];

                    var total = price * quantity;
                    user.Wallet += total;
                    var item = user.Inventory.Single(x => x.DrugId == drug.DrugId);
                    item.Quantity -= quantity;

                    try
                    {
                        db.Commit();
                    }
                    catch
                    {
                        await context.PostAsync("Something happened when saving your sell inventory. Yeah, I'm still an alpha bot...");
                    }

                    await context.PostAsync($"You sold {qty} for {total:C0}.");

                    await context.PostAsync($"You have {user.Wallet:C0} in your wallet.");

                    this.Done(context);
                }
                else
                {
                    await context.PostAsync("You don't have that much to sell...");

                    this.Done(context);
                }
            }
        }
コード例 #26
0
ファイル: BuyDialog.cs プロジェクト: davidlfox/DrugBot
        private async Task BuyQuantityAsync(IDialogContext context, IAwaitable <long> result)
        {
            var qty = await result;

            // yeah, i know this could truncate
            if (qty < 1)
            {
                await context.PostAsync("Looks like you don't want to buy any--thanks for wasting my time");

                this.Done(context);
            }
            else
            {
                var quantity = Convert.ToInt32(qty);

                // todo: put this somewhere common
                var db = new DrugBotDataContext();

                var userId = context.UserData.Get <int>(StateKeys.UserId);
                var user   = db.Users.FirstOrDefault(x => x.UserId == userId);

                if (user.InventorySize >= user.Inventory.Sum(x => x.Quantity) + qty)
                {
                    var drugs = db.GetDrugs().ToList()
                                .Select(x => new
                    {
                        Name      = x.Name,
                        NameLower = x.Name.ToLower(),
                        DrugId    = x.DrugId,
                    });

                    if (user != null)
                    {
                        // determine drug price
                        var drugPrices = this.GetDrugPrices(context);
                        var drugToBuy  = context.UserData.Get <string>(StateKeys.DrugToBuy);
                        var drug       = drugs.Single(x => x.NameLower == drugToBuy);
                        var price      = drugPrices[drug.DrugId];

                        // check wallet for enough money
                        if (user.Wallet >= price * qty)
                        {
                            var cost = price * quantity;

                            // do transaction
                            user.Wallet -= cost;
                            await context.PostAsync($"You spent {cost:C0} on {qty} units of {drug.Name}");

                            await context.PostAsync($"You have {user.Wallet:C0} remaining");

                            // add inventory
                            if (user.Inventory.Any(x => x.Drug.Name == drug.Name))
                            {
                                // already has zero or more of this drug, add to it
                                var inventory = user.Inventory.FirstOrDefault(x => x.Drug.Name == drug.Name);
                                inventory.Quantity += quantity;
                            }
                            else
                            {
                                // add this inventory for the firs time
                                var inventory = new InventoryItem
                                {
                                    UserId   = user.UserId,
                                    DrugId   = drug.DrugId,
                                    Quantity = quantity,
                                };
                                db.AddInventory(inventory);
                            }

                            try
                            {
                                db.SaveChanges();
                            }
                            catch
                            {
                                await context.PostAsync("Something happened when saving your buy inventory. Yeah, I'm still an alpha bot...");
                            }

                            this.Done(context);
                        }
                        else
                        {
                            await context.PostAsync("You don't have enough money to buy that.");

                            this.Done(context);
                        }
                    }
                }
                else
                {
                    // not enough inventory space
                    await context.PostAsync("You don't have enough inventory space to buy all that.");

                    this.Done(context);
                }
            }
        }
コード例 #27
0
ファイル: MainMenuDialog.cs プロジェクト: davidlfox/DrugBot
        private async Task ResumeMainMenu(IDialogContext context, IAwaitable <GameState> result)
        {
            var state = await result;

            if (state.IsGameOver)
            {
                var user = this.GetUser(context);

                var score = user.Wallet;

                if (user.LoanDebt > 0)
                {
                    await context.PostAsync($"Ya' punk #$%! kid--I'm gonna break both your legs and take back my {user.LoanDebt:C0}!");

                    await context.PostAsync("The loan shark proceeds to break your legs and take his money.");

                    score = user.Wallet - user.LoanDebt;
                }

                // record log of game before resetting
                var db = new DrugBotDataContext();

                var game = new Game {
                    UserId = user.UserId, Score = score
                };
                db.Games.Add(game);
                db.Commit();

                // get their rank
                var orderedGame = db.Games
                                  .OrderByDescending(x => x.Score)
                                  .AsEnumerable()
                                  .Select((x, i) => new { Game = x, Rank = i + 1 })
                                  .Single(x => x.Game.GameId == game.GameId);

                await context.PostAsync("Game Over.");

                await context.PostAsync($"You finished with {score:C0} " +
                                        $"({StringHelper.AddOrdinal(orderedGame.Rank)} overall)");

                await this.ShowLeaderboard(context);

                await context.PostAsync("Type PLAY to start another game!");

                // reset user (this commits db changes)
                this.ResetUser(context);

                this.Done(context);
            }
            else if (state.IsTraveling)
            {
                var user = this.GetUser(context);

                // todo: random events for the day
                if (RandomEvent.IsGoingToHappen)
                {
                    // pass context and user to do db things, receive event info
                    var randomEvent = RandomEvent.Get(context, user.UserId);
                    context.UserData.SetValue(StateKeys.RandomEvent, randomEvent);
                }

                // get day and location
                var location = this.GetLocations().Single(x => x.LocationId == user.LocationId);
                await context.PostAsync($"It's day {user.DayOfGame}. You're in {location.Name}.");
                await StartAsync(context);
            }
            else
            {
                // print menu and start again--hopefully
                await StartAsync(context);
            }
        }