diff options
Diffstat (limited to 'internal/game/cmd_trigger_utility.go')
| -rw-r--r-- | internal/game/cmd_trigger_utility.go | 69 |
1 files changed, 60 insertions, 9 deletions
diff --git a/internal/game/cmd_trigger_utility.go b/internal/game/cmd_trigger_utility.go index 09eabb1..b5a168b 100644 --- a/internal/game/cmd_trigger_utility.go +++ b/internal/game/cmd_trigger_utility.go @@ -136,19 +136,52 @@ func (g *Game) triggerEmGrab(sess *net.Session, p *player.Player, mod *ModDef, t } qty := groundItems[matchedID] - g.World.RemoveGroundItem(p.RoomID, matchedID, qty) - def, _ := g.ItemStore.Load(matchedID) name := matchedID if def != nil { name = def.Name } - freeSlot := p.FirstFreeSlot() - p.SetInvSlot(freeSlot, &player.InventorySlot{ItemID: matchedID, Quantity: qty}) + // Credits are currency, not an inventory item: collect them the same way + // the get command does. + if matchedID == "credits" { + g.World.RemoveGroundItem(p.RoomID, matchedID, qty) + g.grantCredits(p, qty) + g.triggerModReward(sess, p, mod, 1.0) + sess.WriteLine(fmt.Sprintf("You magnetically pull %d credits toward you.", qty)) + return + } - g.triggerModReward(sess, p, mod, 1.0) + if def != nil && def.Stackable { + g.World.RemoveGroundItem(p.RoomID, matchedID, qty) + if !placeCraftOutput(p, matchedID, def, qty) { + g.World.AddGroundItem(p.RoomID, matchedID, qty) + sess.WriteLine("Your inventory is full.") + return + } + } else { + // Non-stackable items take one slot each; leave any remainder on the + // ground instead of cramming N items into a single slot. + taken := 0 + for taken < qty { + freeSlot := p.FirstFreeSlot() + if freeSlot < 0 { + break + } + p.SetInvSlot(freeSlot, &player.InventorySlot{ItemID: matchedID, Quantity: 1}) + taken++ + } + if taken == 0 { + sess.WriteLine("Your inventory is full.") + return + } + g.World.RemoveGroundItem(p.RoomID, matchedID, taken) + if taken < qty { + sess.WriteLine(fmt.Sprintf("Your inventory fills up; %d %s remain on the ground.", qty-taken, name)) + } + } + g.triggerModReward(sess, p, mod, 1.0) sess.WriteLine(fmt.Sprintf("You magnetically pull the %s toward you.", g.itemColorize(sess, def, name))) } @@ -214,6 +247,13 @@ func (g *Game) triggerSuperheat(sess *net.Session, p *player.Player, mod *ModDef g.cancelAction(p) } + // Verify the output can be placed BEFORE consuming: a full inventory + // must never destroy ingredients without producing the bar. + if !craftOutputFits(p, match.ID, match) { + sess.WriteLine("Your inventory is too full!") + return + } + consumeIngredients(c, p.CountItem, p.RemoveItem) outputQty := c.OutputQty @@ -288,19 +328,30 @@ func (g *Game) triggerPlankMake(sess *net.Session, p *player.Player, mod *ModDef return } + plankDef, _ := g.ItemStore.Load(info.plankID) + // Check placement BEFORE consuming the log and credits: a full + // inventory must never delete materials without producing planks. + if !craftOutputFits(p, info.plankID, plankDef) { + sess.WriteLine("Your inventory is full.") + return + } + if p.Action != nil { g.cancelAction(p) } - p.RemoveItem(inv.ItemID, 1) + logID := inv.ItemID + p.RemoveItem(logID, 1) p.Credits -= info.cost - freeSlot := p.FirstFreeSlot() - if freeSlot == -1 { + if !placeCraftOutput(p, info.plankID, plankDef, 1) { + // Defensive: craftOutputFits guaranteed placement. Refund the + // log (to the ground, so it can never be lost) and the credits. + p.Credits += info.cost + g.World.AddGroundItem(p.RoomID, logID, 1) sess.WriteLine("Your inventory is full.") return } - p.SetInvSlot(freeSlot, &player.InventorySlot{ItemID: info.plankID, Quantity: 1}) g.triggerModReward(sess, p, mod, 1.0, xpGain{Skill: string(player.Construction), XP: 10}) |
