diff options
| author | historia <[not public]> | 2026-06-20 23:43:35 -0400 |
|---|---|---|
| committer | historia <[not public]> | 2026-06-20 23:43:35 -0400 |
| commit | 470bc5bd99b793e46305310b5fbeb3068eba45f1 (patch) | |
| tree | ff268fab1a8e7699cd6404e6e86c2d4bd1c6f2f6 /internal/game/core_production.go | |
| parent | 010fa439399581391fcd509d2058191ff4fa74b3 (diff) | |
| download | thehouseoficarus-470bc5bd99b793e46305310b5fbeb3068eba45f1.tar.gz | |
refactor: removed separate crafting recipes and combined them into item YAML
Diffstat (limited to 'internal/game/core_production.go')
| -rw-r--r-- | internal/game/core_production.go | 406 |
1 files changed, 187 insertions, 219 deletions
diff --git a/internal/game/core_production.go b/internal/game/core_production.go index 59517d5..4aecc54 100644 --- a/internal/game/core_production.go +++ b/internal/game/core_production.go @@ -13,47 +13,61 @@ import ( "thehouseoficarus/internal/net" "thehouseoficarus/internal/object" "thehouseoficarus/internal/player" - ) -func (g *Game) startProduction(sess *net.Session, p *player.Player, recipe *action.RecipeDef, actionType, displayVerb, startMsg, endMsg string, count int) { +func craftFirstItemName(c *object.CraftDef, load func(string) (string, bool)) string { + if c == nil { + return "" + } + for _, e := range c.Consume { + for _, id := range e.Items { + if name, ok := load(id); ok { + return name + } + return id + } + } + return "" +} + +func (g *Game) startProduction(sess *net.Session, p *player.Player, item *object.ItemDef, craft *object.CraftDef, actionType, displayVerb, startMsg, endMsg string, count int) { g.cancelAction(p) g.cancelBgAction(p) - skill := recipe.EffectiveSkill() + skill := craft.EffectiveSkill() if skill != "" { skillLevel := p.Level(player.SkillName(skill)) - if skillLevel < recipe.Level { - sess.WriteLine(fmt.Sprintf("You need level %d %s to do that.", recipe.Level, skill)) + if skillLevel < craft.Level { + sess.WriteLine(fmt.Sprintf("You need level %d %s to do that.", craft.Level, skill)) g.reprompt(sess) return } } - if !recipe.HasAllItemsQty(p.CountItem) { + if !craftHasAllItemsQty(craft, p.CountItem) { sess.WriteLine("You don't have the required materials.") g.reprompt(sess) return } - outDef, _ := g.ItemStore.Load(recipe.Output) + outDef, _ := g.ItemStore.Load(item.ID) - wait := recipe.Wait + wait := craft.Wait if wait <= 0 { wait = 4 } - outputName := recipe.Output + outputName := item.ID if outDef != nil { outputName = outDef.Name } p.Action = &action.Action{ Type: actionType, - TargetID: recipe.ID, + TargetID: item.ID, TargetName: outputName, Data: map[string]any{ - "recipe_id": recipe.ID, + "item_id": item.ID, "phase": 0, "wait": wait, "start_msg": startMsg, @@ -68,13 +82,18 @@ func (g *Game) startProduction(sess *net.Session, p *player.Player, recipe *acti g.broadcastAction(sess, "\n%s starts %s.", p.Name, displayVerb) } -func (g *Game) startProductionFromRecipe(sess *net.Session, p *player.Player, recipe *action.RecipeDef, count int) { - _, stationName := g.findStation(p.RoomID, recipe.Station) +func (g *Game) startProductionFromItem(sess *net.Session, p *player.Player, item *object.ItemDef, count int) { + craft := item.FirstCraft() + if craft == nil { + return + } + + _, stationName := g.findStation(p.RoomID, craft.Station) if stationName == "" { stationName = "inventory" } - firstItem := recipe.FirstItemName(func(id string) (string, bool) { + firstItem := craftFirstItemName(craft, func(id string) (string, bool) { def, err := g.ItemStore.Load(id) if err != nil { return id, false @@ -82,9 +101,9 @@ func (g *Game) startProductionFromRecipe(sess *net.Session, p *player.Player, re return def.Name, true }) - info, ok := productionTypes[recipe.Type] + info, ok := productionTypes[craft.Type] if !ok { - info = productionTypeInfo{recipe.Type, recipe.Type} + info = productionTypeInfo{craft.Type, craft.Type} } actionType := info.ActionType displayVerb := info.DisplayVerb @@ -97,67 +116,79 @@ func (g *Game) startProductionFromRecipe(sess *net.Session, p *player.Player, re } endMsg = fmt.Sprintf("You've finished %s.", displayVerb) - g.startProduction(sess, p, recipe, actionType, displayVerb, startMsg, endMsg, count) + g.startProduction(sess, p, item, craft, actionType, displayVerb, startMsg, endMsg, count) } -func (g *Game) loadRecipe(recipeID string) *action.RecipeDef { - if r := g.RecipeStore.GetByID(recipeID); r != nil { - return r +func (g *Game) loadCraftItem(itemID string) *object.ItemDef { + item, err := g.ItemStore.Load(itemID) + if err != nil || len(item.Craft) == 0 { + return nil } - if strings.HasPrefix(recipeID, "combine_") { - itemID := strings.TrimPrefix(recipeID, "combine_") - if itemDef, err := g.ItemStore.Load(itemID); err == nil && len(itemDef.MadeFrom) > 0 { - return g.buildCombineRecipe(itemDef) - } - } - return nil + return item } func (g *Game) advanceProduction(sess *net.Session, p *player.Player) bool { - recipeID := p.Action.Data["recipe_id"].(string) + itemID := p.Action.Data["item_id"].(string) phase := p.Action.Data["phase"].(int) wait := p.Action.Data["wait"].(float64) startMsg, _ := p.Action.Data["start_msg"].(string) endMsg, _ := p.Action.Data["end_msg"].(string) remaining, _ := p.Action.Data["remaining"].(int) - recipe := g.loadRecipe(recipeID) - if recipe == nil { + item := g.loadCraftItem(itemID) + if item == nil { g.cancelAction(p) return false } + craft := item.FirstCraft() if phase == 0 { if startMsg != "" { sess.WriteLine(fmt.Sprintf("\n%s", startMsg)) } + if len(craft.Steps) > 0 { + p.Action.Data["next_step_index"] = 0 + p.Action.Data["steps_accumulated_ticks"] = float64(0) + } p.Action.Data["phase"] = 1 p.Action.WaitLeft = engine.ToTicks(wait) return true } - skill := recipe.EffectiveSkill() + if stepsIdx, ok := p.Action.Data["next_step_index"].(int); ok && stepsIdx < len(craft.Steps) { + accTicks, _ := p.Action.Data["steps_accumulated_ticks"].(float64) + accTicks += wait + p.Action.Data["steps_accumulated_ticks"] = accTicks + for i := stepsIdx; i < len(craft.Steps); i++ { + if accTicks >= craft.Steps[i].Tick { + sess.WriteLine(craft.Steps[i].Message) + p.Action.Data["next_step_index"] = i + 1 + } + } + } + + skill := craft.EffectiveSkill() skillLevel := p.Level(player.SkillName(skill)) chance := 1.0 - if recipe.Success != nil { - chance = action.SuccessChance(*recipe.Success, skillLevel, recipe.Level) + if craft.Success != nil { + chance = action.SuccessChance(action.SuccessFormula(*craft.Success), skillLevel, craft.Level) } if rand.Float64() < chance { - outputQty := recipe.OutputQty + outputQty := craft.OutputQty if outputQty <= 0 { outputQty = 1 } - byproducts := g.collectByproducts(p, recipe) + byproducts := g.collectByproducts(p, item) placed := false - outDef, _ := g.ItemStore.Load(recipe.Output) + outDef, _ := g.ItemStore.Load(item.ID) if outDef != nil && outDef.Stackable { for i := 0; i < 28; i++ { slot := p.InvSlot(i) - if slot != nil && slot.ItemID == recipe.Output { - recipe.ConsumeAll(p.HasItem, p.RemoveItem) + if slot != nil && slot.ItemID == item.ID { + craftConsumeAll(craft, p.HasItem, p.RemoveItem) slot.Quantity += outputQty placed = true break @@ -165,14 +196,14 @@ func (g *Game) advanceProduction(sess *net.Session, p *player.Player) bool { } } if !placed { - recipe.ConsumeAll(p.HasItem, p.RemoveItem) + craftConsumeAll(craft, p.HasItem, p.RemoveItem) freeSlot := p.FirstFreeSlot() if freeSlot == -1 { sess.WriteLine("Your inventory is too full!") g.cancelAction(p) return false } - p.SetInvSlot(freeSlot, &player.InventorySlot{ItemID: recipe.Output, Quantity: outputQty}) + p.SetInvSlot(freeSlot, &player.InventorySlot{ItemID: item.ID, Quantity: outputQty}) } for _, bp := range byproducts { @@ -181,38 +212,38 @@ func (g *Game) advanceProduction(sess *net.Session, p *player.Player) bool { } } - if recipe.XP > 0 { - if newLevel := p.AddSkillXP(player.SkillName(skill), recipe.XP); newLevel > 0 { + if craft.XP > 0 { + if newLevel := p.AddSkillXP(player.SkillName(skill), craft.XP); newLevel > 0 { sess.WriteLine(g.colorize(sess, "level_up", fmt.Sprintf("*** You are now level %d %s! ***", newLevel, skill))) } } g.AccountStore.SaveCharacter(p) - msg := recipe.Message + msg := craft.Message if msg == "" { - outputName := recipe.Output + outputName := item.ID if outDef != nil { outputName = outDef.Name } msg = fmt.Sprintf("You produce %s.", outputName) } - if p.OptionBool("xp_drops") && recipe.XP > 0 { + if p.OptionBool("xp_drops") && craft.XP > 0 { abbr := player.SkillAbbr[player.SkillName(skill)] - msg += g.colorize(sess, "xp", fmt.Sprintf(" (+%dxp %s)", recipe.XP, abbr)) + msg += g.colorize(sess, "xp", fmt.Sprintf(" (+%dxp %s)", craft.XP, abbr)) } sess.WriteLine(msg) } else { - recipe.ConsumeAll(p.HasItem, p.RemoveItem) + craftConsumeAll(craft, p.HasItem, p.RemoveItem) - if recipe.Fail != "" { + if craft.Fail != "" { freeSlot := p.FirstFreeSlot() if freeSlot >= 0 { - p.SetInvSlot(freeSlot, &player.InventorySlot{ItemID: recipe.Fail, Quantity: 1}) + p.SetInvSlot(freeSlot, &player.InventorySlot{ItemID: craft.Fail, Quantity: 1}) } } g.AccountStore.SaveCharacter(p) - msg := recipe.FailMessage + msg := craft.FailMessage if msg == "" { msg = "You fail and the materials are lost." } @@ -231,7 +262,7 @@ func (g *Game) advanceProduction(sess *net.Session, p *player.Player) bool { } } - if g.canContinueProduction(p, recipe) { + if g.canContinueProduction(p, item) { p.Action.WaitLeft = engine.ToTicks(wait) return true } @@ -243,9 +274,13 @@ func (g *Game) advanceProduction(sess *net.Session, p *player.Player) bool { return false } -func (g *Game) collectByproducts(p *player.Player, recipe *action.RecipeDef) []string { +func (g *Game) collectByproducts(p *player.Player, item *object.ItemDef) []string { + craft := item.FirstCraft() + if craft == nil { + return nil + } var byproducts []string - for _, e := range recipe.Consume { + for _, e := range craft.Consume { if len(e.Byproducts) == 0 { continue } @@ -259,19 +294,23 @@ func (g *Game) collectByproducts(p *player.Player, recipe *action.RecipeDef) []s return byproducts } -func (g *Game) canContinueProduction(p *player.Player, recipe *action.RecipeDef) bool { - if !recipe.HasAllItemsQty(p.CountItem) { +func (g *Game) canContinueProduction(p *player.Player, item *object.ItemDef) bool { + craft := item.FirstCraft() + if craft == nil { return false } - outputQty := recipe.OutputQty + if !craftHasAllItemsQty(craft, p.CountItem) { + return false + } + outputQty := craft.OutputQty if outputQty <= 0 { outputQty = 1 } - outDef, _ := g.ItemStore.Load(recipe.Output) + outDef, _ := g.ItemStore.Load(item.ID) if outDef != nil && outDef.Stackable { for i := 0; i < 28; i++ { slot := p.InvSlot(i) - if slot != nil && slot.ItemID == recipe.Output { + if slot != nil && slot.ItemID == item.ID { return true } } @@ -316,7 +355,7 @@ func (g *Game) handleRecipeChoice(sess *net.Session, input string) { if name == "" { continue } - if strings.ToLower(name) == lower || action.WordPrefixMatch(input, name) { + if strings.ToLower(name) == lower || object.WordPrefixMatch(input, name) { if matchIdx >= 0 { sess.WriteLine("That's ambiguous.") return @@ -338,21 +377,11 @@ func (g *Game) handleRecipeChoice(sess *net.Session, input string) { } func (g *Game) menuEntryName(entry map[string]string) string { - if rid, ok := entry["recipe_id"]; ok { - if r := g.RecipeStore.GetByID(rid); r != nil { - if def, err := g.ItemStore.Load(r.Output); err == nil { - return def.Name - } - return r.Output - } - } - if rid, ok := entry["fletch_recipe_id"]; ok { - if r := g.RecipeStore.GetByID(rid); r != nil { - if def, err := g.ItemStore.Load(r.Output); err == nil { - return def.Name - } - return r.Output + if iid, ok := entry["item_id"]; ok { + if def, _ := g.ItemStore.Load(iid); def != nil { + return def.Name } + return iid } if barID, ok := entry["bar_id"]; ok { if def, _ := g.ItemStore.Load(barID); def != nil { @@ -360,51 +389,34 @@ func (g *Game) menuEntryName(entry map[string]string) string { } return barID } - if cid, ok := entry["combine_item"]; ok { - if def, _ := g.ItemStore.Load(cid); def != nil { - return def.Name - } - return cid - } return "" } func (g *Game) dispatchMenuEntry(sess *net.Session, entry map[string]string) { - if cid, ok := entry["combine_item"]; ok { - g.promptHowMany(sess, "combine_"+cid) + if iid, ok := entry["item_id"]; ok { + g.promptHowMany(sess, iid) return } if barID, ok := entry["bar_id"]; ok { - p := sess.Player - allRecipes, _ := g.RecipeStore.LoadAll() - g.showSmithTable(sess, p, barID, allRecipes) - return - } - if rid, ok := entry["fletch_recipe_id"]; ok { - p := sess.Player - if r := g.RecipeStore.GetByID(rid); r != nil { - g.startFletchAction(sess, p, r, 0) - return - } - g.reprompt(sess) - return - } - if rid, ok := entry["recipe_id"]; ok { - g.promptHowMany(sess, rid) + g.showSmithTable(sess, sess.Player, barID) return } g.reprompt(sess) } -func (g *Game) formatMaterials(r *action.RecipeDef) string { +func (g *Game) formatMaterials(item *object.ItemDef) string { + craft := item.FirstCraft() + if craft == nil { + return "" + } var parts []string - for _, e := range r.Consume { + for _, e := range craft.Consume { itemName := e.Items[0] if def, err := g.ItemStore.Load(e.Items[0]); err == nil { itemName = def.Name } - if e.Quantity > 1 { - parts = append(parts, fmt.Sprintf("%s x%d", itemName, e.Quantity)) + if e.Quantity > 1 { + parts = append(parts, fmt.Sprintf("%s x%d", itemName, e.Quantity)) } else { parts = append(parts, itemName) } @@ -412,9 +424,9 @@ func (g *Game) formatMaterials(r *action.RecipeDef) string { return strings.Join(parts, ", ") } -func (g *Game) showProductionTable(sess *net.Session, p *player.Player, recipes []action.RecipeDef, title, skill, lastFlagKey, promptVerb string, background bool) { - sort.Slice(recipes, func(i, j int) bool { - return recipes[i].Level < recipes[j].Level +func (g *Game) showProductionTable(sess *net.Session, p *player.Player, items []*object.ItemDef, title, skill, lastFlagKey, promptVerb string, background bool) { + sort.Slice(items, func(i, j int) bool { + return items[i].FirstCraft().Level < items[j].FirstCraft().Level }) mode := g.colorMode(sess) @@ -426,14 +438,15 @@ func (g *Game) showProductionTable(sess *net.Session, p *player.Player, recipes Columns: []string{"#", "Product", "Materials", "Level"}, } - for i, r := range recipes { - outDef, _ := g.ItemStore.Load(r.Output) - productName := r.Output + for i, item := range items { + craft := item.FirstCraft() + outDef, _ := g.ItemStore.Load(item.ID) + productName := item.ID if outDef != nil { productName = outDef.Name } - outputQty := r.OutputQty + outputQty := craft.OutputQty if outputQty <= 0 { outputQty = 1 } @@ -441,11 +454,11 @@ func (g *Game) showProductionTable(sess *net.Session, p *player.Player, recipes productName = fmt.Sprintf("%s x%d", productName, outputQty) } - matStr := g.formatMaterials(&r) - levelStr := fmt.Sprint(r.Level) + matStr := g.formatMaterials(item) + levelStr := fmt.Sprint(craft.Level) numStr := fmt.Sprintf("%d", i+1) - canMake := skillLevel >= r.Level && r.HasAllItemsQty(p.CountItem) + canMake := skillLevel >= craft.Level && craftHasAllItemsQty(craft, p.CountItem) if canMake { productName = g.itemColorize(sess, outDef, productName) } else { @@ -464,12 +477,12 @@ func (g *Game) showProductionTable(sess *net.Session, p *player.Player, recipes sess.WriteLine(line) } - lastRecipeID, _ := p.Flags[lastFlagKey].(string) + lastItemID, _ := p.Flags[lastFlagKey].(string) hint := "" - if lastRecipeID != "" { - for _, r := range recipes { - if r.ID == lastRecipeID { - if outDef, err := g.ItemStore.Load(r.Output); err == nil { + if lastItemID != "" { + for _, item := range items { + if item.ID == lastItemID { + if outDef, err := g.ItemStore.Load(item.ID); err == nil { hint = outDef.Name } break @@ -483,7 +496,7 @@ func (g *Game) showProductionTable(sess *net.Session, p *player.Player, recipes sess.Write(fmt.Sprintf("%s what: ", promptVerb)) } - sess.PendingMenu = recipeMenuData(recipeDefIDs(recipes)) + sess.PendingMenu = itemMenuData(itemIDs(items)) sess.PendingSkill = skill sess.PendingLastFlag = lastFlagKey sess.PendingBackground = background @@ -504,26 +517,26 @@ func (g *Game) handleProductChoice(sess *net.Session, input string) { input = strings.TrimSpace(input) - var recipes []action.RecipeDef + var items []*object.ItemDef for _, entry := range menuData { - rid := entry["recipe_id"] - if r := g.RecipeStore.GetByID(rid); r != nil { - recipes = append(recipes, *r) + iid := entry["item_id"] + if item := g.loadCraftItem(iid); item != nil { + items = append(items, item) } } - if len(recipes) == 0 { + if len(items) == 0 { g.reprompt(sess) return } - sort.Slice(recipes, func(i, j int) bool { - return recipes[i].Level < recipes[j].Level + sort.Slice(items, func(i, j int) bool { + return items[i].FirstCraft().Level < items[j].FirstCraft().Level }) - lastRecipeID, _ := p.Flags[lastFlagKey].(string) + lastItemID, _ := p.Flags[lastFlagKey].(string) - sel, errMsg := g.resolveRecipeByInput(input, recipes, lastRecipeID) + sel, errMsg := g.resolveCraftByInput(input, items, lastItemID) switch errMsg { case "ambiguous": sess.WriteLine("That's ambiguous.") @@ -535,26 +548,27 @@ func (g *Game) handleProductChoice(sess *net.Session, input string) { return } + craft := sel.Item.FirstCraft() skillLevel := p.Level(player.SkillName(skill)) - if skillLevel < sel.Recipe.Level { - sess.WriteLine(fmt.Sprintf("You need level %d %s to make that.", sel.Recipe.Level, skill)) + if skillLevel < craft.Level { + sess.WriteLine(fmt.Sprintf("You need level %d %s to make that.", craft.Level, skill)) g.reprompt(sess) return } - if !sel.Recipe.HasAllItemsQty(p.CountItem) { + if !craftHasAllItemsQty(craft, p.CountItem) { sess.WriteLine("You don't have the materials for that.") g.reprompt(sess) return } p.EnsureFlags() - p.Flags[lastFlagKey] = sel.Recipe.ID + p.Flags[lastFlagKey] = sel.Item.ID g.AccountStore.SaveCharacter(p) if background { - g.startFletchAction(sess, p, sel.Recipe, sel.Count) + g.startFletchAction(sess, p, sel.Item, sel.Count) } else { - g.startProductionFromRecipe(sess, p, sel.Recipe, sel.Count) + g.startProductionFromItem(sess, p, sel.Item, sel.Count) } } @@ -591,10 +605,6 @@ func (g *Game) hasToolType(p *player.Player, toolType string) bool { _, _, found := g.findTool(p, []string{toolType}) return found } -type recipeEntry struct { - ItemName string - Recipe action.RecipeDef -} type productionTypeInfo struct { ActionType string @@ -621,15 +631,15 @@ func init() { } } -func recipeMenuData(recipeIDs []string) []map[string]string { - out := make([]map[string]string, len(recipeIDs)) - for i, id := range recipeIDs { - out[i] = map[string]string{"recipe_id": id} +func itemMenuData(itemIDs []string) []map[string]string { + out := make([]map[string]string, len(itemIDs)) + for i, id := range itemIDs { + out[i] = map[string]string{"item_id": id} } return out } -func recipeDefIDs(defs []action.RecipeDef) []string { +func itemIDs(defs []*object.ItemDef) []string { ids := make([]string, len(defs)) for i, d := range defs { ids[i] = d.ID @@ -637,33 +647,25 @@ func recipeDefIDs(defs []action.RecipeDef) []string { return ids } -func entryMenuData(entries []recipeEntry) []map[string]string { - out := make([]map[string]string, len(entries)) - for i, e := range entries { - out[i] = map[string]string{"recipe_id": e.Recipe.ID} - } - return out -} - -func (g *Game) promptHowMany(sess *net.Session, recipeID string) { - sess.PendingRecipeID = recipeID +func (g *Game) promptHowMany(sess *net.Session, itemID string) { + sess.PendingItemID = itemID sess.State = net.StateHowMany sess.Write("How many (return for all)?: ") } -type recipeSelection struct { - Recipe *action.RecipeDef - Count int +type craftSelection struct { + Item *object.ItemDef + Count int } -func (g *Game) resolveRecipeByInput(input string, recipes []action.RecipeDef, lastRecipeID string) (sel recipeSelection, errMsg string) { +func (g *Game) resolveCraftByInput(input string, items []*object.ItemDef, lastItemID string) (sel craftSelection, errMsg string) { if input == "" { - if lastRecipeID == "" { + if lastItemID == "" { return sel, "never_mind" } - for i := range recipes { - if recipes[i].ID == lastRecipeID { - sel.Recipe = &recipes[i] + for i := range items { + if items[i].ID == lastItemID { + sel.Item = items[i] return sel, "" } } @@ -673,22 +675,22 @@ func (g *Game) resolveRecipeByInput(input string, recipes []action.RecipeDef, la qty, productName := parseQty(input) productName = strings.TrimSpace(productName) - if idx, err := strconv.Atoi(productName); err == nil && idx > 0 && idx <= len(recipes) { - sel.Recipe = &recipes[idx-1] + if idx, err := strconv.Atoi(productName); err == nil && idx > 0 && idx <= len(items) { + sel.Item = items[idx-1] sel.Count = qty return sel, "" } matchCount := 0 - for i := range recipes { - outDef, _ := g.ItemStore.Load(recipes[i].Output) - name := recipes[i].Output + for i := range items { + outDef, _ := g.ItemStore.Load(items[i].ID) + name := items[i].ID if outDef != nil { name = outDef.Name } - if action.WordPrefixMatch(productName, name) { + if object.WordPrefixMatch(productName, name) { if matchCount == 0 { - sel.Recipe = &recipes[i] + sel.Item = items[i] sel.Count = qty } matchCount++ @@ -697,7 +699,7 @@ func (g *Game) resolveRecipeByInput(input string, recipes []action.RecipeDef, la if matchCount > 1 { return sel, "ambiguous" } - if sel.Recipe == nil { + if sel.Item == nil { return sel, "never_mind" } return sel, "" @@ -716,41 +718,42 @@ func (g *Game) showMenuTable(sess *net.Session, title string, names []string) { } } -func (g *Game) recipeName(sess *net.Session, r *action.RecipeDef) string { - if r.Output != "" { - if def, err := g.ItemStore.Load(r.Output); err == nil { +func (g *Game) itemName(sess *net.Session, item *object.ItemDef) string { + if item != nil { + if def, err := g.ItemStore.Load(item.ID); err == nil { return g.itemColorize(sess, def, def.Name) } + return item.ID } - return r.DisplayName() + return "" } -func (g *Game) showRecipeChoice(sess *net.Session, p *player.Player, recipes []action.RecipeDef, emptyMsg, title string, autoOption string) { - if len(recipes) == 0 { +func (g *Game) showRecipeChoice(sess *net.Session, p *player.Player, items []*object.ItemDef, emptyMsg, title string, autoOption string) { + if len(items) == 0 { sess.WriteLine(emptyMsg) return } - if len(recipes) == 1 { + if len(items) == 1 { if autoOption != "" && p.OptionBool(autoOption) { - g.startProductionFromRecipe(sess, p, &recipes[0], 0) + g.startProductionFromItem(sess, p, items[0], 0) return } - g.promptHowMany(sess, recipes[0].ID) + g.promptHowMany(sess, items[0].ID) return } sess.State = net.StateRecipeChoice - sess.PendingMenu = recipeMenuData(recipeDefIDs(recipes)) + sess.PendingMenu = itemMenuData(itemIDs(items)) var names []string - for i := range recipes { - names = append(names, g.recipeName(sess, &recipes[i])) + for _, item := range items { + names = append(names, g.itemName(sess, item)) } g.showMenuTable(sess, title, names) } func (g *Game) handleHowMany(sess *net.Session, input string) { p := sess.Player - recipeID := sess.PendingRecipeID - sess.PendingRecipeID = "" + itemID := sess.PendingItemID + sess.PendingItemID = "" sess.State = net.StateGame input = strings.TrimSpace(input) @@ -766,46 +769,11 @@ func (g *Game) handleHowMany(sess *net.Session, input string) { return } - var recipe *action.RecipeDef - if strings.HasPrefix(recipeID, "combine_") { - itemID := strings.TrimPrefix(recipeID, "combine_") - itemDef, err := g.ItemStore.Load(itemID) - if err != nil || len(itemDef.MadeFrom) == 0 { - g.reprompt(sess) - return - } - recipe = g.buildCombineRecipe(itemDef) - } else { - recipe = g.RecipeStore.GetByID(recipeID) - } - - if recipe == nil { + item := g.loadCraftItem(itemID) + if item == nil { g.reprompt(sess) return } - g.startProductionFromRecipe(sess, p, recipe, count) -} - -func (g *Game) buildCombineRecipe(def *object.ItemDef) *action.RecipeDef { - var consume []action.ConsumeEntry - for _, mf := range def.MadeFrom { - consume = append(consume, action.ConsumeEntry{ - Items: mf.Items, - Quantity: mf.Quantity, - Byproducts: mf.Byproducts, - }) - } - wait := def.Ticks - if wait <= 0 { - wait = 2 - } - return &action.RecipeDef{ - ID: "combine_" + def.ID, - Type: "combine", - Wait: wait, - Consume: consume, - Output: def.ID, - Message: fmt.Sprintf("You create %s.", def.Name), - } + g.startProductionFromItem(sess, p, item, count) } |
