public void Execute(List <string> extraWords, Character interactingCharacter) { var useableLocationItems = interactingCharacter.GetLocation().GetUseableItems() .Select(i => new KeyValuePair <Item, string>( i.Key, i.Key.GetDescription(i.Value).UppercaseFirstChar() )); var useableCharacterItems = interactingCharacter.GetUseableInventoryItems() .Select(i => new KeyValuePair <Item, string>( i.Key, i.Key.GetDescription(i.Value).UppercaseFirstChar() )); // This represents all items that can be used (either directory or indirectly) var allUseableItems = useableLocationItems .Union(useableCharacterItems) .ToDictionary(i => i.Key, i => i.Value); // This also removes duplicates // This represnts only primary interaction items var allPrimaryItems = allUseableItems .Where(i => i.Key.IsInteractionPrimary) .ToDictionary(i => i.Key, i => i.Value); // This also removes duplicates // The end goal of interact is to interact with a primary item, // so if none of those exist here, we are done. if (!allPrimaryItems.Any()) { interactingCharacter.SendDescriptiveTextDtoMessage("There is nothing available to interact with."); interactingCharacter.GetLocation().SendDescriptiveTextDtoMessage($"{interactingCharacter.Name} is looking around for something.", interactingCharacter); return; } Item primaryItem = null; Item secondaryItem = null; // If there were extra words typed in, then attempt to auto-map them if (extraWords.Count > 0) { // Try to auto-determine the choices if extra words are typed in var wordItemMap = WordTranslator.WordsToItems(extraWords, allUseableItems.Keys.ToList()); var foundItems = wordItemMap .Where(i => i.Value != null) .Select(i => i.Value) .ToList(); // The primary item is considered the last item in the sentence that is a primary interaction item primaryItem = foundItems.LastOrDefault(i => i.IsInteractionPrimary); // This example contains only 1 item that has its primary property set (keyhole) // Considering that a player could type sentences like this // use key on keyhole - This syntax works also when there are 2 primaries involved // use keyhole with key - This syntax won't work with 2 primaries, it will get them backwards // For this reason, we disable this pattern all-together to avoid confusion // In cases where we are working with 2 primary items, the code can't really determine if the first // or the second is the primary. It works fine with 1 primary only both ways, but then messes up when there // are two primaries. Therefore to make it so sentences always produce a dependable result we make the // rule that a secondary item MUST come before the primary item in the sentence. // We only set secondary if a primary item was found though if (primaryItem != null) { foreach (var foundItem in foundItems) { // We reached the primary item, stop looking as it is invalid // for the secondary item to exist past the primary if (foundItem.TrackingId == primaryItem.TrackingId) { break; } secondaryItem = foundItem; break; } } if ( primaryItem == null || // extra words were typed, but no primary found (primaryItem != null && secondaryItem == null && foundItems.Count > 1) || // the extra words looked like more items than what we could map to (primaryItem != null && secondaryItem != null && foundItems.Count > 2) // the extra words looked like more items than what we could map to ) { interactingCharacter.SendDescriptiveTextDtoMessage("I don't quite understand, make sure the target item you want to use is last in the sentence."); return; } // Otherwise the extra words seem to have translated into the items to use properly primaryItem.Interact(secondaryItem, interactingCharacter); } }
public void Execute(List <string> extraWords, Character grabbingCharacter) { var grabbingCharacterLocation = GrainClusterClient.Universe.GetCharacterLocation(grabbingCharacter.TrackingId).Result; var locationItems = GrainClusterClient.Universe.GetLocationItems(grabbingCharacterLocation.TrackingId).Result; if (locationItems == null || locationItems.Count == 0) { grabbingCharacter.SendDescriptiveTextDtoMessage("There is nothing to grab."); grabbingCharacter.GetLocation().SendDescriptiveTextDtoMessage($"{grabbingCharacter.Name} is looking around for something.", grabbingCharacter); return; } var availableItems = locationItems .Where(i => !i.Key.IsBound && i.Key.IsVisible) // Filter out bound and invisible items because these cannot be picked up .Select(i => new KeyValuePair <Item, string>( i.Key, i.Key.GetDescription(i.Value).UppercaseFirstChar() )) .ToDictionary(i => i.Key, i => i.Value); if (!availableItems.Any()) { grabbingCharacter.SendDescriptiveTextDtoMessage("There is nothing that can be grabbed."); grabbingCharacter.GetLocation().SendDescriptiveTextDtoMessage($"{grabbingCharacter.Name} is looking around for something.", grabbingCharacter); return; } // Try to auto-determine what the player is trying to grab var wordItemMap = WordTranslator.WordsToItems(extraWords, availableItems.Keys.ToList()); var foundItems = wordItemMap .Where(i => i.Value != null) .Select(i => i.Value) .ToList(); Item itemToGrab; if (foundItems.Count == 0) { grabbingCharacter.SendDescriptiveTextDtoMessage("There is nothing like that here."); grabbingCharacter.GetLocation().SendDescriptiveTextDtoMessage($"{grabbingCharacter.Name} is looking around for something.", grabbingCharacter); return; } itemToGrab = foundItems[0]; var itemAmountToGrab = locationItems[itemToGrab]; if (itemAmountToGrab > 1) { var leftWords = wordItemMap.Where(i => i.Value == null).Select(i => i.Key).ToList(); var wordNumberMap = WordTranslator.WordsToNumbers(leftWords); var foundNumbers = wordNumberMap.Where(i => i.Value.HasValue).Select(i => i.Value.Value).ToList(); if (foundNumbers.Count > 0) { itemAmountToGrab = foundNumbers[0]; } if (itemAmountToGrab <= 0) { return; } if (itemAmountToGrab > locationItems[itemToGrab]) { itemAmountToGrab = locationItems[itemToGrab]; } } itemToGrab.Grab(itemAmountToGrab, grabbingCharacter); }
public void Execute(List <string> extraWords, Character droppingCharacter) { var droppingCharacterLocation = GrainClusterClient.Universe.GetCharacterLocation(droppingCharacter.TrackingId).Result; var droppingCharacterItems = GrainClusterClient.Universe.GetCharacterItems(droppingCharacter.TrackingId).Result; if (droppingCharacterItems == null || droppingCharacterItems.Count == 0) { droppingCharacter.SendDescriptiveTextDtoMessage("You have no items."); droppingCharacter.GetLocation().SendDescriptiveTextDtoMessage($"{droppingCharacter.Name} is happy that they have no items.", droppingCharacter); return; } var availableItems = droppingCharacterItems .Where(i => !i.Key.IsBound && i.Key.IsVisible) // Filter out bound and invisible items because these cannot be dropped .Select(i => new KeyValuePair <Item, string>( i.Key, i.Key.GetDescription(i.Value).UppercaseFirstChar() )) .ToDictionary(i => i.Key, i => i.Value); if (!availableItems.Any()) { droppingCharacter.SendDescriptiveTextDtoMessage("You have nothing that can be dropped."); droppingCharacter.GetLocation().SendDescriptiveTextDtoMessage($"{droppingCharacter.Name} is digging around in their inventory looking for something.", droppingCharacter); // TODO: he/she/pronoun ? return; } // Try to auto-determine what the character is trying to drop var wordItemMap = WordTranslator.WordsToItems(extraWords, availableItems.Keys.ToList()); var foundItems = wordItemMap .Where(i => i.Value != null) .Select(i => i.Value) .ToList(); Item itemToDrop; if (foundItems.Count == 0) { droppingCharacter.SendDescriptiveTextDtoMessage("You don't have anything like that."); droppingCharacter.GetLocation().SendDescriptiveTextDtoMessage($"{droppingCharacter.Name} is digging around in their inventory looking for something.", droppingCharacter); // TODO: he/she/pronoun ? return; } itemToDrop = foundItems[0]; var itemAmountToDrop = droppingCharacterItems[itemToDrop]; if (itemAmountToDrop > 1) { var leftWords = wordItemMap.Where(i => i.Value == null).Select(i => i.Key).ToList(); var wordNumberMap = WordTranslator.WordsToNumbers(leftWords); var foundNumbers = wordNumberMap.Where(i => i.Value.HasValue).Select(i => i.Value.Value).ToList(); if (foundNumbers.Count > 0) { itemAmountToDrop = foundNumbers[0]; } if (itemAmountToDrop <= 0) { return; } if (itemAmountToDrop > droppingCharacterItems[itemToDrop]) { itemAmountToDrop = droppingCharacterItems[itemToDrop]; } } itemToDrop.Drop(itemAmountToDrop, droppingCharacter); }