package game import ( "fmt" "thehouseoficarus/internal/action" "thehouseoficarus/internal/engine" "thehouseoficarus/internal/net" "thehouseoficarus/internal/object" "thehouseoficarus/internal/player" ) func (g *Game) startFletchAction(sess *net.Session, p *player.Player, item *object.ItemDef, count int) { p.EnsureFlags() p.Flags["last_fletch"] = item.ID g.AccountStore.SaveCharacter(p) if item.FirstCraft().Wait <= 0 { g.doInstantFletch(sess, p, item, count) return } g.startTimedFletch(sess, p, item, count) } func (g *Game) doInstantFletch(sess *net.Session, p *player.Player, item *object.ItemDef, count int) { c := item.FirstCraft() outputQty := c.OutputQty if outputQty <= 0 { outputQty = 1 } batches := 0 totalOutput := 0 skill := player.SkillName(c.EffectiveSkill()) tmpItem := &object.ItemDef{Craft: object.CraftList{*c}} for { if !g.canDoFletchItem(p, tmpItem) { break } placed := false if item.Stackable { for i := 0; i < 28; i++ { slot := p.InvSlot(i) if slot != nil && slot.ItemID == item.ID { craftConsumeAll(c, p.HasItem, p.RemoveItem) slot.Quantity += outputQty placed = true break } } } if !placed { craftConsumeAll(c, p.HasItem, p.RemoveItem) freeSlot := p.FirstFreeSlot() if freeSlot == -1 { break } p.SetInvSlot(freeSlot, &player.InventorySlot{ItemID: item.ID, Quantity: outputQty}) } if c.XP > 0 { g.awardSkillXP(sess, p, skill, c.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) outDef, _ := g.ItemStore.Load(item.ID) outputName := item.Name if outDef != nil { outputName = g.itemColorize(sess, outDef, outDef.Name) } msg := fmt.Sprintf("You fletch %d %s.", totalOutput, outputName) if p.OptionBool("xp_drops") && c.XP > 0 { totalXP := c.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, item *object.ItemDef, count int) { craft := item.FirstCraft() startMsg := g.resolveCraftMessage(sess, craft.StartMessage, "You begin fletching %i1.", craft, item.ID, nil, p.HasItem) sess.WriteLine(startMsg) broadcastName := item.Name if def, _ := g.ItemStore.Load(item.ID); def != nil { broadcastName = def.Name } g.broadcastAction(sess, "%s starts fletching.", p.Name) _ = broadcastName p.BackgroundAction = &action.Action{ Type: "fletch", TargetID: item.ID, TargetName: item.Name, Data: map[string]any{ "item_id": item.ID, "phase": 0, "wait": craft.Wait, "remaining": count, }, WaitLeft: engine.ToTicks(1), } p.BackgroundActionState = &ActionState{Type: ActionFletching, TargetName: item.Name} } func (g *Game) advanceFletch(sess *net.Session, p *player.Player) { itemID, _ := p.BackgroundAction.Data["item_id"].(string) phase, _ := p.BackgroundAction.Data["phase"].(int) wait, _ := p.BackgroundAction.Data["wait"].(float64) remaining, _ := p.BackgroundAction.Data["remaining"].(int) item := g.loadCraftItem(itemID) if item == nil { g.cancelBgAction(p) return } c := item.FirstCraft() if phase == 0 { p.BackgroundAction.Data["phase"] = 1 p.BackgroundAction.WaitLeft = engine.ToTicks(wait) return } tmpItem := &object.ItemDef{Craft: object.CraftList{*c}} if !g.canDoFletchItem(p, tmpItem) { sess.WriteLine("You've run out of fletching materials.") g.cancelBgAction(p) return } outputQty := c.OutputQty if outputQty <= 0 { outputQty = 1 } skill := player.SkillName(c.EffectiveSkill()) placed := false if item.Stackable { for i := 0; i < 28; i++ { slot := p.InvSlot(i) if slot != nil && slot.ItemID == item.ID { craftConsumeAll(c, p.HasItem, p.RemoveItem) slot.Quantity += outputQty placed = true break } } } if !placed { craftConsumeAll(c, p.HasItem, p.RemoveItem) freeSlot := p.FirstFreeSlot() if freeSlot == -1 { sess.WriteLine("Your inventory is too full!") g.cancelBgAction(p) return } p.SetInvSlot(freeSlot, &player.InventorySlot{ItemID: item.ID, Quantity: outputQty}) } if c.XP > 0 { g.awardSkillXP(sess, p, skill, c.XP) } g.AccountStore.SaveCharacter(p) msg := g.resolveCraftMessage(sess, c.Message, "You fletch a %n.", c, item.ID, nil, p.HasItem) if p.OptionBool("xp_drops") && c.XP > 0 { abbr := player.SkillAbbr[skill] msg += g.colorize(sess, "xp", fmt.Sprintf(" (+%dxp %s)", c.XP, abbr)) } sess.WriteLine(msg) if remaining > 0 { remaining-- p.BackgroundAction.Data["remaining"] = remaining if remaining <= 0 { sess.WriteLine("You've finished fletching.") g.cancelBgAction(p) return } } if !g.canContinueProduction(p, item) { sess.WriteLine("You've run out of fletching materials.") g.cancelBgAction(p) return } p.BackgroundAction.WaitLeft = engine.ToTicks(wait) }