shops
Last updated on
Clothing shops that open the fitting room, bill per changed clothing slot, offer ready-made looks and keep saved outfits with share codes.
Places clothing shops in the world. At a shop a player picks "Try clothes on" on the target eye and the appearance fitting room opens. When the player keeps the new clothes, they pay for each clothing slot that changed, before the look is saved. Inside the room the shop adds four groups: ready-made looks (uniforms), saved outfits, "Save outfit" and "Outfit code". Saved outfits can be shared with an 8-character code another player types in a shop's fitting room, where it is billed at that shop's prices. Use it to sell clothes; it stocks no garments of its own.
| Side | both |
| Requires | character, appearance (hard) |
| Optional | target (the shop row), menu (looks and outfit lists), form (outfit name and code entry) |
| Contract | none |
| Config | config/shops.lua (shared) |
| Data | opx77_saved_outfits |
How a bill works
The server cannot see the clothing catalogue (it is client-only), so it prices slots, not garments.
- The shop opens a priced room (
OpenWardrobewith acharge). - When the room's save arrives, the server compares it with the stored record and lists the slots that changed:
Head,Face,InnerChest,OuterChest,Legs,Feet,Outfit,UnderwearTop,UnderwearBottom. Taking a garment off counts as a change. The client reports nothing. - The server adds up the shop's price for each changed slot and takes it from
CURRENCYbefore the look is written. A slot without a price is free. Underwear is free by default. - If the bill cannot be paid, the save is refused (
clothing.unpaid) and the stored look goes back on. If the write fails after payment, the money is refunded. - A uniform is billed on Save, not when picked. Its
COSTrides on the save permission and is charged once, by the save that keeps it; Cancel costs nothing. The slots it covers are not billed again by the room. If its bill is refused, the save is refused, every charge of that save is refunded, and the uniform can still be saved later. - The bill is shown before Save. The room's status line reads On Save: 1,050 €$: the changed slots at this shop's prices, plus any uniform picked here. The shop's price list arrives with its looks. Display only: the server bills from its own tables.
- A long browse does not lose the save: while the room is open it is kept alive every 2 minutes, up to 30 minutes.
- The server re-checks reach, bucket, the job gate and that the player is not down before opening the room, billing, or dressing.
Ready-made looks
A look from LOOKS is a partial outfit with its own COST. It sets the slots it names and leaves the others as they are; false empties a slot. Looks are filtered by job before the list is sent, so a player only sees what they may take.
Saved outfits and share codes
- "Save outfit" stores the clothing currently saved for the character (not the unsaved preview) under a name. If the room is open, the save happens when the room closes.
- A character keeps up to
OUTFITS.MAX_PER_CHARACTERoutfits. - "Get a share code" gives the outfit a code made from
23456789ABCDEFGHJKLMNPQRSTUVWXYZ(noI,O,0,1). Typing is case-insensitive and ignores dashes and spaces. A code is not a secret. - Wearing one of your saved outfits is free. It grants one save of exactly that look, not a free room.
- A share code is redeemed only inside a shop's fitting room, at that shop's counter (reach, bucket, job gate, not down) with that shop's room open (
shops:<key>, read throughPricedRoom). The outfit goes onto the room's draft with no free grant: on Save, the changed pieces are billed at this shop'sPRICES, like rack pieces. Cancel costs nothing. Elsewhere the code answersredeemAtShop; at the counter without the room,redeemInRoom. - The save, list, load, delete and share doors accept one press per 750 ms per player; typing a code, one per 2 s.
- Deleting a character deletes its saved outfits.
Configuration
config/shops.lua sets OPX.Config.MODULES.shops.
| Key | Default | Effect |
|---|---|---|
enabled | true | false switches the module off. |
PRICES | Head 250, Face 250, InnerChest 400, OuterChest 600, Legs 450, Feet 300, Outfit 900 | Price per changed slot. A slot not listed is free. Unknown slot names are dropped with a boot warning. |
CHARGE | true | false makes every shop free (prices and look costs). |
CURRENCY | 'EDDIES' | Money type a bill is taken from. |
REACH | 3.0 | Metres from the shop. Re-measured on the server, which allows REACH_SLACK (1 m) more. Also the target sphere radius. |
SHOPS | jinguji, thrift_watson | The shops, keyed by slug. See below. |
OUTFITS | { MAX_PER_CHARACTER = 24, MAX_NAME_BYTES = 48, SHARING = true, CODE_LENGTH = 8 } | Saved outfits. SHARING = false stops minting and redeeming codes. CODE_LENGTH 4–16. |
LOOKS | ncpd_patrol, corpo_black | Ready-made looks. See below. |
thrift_watson = {
LABEL = 'Second-hand, Watson',
X = -1180.0, Y = 1550.0, Z = 25.0,
PRICES = { Head = 80, Face = 80, InnerChest = 120, OuterChest = 180,
Legs = 140, Feet = 100, Outfit = 300 },
},LABEL: name used in bills and audit. Defaults to the key.X,Y,Z: position. Required.BUCKET: routing bucket,0when omitted. A shop serves its own bucket only (there is no "every bucket").PRICES: override merged over the defaultPRICES; it can only add or change slots, never remove one.{}changes nothing; a slot set to0is free at that shop. A free shop is0for every slot (orCHARGE = falsefrees every shop).JOBS:{ job = minimumGrade }.nil= anybody.ON_DUTY:true= the job must be on duty.
corpo_black = {
LABEL = 'Corporate black',
COST = 2500,
WEAR = { InnerChest = 'Items.Formal_Shirt_01', OuterChest = 'Items.Formal_Jacket_01',
Legs = 'Items.Formal_Pants_01', Feet = 'Items.Formal_Shoes_01', Head = false, Face = false },
},LABEL: shown in the list.COST: one price for the whole look.0is free.JOBS,ON_DUTY: same as a shop.AT: list of shop keys that offer it.nil= every shop.WEAR:{ Slot = 'Items.Record' | false }. Slots not named are left unchanged.
Refusal codes
Every refusal is a toast with locale key shops.<code>. The bill and look purchase can also show the character module's money key (for example money.insufficient).
| Code | Meaning |
|---|---|
no_such_shop | No shop with that key. |
too_far | Out of reach, or another bucket. |
position_unknown | The server cannot read the player's position. |
not_for_you | The shop's job gate refused. |
downed | The player is down (Nobody serves you from the floor.). |
redeemAtShop | A share code typed away from a clothing shop's counter. |
redeemInRoom | A share code typed at the counter without that shop's fitting room open. |
unavailable | appearance cannot open the room or dress the player. |
cannotPay | The bill or look cost could not be taken. |
noSuchLook | No look with that key. |
notForYou | The look's job gate refused. |
notHere | This shop does not carry that look. |
noCharacter | No character loaded. |
nameNeeded | Empty outfit name. |
tooMany | Outfit limit reached. |
nothingWorn | No stored clothing to save. |
saveFailed | Database write failed. |
listFailed | Database read failed. |
noSuchOutfit | Not one of this character's outfits. |
outfitUnreadable | The stored outfit could not be decoded. |
sharingOff | OUTFITS.SHARING is off. |
badCode | Not a valid code. |
noSuchCode | No outfit has that code. |
codeFailed | No unique code after five tries. |