diff options
Diffstat (limited to 'internal/game/production_engine.go')
| -rw-r--r-- | internal/game/production_engine.go | 58 |
1 files changed, 46 insertions, 12 deletions
diff --git a/internal/game/production_engine.go b/internal/game/production_engine.go index f80daa2..4717fbf 100644 --- a/internal/game/production_engine.go +++ b/internal/game/production_engine.go @@ -72,7 +72,7 @@ func (g *Game) resolveCraftMessage(sess *net.Session, itemMsg, defaultMsg string return g.resolveCraftVar(sess, msg, craft, outputID, byproducts, hasItem) } -func (g *Game) startProduction(sess *net.Session, p *player.Player, item *item.ItemDef, craft *item.CraftDef, actionType behavior.ActionType, displayVerb, startMsg, endMsg string, count int) { +func (g *Game) startProduction(sess *net.Session, p *player.Player, item *item.ItemDef, craft *item.CraftDef, actionType behavior.ActionType, displayVerb, startMsg, endMsg string, count int, craftIndex int) { g.cancelAction(p) g.cancelBgAction(p) @@ -110,6 +110,7 @@ func (g *Game) startProduction(sess *net.Session, p *player.Player, item *item.I TargetName: outputName, Data: &behavior.ProductionData{ ItemID: item.ID, + CraftIndex: craftIndex, Phase: 0, TicksPerCycle: wait, StartMessage: startMsg, @@ -122,11 +123,42 @@ func (g *Game) startProduction(sess *net.Session, p *player.Player, item *item.I g.broadcastAction(sess, "%s starts %s.", p.Name, displayVerb) } +// usableCraftIndex returns the index of the first recipe of item the player +// satisfies (level and ingredients), or -1. Availability checks scan every +// recipe, so execution must select the same one instead of always Craft[0]. +func (g *Game) usableCraftIndex(p *player.Player, item *item.ItemDef) int { + for i := range item.Craft { + c := &item.Craft[i] + skill := c.EffectiveSkill() + if skill != "" && p.Level(player.SkillName(skill)) < c.Level { + continue + } + if !craftHasAllItemsQty(c, p.CountItem) { + continue + } + return i + } + return -1 +} + +// usableCraft is usableCraftIndex with a first-recipe fallback for callers +// that only need a display recipe. +func (g *Game) usableCraft(p *player.Player, item *item.ItemDef) *item.CraftDef { + if idx := g.usableCraftIndex(p, item); idx >= 0 { + return &item.Craft[idx] + } + return item.FirstCraft() +} + func (g *Game) startProductionFromItem(sess *net.Session, p *player.Player, item *item.ItemDef, count int) { - craft := item.FirstCraft() - if craft == nil { + idx := g.usableCraftIndex(p, item) + if idx < 0 { + idx = 0 + } + if idx >= len(item.Craft) { return } + craft := &item.Craft[idx] // Normalize the empty craft type to "combine" here as well as in the // craft index: an omitted `type:` is combine, but the index's normalized @@ -137,7 +169,7 @@ func (g *Game) startProductionFromItem(sess *net.Session, p *player.Player, item craftType = "combine" } if craftType == "combine" { - g.startCombine(sess, p, item, craft, count) + g.startCombine(sess, p, item, craft, count, idx) return } @@ -172,7 +204,7 @@ func (g *Game) startProductionFromItem(sess *net.Session, p *player.Player, item endMsg := g.resolveCraftMessage(sess, craft.EndMessage, info.EndMessage, craft, item.ID, nil, p.HasItem) - g.startProduction(sess, p, item, craft, info.ActionType, info.DisplayVerb, startMsg, endMsg, count) + g.startProduction(sess, p, item, craft, info.ActionType, info.DisplayVerb, startMsg, endMsg, count, idx) } func (g *Game) loadCraftItem(itemID string) *item.ItemDef { @@ -201,7 +233,11 @@ func (g *Game) advanceProduction(sess *net.Session, p *player.Player) { g.cancelAction(p) return } - craft := item.FirstCraft() + idx := d.CraftIndex + if idx < 0 || idx >= len(item.Craft) { + idx = 0 + } + craft := &item.Craft[idx] if phase == 0 { if startMsg != "" { @@ -250,7 +286,7 @@ func (g *Game) advanceProduction(sess *net.Session, p *player.Player) { // Byproducts must be collected BEFORE consumption: the resolver // maps each ingredient entry to the alternative actually being // consumed, which requires the items still present. - byproducts := g.collectByproducts(p, item) + byproducts := g.collectByproducts(p, craft) if !consumeIngredients(craft, p.CountItem, p.RemoveItem) { // Cannot happen after the availability gate above, but never @@ -323,7 +359,7 @@ func (g *Game) advanceProduction(sess *net.Session, p *player.Player) { } } - if g.canContinueProduction(p, item) { + if g.canContinueProduction(p, item, craft) { p.Action.WaitLeft = engine.ToTicks(wait) return } @@ -334,8 +370,7 @@ func (g *Game) advanceProduction(sess *net.Session, p *player.Player) { g.cancelAction(p) } -func (g *Game) collectByproducts(p *player.Player, item *item.ItemDef) []string { - craft := item.FirstCraft() +func (g *Game) collectByproducts(p *player.Player, craft *item.CraftDef) []string { if craft == nil { return nil } @@ -433,8 +468,7 @@ func (g *Game) placeCraftByproducts(p *player.Player, byproducts []string) { } } -func (g *Game) canContinueProduction(p *player.Player, item *item.ItemDef) bool { - craft := item.FirstCraft() +func (g *Game) canContinueProduction(p *player.Player, item *item.ItemDef, craft *item.CraftDef) bool { if craft == nil { return false } |
