diff options
| author | historia <[not public]> | 2026-06-18 18:50:54 -0400 |
|---|---|---|
| committer | historia <[not public]> | 2026-06-18 18:50:54 -0400 |
| commit | 17e7725f252c7f5d3be2e9c37d62751c631f196f (patch) | |
| tree | 40698c5c95cb21302adbb8cd021bd8d049b6fce1 /internal/game/action_fletch.go | |
| parent | fae979b75e37b6ad57e57062a1b637a37ec87174 (diff) | |
| download | thehouseoficarus-17e7725f252c7f5d3be2e9c37d62751c631f196f.tar.gz | |
feat: fletching added including zero-time bolt feathering, which probably will break lots of things
Diffstat (limited to 'internal/game/action_fletch.go')
| -rw-r--r-- | internal/game/action_fletch.go | 215 |
1 files changed, 215 insertions, 0 deletions
diff --git a/internal/game/action_fletch.go b/internal/game/action_fletch.go new file mode 100644 index 0000000..734453b --- /dev/null +++ b/internal/game/action_fletch.go @@ -0,0 +1,215 @@ +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) { + if p.Flags == nil { + p.Flags = make(map[string]any) + } + 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 + 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 { + if newLevel := p.AddSkillXP(player.Fletching, recipe.XP); newLevel > 0 { + sess.WriteLine(g.colorize(sess, "level_up", fmt.Sprintf("*** You are now level %d fletching! ***", newLevel))) + } + } + + 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[player.Fletching] + 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} + + 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.loadProductionRecipe(recipeID) + if recipe == nil { + g.CancelBackgroundAction(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.CancelBackgroundAction(p) + return + } + + outDef, _ := g.ItemStore.Load(recipe.Output) + outputQty := recipe.OutputQty + if outputQty <= 0 { + outputQty = 1 + } + + 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.CancelBackgroundAction(p) + return + } + p.SetInvSlot(freeSlot, &player.InventorySlot{ItemID: recipe.Output, Quantity: outputQty}) + } + + if recipe.XP > 0 { + if newLevel := p.AddSkillXP(player.Fletching, recipe.XP); newLevel > 0 { + sess.WriteLine(g.colorize(sess, "level_up", fmt.Sprintf("*** You are now level %d fletching! ***", newLevel))) + } + } + 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[player.Fletching] + 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.CancelBackgroundAction(p) + return + } + } + + if !g.canContinueProduction(p, recipe) { + sess.WriteLine("\nYou've run out of fletching materials.") + g.CancelBackgroundAction(p) + return + } + + p.BackgroundAction.WaitLeft = engine.ToTicks(wait) +} |
