aboutsummaryrefslogtreecommitdiff
path: root/internal/game/cmd_trigger_utility.go
diff options
context:
space:
mode:
Diffstat (limited to 'internal/game/cmd_trigger_utility.go')
-rw-r--r--internal/game/cmd_trigger_utility.go69
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})