From 7a15a5d70004b28bf2a710fa0f536af2446e5b17 Mon Sep 17 00:00:00 2001 From: historia <[not public]> Date: Mon, 5 Oct 2026 17:49:48 -0400 Subject: fix: production multi-step recipes, drop-weight validation, journal versioning --- internal/game/act_fletch.go | 52 +++++++++++++++++++++++++++++++++++---------- 1 file changed, 41 insertions(+), 11 deletions(-) (limited to 'internal/game/act_fletch.go') diff --git a/internal/game/act_fletch.go b/internal/game/act_fletch.go index d4adff0..ba55516 100644 --- a/internal/game/act_fletch.go +++ b/internal/game/act_fletch.go @@ -15,16 +15,41 @@ func (g *Game) startFletchAction(sess *net.Session, p *player.Player, def *item. g.setPlayerFlag(p, "last_fletch", def.ID) g.saveCharacter(p) - if def.FirstCraft().TicksPerCycle <= 0 { - g.doInstantFletch(sess, p, def, count) + idx := g.usableFletchCraftIndex(p, def) + if idx < 0 { + sess.WriteLine("You don't have the materials for that.") + return + } + if def.Craft[idx].TicksPerCycle <= 0 { + g.doInstantFletch(sess, p, def, idx, count) return } - g.startTimedFletch(sess, p, def, count) + g.startTimedFletch(sess, p, def, idx, count) } -func (g *Game) doInstantFletch(sess *net.Session, p *player.Player, def *item.ItemDef, count int) { - c := def.FirstCraft() +// usableFletchCraftIndex selects the first fletching recipe the player both +// satisfies and has the tools for. Availability scans every recipe, so +// execution must use the same one instead of always Craft[0]. +func (g *Game) usableFletchCraftIndex(p *player.Player, def *item.ItemDef) int { + for i := range def.Craft { + c := &def.Craft[i] + if p.Level(player.Fletching) < c.Level { + continue + } + if !craftHasAllItemsQty(c, p.CountItem) { + continue + } + if !g.hasFletchTools(p, def) { + continue + } + return i + } + return -1 +} + +func (g *Game) doInstantFletch(sess *net.Session, p *player.Player, def *item.ItemDef, craftIdx, count int) { + c := &def.Craft[craftIdx] outputQty := c.OutputQty if outputQty <= 0 { outputQty = 1 @@ -47,7 +72,7 @@ func (g *Game) doInstantFletch(sess *net.Session, p *player.Player, def *item.It break } - byproducts := g.collectByproducts(p, def) + byproducts := g.collectByproducts(p, c) if !consumeIngredients(c, p.CountItem, p.RemoveItem) { break @@ -101,8 +126,8 @@ func (g *Game) doInstantFletch(sess *net.Session, p *player.Player, def *item.It sess.WriteLine(msg) } -func (g *Game) startTimedFletch(sess *net.Session, p *player.Player, def *item.ItemDef, count int) { - craft := def.FirstCraft() +func (g *Game) startTimedFletch(sess *net.Session, p *player.Player, def *item.ItemDef, craftIdx, count int) { + craft := &def.Craft[craftIdx] startMsg := g.resolveCraftMessage(sess, craft.StartMessage, "You begin fletching %i1.", craft, def.ID, nil, p.HasItem) @@ -121,6 +146,7 @@ func (g *Game) startTimedFletch(sess *net.Session, p *player.Player, def *item.I TargetName: def.Name, Data: &behavior.FletchData{ ItemID: def.ID, + CraftIndex: craftIdx, Phase: 0, TicksPerCycle: craft.TicksPerCycle, Remaining: count, @@ -145,7 +171,11 @@ func (g *Game) advanceFletch(sess *net.Session, p *player.Player) { g.cancelBgAction(p) return } - c := def.FirstCraft() + idx := data.CraftIndex + if idx < 0 || idx >= len(def.Craft) { + idx = 0 + } + c := &def.Craft[idx] if phase == 0 { data.Phase = 1 @@ -174,7 +204,7 @@ func (g *Game) advanceFletch(sess *net.Session, p *player.Player) { } skill := player.SkillName(c.EffectiveSkill()) - byproducts := g.collectByproducts(p, def) + byproducts := g.collectByproducts(p, c) hasItem := craftConsumedHasItem(c, p.CountItem, p.HasItem) if !consumeIngredients(c, p.CountItem, p.RemoveItem) { @@ -222,7 +252,7 @@ func (g *Game) advanceFletch(sess *net.Session, p *player.Player) { } } - if !g.canContinueProduction(p, def) { + if !g.canContinueProduction(p, def, c) { sess.WriteLine("You've run out of fletching materials.") g.cancelBgAction(p) return -- cgit v1.2.3