package game import ( "fmt" "strings" "thehouseoficarus/internal/action" "thehouseoficarus/internal/net" "thehouseoficarus/internal/object" "thehouseoficarus/internal/player" ) func (g *Game) doUse(sess *net.Session, input string) { if strings.TrimSpace(input) == "" { g.doHelp(sess, "use") return } p := sess.Player.(*player.Player) g.CancelAction(p) if g.tryRecharge(sess, p, input) { return } lower := strings.ToLower(input) sep := "" if strings.Contains(lower, " on ") { sep = " on " } else if strings.Contains(lower, " with ") { sep = " with " } if sep != "" { parts := strings.SplitN(lower, sep, 2) itemA := strings.TrimSpace(parts[0]) itemB := strings.TrimSpace(parts[1]) if itemA == itemB { sess.WriteLine("You can't use that with itself.") return } g.doUseItemOnTarget(sess, p, itemA, itemB) return } if len(strings.Fields(input)) >= 2 { g.doUseItemOnTarget(sess, p, strings.Fields(input)[0], strings.Join(strings.Fields(input)[1:], " ")) return } g.StartAction(sess, "use", input) } func (g *Game) doUseItemOnTarget(sess *net.Session, p *player.Player, itemAName, itemBName string) { matchesA := g.findInventoryMatches(itemAName, p) if len(matchesA) == 0 { sess.WriteLine(fmt.Sprintf("You don't have any '%s'.", itemAName)) return } uniqueA := uniqueItemNames(matchesA) if len(uniqueA) > 1 { g.showWhichOne(sess, matchesA) return } itemAID := matchesA[0].ID matchesB := g.findInventoryMatches(itemBName, p) objInstances := g.World.FindObjInstances(p.RoomID, itemBName) if len(objInstances) > 0 { objSt := &objInstances[0] def, _ := g.ObjectStore.Load(objSt.DefID) if def == nil { g.StartAction(sess, "use", itemBName) return } stationIDs := []string{def.ID} recipes, err := g.RecipeStore.FindByStation(itemAID, stationIDs, "") if err == nil && len(recipes) > 0 { if recipes[0].Type == "smelting" { filtered := recipes[:0:0] for _, r := range recipes { if r.Type != "smelting" { continue } if !r.HasAllItemsQty(p.CountItem) { continue } skillLevel := p.Level(player.SkillName(r.EffectiveSkill())) if skillLevel < r.Level { continue } filtered = append(filtered, r) } if len(filtered) == 0 { sess.WriteLine("You can't smelt that here.") return } if len(filtered) == 1 { g.promptHowMany(sess, filtered[0].ID) return } sess.PendingMenu = recipeMenuData(filtered) sess.State = net.StateRecipeChoice var names []string for _, r := range filtered { names = append(names, g.recipeName(sess, &r)) } g.showMenuTable(sess, "What would you like to smelt?", names) return } if recipes[0].Type == "smithing" { if !g.hasToolType(p, "hammer") { sess.WriteLine("You need a hammer to smith.") return } allRecipes, _ := g.RecipeStore.LoadAll() g.showSmithTable(sess, p, itemAID, allRecipes) return } if len(recipes) == 1 { g.promptHowMany(sess, recipes[0].ID) return } sess.PendingMenu = recipeMenuData(recipes) sess.State = net.StateRecipeChoice var names []string for _, r := range recipes { names = append(names, g.recipeName(sess, &r)) } g.showMenuTable(sess, fmt.Sprintf("What would you like to make with %s on the %s?", itemAName, def.Name), names) return } for _, ui := range def.UseInteractions { if ui.Item != itemAID { continue } if ui.Condition != nil && !g.checkCondition(sess, ui.Condition) { continue } if ui.Message != "" { sess.WriteLine(ui.Message) } if ui.Action != nil { g.applyNodeAction(sess, ui.Action) } return } g.StartAction(sess, "use", itemBName) return } matchesB = g.findInventoryMatches(itemBName, p) if len(matchesB) > 0 { uniqueB := uniqueItemNames(matchesB) if len(uniqueB) > 1 { sess.WriteLine("Which '" + itemBName + "'?") seen := make(map[string]bool) for _, m := range matchesB { if seen[m.Name] { continue } seen[m.Name] = true def, _ := g.ItemStore.Load(m.ID) sess.WriteLine(fmt.Sprintf(" - %s", g.itemColorize(sess, def, m.Name))) } return } itemBID := matchesB[0].ID craftRecipes := g.findCraftRecipesForItems(p, itemAID, itemBID) fletchRecipes := g.findFletchRecipesForItems(p, itemAID, itemBID) if len(craftRecipes) > 0 && len(fletchRecipes) > 0 { var menu []map[string]string var names []string for _, r := range craftRecipes { menu = append(menu, map[string]string{"recipe_id": r.ID}) outDef, _ := g.ItemStore.Load(r.Output) name := r.Output if outDef != nil { name = outDef.Name } names = append(names, fmt.Sprintf("%s (Crafting)", name)) } for _, r := range fletchRecipes { menu = append(menu, map[string]string{"fletch_recipe_id": r.ID}) outDef, _ := g.ItemStore.Load(r.Output) name := r.Output if outDef != nil { name = outDef.Name } names = append(names, fmt.Sprintf("%s (Fletching)", name)) } sess.PendingMenu = menu sess.State = net.StateRecipeChoice g.showMenuTable(sess, "What would you like to make?", names) return } if len(craftRecipes) > 0 { var available []action.RecipeDef for _, r := range craftRecipes { if g.canDoCraftRecipe(p, &r) { available = append(available, r) } } if len(available) == 1 { g.startCraftRecipe(sess, p, &available[0], 0) return } if len(available) > 1 { g.showProductionTable(sess, p, available, "Crafting", "crafting", "last_craft", "Craft", false) return } } if len(fletchRecipes) > 0 { var available []action.RecipeDef for _, r := range fletchRecipes { if g.canDoFletchRecipe(p, &r) { available = append(available, r) } } if len(available) == 1 { g.startFletchAction(sess, p, &available[0], 0) return } if len(available) > 1 { g.showProductionTable(sess, p, available, "Fletching", "fletching", "last_fletch", "Fletch", true) return } } matched := g.findCombineResults(sess, p, itemAID, itemBID) if len(matched) == 1 { g.promptHowMany(sess, "combine_"+matched[0].ID) return } if len(matched) > 1 { sess.PendingMenu = combineMenuData(matched) sess.State = net.StateRecipeChoice var names []string for _, def := range matched { names = append(names, g.itemColorize(sess, def, def.Name)) } g.showMenuTable(sess, "What would you like to make?", names) return } sess.WriteLine("You can't combine those items.") return } sess.WriteLine(fmt.Sprintf("There's no '%s' here to use that on.", itemBName)) } func (g *Game) findCombineResults(sess *net.Session, p *player.Player, itemAID, itemBID string) []*object.ItemDef { items, err := g.ItemStore.LoadAll() if err != nil { return nil } var matched []*object.ItemDef for _, def := range items { if len(def.MadeFrom) == 0 { continue } aEntry := -1 bEntry := -1 for ei, entry := range def.MadeFrom { for _, id := range entry.Items { if id == itemAID && aEntry < 0 { aEntry = ei } if id == itemBID && bEntry < 0 { bEntry = ei } } } if aEntry >= 0 && bEntry >= 0 && aEntry != bEntry && madeFromItemsAvailable(p, def.MadeFrom) { matched = append(matched, def) } } return matched } func combineMenuData(defs []*object.ItemDef) []map[string]string { out := make([]map[string]string, len(defs)) for i, d := range defs { out[i] = map[string]string{"combine_item": d.ID} } return out } func madeFromItemsAvailable(p *player.Player, madeFrom []object.MadeFromEntry) bool { for _, entry := range madeFrom { found := false for _, id := range entry.Items { if p.HasItem(id) { found = true break } } if !found { return false } } return true }