Container
container-2
This contract defines the behavior of containers: a backpack, a chest, or a set of slots.
This contract decides when a container is full, what happens to items that do not fit, and which slot receives or gives an item first.
Use in your package
The first button opens the authoring tool with this contract added and its questions unanswered. You can also download the zip file and add the contract later.
What is in the zip file
The zip file holds the contract 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/. Fill in the answers there.
Questions
Up to 6 questions. Some appear only after earlier answers.
- What makes this container full?
- A delivery reaches the container, but not all the items fit. What goes in?
- What happens to the items that do not fit?
- Several slots could hold a new item. Which slot gets it?
- The game needs an item for one of its own rules. Which matching slot does it take from?
- Which item types can this container hold?
Try the answers
Pick answers to see which rules and tests apply. Nothing is saved here. In the zip file and in the authoring tool, the questions have no answers yet.
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.
Numbers and rules2 numbers, 2 rules
Numbers
Each setting takes a number, or a reference to a decided number in your tuning. It cannot reference an open number. Stay inside any range shown.
Slot count
slot-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
size-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.
Rules
slot-count >= 0size-budget >= 0
Lists1 list
Some settings are lists of rows.
A reference points to a number or a rule in your design. For a number, use the address of a decided number in your tuning, not an open one. For a rule, use its file and heading, such as 02-mechanics.md#recovery. The reference must match exactly one heading in that file. No > DELEGATED: or > PERSONALIZATION: tag may cover any part of the section under that heading. Each field's description says what it needs.
Items
items
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 (the checking tool) 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.
Each row is: id, slot-rules-declared-in, stack-limit, size, when-forced-out, forced-out-order.
Every field
| Field | Kind | When it appears | Meaning |
|---|---|---|---|
id |
string | Required | A short name for the item type in your game's words, such as berries or axe. |
slot-rules-declared-in |
reference | Present when Type restriction is By slot. | 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 |
integer | Present when Capacity limit is Slot count or Slots and size or No limit. | 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 |
number | Present when Capacity limit is Size budget or Slots and size. | 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 |
choice: never, dropped-nearby, moved-to-another-store, destroyed | Required | 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 |
integer | Present when row when forced out is Dropped nearby or Moved to another store or Destroyed. | 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. |
For builders
Exact wording for builders and 14 pack tests
Exact wording for builders
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.
Verification pack
sha256:ae851e93d7e94c3f971f69b518935f2a6367204ca88178a9f6defd4530a15eb2
The format calls an adoption that has its matching pack Checked. The tests are included, but this does not mean that a game has passed them. An adoption without the pack is Promised. The builder must still build the chosen behavior.
14 pack tests
Placeholders are filled from the adoption's answers, numbers, rows, and test inputs.
a delivery that fits is accepted whole
delivery-that-fits
Applies for every adoption
A delivery that Instance has room for is accepted whole. The container gains exactly what was offered and keeps everything it already held. Nothing is left over.
- Given
the
Instancecontainer with room for the whole of the delivery below- When
- a delivery offers n items of a type
Instanceaccepts
- a delivery offers n items of a type
- Then
Instanceholds exactly n more items of that type than it did- nothing already in
Instanceis removed, destroyed, or changed into another type - nothing is handed back, dropped, or destroyed
- Diagnostics
Instance-contents-before-after
a delivery that does not fit is refused whole
refuses-whole
Applies when Partial acceptance is All or nothing.
A delivery larger than the room available does not change Instance. 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.
- Given
the
Instancecontainer with room for fewer than n items of a type it accepts- When
- a delivery offers n items of that type
- Then
Instanceholds 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
Instance-contents-before-afterInstance-delivery-report
a delivery that does not fit is split
takes-what-fits
Applies when Partial acceptance is Fill what fits.
When a delivery is larger than the room available, Instance takes the items that fit, and the delivery reports the number of items that did not fit. The part that did not fit is Bind leftover phrase. This game's own prose decides where that part goes next and who is responsible for it after that.
- Given
the
Instancecontainer with room for m items of a type it accepts, where m is more than zero and less than n- When
- a delivery offers n items of that type
- Then
Instanceholds exactly m more items of that type- the remaining n minus m items are
Bind leftover phrase - the delivery reports n minus m as the number it could not take
- Diagnostics
Instance-contents-before-afterInstance-delivery-report
the container is full when its slots are full
slots-are-the-limit
Applies when Capacity limit is Slot count or Slots and size.
This container is full when every slot stated by the value at Value cite slot count 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.
- Given
the
Instancecontainer with allValue cite slot countslots 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
Instancetakes none of it- the number of slots in use is still the number stated by
Value cite slot count
- Diagnostics
Instance-slot-occupancyInstance-delivery-report
the container is full when its size budget is spent
size-is-the-limit
Applies when Capacity limit is Size budget or Slots and size.
This container is full when the next item's size would take the total past the value at Value cite size budget. Sizes come from the item rows and the budget from that value; this test restates neither number.
- Given
the
Instancecontainer holding items whose sizes add up to less thanValue cite size budget- When
- a delivery offers items whose sizes would take the total past
Value cite size budget
- a delivery offers items whose sizes would take the total past
- Then
- the sizes of the items
Instanceholds never add up to more thanValue cite size budget - each item's size is the size written on its own type's row, in the unit this game's prose names for the budget
- the sizes of the items
- Diagnostics
Instance-size-totalInstance-delivery-report
no delivery is refused for lack of room
never-refuses
Applies when Capacity limit is No limit.
This container has no capacity limit, so no delivery can fail for lack of room. This container's capacity answer records that decision.
- Given
the
Instancecontainer holding any amount at all- When
- a delivery offers any number of items of a type
Instanceaccepts
- a delivery offers any number of items of a type
- Then
- every offered item goes in
- nothing is handed back, dropped, or destroyed for lack of room
- the result is the same whatever amount the container already holds
- Diagnostics
Instance-contents-before-after
an accepted item is placed in the declared slot
fill-order-holds
Applies when Fill order is Top up then first empty or First slot that fits or Append.
An item that Instance accepts is placed Bind fill phrase. 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.
- Given
the
Instancecontainer 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 asInputs scopestates- When
- a delivery offers one more item of that type
- Then
- the item is placed
Bind fill phrase - the same delivery made again from the same starting contents is placed in the same slot
- the item is placed
- Diagnostics
Instance-slot-occupancyInstance-fill-trace
the game takes from the declared slot
draw-order-by-position
Applies when Draw order is First in order or Last in order.
A take that the game makes from Instance on its own comes Bind draw phrase. The same take from the same starting contents comes from the same slot every time. The slots are numbered as Inputs scope states.
- Given
the
Instancecontainer holding the same type in at least two slots, its slots numbered asInputs scopestates- When
- the game takes fewer of that type than
Instanceholds, on its own rather than at a player's direction
- the game takes fewer of that type than
- Then
- the items come
Bind draw phrase - 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
- the items come
- Diagnostics
Instance-slot-occupancyInstance-take-trace
the time at which each stack received items decides which stack the game takes from
draw-order-by-arrival
Applies when Draw order is Newest first or Oldest first.
A take that the game makes on its own comes Bind arrival phrase. The position of a stack does not decide which stack supplies the take. Instance records when each stack received items. The draw-order answer states whether adding items to an existing stack counts as receiving.
- Given
the
Instancecontainer holding the same type in at least two stacks that received items at different times, one of them receiving more items after the other stack was made- When
- the game takes fewer of that type than
Instanceholds, on its own rather than at a player's direction
- the game takes fewer of that type than
- Then
- the items come
Bind arrival phrase - the position of each stack makes no difference to which stack supplies the take
- the same take made again from the same starting contents and the same arrival history comes from the same stack
- the items come
- Diagnostics
Instance-stack-arrival-logInstance-take-trace
Row.id stacks no higher than its limit
stack-limit-holds
Applies when Capacity limit is Slot count or Slots and size or No limit.
A stack of Row.id in Instance never holds more than Row.stack limit. This number is the stack limit on the row for Row.id in this adoption.
- Given
the
Instancecontainer with one slot holdingRow.stack limitofRow.id- When
- a delivery offers one more
Row.id
- a delivery offers one more
- Then
- that slot still holds exactly
Row.stack limitofRow.id - 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
Instance-slot-occupancyInstance-delivery-report
a type the list does not name is refused
unlisted-type-refused
Applies when Type restriction is Only these.
This container holds only the types its item list names. A delivery of anything else is refused whole even when there is room. The refused item is not destroyed. Where the item list is this game's whole catalog, no unlisted type exists to offer and this test has no reachable case: a builder records it as unreachable rather than inventing a type to refuse.
- Given
the
Instancecontainer with free room- When
- a delivery offers an item of a type the item list does not name
- Then
Instancetakes none of it, however much room it has- nothing already in
Instancechanges - the refused item is not destroyed
- Diagnostics
Instance-contents-before-afterInstance-delivery-report
Row.id leaves Instance in the declared way
forced-out-holds
Applies when row when forced out is Dropped nearby or Moved to another store or Destroyed.
When Instance is made to give items up, Row.id is Bind fate phrase, and it leaves at position Row.forced out order in the declared order. When the container has slots and Row.id is in more than one slot, the last of those slots is emptied first. The row number orders the types, and that rule orders the slots inside one type.
- Given
the
Instancecontainer holding more than oneRow.idand, when it has slots and more than one slot is needed for that many, holding that type in more than one slot, together with any types carrying lower or higher forced-out order numbers- When
Instanceis made to give items up without a take
- Then
Row.idisBind fate phraseRow.idleaves at positionRow.forced out orderin the order: any type present with a lower number has left before it, and any type present with a higher number leaves after it- when the container has slots and
Row.idis in more than one slot, the last occupied slot of that type is emptied first, and the other occupied slots of that type follow from last to first in the container's own order - no type that did not have to leave leaves
- Diagnostics
Instance-forced-removal-logInstance-contents-before-after
Row.id is never given up by Instance itself
never-forced-out
Applies when row when forced out is Never.
Nothing that this container does on its own removes Row.id from it. When Instance must give items up, it skips this type. When giving up every type that can leave is still not enough, Instance refuses the change. When a player drops, sells, or destroys Row.id, this game's own rules apply. This test does not cover that case.
Where this game has no way to shrink Instance 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.
- Given
the
Instancecontainer holdingRow.idat 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
Row.idleavesInstance: 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,
Instancerefuses the change - no
Row.idis dropped, moved to another store, or destroyed byInstanceitself
- no
- Diagnostics
Instance-forced-removal-logInstance-contents-before-after
the limit holds after every delivery and take
capacity-holds
Applies when Capacity limit is Slot count or Size budget or Slots and size.
For every delivery and take in this adoption's verification scope (Inputs scope), Bind limit clause. This adoption supplies the scope and seeds through its verification inputs. This test checks the limit that this container's capacity answer states.
- Diagnostics
Instance-contents-trace- first-violating-delivery-or-take
- Holds
after every delivery and every take,
Bind limit clause- Seeds
Inputs seeds- Scope
Inputs scope