public static bool CanCraft(ArcadeUser user, Recipe recipe) { if (recipe == null) { throw new Exception("Could not find a recipe with the specified ID"); } foreach ((string itemId, int amount) in recipe.Components) { if (!ItemHelper.HasItem(user, itemId) || ItemHelper.GetOwnedAmount(user, itemId) != amount) { return(false); } } return(true); }
// This is only invoked if the ID is either the Host or the Participant. public override async Task <MatchResult> InvokeAsync(SocketMessage message) { // gets the account that executed this. var account = GetAccount(message.Author.Id); // Get the input from the message string input = message.Content; // CANCEL: This cancels the current trade, regardless of who executed it. if (input == "cancel") { await SetStateAsync(TradeState.Cancel); await UpdateMessageAsync(WriteOnCancel(account)); return(MatchResult.Success); } // If the current invoker is not the current speaker, ignore their inputs if (CurrentId.HasValue) { if (CurrentId.Value != account.Id) { return(MatchResult.Continue); } } switch (State) { case TradeState.Invite: // ACCEPT if (input == "accept" && account.Id == Participant.Id) { // If the user accepted the trade invitation, go to the base trade menu. await SetStateAsync(TradeState.Menu, $"> ☑️ **{Participant.Username}** has agreed to trade."); Participant.CanTrade = false; return(MatchResult.Continue); } // DECLINE if (input == "decline" && account.Id == Participant.Id) { await SetStateAsync(TradeState.Cancel); await UpdateMessageAsync(WriteOnCancel(account)); return(MatchResult.Success); } break; case TradeState.Menu: // ACCEPT: This marks the user who executed it that they accepted their end of the trade. // If both users accept, then the trade goes through. Take all specified items from both, swap, and give both the other's items. if (input == "ready") { if (IsOfferEmpty()) { await SetStateAsync(TradeState.Menu, Format.Warning("There aren't any items specified!")); return(MatchResult.Continue); } if (CanStartTrade()) { Trade(); await SetStateAsync(TradeState.Success); return(MatchResult.Success); } MarkAsReady(account.Id); await SetStateAsync(TradeState.Menu); return(MatchResult.Continue); } if (input == "inventory") { // If someone is already inspecting their backpack, ignore input. if (CurrentId.HasValue) { return(MatchResult.Continue); } CurrentId = account.Id; await SetStateAsync(TradeState.Inventory); return(MatchResult.Continue); } break; case TradeState.Inventory: // BACK: Used by the current invoker to return to the menu. if (input == "back") { CurrentId = null; await SetStateAsync(TradeState.Menu); return(MatchResult.Continue); } // TODO: Handle unique item ID when trading. // Check if the specified item exists in the invoker inventory if (!ItemHelper.HasItem(account, input)) { await SetStateAsync(TradeState.Inventory, Format.Warning("An invalid item ID was specified.")); return(MatchResult.Continue); } // If the specified item was already selected, remove it from their trade. if (GetCurrentItems().ContainsKey(input)) { RemoveItemFromCurrent(input); await SetStateAsync(TradeState.Inventory, "> 📤 Removed the specified item from your offer."); HostReady = false; ParticipantReady = false; return(MatchResult.Continue); } ItemData selectedItem = ItemHelper.DataOf(account, input); if (!ItemHelper.CanTrade(input, selectedItem)) { await SetStateAsync(TradeState.Inventory, Format.Warning("This item is unavailable for trading.")); return(MatchResult.Continue); } AddItemToCurrent(input); await SetStateAsync(TradeState.Inventory, "> 📥 Added the specified item to your offer."); HostReady = false; ParticipantReady = false; return(MatchResult.Continue); } return(MatchResult.Continue); }