Workshop stockpile
workshop-stockpile · an adoption of Container, version 2
Use in your package
The first button opens the authoring tool with these answers and numbers already filled in. You still add the rules and tuning of your own game.
What is in the zip file
The zip file holds the adoption and its acceptance tests. In the authoring tool, choose Add contract and pick this zip file. If you edit your package outside the authoring tool, unpack the zip file in your package folder. The files of the zip file go into contracts/.
The contract that this adoption uses
This contract covers a container, such as a bag or a chest, that holds distinct items. A delivery is a group of items that arrives at the container. This contract says when the container is full and what happens when some items of a delivery do not fit. It also says which items the container accepts and which slot fills or empties first. It covers slots and size budgets. This version does not cover containers where an item occupies a width-and-height footprint, such as a grid inventory. This contract does not cover counted amounts such as gold. The Ranged value contract covers counted amounts.
Questions
The supplied answer is marked on each question. Pick other answers to see what changes. Nothing is saved here: the zip file and the authoring tool use the supplied answers.
What makes this container full?
Why this is asked
Capacity changes what the container can hold and how it fills. This contract supports one size measure. Containers where items occupy a width-and-height footprint are outside this version.
A delivery reaches the container, but not all the items fit. What goes in?
- Asked when
- Capacity limit is Slot count or Size budget or Slots and size.
Why this is asked
Two containers with the same free space can act differently. One accepts what fits; the other refuses the whole delivery.
What happens to the items that do not fit?
- Asked when
- Partial acceptance is Fill what fits.
Why this is asked
Items that do not fit must go to a stated place. Otherwise one build may return them while another build drops or destroys them.
Several slots could hold a new item. Which slot gets it?
- Asked when
- Capacity limit is Slot count or Slots and size or No limit.
Why this is asked
Two teams that build the same design can fill the same container differently. That changes what players see and what the game removes later. Rules that score slots, rotate between containers, or use a custom sequence stay in your game's prose.
The game needs an item for one of its own rules. Which matching slot does it take from?
Why this is asked
Automatic use needs a stable choice because it can change which stack remains for the player. A rotating choice over counted amounts belongs in the Ranged value contract.
Which item types can this container hold?
Why this is asked
A clear item rule prevents unnoticed differences between what the game accepts and what the designer intended. Rules that come from another list or from program code stay in your game's prose.
Numbers2 numbers
Each value is either a number set here or a reference to a decided number in your tuning. It cannot reference an open number.
Slot count = 24
fixed as writtenslot-count
How many slots the container has. Use at least one when slots set capacity. Use zero when this container has no slot limit. If your game stores this number elsewhere, move it here so two copies cannot disagree.
Size budget = 0
fixed as writtensize-budget
The largest total size the container holds. Your game chooses the unit, such as kilograms or bulk. Every item uses the same unit. Use zero when size does not limit the container.
Rules2 rules
A rule is a check between the numbers. Validation reports a rule that fails.
slot-count >= 0size-budget >= 0
Lists1 list
Each list holds the rows this adoption supplies. A list can be empty.
Items
items
| Id | Slot rules declared in | Stack limit | Size | When forced out | Forced out order |
|---|---|---|---|---|---|
firewood | — | 40 | — | never | — |
clay | — | 40 | — | never | — |
ore-rock | — | 40 | — | never | — |
charcoal | — | 40 | — | never | — |
kiln-brick | — | 20 | — | never | — |
kiln-lining | — | 4 | — | never | — |
copper-ingot | — | 10 | — | never | — |
glaze-slip | — | 10 | — | never | — |
wardstone | — | 1 | — | never | — |
Test inputsscope and seeds
Some tests need a scope or seeds from the adoption before they can run.
capacity-holds
Capacity holds
- Scope
- sequences of gathering yields, craft input removals, and craft output deliveries over one run of the workshop
- Seeds
["workshop-stockpile-audit-a","workshop-stockpile-audit-b"]
fill-order-holds
Fill order holds
- Scope
- 02-mechanics.md#the-workshop
draw-order-by-position
Draw order by position
- Scope
- 02-mechanics.md#the-workshop
Acceptance tests24 tests apply
The contract comes with 14 tests. A test that runs once per row is counted once for each row. Tests that do not apply to these answers are still listed, with the reason.
delivery-that-fits
a delivery that fits is accepted whole
Applies to workshop-stockpile.
A delivery that workshop-stockpile has room for is accepted whole. The container gains exactly what was offered and keeps everything it already held. Nothing is left over.
Test steps and diagnostics
- Given
the
workshop-stockpilecontainer with room for the whole of the delivery below- When
- a delivery offers n items of a type
workshop-stockpileaccepts
- a delivery offers n items of a type
- Then
workshop-stockpileholds exactly n more items of that type than it did- nothing already in
workshop-stockpileis removed, destroyed, or changed into another type - nothing is handed back, dropped, or destroyed
- Diagnostics
workshop-stockpile-contents-before-after
refuses-whole
a delivery that does not fit is refused whole
Applies to workshop-stockpile.
A delivery larger than the room available does not change workshop-stockpile. No item of the delivery goes in, not even the items that would fit. The delivery reports that it did not happen. Whether the action that offered the items still occurs is decided in this game's own prose, not in this contract.
Test steps and diagnostics
- Given
the
workshop-stockpilecontainer with room for fewer than n items of a type it accepts- When
- a delivery offers n items of that type
- Then
workshop-stockpileholds exactly what it held before- none of the n items goes in, not even the items that would fit
- the delivery reports that it did not happen
- Diagnostics
workshop-stockpile-contents-before-afterworkshop-stockpile-delivery-report
takes-what-fits
a delivery that does not fit is split
Does not apply to workshop-stockpile: partial acceptance is all or nothing, not fill what fits.
slots-are-the-limit
the container is full when its slots are full
Applies to workshop-stockpile.
This container is full when every slot stated by the value at slot-count = 24 is in use and none of them can take more of what is being offered. This test cites that value and restates the number nowhere.
Test steps and diagnostics
- Given
the
workshop-stockpilecontainer with allslot-count = 24slots in use and no slot in use able to take more of the type below- When
- a delivery offers one item of that type
- Then
workshop-stockpiletakes none of it- the number of slots in use is still the number stated by
slot-count = 24
- Diagnostics
workshop-stockpile-slot-occupancyworkshop-stockpile-delivery-report
size-is-the-limit
the container is full when its size budget is spent
Does not apply to workshop-stockpile: capacity limit is slot count, not size budget or slots and size.
never-refuses
no delivery is refused for lack of room
Does not apply to workshop-stockpile: capacity limit is slot count, not no limit.
fill-order-holds
an accepted item is placed in the declared slot
Applies to workshop-stockpile.
An item that workshop-stockpile accepts is placed in a slot that already holds that type while any such slot can take more, and only then in the first empty slot. The rule is repeatable: the same delivery from the same starting contents is placed in the same slot every time. Slot numbering is the numbering identified by this adoption's verification scope.
Test steps and diagnostics
- Given
the
workshop-stockpilecontainer holding some of a type in one slot, with at least one other slot free and at least one slot freed by an earlier removal, its slots numbered as02-mechanics.md#the-workshopstates- When
- a delivery offers one more item of that type
- Then
- the item is placed in a slot that already holds that type while any such slot can take more, and only then in the first empty slot
- the same delivery made again from the same starting contents is placed in the same slot
- Diagnostics
workshop-stockpile-slot-occupancyworkshop-stockpile-fill-trace
draw-order-by-position
the game takes from the declared slot
Applies to workshop-stockpile.
A take that the game makes from workshop-stockpile on its own comes from the first slot in the container's own order that holds the type, moving on only when that slot is empty. The same take from the same starting contents comes from the same slot every time. The slots are numbered as 02-mechanics.md#the-workshop states.
Test steps and diagnostics
- Given
the
workshop-stockpilecontainer holding the same type in at least two slots, its slots numbered as02-mechanics.md#the-workshopstates- When
- the game takes fewer of that type than
workshop-stockpileholds, on its own rather than at a player's direction
- the game takes fewer of that type than
- Then
- the items come from the first slot in the container's own order that holds the type, moving on only when that slot is empty
- the same take made again from the same starting contents comes from the same slot
- no slot other than the one the rule names changes while that slot can still supply the take
- Diagnostics
workshop-stockpile-slot-occupancyworkshop-stockpile-take-trace
draw-order-by-arrival
the time at which each stack received items decides which stack the game takes from
Does not apply to workshop-stockpile: draw order is first in order, not newest first or oldest first.
stack-limit-holds · firewood
firewood stacks no higher than its limit
Applies to the firewood row.
A stack of firewood in workshop-stockpile never holds more than 40. This number is the stack limit on the row for firewood in this adoption.
Test steps and diagnostics
- Given
the
workshop-stockpilecontainer with one slot holding40offirewood- When
- a delivery offers one more
firewood
- a delivery offers one more
- Then
- that slot still holds exactly
40offirewood - the extra one starts a new stack in a free slot; where this container's slots can run out and none is free, it counts as not fitting, and the partial-acceptance answer applies
- that slot still holds exactly
- Diagnostics
workshop-stockpile-slot-occupancyworkshop-stockpile-delivery-report
stack-limit-holds · clay
clay stacks no higher than its limit
Applies to the clay row.
A stack of clay in workshop-stockpile never holds more than 40. This number is the stack limit on the row for clay in this adoption.
Test steps and diagnostics
- Given
the
workshop-stockpilecontainer with one slot holding40ofclay- When
- a delivery offers one more
clay
- a delivery offers one more
- Then
- that slot still holds exactly
40ofclay - the extra one starts a new stack in a free slot; where this container's slots can run out and none is free, it counts as not fitting, and the partial-acceptance answer applies
- that slot still holds exactly
- Diagnostics
workshop-stockpile-slot-occupancyworkshop-stockpile-delivery-report
stack-limit-holds · ore-rock
ore-rock stacks no higher than its limit
Applies to the ore-rock row.
A stack of ore-rock in workshop-stockpile never holds more than 40. This number is the stack limit on the row for ore-rock in this adoption.
Test steps and diagnostics
- Given
the
workshop-stockpilecontainer with one slot holding40ofore-rock- When
- a delivery offers one more
ore-rock
- a delivery offers one more
- Then
- that slot still holds exactly
40ofore-rock - the extra one starts a new stack in a free slot; where this container's slots can run out and none is free, it counts as not fitting, and the partial-acceptance answer applies
- that slot still holds exactly
- Diagnostics
workshop-stockpile-slot-occupancyworkshop-stockpile-delivery-report
stack-limit-holds · charcoal
charcoal stacks no higher than its limit
Applies to the charcoal row.
A stack of charcoal in workshop-stockpile never holds more than 40. This number is the stack limit on the row for charcoal in this adoption.
Test steps and diagnostics
- Given
the
workshop-stockpilecontainer with one slot holding40ofcharcoal- When
- a delivery offers one more
charcoal
- a delivery offers one more
- Then
- that slot still holds exactly
40ofcharcoal - the extra one starts a new stack in a free slot; where this container's slots can run out and none is free, it counts as not fitting, and the partial-acceptance answer applies
- that slot still holds exactly
- Diagnostics
workshop-stockpile-slot-occupancyworkshop-stockpile-delivery-report
stack-limit-holds · kiln-brick
kiln-brick stacks no higher than its limit
Applies to the kiln-brick row.
A stack of kiln-brick in workshop-stockpile never holds more than 20. This number is the stack limit on the row for kiln-brick in this adoption.
Test steps and diagnostics
- Given
the
workshop-stockpilecontainer with one slot holding20ofkiln-brick- When
- a delivery offers one more
kiln-brick
- a delivery offers one more
- Then
- that slot still holds exactly
20ofkiln-brick - the extra one starts a new stack in a free slot; where this container's slots can run out and none is free, it counts as not fitting, and the partial-acceptance answer applies
- that slot still holds exactly
- Diagnostics
workshop-stockpile-slot-occupancyworkshop-stockpile-delivery-report
stack-limit-holds · kiln-lining
kiln-lining stacks no higher than its limit
Applies to the kiln-lining row.
A stack of kiln-lining in workshop-stockpile never holds more than 4. This number is the stack limit on the row for kiln-lining in this adoption.
Test steps and diagnostics
- Given
the
workshop-stockpilecontainer with one slot holding4ofkiln-lining- When
- a delivery offers one more
kiln-lining
- a delivery offers one more
- Then
- that slot still holds exactly
4ofkiln-lining - the extra one starts a new stack in a free slot; where this container's slots can run out and none is free, it counts as not fitting, and the partial-acceptance answer applies
- that slot still holds exactly
- Diagnostics
workshop-stockpile-slot-occupancyworkshop-stockpile-delivery-report
stack-limit-holds · copper-ingot
copper-ingot stacks no higher than its limit
Applies to the copper-ingot row.
A stack of copper-ingot in workshop-stockpile never holds more than 10. This number is the stack limit on the row for copper-ingot in this adoption.
Test steps and diagnostics
- Given
the
workshop-stockpilecontainer with one slot holding10ofcopper-ingot- When
- a delivery offers one more
copper-ingot
- a delivery offers one more
- Then
- that slot still holds exactly
10ofcopper-ingot - the extra one starts a new stack in a free slot; where this container's slots can run out and none is free, it counts as not fitting, and the partial-acceptance answer applies
- that slot still holds exactly
- Diagnostics
workshop-stockpile-slot-occupancyworkshop-stockpile-delivery-report
stack-limit-holds · glaze-slip
glaze-slip stacks no higher than its limit
Applies to the glaze-slip row.
A stack of glaze-slip in workshop-stockpile never holds more than 10. This number is the stack limit on the row for glaze-slip in this adoption.
Test steps and diagnostics
- Given
the
workshop-stockpilecontainer with one slot holding10ofglaze-slip- When
- a delivery offers one more
glaze-slip
- a delivery offers one more
- Then
- that slot still holds exactly
10ofglaze-slip - the extra one starts a new stack in a free slot; where this container's slots can run out and none is free, it counts as not fitting, and the partial-acceptance answer applies
- that slot still holds exactly
- Diagnostics
workshop-stockpile-slot-occupancyworkshop-stockpile-delivery-report
stack-limit-holds · wardstone
wardstone stacks no higher than its limit
Applies to the wardstone row.
A stack of wardstone in workshop-stockpile never holds more than 1. This number is the stack limit on the row for wardstone in this adoption.
Test steps and diagnostics
- Given
the
workshop-stockpilecontainer with one slot holding1ofwardstone- When
- a delivery offers one more
wardstone
- a delivery offers one more
- Then
- that slot still holds exactly
1ofwardstone - the extra one starts a new stack in a free slot; where this container's slots can run out and none is free, it counts as not fitting, and the partial-acceptance answer applies
- that slot still holds exactly
- Diagnostics
workshop-stockpile-slot-occupancyworkshop-stockpile-delivery-report
unlisted-type-refused
a type the list does not name is refused
Does not apply to workshop-stockpile: type restriction is any item, not only these.
forced-out-holds
Row.id leaves workshop-stockpile in the declared way
Does not apply to workshop-stockpile: no row in items matches when-forced-out dropped nearby or moved to another store or destroyed.
never-forced-out · firewood
firewood is never given up by workshop-stockpile itself
Applies to the firewood row.
Nothing that this container does on its own removes firewood from it. When workshop-stockpile must give items up, it skips this type. When giving up every type that can leave is still not enough, workshop-stockpile refuses the change. When a player drops, sells, or destroys firewood, this game's own rules apply. This test does not cover that case.
Where this game has no way to shrink workshop-stockpile or change its rules while it runs, this test has no reachable case: a builder records it as unreachable rather than inventing a trigger for it.
Test steps and diagnostics
- Given
the
workshop-stockpilecontainer holdingfirewoodat a moment when a change would make it hold more than it can: its slots shrank, or its rules changed- When
- that change is attempted
- Then
- no
firewoodleavesworkshop-stockpile: the type is skipped while types that can leave are given up in their declared order - if giving up every type that can leave is still not enough,
workshop-stockpilerefuses the change - no
firewoodis dropped, moved to another store, or destroyed byworkshop-stockpileitself
- no
- Diagnostics
workshop-stockpile-forced-removal-logworkshop-stockpile-contents-before-after
never-forced-out · clay
clay is never given up by workshop-stockpile itself
Applies to the clay row.
Nothing that this container does on its own removes clay from it. When workshop-stockpile must give items up, it skips this type. When giving up every type that can leave is still not enough, workshop-stockpile refuses the change. When a player drops, sells, or destroys clay, this game's own rules apply. This test does not cover that case.
Where this game has no way to shrink workshop-stockpile or change its rules while it runs, this test has no reachable case: a builder records it as unreachable rather than inventing a trigger for it.
Test steps and diagnostics
- Given
the
workshop-stockpilecontainer holdingclayat a moment when a change would make it hold more than it can: its slots shrank, or its rules changed- When
- that change is attempted
- Then
- no
clayleavesworkshop-stockpile: the type is skipped while types that can leave are given up in their declared order - if giving up every type that can leave is still not enough,
workshop-stockpilerefuses the change - no
clayis dropped, moved to another store, or destroyed byworkshop-stockpileitself
- no
- Diagnostics
workshop-stockpile-forced-removal-logworkshop-stockpile-contents-before-after
never-forced-out · ore-rock
ore-rock is never given up by workshop-stockpile itself
Applies to the ore-rock row.
Nothing that this container does on its own removes ore-rock from it. When workshop-stockpile must give items up, it skips this type. When giving up every type that can leave is still not enough, workshop-stockpile refuses the change. When a player drops, sells, or destroys ore-rock, this game's own rules apply. This test does not cover that case.
Where this game has no way to shrink workshop-stockpile or change its rules while it runs, this test has no reachable case: a builder records it as unreachable rather than inventing a trigger for it.
Test steps and diagnostics
- Given
the
workshop-stockpilecontainer holdingore-rockat a moment when a change would make it hold more than it can: its slots shrank, or its rules changed- When
- that change is attempted
- Then
- no
ore-rockleavesworkshop-stockpile: the type is skipped while types that can leave are given up in their declared order - if giving up every type that can leave is still not enough,
workshop-stockpilerefuses the change - no
ore-rockis dropped, moved to another store, or destroyed byworkshop-stockpileitself
- no
- Diagnostics
workshop-stockpile-forced-removal-logworkshop-stockpile-contents-before-after
never-forced-out · charcoal
charcoal is never given up by workshop-stockpile itself
Applies to the charcoal row.
Nothing that this container does on its own removes charcoal from it. When workshop-stockpile must give items up, it skips this type. When giving up every type that can leave is still not enough, workshop-stockpile refuses the change. When a player drops, sells, or destroys charcoal, this game's own rules apply. This test does not cover that case.
Where this game has no way to shrink workshop-stockpile or change its rules while it runs, this test has no reachable case: a builder records it as unreachable rather than inventing a trigger for it.
Test steps and diagnostics
- Given
the
workshop-stockpilecontainer holdingcharcoalat a moment when a change would make it hold more than it can: its slots shrank, or its rules changed- When
- that change is attempted
- Then
- no
charcoalleavesworkshop-stockpile: the type is skipped while types that can leave are given up in their declared order - if giving up every type that can leave is still not enough,
workshop-stockpilerefuses the change - no
charcoalis dropped, moved to another store, or destroyed byworkshop-stockpileitself
- no
- Diagnostics
workshop-stockpile-forced-removal-logworkshop-stockpile-contents-before-after
never-forced-out · kiln-brick
kiln-brick is never given up by workshop-stockpile itself
Applies to the kiln-brick row.
Nothing that this container does on its own removes kiln-brick from it. When workshop-stockpile must give items up, it skips this type. When giving up every type that can leave is still not enough, workshop-stockpile refuses the change. When a player drops, sells, or destroys kiln-brick, this game's own rules apply. This test does not cover that case.
Where this game has no way to shrink workshop-stockpile or change its rules while it runs, this test has no reachable case: a builder records it as unreachable rather than inventing a trigger for it.
Test steps and diagnostics
- Given
the
workshop-stockpilecontainer holdingkiln-brickat a moment when a change would make it hold more than it can: its slots shrank, or its rules changed- When
- that change is attempted
- Then
- no
kiln-brickleavesworkshop-stockpile: the type is skipped while types that can leave are given up in their declared order - if giving up every type that can leave is still not enough,
workshop-stockpilerefuses the change - no
kiln-brickis dropped, moved to another store, or destroyed byworkshop-stockpileitself
- no
- Diagnostics
workshop-stockpile-forced-removal-logworkshop-stockpile-contents-before-after
never-forced-out · kiln-lining
kiln-lining is never given up by workshop-stockpile itself
Applies to the kiln-lining row.
Nothing that this container does on its own removes kiln-lining from it. When workshop-stockpile must give items up, it skips this type. When giving up every type that can leave is still not enough, workshop-stockpile refuses the change. When a player drops, sells, or destroys kiln-lining, this game's own rules apply. This test does not cover that case.
Where this game has no way to shrink workshop-stockpile or change its rules while it runs, this test has no reachable case: a builder records it as unreachable rather than inventing a trigger for it.
Test steps and diagnostics
- Given
the
workshop-stockpilecontainer holdingkiln-liningat a moment when a change would make it hold more than it can: its slots shrank, or its rules changed- When
- that change is attempted
- Then
- no
kiln-liningleavesworkshop-stockpile: the type is skipped while types that can leave are given up in their declared order - if giving up every type that can leave is still not enough,
workshop-stockpilerefuses the change - no
kiln-liningis dropped, moved to another store, or destroyed byworkshop-stockpileitself
- no
- Diagnostics
workshop-stockpile-forced-removal-logworkshop-stockpile-contents-before-after
never-forced-out · copper-ingot
copper-ingot is never given up by workshop-stockpile itself
Applies to the copper-ingot row.
Nothing that this container does on its own removes copper-ingot from it. When workshop-stockpile must give items up, it skips this type. When giving up every type that can leave is still not enough, workshop-stockpile refuses the change. When a player drops, sells, or destroys copper-ingot, this game's own rules apply. This test does not cover that case.
Where this game has no way to shrink workshop-stockpile or change its rules while it runs, this test has no reachable case: a builder records it as unreachable rather than inventing a trigger for it.
Test steps and diagnostics
- Given
the
workshop-stockpilecontainer holdingcopper-ingotat a moment when a change would make it hold more than it can: its slots shrank, or its rules changed- When
- that change is attempted
- Then
- no
copper-ingotleavesworkshop-stockpile: the type is skipped while types that can leave are given up in their declared order - if giving up every type that can leave is still not enough,
workshop-stockpilerefuses the change - no
copper-ingotis dropped, moved to another store, or destroyed byworkshop-stockpileitself
- no
- Diagnostics
workshop-stockpile-forced-removal-logworkshop-stockpile-contents-before-after
never-forced-out · glaze-slip
glaze-slip is never given up by workshop-stockpile itself
Applies to the glaze-slip row.
Nothing that this container does on its own removes glaze-slip from it. When workshop-stockpile must give items up, it skips this type. When giving up every type that can leave is still not enough, workshop-stockpile refuses the change. When a player drops, sells, or destroys glaze-slip, this game's own rules apply. This test does not cover that case.
Where this game has no way to shrink workshop-stockpile or change its rules while it runs, this test has no reachable case: a builder records it as unreachable rather than inventing a trigger for it.
Test steps and diagnostics
- Given
the
workshop-stockpilecontainer holdingglaze-slipat a moment when a change would make it hold more than it can: its slots shrank, or its rules changed- When
- that change is attempted
- Then
- no
glaze-slipleavesworkshop-stockpile: the type is skipped while types that can leave are given up in their declared order - if giving up every type that can leave is still not enough,
workshop-stockpilerefuses the change - no
glaze-slipis dropped, moved to another store, or destroyed byworkshop-stockpileitself
- no
- Diagnostics
workshop-stockpile-forced-removal-logworkshop-stockpile-contents-before-after
never-forced-out · wardstone
wardstone is never given up by workshop-stockpile itself
Applies to the wardstone row.
Nothing that this container does on its own removes wardstone from it. When workshop-stockpile must give items up, it skips this type. When giving up every type that can leave is still not enough, workshop-stockpile refuses the change. When a player drops, sells, or destroys wardstone, this game's own rules apply. This test does not cover that case.
Where this game has no way to shrink workshop-stockpile or change its rules while it runs, this test has no reachable case: a builder records it as unreachable rather than inventing a trigger for it.
Test steps and diagnostics
- Given
the
workshop-stockpilecontainer holdingwardstoneat a moment when a change would make it hold more than it can: its slots shrank, or its rules changed- When
- that change is attempted
- Then
- no
wardstoneleavesworkshop-stockpile: the type is skipped while types that can leave are given up in their declared order - if giving up every type that can leave is still not enough,
workshop-stockpilerefuses the change - no
wardstoneis dropped, moved to another store, or destroyed byworkshop-stockpileitself
- no
- Diagnostics
workshop-stockpile-forced-removal-logworkshop-stockpile-contents-before-after
capacity-holds
the limit holds after every delivery and take
Applies to workshop-stockpile.
For every delivery and take in this adoption's verification scope (sequences of gathering yields, craft input removals, and craft output deliveries over one run of the workshop), the number of slots in use never goes above the container's declared slot count. This adoption supplies the scope and seeds through its verification inputs. This test checks the limit that this container's capacity answer states.
Test steps and diagnostics
- Diagnostics
workshop-stockpile-contents-trace- first-violating-delivery-or-take
- Holds
after every delivery and every take, the number of slots in use never goes above the container's declared slot count
- Seeds
["workshop-stockpile-audit-a","workshop-stockpile-audit-b"]- Scope
sequences of gathering yields, craft input removals, and craft output deliveries over one run of the workshop
JSONthe adoption as one file
Answers you try on this page do not change this file. To change an adoption, open it in the authoring tool.
{
"contract": "container",
"version": 2,
"origin": "https://opengdd.org/contracts/container-2",
"summary": "This contract covers a container, such as a bag or a chest, that holds distinct items. A delivery is a group of items that arrives at the container. This contract says when the container is full and what happens when some items of a delivery do not fit. It also says which items the container accepts and which slot fills or empties first. It covers slots and size budgets. This version does not cover containers where an item occupies a width-and-height footprint, such as a grid inventory. This contract does not cover counted amounts such as gold. The Ranged value contract covers counted amounts.",
"mechanism": [
"One container holds items. Two items of one type are interchangeable. Items that differ inside one type, for example by wear or by charges, are separate types in this contract, or this game's prose says how they are handled. A slot holds one stack. A stack is items of one type together.",
"The container's own order is the order in which the game's material numbers or lists its slots. In the text below, first and last mean first and last in that order. A container with no slots has no order. Containers where an item occupies a width-and-height footprint, including attaché cases and grid inventories, are outside this version.",
"A delivery offers a type and an amount. A take asks for a type and an amount. A take that asks for more of a type than the container holds yields the amount that the container holds and reports the shortfall.",
"A delivery that fits is accepted whole. For a delivery that does not fit, the partial-acceptance answer applies. For the items that are left over, the leftover-destination answer applies.",
"A stack never holds more than the stack limit on its type's row. An amount above that limit starts a new stack in a free slot, or counts as not fitting if no slot is free. Under the type-restriction answer any-item, two rules apply to a type with no row. Where slots alone set the limit, such a type stacks one item per slot, and in a forced removal it does not leave, as if its when-forced-out value were never. Under a size budget, such a type has no size. A delivery of such a type is therefore refused, and the refused items stay intact, until a row names its size.",
"A forced removal is an item leaving without a take: the container shrank, its rules changed, or its owner is gone. Each item row says what happens to its type and gives the position of its type in the order in which the types leave. In a container with slots, items of one type leave from the last occupied slot of that type first.",
"One adoption file describes one container. Two containers need two files, each with its own rows. Moving an item between two containers is a take from one container and then a delivery to the other. This contract states no other rule between the two containers. Rearranging items by hand is player input. The player chooses the slots, and the fill-order answer does not apply. In a container with slots, a sort delivers the contents again in the order that the sort names. The fill-order answer then decides the slot for each of these deliveries. In a container with no slots, a sort changes nothing that can be observed.",
"The same delivery made from the same starting contents has the same result. The same take made from the same starting contents comes from the same slot."
],
"questions": {
"capacity-limit": {
"asks": "What makes this container full?",
"rationale": "Capacity changes what the container can hold and how it fills. This contract supports one size measure. Containers where items occupy a width-and-height footprint are outside this version.",
"options": {
"slot-count": {
"meaning": "A fixed number of slots makes it full. A shop with twenty stock slots refuses an item of a new type when all twenty slots hold stacks. A stack that has room can still accept an item of its own type."
},
"size-budget": {
"meaning": "A size budget makes it full, and the container has no slots. A card deck with a thirty-point build budget can hold cards of different costs until their costs add up to thirty points."
},
"slots-and-size": {
"meaning": "A slot limit and a size budget both apply. A bag with three free slots can still refuse an anvil when its weight budget is full."
},
"no-limit": {
"meaning": "It never fills. A new item always has room, so nothing is refused because the container ran out of space.",
"rationale": "Use this when room can never run out. It avoids a fake large limit that readers may mistake for a real limit."
}
}
},
"partial-acceptance": {
"asks": "A delivery reaches the container, but not all the items fit. What goes in?",
"rationale": "Two containers with the same free space can act differently. One accepts what fits; the other refuses the whole delivery.",
"when": {
"flag": {
"capacity-limit": [
"slot-count",
"size-budget",
"slots-and-size"
]
}
},
"options": {
"all-or-nothing": {
"meaning": "The whole delivery is refused. A ten-arrow pickup adds no arrows when the container has room for only five. Each offered type and amount is one delivery. A craft with several outputs makes several deliveries, so some outputs may enter before another is refused. The refused items stay with whatever offered them. Your game's own rules decide what the action that offered them does next."
},
"fill-what-fits": {
"meaning": "Everything that fits goes in. A ten-arrow pickup adds five when only five fit; the other five remain outside."
}
}
},
"leftover-destination": {
"asks": "What happens to the items that do not fit?",
"rationale": "Items that do not fit must go to a stated place. Otherwise one build may return them while another build drops or destroys them.",
"when": {
"flag": {
"partial-acceptance": [
"fill-what-fits"
]
}
},
"options": {
"back-to-the-sender": {
"meaning": "The leftover goes back to the sender. Arrows that do not fit return to the chest or pickup that offered them."
},
"left-where-it-is": {
"meaning": "The leftover stays where the delivery arrived. Arrows that do not fit become a loose pickup beside the bag."
},
"another-store": {
"meaning": "The leftover moves to another store named by your game. Arrows that do not fit may go to a stash."
},
"destroyed": {
"meaning": "The leftover is destroyed. Arrows that do not fit disappear instead of returning, dropping, or moving elsewhere."
}
}
},
"fill-order": {
"asks": "Several slots could hold a new item. Which slot gets it?",
"rationale": "Two teams that build the same design can fill the same container differently. That changes what players see and what the game removes later. Rules that score slots, rotate between containers, or use a custom sequence stay in your game's prose.",
"when": {
"flag": {
"capacity-limit": [
"slot-count",
"slots-and-size",
"no-limit"
]
}
},
"options": {
"top-up-then-first-empty": {
"meaning": "A new item goes to a stack of the same type that has room. When no stack of that type has room, the item goes to the first empty slot. A potion goes to the first potion stack with room, and to the first empty slot only when no potion stack has room."
},
"first-slot-that-fits": {
"meaning": "The first slot that can hold the item gets it. An empty first hotbar slot receives the item, even when a later stack of the same type has room."
},
"append": {
"meaning": "New items go after everything already held. An empty slot in the middle stays unused until the items after it are gone. A bag with a slot limit can count as full while that gap remains."
},
"not-applicable": {
"meaning": "Choose this only when each item has one reserved slot. If slots are unlimited, choose Append instead."
}
}
},
"draw-order": {
"asks": "The game needs an item for one of its own rules. Which matching slot does it take from?",
"rationale": "Automatic use needs a stable choice because it can change which stack remains for the player. A rotating choice over counted amounts belongs in the Ranged value contract.",
"options": {
"first-in-order": {
"meaning": "The first matching slot supplies the item. Crafting uses the earliest stack in the bag before later stacks."
},
"last-in-order": {
"meaning": "The last matching slot supplies the item. Crafting empties the last matching stack before earlier stacks."
},
"newest-first": {
"meaning": "The stack that received items most recently supplies them first. Adding potions to an older potion stack makes that stack the newest again."
},
"oldest-first": {
"meaning": "The stack that began first supplies items first. Adding potions to an old potion stack does not make that stack newer.",
"rationale": "Use this when the longest-held stack must leave first, such as a magazine or queue."
},
"not-applicable": {
"meaning": "The game never has to choose between matching slots. The player chooses a slot, only one can match, or the container has no slots."
}
}
},
"type-restriction": {
"asks": "Which item types can this container hold?",
"rationale": "A clear item rule prevents unnoticed differences between what the game accepts and what the designer intended. Rules that come from another list or from program code stay in your game's prose.",
"options": {
"only-these": {
"meaning": "Only listed item types can enter. A potion bag refuses a sword. The sword stays where it was; nothing is destroyed. An empty list means the container accepts nothing."
},
"any-item": {
"meaning": "Every item type may enter when the contract knows how much room the type needs. Where slots alone set the limit, a type that no row names, such as a quest letter, uses one slot for each item and cannot be forced out. Under a size budget, a type that no row names is refused until a row names its size. The refused items are not destroyed."
},
"by-slot": {
"meaning": "Each slot has its own item rule. An armor slot accepts a helmet but refuses a potion without destroying it. List every type that needs a stacking or forced-out rule.",
"semantics": "Each item row's slot-rules-declared-in citation is binding. It points to prose that lists every slot and every item type that the slot accepts. A slot refuses an item of a type that the prose does not list for that slot, and the refused item stays intact."
}
}
}
},
"declares": {
"values": {
"slot-count": {
"description": "How many slots the container has. Use at least one when slots set capacity. Use zero when this container has no slot limit. If your game stores this number elsewhere, move it here so two copies cannot disagree."
},
"size-budget": {
"description": "The largest total size the container holds. Your game chooses the unit, such as kilograms or bulk. Every item uses the same unit. Use zero when size does not limit the container."
}
},
"rows": {
"items": {
"description": "The item types whose rules this contract records. Use one row for each type. For a restricted container, the rows are also the allowed list. For any-item, two things together decide entry, stacking, and forced removal for every type: the rows, and the rules of this contract for a type that no row names. The validator checks each row's fields. A reviewer checks that the game's own prose does not give a type that no row names a rule that differs from those rules.",
"record": {
"id": {
"type": "string",
"required": true,
"pattern": "kebab-case",
"unique": true,
"description": "A short name for the item type in your game's words, such as berries or axe."
},
"slot-rules-declared-in": {
"type": "citation",
"when": {
"flag": {
"type-restriction": [
"by-slot"
]
}
},
"description": "Where your game's rules list every slot and every item type that the slot accepts. This citation is the binding rule for the slots. Use the same citation on every row when one section holds the whole list."
},
"stack-limit": {
"type": "integer",
"when": {
"flag": {
"capacity-limit": [
"slot-count",
"slots-and-size",
"no-limit"
]
}
},
"description": "How many items of this type fit in one slot. It is required whenever the container has slots, including when it never fills. Use one for an item that does not stack, or another positive whole number."
},
"size": {
"type": "number",
"when": {
"flag": {
"capacity-limit": [
"size-budget",
"slots-and-size"
]
}
},
"description": "How much of the size budget one item uses. Use the same unit as the container's budget. Use zero or more."
},
"when-forced-out": {
"type": "string",
"required": true,
"options": [
"never",
"dropped-nearby",
"moved-to-another-store",
"destroyed"
],
"description": "What happens to this item when the container must give items up. It may stay, drop nearby, move to another store, or be destroyed. An item marked to stay is skipped. The container tries other types in their chosen order. It refuses the forced removal if too few items can leave. If destroying an item could make the game impossible to finish, say so and test it in your own rules."
},
"forced-out-order": {
"type": "integer",
"unique": true,
"when": {
"row": {
"when-forced-out": [
"dropped-nearby",
"moved-to-another-store",
"destroyed"
]
}
},
"description": "The order in which item types leave, lowest number first. Give each movable type a different number. Items of one type leave from its last occupied slot first. The size of the gaps between numbers does not matter."
}
}
}
}
},
"pack": "sha256:ae851e93d7e94c3f971f69b518935f2a6367204ca88178a9f6defd4530a15eb2",
"rules": {
"slot-count-not-negative": "slot-count >= 0",
"size-budget-not-negative": "size-budget >= 0"
},
"answers": {
"capacity-limit": "slot-count",
"partial-acceptance": "all-or-nothing",
"fill-order": "top-up-then-first-empty",
"draw-order": "first-in-order",
"type-restriction": "any-item"
},
"values": {
"slot-count": 24,
"size-budget": 0
},
"rows": {
"items": [
{
"id": "firewood",
"stack-limit": 40,
"when-forced-out": "never"
},
{
"id": "clay",
"stack-limit": 40,
"when-forced-out": "never"
},
{
"id": "ore-rock",
"stack-limit": 40,
"when-forced-out": "never"
},
{
"id": "charcoal",
"stack-limit": 40,
"when-forced-out": "never"
},
{
"id": "kiln-brick",
"stack-limit": 20,
"when-forced-out": "never"
},
{
"id": "kiln-lining",
"stack-limit": 4,
"when-forced-out": "never"
},
{
"id": "copper-ingot",
"stack-limit": 10,
"when-forced-out": "never"
},
{
"id": "glaze-slip",
"stack-limit": 10,
"when-forced-out": "never"
},
{
"id": "wardstone",
"stack-limit": 1,
"when-forced-out": "never"
}
]
},
"verification": {
"capacity-holds": {
"scope": "sequences of gathering yields, craft input removals, and craft output deliveries over one run of the workshop",
"seeds": [
"workshop-stockpile-audit-a",
"workshop-stockpile-audit-b"
]
},
"fill-order-holds": {
"scope": "02-mechanics.md#the-workshop"
},
"draw-order-by-position": {
"scope": "02-mechanics.md#the-workshop"
}
}
}