aboutsummaryrefslogtreecommitdiff
path: root/internal/game/act_farm.go
diff options
context:
space:
mode:
Diffstat (limited to 'internal/game/act_farm.go')
-rw-r--r--internal/game/act_farm.go77
1 files changed, 51 insertions, 26 deletions
diff --git a/internal/game/act_farm.go b/internal/game/act_farm.go
index 1e576c3..48fbec7 100644
--- a/internal/game/act_farm.go
+++ b/internal/game/act_farm.go
@@ -242,43 +242,68 @@ func (g *Game) advanceHarvest(sess *net.Session, p *player.Player) {
bonus := p.Level(player.Farming) / 20
yield += bonus
- freeSlots := p.FreeSlots()
- if yield > freeSlots {
- productDef, _ := g.ItemStore.Load(product)
- if productDef == nil || !productDef.Stackable {
+ productDef, _ := g.ItemStore.Load(product)
+ stackable := productDef != nil && productDef.Stackable
+
+ // The delivery target is chosen before the crop is consumed: a harvest
+ // that cannot be stored must leave the patch ready instead of being
+ // silently destroyed. A stackable product merges into an existing stack
+ // and therefore needs no free slot.
+ mergeSlot := -1
+ freeSlot := -1
+ noRoom := false
+ if stackable {
+ quality, maxQuality := stackProps(productDef)
+ for i := 0; i < 28; i++ {
+ s := p.InvSlot(i)
+ // Only a stack with the properties a fresh harvest stack gets
+ // may absorb it; merging into a differently qualified stack
+ // would silently destroy one of the two qualities.
+ if s != nil && s.ItemID == product && s.Quality == quality && s.MaxQuality == maxQuality {
+ mergeSlot = i
+ break
+ }
+ }
+ if mergeSlot < 0 {
+ freeSlot = p.FirstFreeSlot()
+ }
+ noRoom = mergeSlot < 0 && freeSlot < 0
+ } else {
+ // One slot per unit: the clamp and the placement loop must count
+ // slots the same way (a nil 0..27 slot).
+ freeSlots := 0
+ for i := 0; i < 28; i++ {
+ if p.InvSlot(i) == nil {
+ freeSlots++
+ }
+ }
+ if yield > freeSlots {
yield = freeSlots
}
+ noRoom = yield <= 0
}
- if yield <= 0 {
+ if noRoom {
sess.WriteLine("Your inventory is too full!")
p.Action = nil
return
}
- productDef, _ := g.ItemStore.Load(product)
- if productDef != nil && productDef.Stackable {
- added := 0
- for i := 0; i < 28 && added < yield; i++ {
- slot := p.InvSlot(i)
- if slot != nil && slot.ItemID == product {
- slot.Quantity += yield
- added = yield
- break
- }
- }
- if added == 0 {
- freeSlot := p.FirstFreeSlot()
- if freeSlot >= 0 {
- p.SetInvSlot(freeSlot, &player.InventorySlot{ItemID: product, Quantity: yield})
- }
+ placed := yield
+ if stackable {
+ if mergeSlot >= 0 {
+ p.InvSlot(mergeSlot).Quantity += yield
+ } else {
+ p.SetInvSlot(freeSlot, g.newInventorySlot(product, yield))
}
} else {
- for i := 0; i < yield; i++ {
- freeSlot := p.FirstFreeSlot()
- if freeSlot < 0 {
+ placed = 0
+ for placed < yield {
+ fs := p.FirstFreeSlot()
+ if fs < 0 {
break
}
- p.SetInvSlot(freeSlot, &player.InventorySlot{ItemID: product, Quantity: 1})
+ p.SetInvSlot(fs, g.newInventorySlot(product, 1))
+ placed++
}
}
@@ -302,7 +327,7 @@ func (g *Game) advanceHarvest(sess *net.Session, p *player.Player) {
productName = g.itemColorize(sess, productDef, productDef.Name)
}
patchName := patchDisplayName(prefix)
- msg := fmt.Sprintf("You harvest %d %s from the %s.", yield, productName, patchName)
+ msg := fmt.Sprintf("You harvest %d %s from the %s.", placed, productName, patchName)
if int(xp) > 0 && p.OptionBool("xp_drops") {
msg += g.formatXpDropSingle(sess, p, player.Farming, int(xp))
}