diff options
| author | historia <[not public]> | 2026-06-16 04:17:43 -0400 |
|---|---|---|
| committer | historia <[not public]> | 2026-06-16 04:17:43 -0400 |
| commit | 085e728d22a3369bd110b77409914cfbe9ebe611 (patch) | |
| tree | eeb88cb1ceb91cc9ea2b5a1877c3c66328fab503 /internal/game/cmd_cook.go | |
| parent | 43f21aabae8924f35c12c8485e690aeefe0089fb (diff) | |
| download | thehouseoficarus-085e728d22a3369bd110b77409914cfbe9ebe611.tar.gz | |
feat: recipe system, combining items, cooking skill
Diffstat (limited to 'internal/game/cmd_cook.go')
| -rw-r--r-- | internal/game/cmd_cook.go | 246 |
1 files changed, 246 insertions, 0 deletions
diff --git a/internal/game/cmd_cook.go b/internal/game/cmd_cook.go new file mode 100644 index 0000000..be5fa3a --- /dev/null +++ b/internal/game/cmd_cook.go @@ -0,0 +1,246 @@ +package game + +import ( + "fmt" + "strconv" + "strings" + + "thirdcollapse/internal/action" + "thirdcollapse/internal/net" + "thirdcollapse/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) +} |
