package game import ( "fmt" "strconv" "strings" "thehouseoficarus/internal/action" "thehouseoficarus/internal/net" "thehouseoficarus/internal/player" ) type cookableEntry struct { ItemName string Recipe action.RecipeDef } func (g *Game) doCook(sess *net.Session, input string) { p := sess.Player.(*player.Player) g.CancelAction(p) stationName := g.findCookingStation(p.RoomID) if stationName == "" { sess.WriteLine("You need a fire or cooking range to cook.") return } allRecipes, err := g.RecipeStore.LoadAll() if err != nil { sess.WriteLine("Error loading recipes.") return } if input == "" { g.showCookMenu(sess, p, allRecipes, stationName) return } qty, itemName := parseQty(input) _ = qty matches := g.findInventoryMatches(itemName, p) if len(matches) == 0 { sess.WriteLine(fmt.Sprintf("You don't have any '%s'.", itemName)) return } unique := uniqueItemNames(matches) if len(unique) > 1 { sess.WriteLine("Which one?") for _, name := range unique { sess.WriteLine(fmt.Sprintf(" - %s", name)) } return } itemID := matches[0].ID var recipes []action.RecipeDef for _, r := range allRecipes { if r.Type != "cooking" { continue } if stationOK(stationName, r.Station) && r.MatchesEntry(itemID) && r.HasAllItems(p.HasItem) { recipes = append(recipes, r) } } if len(recipes) == 0 { sess.WriteLine("You can't cook that here.") return } if len(recipes) == 1 { g.startCook(sess, p, &recipes[0], stationName) return } sess.PendingRecipeItem = itemID sess.PendingCookMenu = recipesToMenuData(recipes) sess.State = net.StateCookRecipe sess.WriteLine(fmt.Sprintf("\nWhat would you like to cook on the %s?", stationName)) for i, r := range recipes { sess.WriteLine(fmt.Sprintf(" %d) %s", i+1, g.recipeName(sess, &r))) } sess.WriteLine(fmt.Sprintf(" %d) Nothing", len(recipes)+1)) } func (g *Game) showCookMenu(sess *net.Session, p *player.Player, allRecipes []action.RecipeDef, stationName string) { seen := make(map[string]bool) var cookables []cookableEntry for _, r := range allRecipes { if r.Type != "cooking" { continue } if !stationOK(stationName, r.Station) { continue } if seen[r.ID] { continue } if !r.HasAllItems(p.HasItem) { continue } seen[r.ID] = true cookables = append(cookables, cookableEntry{g.recipeName(sess, &r), r}) } if len(cookables) == 0 { sess.WriteLine("You don't have anything you can cook.") return } if len(cookables) == 1 { g.startCook(sess, p, &cookables[0].Recipe, stationName) return } sess.PendingRecipeItem = "" sess.State = net.StateCookRecipe sess.WriteLine(fmt.Sprintf("\nWhat would you like to cook on the %s?", stationName)) for i, c := range cookables { sess.WriteLine(fmt.Sprintf(" %d) %s", i+1, c.ItemName)) } sess.WriteLine(fmt.Sprintf(" %d) Nothing", len(cookables)+1)) sess.PendingCookMenu = makeCookMenuData(cookables) } func (g *Game) recipeName(sess *net.Session, r *action.RecipeDef) string { if r.Output != "" { if def, err := g.ItemStore.Load(r.Output); err == nil { return g.itemColorize(sess, def, def.Name) } } return r.DisplayName() } func makeCookMenuData(cookables []cookableEntry) []map[string]string { out := make([]map[string]string, len(cookables)) for i, c := range cookables { out[i] = map[string]string{"recipe_id": c.Recipe.ID} } return out } func recipesToMenuData(recipes []action.RecipeDef) []map[string]string { out := make([]map[string]string, len(recipes)) for i, r := range recipes { out[i] = map[string]string{"recipe_id": r.ID} } return out } func stationOK(stationName string, recipeStations []string) bool { if len(recipeStations) == 0 { return false } for _, rs := range recipeStations { if (rs == "fire" && stationName == "fire") || (rs == "cooking_range" && stationName == "cooking range") { return true } } return false } func (g *Game) findCookingStation(roomID int) string { for _, obj := range g.World.AllObjInstances(roomID) { if obj.Depleted { continue } if obj.DefID == "fire" { return "fire" } if obj.DefID == "cooking_range" { return "cooking range" } } return "" } func (g *Game) handleCookRecipe(sess *net.Session, input string) { p := sess.Player.(*player.Player) input = strings.TrimSpace(input) if input == "" { return } choice, err := strconv.Atoi(input) if err != nil { sess.State = net.StateGame sess.PendingRecipeItem = "" sess.PendingCookMenu = nil sess.WriteLine("You decide not to cook anything.") g.reprompt(sess) return } if len(sess.PendingCookMenu) > 0 { menuData := sess.PendingCookMenu sess.PendingCookMenu = nil if choice <= 0 || choice > len(menuData)+1 { sess.WriteLine("Invalid choice.") return } sess.State = net.StateGame if choice == len(menuData)+1 { sess.WriteLine("You decide not to cook anything.") g.reprompt(sess) return } entry := menuData[choice-1] if cid, ok := entry["combine_item"]; ok { def, err := g.ItemStore.Load(cid) if err == nil { p := sess.Player.(*player.Player) g.produceCombined(sess, p, def) } g.reprompt(sess) return } all, err := g.RecipeStore.LoadAll() if err != nil { g.reprompt(sess) return } for _, r := range all { if r.ID == entry["recipe_id"] { stationName := "inventory" if len(r.Station) > 0 { stationName = g.findCookingStation(p.RoomID) } g.startCook(sess, p, &r, stationName) return } } g.reprompt(sess) return } sess.State = net.StateGame g.reprompt(sess) }