package game import ( "fmt" "sort" "strings" "thehouseoficarus/internal/action" "thehouseoficarus/internal/net" "thehouseoficarus/internal/player" ) func (g *Game) doSmith(sess *net.Session, input string) { p := sess.Player.(*player.Player) g.CancelAction(p) stationDefID, _ := g.findStation(p.RoomID, []string{"anvil"}) if stationDefID == "" { sess.WriteLine("You need an anvil to smith.") return } if !g.hasToolType(p, "hammer") { sess.WriteLine("You need a hammer to smith.") return } allRecipes, err := g.RecipeStore.LoadAll() if err != nil { sess.WriteLine("Error loading recipes.") return } if input != "" { matches := g.findInventoryMatches(input, p) if len(matches) == 0 { sess.WriteLine(fmt.Sprintf("You don't have any '%s'.", input)) return } unique := uniqueItemNames(matches) if len(unique) > 1 { g.showWhichOne(sess, matches) return } barID := matches[0].ID if !hasSmithingRecipes(allRecipes, barID) { sess.WriteLine("You can't smith that.") return } g.showSmithTable(sess, p, barID, allRecipes) return } barTypes := findSmithableBars(allRecipes, p) if len(barTypes) == 0 { sess.WriteLine("You don't have any bars to smith.") return } if len(barTypes) == 1 { if p.OptionBool("smith_all") { if recipe := g.findSingleSmithRecipe(p, barTypes[0], allRecipes); recipe != nil { g.startProductionFromRecipe(sess, p, recipe, 0) return } } g.showSmithTable(sess, p, barTypes[0], allRecipes) return } sess.PendingMenu = barMenuData(barTypes) sess.State = net.StateRecipeChoice var names []string for _, barID := range barTypes { def, _ := g.ItemStore.Load(barID) name := barID if def != nil { name = g.itemColorize(sess, def, def.Name) } names = append(names, name) } g.showMenuTable(sess, "Which bars would you like to smith?", names) } func (g *Game) showSmithTable(sess *net.Session, p *player.Player, barID string, allRecipes []action.RecipeDef) { barDef, _ := g.ItemStore.Load(barID) barName := barID if barDef != nil { barName = barDef.Name } var recipes []action.RecipeDef for _, r := range allRecipes { if r.Type == "smithing" && r.MatchesEntry(barID) { recipes = append(recipes, r) } } if len(recipes) == 0 { sess.WriteLine("There's nothing to smith with that.") return } lastFlag := fmt.Sprintf("last_smith_%s", barID) g.showProductionTable(sess, p, recipes, titleCase(barName)+" Smithing", "smithing", lastFlag, "Produce", false) } func hasSmithingRecipes(allRecipes []action.RecipeDef, barID string) bool { for _, r := range allRecipes { if r.Type == "smithing" && r.MatchesEntry(barID) { return true } } return false } func findSmithableBars(allRecipes []action.RecipeDef, p *player.Player) []string { barSet := make(map[string]bool) for _, r := range allRecipes { if r.Type != "smithing" { continue } for _, e := range r.Consume { for _, id := range e.Items { if p.HasItem(id) { barSet[id] = true } } } } var bars []string for id := range barSet { bars = append(bars, id) } sort.Strings(bars) return bars } func barMenuData(barIDs []string) []map[string]string { out := make([]map[string]string, len(barIDs)) for i, id := range barIDs { out[i] = map[string]string{"bar_id": id} } return out } func (g *Game) findSingleSmithRecipe(p *player.Player, barID string, allRecipes []action.RecipeDef) *action.RecipeDef { var makeable []*action.RecipeDef skillLevel := p.Level(player.Smithing) for i, r := range allRecipes { if r.Type != "smithing" || !r.MatchesEntry(barID) { continue } if skillLevel >= r.Level && r.HasAllItemsQty(p.CountItem) { makeable = append(makeable, &allRecipes[i]) } } if len(makeable) == 1 { return makeable[0] } return nil } func titleCase(s string) string { words := strings.Fields(s) for i, w := range words { if len(w) > 0 { words[i] = strings.ToUpper(w[:1]) + w[1:] } } return strings.Join(words, " ") }