package game import ( "thehouseoficarus/internal/behavior" "thehouseoficarus/internal/engine" "thehouseoficarus/internal/item" "thehouseoficarus/internal/net" "thehouseoficarus/internal/player" ) func (g *Game) startCombine(sess *net.Session, p *player.Player, item *item.ItemDef, craft *item.CraftDef, count int) { g.cancelAction(p) g.cancelBgAction(p) if !craftHasAllItemsQty(craft, p.CountItem) { sess.WriteLine("You don't have the required materials.") g.reprompt(sess) return } outDef, _ := g.ItemStore.Load(item.ID) outputName := item.ID if outDef != nil { outputName = outDef.Name } startMsg := g.resolveCraftMessage(sess, craft.StartMessage, "You start combining %i1.", craft, item.ID, nil, p.HasItem) endMsg := g.resolveCraftMessage(sess, craft.EndMessage, "You've finished combining.", craft, item.ID, nil, p.HasItem) p.Action = &behavior.Action{ Type: behavior.TypeCombine, TargetID: item.ID, TargetName: outputName, Data: &behavior.CombineData{ ItemID: item.ID, Phase: 0, StepIndex: 0, Remaining: count, StartMessage: startMsg, EndMessage: endMsg, TicksPerCycle: craft.TicksPerCycle, }, WaitLeft: engine.ToTicks(1), } g.broadcastAction(sess, "%s starts combining.", p.Name) } func (g *Game) advanceCombine(sess *net.Session, p *player.Player) { d, ok := p.Action.Data.(*behavior.CombineData) if !ok { g.cancelAction(p) return } item := g.loadCraftItem(d.ItemID) if item == nil { g.cancelAction(p) return } craft := item.FirstCraft() switch d.Phase { case 0: if d.StartMessage != "" { sess.WriteLine(d.StartMessage) } d.Phase = 1 if len(craft.Steps) > 0 { p.Action.WaitLeft = engine.ToTicks(craft.Steps[0].Delay) } else { firstWait := craft.TicksPerCycle if firstWait <= 0 { firstWait = 4 } p.Action.WaitLeft = engine.ToTicks(firstWait) } return case 1: if len(craft.Steps) > 0 && d.StepIndex < len(craft.Steps) { step := craft.Steps[d.StepIndex] sess.WriteLine(g.resolveCraftVar(sess, step.Message, craft, item.ID, nil, p.HasItem)) d.StepIndex++ if d.StepIndex < len(craft.Steps) { p.Action.WaitLeft = engine.ToTicks(craft.Steps[d.StepIndex].Delay) return } } d.Phase = 2 p.Action.WaitLeft = engine.ToTicks(1) return case 2: if !craftHasAllItemsQty(craft, p.CountItem) { if d.EndMessage != "" { sess.WriteLine(d.EndMessage) } g.cancelAction(p) return } consumeIngredients(craft, p.HasItem, p.RemoveItem) outputQty := craft.OutputQty if outputQty <= 0 { outputQty = 1 } outDef, _ := g.ItemStore.Load(item.ID) placed := false if outDef != nil && outDef.Stackable { for i := 0; i < 28; i++ { slot := p.InvSlot(i) if slot != nil && slot.ItemID == item.ID { slot.Quantity += outputQty placed = true break } } } if !placed { freeSlot := p.FirstFreeSlot() if freeSlot == -1 { sess.WriteLine("Your inventory is too full!") g.cancelAction(p) return } p.SetInvSlot(freeSlot, &player.InventorySlot{ItemID: item.ID, Quantity: outputQty}) } g.AccountStore.SaveCharacter(p) if d.Remaining > 0 { d.Remaining-- if d.Remaining <= 0 { if d.EndMessage != "" { sess.WriteLine(d.EndMessage) } g.cancelAction(p) return } } if !craftHasAllItemsQty(craft, p.CountItem) { if d.EndMessage != "" { sess.WriteLine(d.EndMessage) } g.cancelAction(p) return } d.Phase = 0 d.StepIndex = 0 p.Action.WaitLeft = engine.ToTicks(1) } }