# Chest Shops

A player turns a single chest into a shop via **shift+left-click with an item in hand**, the sign is created automatically. All trading happens through the sign; the chest stays locked for everyone except owner/team manager/admin. Every shop is `SELLING` (sells from the chest) or `BUYING` (buys from players) and belongs to a player or a [team](teams.md) (money then flows through the team treasury).

## Commands

| Command | Syntax | Permission | Default | Description |
|---|---|---|---|---|
| `/shop info` | `/shop info` (look at block) | `shop.use` | `true` | Owner, item, price, type, stock, coordinates |
| `/shop remove` | `/shop remove` (look at block) | `shop.use` | `true` | Removes the shop (management right required) |
| `/team shop` | `/team shop` (look at block) | `team.shop` + team right | `true` | Converts the shop into a team shop |
| `/shop list` | `/shop list` | `shop.admin` | op | All shops with type, owner, item, price, position |
| `/shop reload` | `/shop reload` | `shop.admin` | op | Reloads config and shops |
| `/shopedit` | (internal menu, right-click the sign) | `shop.create` | `true` | Change price, toggle type, remove shop |
| `/shopconfirm` / `/shopcancel` | (internal chat buttons) | `shop.use` | `true` | Confirms/cancels a transaction |

## Additional permissions

| Permission | Default | Description |
|---|---|---|
| `shop.create` | `true` | Create shops via shift+click |
| `shop.bypass.maxshops` | false | Bypasses the personal and team shop limits |
| `shop.bypass.selftrade` | op | Allows trading at your own shop |
| `shop.limit.<n>` | `false` | Individual shop limit (highest value wins) |
| `shop.limit.unlimited` | false | No shop limit |
| `shop.info` | `true` | Read other players' shop signs with a right-click (owner, item, price, stock) |

## How a trade works

1. **Left-click the sign**, an anvil GUI asks for the quantity (for selling limited by player stock, chest space and owner balance).
2. Clickable `[✔ Confirm]`/`[✘ Cancel]` buttons appear in chat (valid 30 seconds, `general.confirmation-timeout`).
3. On confirmation everything is re-checked and booked atomically: if any step fails, money and items are returned automatically. If not everything fits into the inventory, the remaining items drop at your feet (no loss).

When selling to a buying shop (`BUYING`) only the 36 storage slots are counted and taken; worn armour and the offhand item are never sold. If a buyer dies between confirmation and hand-over, the purchased items drop at the death position instead of vanishing with the death inventory.

> **Note:** If the owner changes price or type in the meantime, the confirmation cancels automatically. Price and quantity inputs use anvil windows (not chat) and understand `k`/`M` suffixes like `1.5k`.

> **Tip:** The optional tax (`tax-percentage`, 0 to 100) is credited to nobody, it is a pure money sink against inflation. If the tax swallows the whole amount (e.g. price 0.01 at 50 %), the trade is still valid: the buyer pays, the owner or seller receives 0.00.

**Right-clicking your own sign** opens the edit menu: change price, toggle type and remove the shop (the latter two are cooldown protected, `cooldown.commands.shopedit`). Switching a team shop to `BUYING` additionally needs the team right `WITHDRAW`, because buying shops spend team money.

**Team shops** (`/team shop`): needs team membership with the team right `EDIT_TEAM_SHOPS` (or `shop.admin`). They do not count against the personal limit but against `max-shops-per-team`. Team shops can only be created inside a claim that belongs to the team (like team containers).

## Sign

The sign is waxed automatically and redrawn on every change:

| Line | Content | Color |
|---|---|---|
| 1 | `[Shop]` | Pink |
| 2 | Owner (player or `Team <name>`) | Aqua |
| 3 | Item name | Yellow |
| 4 | `Sell <price>` / `Buy <price>` (compact format like `10k`) | Green when available, otherwise red |

## Protections

