aboutsummaryrefslogtreecommitdiff
path: root/internal/game/production_engine.go
diff options
context:
space:
mode:
Diffstat (limited to 'internal/game/production_engine.go')
-rw-r--r--internal/game/production_engine.go58
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
}