====== Creation Law — Shops ====== You know classic Diku shop tables / ''sedit''. Neo has **no** ''sedit''. A shop is a workspace prototype keyed by an existing **mobile VID**, edited with ''@shop …'', reviewed with ''@examine shop'', then committed with ''@save shop''. Hub: [[immortal:creationlaw|Creation Law]]. Build the keeper mobile first: [[immortal:creationlaw:mobiles|Mobiles]]. Place it: [[immortal:creationlaw:zones|Zones]]. Player-facing buy/list/auction flow: [[player:gamelaw:shopkeepers|Shopkeepers]]. ===== Why a shop is not the mobile ===== The mobile is the body players talk to. The **shop** row (H2 table ''shopkeeper'') is the trade config: home room, produce list, item types traded, hours, and keeper messages. When a mobile has ''Acts.SHOPKEEPER'', runtime looks up ''ShopkeeperDB.at(mobile.vid())''. So the build order is: **mobile (with SHOPKEEPER)** → **shop workspace on that same VID** → **zone place** → ''zone reset''. Creating ''@new shop'' before the mobile exists fails. Forgetting the Acts flag leaves a shop row that never handles ''list'' / ''buy''. ===== Prerequisites ===== * An ''npc'' prototype already ''@save''d (same VID you will use for the shop) * On ''npc_stats'': ''@npc_stats flags acts shopkeeper'' (and usually ''sentinel'' so the keeper stays put) * A room that already exists for ''@shop room'' * Item prototypes you intend to ''produces'' (optional slots — up to 10) ===== Step-by-step: first shop ===== **1. Confirm the mobile** (build it if needed — [[immortal:creationlaw:mobiles|Mobiles]]): > @load npc_stats 1210 Okay. > @npc_stats flags acts shopkeeper Okay. > @npc_stats flags acts sentinel Okay. > @examine npc_stats > @save npc_stats Okay. > **2. Open the shop draft** — VID **is** the mobile VID (must be in your mobile range; mobile must exist; no second shop draft while one is open): > @new shop 1210 Okay. > Echoes you will see on failure (exact Immortality strings): * ''A new shop entry already exists in your buffer.'' — ''@examine shop'' then ''@save shop'' or ''@clear shop'' * ''A shop already exists for that .'' * ''No mobile with vid exists.'' * ''That vid is not in your range.'' * Bad usage line in code prints ''@new show '' (typo for ''@new shop''). **3. Home room** (why: ''Shopkeeper.check'' refuses ''@save'' when room is 0 — the room VID must already exist in ''RoomDB''): > @shop room 1200 Okay. > **4. What the keeper trades** (''ItemType'' flags via ''@shop trades''; prefix ''!'' to clear when the modifier supports it). At least **one** type is required to save: > @shop trades weapon Okay. > @shop trades armor Okay. > Bare ''@shop trades'' reprints ''@shop trades (!)'' plus the ''ItemType'' list from code. **5. Produce list** (optional but usual — stock the keeper lists / sells at a fixed cost). Positions **1–10** (''Shopkeeper.MAX_PRODUCES''). Cost must be ≥ 1 gold for any filled slot or ''@save'' returns ''producing vid:… for 0gc'': > @shop produces 1 3100 500 Okay. > @shop produces 2 3101 50 Okay. > Syntax: ''@shop produces ''. The produce setter does **not** verify the item prototype exists at edit time — ''@examine'' shows ''ItemDB.proper'' when the item is known. **6. Hours** — ''hours1'' is **required** to save (''open1'' must be non-zero). Both start and finish for ''hours1'' must be positive integers, and start must be strictly less than finish. ''hours2'' is optional and may only be set after ''hours1'': > @shop hours1 8 12 Okay. > @shop hours2 14 20 Okay. > **7. Keeper messages** (one-line writers — all six are required by ''Shopkeeper.check'' before ''@save''): > @shop keeper_no_item_msg I do not have that item. > @shop customer_no_item_msg You do not seem to have that. > @shop customer_no_cash_msg You cannot afford that. > @shop keeper_no_buy_msg I do not buy that sort of thing. > @shop keeper_buy_msg That will be %d coins. > @shop keeper_sell_msg Sold. > ''keeper_buy_msg'' is passed through ''String.format(..., price)'' on several buy paths — include a ''%d'' where you want the gold amount echoed (same idea as the default string in ''S.keeperBuyMsg''). **8. Review and commit:** > @examine shop --- Shop --- MOBILE : 1210 ROOM : 1200 HOURS1 : 8 to 12 HOURS2 : 14 to 20 --- produces --- ... --- trades --- ... --- keeper has no item --- ... > @save shop Okay. > If ''@save'' returns a short error from ''Shopkeeper.check'', fix the field and save again — the draft stays open until save succeeds or you ''@clear shop''. Exact check strings include: ''no room is set''; ''no item types are set''; ''no customerNoItemMsg set'' (also returned when ''keeper_no_item_msg'' is missing — code quirk); ''no customerNoCashMsg set''; ''no keeperNoBuyMsg set''; ''no keeperBuyMsg set''; ''no keeperSellMsg set''; ''open time must be set''; ''producing vid: for 0gc''. ===== Place the keeper via a zone ===== Why: the shop row alone does not spawn the mobile. Zone reset loads the npc into a room; players then use ''list'' / ''buy'' / ''auction'' / … against that keeper ([[player:gamelaw:shopkeepers|Shopkeepers]]). > @load zone 1299 Okay. > @zone npc 1210 1200 Okay. > @examine zone > @save zone Okay. > zone reset Okay. > ===== ''@shop'' field commands ===== From ''ModifySocial.cmdCrShop'' (real subcommands only): * ''room '' — home / shop room (room must exist) * ''produces '' — produce slot 1–10 * ''trades (!)'' — types the keeper will handle * ''keeper_no_item_msg'' — one-line writer * ''customer_no_item_msg'' — one-line writer * ''customer_no_cash_msg'' — one-line writer * ''keeper_no_buy_msg'' — one-line writer * ''keeper_buy_msg'' — one-line writer (often with ''%d'') * ''keeper_sell_msg'' — one-line writer * ''hours1 '' — required window * ''hours2 '' — optional second window Workspace companions (same pattern as rooms/items): ''@new shop'', ''@examine shop'', ''@clear shop'', ''@save shop'', ''@load shop '', ''@destroy shop ''. ===== Edit an existing shop ===== > @load shop 1210 Okay. > @shop produces 1 3100 450 Okay. > @examine shop > @save shop Okay. > ===== Vs classic shop OLC ===== You never enter a numbered shop editor. There is no ''sedit''. You open a ''shop'' workspace on a **mobile VID**, set fields with ''@shop'', ''@examine'', ''@save''. Trade behavior also needs ''Acts.SHOPKEEPER'' on the mobile and a zone placement. ===== Common mistakes ===== * ''@new shop'' before the mobile prototype exists * Mobile without ''flags acts shopkeeper'' * Second ''@new shop'' while a shop draft is still open * ''@save shop'' without ''room'', trades, ''hours1'', or all six messages * Produce cost 0 on a filled slot * Building the shop but never ''@zone npc'' + ''zone reset'' * Expecting ''redit''-style menus — workspace only ===== Code notes / gaps ===== Documented as facts from the Java tree (not guesses): * Help-string typos: ''createNewShop'' usage prints ''@new show ''; bad ''produces'' args print ''@new shop produces …''; ''deleteShop'' usage prints ''@delete shop'' while the verb is ''@destroy''; ''@destroy'''s usage line **omits** ''shop'' even though the handler accepts it. * ''Shopkeeper.check'': when ''keeper_no_item_msg'' is missing it still returns ''no customerNoItemMsg set'' (copy/paste quirk). * ''hours2'' validation message says "ahead of the open1 finish-hour" but the comparison uses ''open1()'' (the start). * Runtime (quick scan of ''MobileScript''): ''trades'', ''produces''/''cost'', ''keeper_no_item_msg'', ''keeper_no_buy_msg'', and ''keeper_buy_msg'' are used. ''room'', ''hours1''/''hours2'', ''customer_no_item_msg'', ''customer_no_cash_msg'', and ''keeper_sell_msg'' are **required to save** and stored, but no call sites were found that gate trading on hours/room or speak those three messages — treat as save requirements / future hooks unless you prove otherwise in a later code pass. ===== Related ===== * [[immortal:creationlaw:mobiles|Mobiles]] — SHOPKEEPER act, npc layers * [[immortal:creationlaw:zones|Zones]] — place the keeper * [[immortal:creationlaw:objects|Objects]] / [[immortal:creationlaw:items|Items]] — produce VIDs * [[player:gamelaw:shopkeepers|Shopkeepers]] — player ''list'' / ''buy'' / ''auction'' / ''offer'' / ''value'' / ''identify'' * [[immortal:creationlaw|Creation Law]] — hub