package game import ( "fmt" "thehouseoficarus/internal/action" "thehouseoficarus/internal/engine" "thehouseoficarus/internal/net" "thehouseoficarus/internal/player" ) func (g *Game) startFletchAction(sess *net.Session, p *player.Player, recipe *action.RecipeDef, count int) { p.EnsureFlags() p.Flags["last_fletch"] = recipe.ID g.AccountStore.SaveCharacter(p) if recipe.Wait <= 0 { g.doInstantFletch(sess, p, recipe, count) return } g.startTimedFletch(sess, p, recipe, count) } func (g *Game) doInstantFletch(sess *net.Session, p *player.Player, recipe *action.RecipeDef, count int) { outDef, _ := g.ItemStore.Load(recipe.Output) outputQty := recipe.OutputQty if outputQty <= 0 { outputQty = 1 } batches := 0 totalOutput := 0 skill := player.SkillName(recipe.EffectiveSkill()) for { if !g.canDoFletchRecipe(p, recipe) { break } placed := false 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) slot.Quantity += outputQty placed = true break } } } if !placed { recipe.ConsumeAll(p.HasItem, p.RemoveItem) freeSlot := p.FirstFreeSlot() if freeSlot == -1 { break } p.SetInvSlot(freeSlot, &player.InventorySlot{ItemID: recipe.Output, Quantity: outputQty}) } if recipe.XP > 0 { g.awardSkillXP(sess, p, skill, recipe.XP) } batches++ totalOutput += outputQty if count > 0 { count-- if count <= 0 { break } } } if batches == 0 { sess.WriteLine("You don't have the materials for that.") return } g.AccountStore.SaveCharacter(p) outputName := recipe.Output if outDef != nil { outputName = outDef.Name } msg := fmt.Sprintf("You fletch %d %s.", totalOutput, outputName) if p.OptionBool("xp_drops") && recipe.XP > 0 { totalXP := recipe.XP * batches abbr := player.SkillAbbr[skill] msg += g.colorize(sess, "xp", fmt.Sprintf(" (+%dxp %s)", totalXP, abbr)) } sess.WriteLine(msg) } func (g *Game) startTimedFletch(sess *net.Session, p *player.Player, recipe *action.RecipeDef, count int) { outDef, _ := g.ItemStore.Load(recipe.Output) outputName := recipe.Output if outDef != nil { outputName = outDef.Name } p.BackgroundAction = &action.Action{ Type: "fletch", TargetID: recipe.ID, TargetName: outputName, Data: map[string]any{ "recipe_id": recipe.ID, "phase": 0, "wait": recipe.Wait, "remaining": count, }, WaitLeft: engine.ToTicks(1), } p.BackgroundActionState = &ActionState{Type: ActionFletching, TargetName: outputName} g.broadcastAction(sess, "\n%s starts fletching.", p.Name) sess.WriteLine(fmt.Sprintf("\nYou begin fletching %s.", outputName)) } func (g *Game) advanceFletch(sess *net.Session, p *player.Player) { recipeID, _ := p.BackgroundAction.Data["recipe_id"].(string) phase, _ := p.BackgroundAction.Data["phase"].(int) wait, _ := p.BackgroundAction.Data["wait"].(float64) remaining, _ := p.BackgroundAction.Data["remaining"].(int) recipe := g.loadRecipe(recipeID) if recipe == nil { g.cancelBgAction(p) return } if phase == 0 { p.BackgroundAction.Data["phase"] = 1 p.BackgroundAction.WaitLeft = engine.ToTicks(wait) return } if !g.canDoFletchRecipe(p, recipe) { sess.WriteLine("\nYou've run out of fletching materials.") g.cancelBgAction(p) return } outDef, _ := g.ItemStore.Load(recipe.Output) outputQty := recipe.OutputQty if outputQty <= 0 { outputQty = 1 } skill := player.SkillName(recipe.EffectiveSkill()) placed := false 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) slot.Quantity += outputQty placed = true break } } } if !placed { recipe.ConsumeAll(p.HasItem, p.RemoveItem) freeSlot := p.FirstFreeSlot() if freeSlot == -1 { sess.WriteLine("\nYour inventory is too full!") g.cancelBgAction(p) return } p.SetInvSlot(freeSlot, &player.InventorySlot{ItemID: recipe.Output, Quantity: outputQty}) } if recipe.XP > 0 { g.awardSkillXP(sess, p, skill, recipe.XP) } g.AccountStore.SaveCharacter(p) outputName := recipe.Output if outDef != nil { outputName = outDef.Name } msg := recipe.Message if msg == "" { msg = fmt.Sprintf("You fletch %s.", outputName) } if p.OptionBool("xp_drops") && recipe.XP > 0 { abbr := player.SkillAbbr[skill] msg += g.colorize(sess, "xp", fmt.Sprintf(" (+%dxp %s)", recipe.XP, abbr)) } sess.WriteLine(msg) if remaining > 0 { remaining-- p.BackgroundAction.Data["remaining"] = remaining if remaining <= 0 { sess.WriteLine("\nYou've finished fletching.") g.cancelBgAction(p) return } } if !g.canContinueProduction(p, recipe) { sess.WriteLine("\nYou've run out of fletching materials.") g.cancelBgAction(p) return } p.BackgroundAction.WaitLeft = engine.ToTicks(wait) }