| Threat | Protection |
|---|---|
| Double chests | Creation rejected; merging afterwards is technically impossible |
| Breaking chest/sign | Only owner/team manager/`shop.admin`, and even they must sneak |
| Explosions | Shop chests and signs are blast proof |
| Pistons | Movements involving shop blocks are cancelled entirely |
| Water/lava/fire/enderman | Cannot replace or destroy shop blocks |
| Hoppers | Can neither drain nor fill shop chests (`hopper-protection`) |
| Unauthorized opening | Chest opens only for managers, trading happens via the sign |
| Team chests | Team-claimed chests cannot become a shop |

## Shops and claims

A chest shop can only be created inside a claim where you may build: your own claim, another player's claim with build trust, or your team claim (`require-claim`). Not only the chest but also the block for the shop sign must lie on that land. The sign is placed automatically on a free side that satisfies this rule; if there is none, creation is rejected with "no free side". Players with `shop.admin` may create shops anywhere. When the claim disappears (abandon, admin deletion, automatic expiration, team disband), every shop on its footprint turns into a plain chest: sign gone, contents stay. Before abandoning, the server tells you the number, the web panel asks for confirmation. Shop owners who are not the one abandoning get a notice, offline on their next login. A claim cannot be shrunk so that shops end up outside: `/shop remove` first, then drag the corner. The claim owner may remove other players' shops from their land with `/shop remove`, on team land members with the team right `EDIT_TEAM_SHOPS`; the shop owner is notified. Transferring a claim keeps its shops. Shops created outside claims before this rule keep working.

## Item matching

A shop trades exactly the item it was created with. Two tolerances are configurable: `matching.ignore-cosmetics` treats an item wearing a cosmetic skin as the item underneath (a shop created with a skinned pickaxe trades plain ones too), `matching.ignore-name-and-lore` (default `false`) treats renamed or re-lored items as the base item; by default a renamed item is its own item, and the hover in the shop info shows its name. Never ignored: enchantments, durability, potion effects, container contents and custom items from resource packs (Nexo, Carpentary), so a shop never accepts something cheaper that merely looks alike.

## Offline notifications

Trades at your shops while you were offline are collected and shown on your next login (`offline-notifications.enabled`). `max-messages-on-join` caps the individual lines, the rest is summarised as a count; entries older than `keep-days` are dropped unseen. The money itself is always credited immediately.

## Configuration (modules/shop.yml)

```yaml
# Enables or disables the chest shop module.
enabled: true

shop:
  # Default limit per player. Override per rank via permission:
  # shop.limit.25 allows 25 shops, shop.limit.unlimited removes the limit.
  max-shops-per-player: 10
  # Maximum shops per team (-1 = unlimited). Team shops do not count
  # against the personal limit.
  max-shops-per-team: 15
  # Shops only inside claims where the creator may build. When the claim
  # disappears, the shops inside turn into plain chests.
  require-claim: true
  # Prevents hoppers from draining or filling shop chests.
  hopper-protection: true
  # Allowed price range per item. max-price is hard capped at 999000000
  # (higher values are clamped on load).
  min-price: 0.01
  max-price: 999000000.0
  # Percentage tax on every completed transaction. The amount is credited
  # to nobody (money sink). 0 = no tax.
  # Values outside 0 to 100 are clamped on load.
  tax-percentage: 0
  # Plays transaction sounds for nearby players too.
  sound-broadcast: false
  integrations:
    coreprotect:
      # Logs transactions to CoreProtect (#shop-buy-<player>).
      transaction-logging: true
    nexo:
      # Resolves Nexo item names on signs/displays.
      enabled: true
    carpentary:
      # Resolves Carpentary item names.
      enabled: true

cooldown:
  commands:
    # Seconds between /shopedit actions (against spam toggling).
    shopedit: 3
```

## Complete example config

```yaml
enabled: true

shop:
  max-shops-per-player: 5
  max-shops-per-team: 20
  require-claim: true
  hopper-protection: true
  min-price: 1.0
  max-price: 1000000.0
  tax-percentage: 5
  sound-broadcast: true
  integrations:
    coreprotect:
      transaction-logging: true
    nexo:
      enabled: false
    carpentary:
      enabled: false

cooldown:
  commands:
    shopedit: 5
```
