{"id":"5e9a8cee19d464f5f0322518ac9ccaf2399c69da6572346b4fb12d36acb17a27","pubkey":"a8d1560d6a647d501699167246f237b36fb123f89168fda11dc743533fec7a08","created_at":1776875770,"kind":30817,"tags":[["d","nostrmon-decentralized-monster-taming-world-protocol"],["title","Nostrmon — Decentralized Monster-Taming World Protocol"],["k","30597"],["k","30259"],["k","38267"],["k","36011"],["k","35253"],["k","39951"],["client","nostrhub.io"]],"content":"# NIP-XX: Nostrmon — Decentralized Monster-Taming World Protocol\n\n`draft` `optional`\n\n## Abstract\n\nThis NIP defines a decentralized monster-taming game protocol on Nostr. \"Nostrmon\" (Nostr Monsters) is a framework inspired by games like Pokémon, where **regions**, **maps**, **Nostrmon creatures**, **NPCs**, and **game saves** are all Nostr addressable events. Anyone can create and publish content — regions, maps, creatures, or NPCs — and clients can assemble these events into a playable, traversable world.\n\n---\n\n## Event Kinds\n\n| Kind  | Name          | Description                                      |\n|-------|---------------|--------------------------------------------------|\n| 30597 | Region        | A named region containing references to maps     |\n| 30259 | Map           | A 2D grid-based map with layered tile data       |\n| 38267 | Nostrmon      | A Nostr Monster creature definition              |\n| 36011 | NPC           | A Non-Player Character (simple or AI-driven)     |\n| 35253 | Game Save     | A player's game progress snapshot                |\n| 39951 | Item          | A usable, holdable, or key item definition       |\n\n---\n\n## Kind 30597 — Region\n\nA **Region** is a named collection of maps that form a coherent geographical area. Each user may publish as many regions as they wish.\n\n### Tags\n\n| Tag        | Req. | Description                                                     |\n|------------|------|-----------------------------------------------------------------|\n| `d`        | ✓    | Unique identifier for the region (slug)                         |\n| `name`     | ✓    | Human-readable region name                                      |\n| `map`      | ✓    | One or more references to map events. Value: `naddr` of map     |\n| `entry`    |      | The `d` tag of the map that serves as the travel entry/exit point for this region |\n| `summary`  |      | Short description of the region                                 |\n| `image`    |      | URL of a banner or splash image for the region                  |\n| `music`    |      | `naddr` of a default music event (kind 36787) for the region    |\n| `t`        |      | Hashtags for discovery (e.g., `nostrmon`)                       |\n| `alt`      | ✓    | NIP-31 human-readable description: `\"Nostrmon region: <name>\"`  |\n\n### Example\n\n```json\n{\n  \"kind\": 30597,\n  \"content\": \"A vast volcanic region with ancient ruins and mysterious tunnels.\",\n  \"tags\": [\n    [\"d\", \"ashfire-region\"],\n    [\"name\", \"Ashfire Region\"],\n    [\"map\", \"naddr1...map1\"],\n    [\"map\", \"naddr1...map2\"],\n    [\"entry\", \"ashfire-gateway\"],\n    [\"summary\", \"A volcanic region full of fire-type Nostrmon.\"],\n    [\"image\", \"https://example.com/ashfire-banner.jpg\"],\n    [\"music\", \"naddr1...battletheme\"],\n    [\"t\", \"nostrmon\"],\n    [\"alt\", \"Nostrmon region: Ashfire Region\"]\n  ]\n}\n```\n\n---\n\n## Kind 30259 — Map\n\nA **Map** is a 2D, grid-based environment with up to 5 layers. Maps are the atomic playable unit of the world.\n\n### Tags\n\n| Tag          | Req. | Description                                                                 |\n|--------------|------|-----------------------------------------------------------------------------|\n| `d`          | ✓    | Unique identifier (slug) for the map                                        |\n| `name`       | ✓    | Human-readable map name                                                     |\n| `type`       | ✓    | Map type: `route`, `area`, `town`, `city`, `dungeon`, `house`               |\n| `width`      | ✓    | Map width in tiles (integer, as string)                                     |\n| `height`     | ✓    | Map height in tiles (integer, as string)                                    |\n| `region`     |      | `naddr` of the region this map belongs to. Absent = \"Unknown Region\"        |\n| `music`      |      | `naddr` of a music event (kind 36787) for this map                         |\n| `multiplayer`|      | `\"true\"` or `\"false\"`. Default: `\"false\"`                                   |\n| `prison`     |      | `\"true\"` or `\"false\"`. Default: `\"false\"`. Disables fast travel on map     |\n| `daynight`   |      | `\"true\"` or `\"false\"`. Whether day/night cycle is visible. Default: `\"true\"` |\n| `entry-map`  |      | `\"true\"` or `\"false\"`. Marks this map as the region's travel gateway. Entry maps can be linked to entry maps of other regions for cross-region warps. |\n| `fasttravel-x` |    | X tile coordinate where the player spawns when fast-traveling to this map (integer string). Default: `\"1\"` |\n| `fasttravel-y` |    | Y tile coordinate where the player spawns when fast-traveling to this map (integer string). Default: `\"1\"` |\n| `image`      |      | URL of a preview image for the map                                          |\n| `t`          |      | Tags for discovery, always include `nostrmon`                               |\n| `alt`        | ✓    | NIP-31 description: `\"Nostrmon map: <name>\"`                                |\n\n### Content\n\nThe `content` field is a JSON object with the following structure:\n\n```typescript\ninterface MapContent {\n  // Layer 1 (REQUIRED): Terrain layer\n  // 2D array [row][col] of terrain tile IDs (integers)\n  terrain: number[][];\n\n  // Layer 2 (REQUIRED): Interactive layer\n  // Sparse array of interactive objects keyed by \"x,y\"\n  interactive: Record<string, InteractiveObject>;\n\n  // Layer 3 (OPTIONAL): Height map for 3D rendering\n  // 2D array [row][col] of height values (0.0–1.0)\n  heightmap?: number[][];\n\n  // Layer 4 (OPTIONAL): Wild encounter zones\n  // Array of encounter zone definitions\n  encounters?: EncounterZone[];\n\n  // Layer 5 (OPTIONAL): Named zones\n  namedZones?: NamedZone[];\n}\n```\n\n### Terrain Tile IDs\n\nTerrain tile IDs are integers. Clients are responsible for rendering tilesets. Suggested standard tile IDs:\n\n| ID  | Type              | Category   | Passable | Notes                              |\n|-----|-------------------|------------|----------|------------------------------------|\n| 0   | Void/Empty        | Special    | No       | No tile                            |\n| 1   | Grass             | Outdoor    | Yes      | May trigger wild encounters        |\n| 2   | Tall Grass        | Outdoor    | Yes      | High encounter rate                |\n| 3   | Water             | Outdoor    | Surf     | Requires Surf ability              |\n| 4   | Deep Water        | Outdoor    | Surf     | Requires Dive ability              |\n| 5   | Sand              | Outdoor    | Yes      |                                    |\n| 6   | Snow              | Outdoor    | Yes      | May slow movement                  |\n| 7   | Ice               | Outdoor    | Yes      | Sliding movement                   |\n| 8   | Mountain          | Outdoor    | No       | Solid obstacle                     |\n| 9   | Rock              | Outdoor    | No       | Solid obstacle                     |\n| 10  | Tree              | Outdoor    | No       | Can be Cut                         |\n| 11  | Flower            | Outdoor    | Yes      |                                    |\n| 12  | Path/Road         | Outdoor    | Yes      |                                    |\n| 13  | Bridge            | Outdoor    | Yes      |                                    |\n| 14  | Cliff             | Outdoor    | No       | Can Surf below                     |\n| 15  | Cave Floor        | Indoor     | Yes      |                                    |\n| 16  | Cave Wall         | Indoor     | No       |                                    |\n| 17  | Cave Water        | Indoor     | Surf     |                                    |\n| 18  | Floor (Indoor)    | Indoor     | Yes      | Generic indoor floor               |\n| 19  | Wall (Indoor)     | Indoor     | No       |                                    |\n| 20  | Carpet            | Indoor     | Yes      |                                    |\n| 21  | Counter           | Indoor     | No       | Shop counter                       |\n| 22  | Bookshelf         | Indoor     | No       |                                    |\n| 23  | Lava              | Special    | No       | Damages player                     |\n| 24  | Pit               | Special    | Fall     | Player falls through               |\n| 25  | Warp Pad          | Special    | Yes      | Visual warp indicator              |\n| 26  | Tall Grass (Cave) | Indoor     | Yes      | Encounters in caves                |\n| 27  | Sand (Indoor)     | Indoor     | Yes      |                                    |\n| 28  | Swamp             | Outdoor    | Yes      | Slow movement, encounters          |\n| 29  | Roof/Overhang     | Overhead   | —        | Renders over player (z-layered)    |\n| 30  | Rail/Track        | Indoor     | Yes      |                                    |\n\n#### House Tiles (Outdoor)\n\nHouse tiles are used on outdoor maps to represent buildings the player can enter via warps.\n\n| ID  | Type                  | Category       | Passable | Notes                                      |\n|-----|-----------------------|----------------|----------|--------------------------------------------|\n| 31  | House Wall            | Outdoor/House  | No       | Generic exterior house wall                |\n| 32  | House Roof            | Outdoor/House  | No       | Roof tile; renders above player level      |\n| 33  | House Door            | Outdoor/House  | Warp     | Entrance/exit point; triggers warp action  |\n| 34  | House Window          | Outdoor/House  | No       | Decorative; may show light at night        |\n| 35  | House Chimney         | Outdoor/House  | No       | Decorative chimney top                     |\n| 36  | House Foundation      | Outdoor/House  | No       | Base/step of a building                    |\n| 37  | Shop Awning           | Outdoor/House  | No       | Overhead awning above shop doorways        |\n| 38  | House Roof (Peaked)   | Outdoor/House  | No       | Peaked/angled roof section                 |\n\n#### Fence & Wall Tiles (Special — Outdoor or Indoor)\n\nFence and wall tiles are traversal obstacles. They can appear in both outdoor and indoor settings.\n\n| ID  | Type              | Category          | Passable | Notes                                          |\n|-----|-------------------|-------------------|----------|------------------------------------------------|\n| 40  | Wooden Fence      | Special/Fence     | No       | Common outdoor low fence; can be jumped over   |\n| 41  | Stone Wall (Ext.) | Special/Fence     | No       | Exterior stone boundary wall                   |\n| 42  | Iron Fence        | Special/Fence     | No       | Metal fence; urban/city areas                  |\n| 43  | Hedge             | Special/Fence     | No       | Living plant fence; can be Cut                 |\n| 44  | Picket Fence      | Special/Fence     | No       | Decorative short fence; used near houses       |\n| 45  | Low Wall          | Special/Fence     | No       | Short interior divider; indoor and outdoor     |\n| 46  | Barricade         | Special/Fence     | No       | Temporary blockade; can be conditional         |\n| 47  | Corner Wall       | Special/Wall      | No       | 90° corner wall piece for interiors            |\n| 48  | Pillar            | Special/Wall      | No       | Decorative or structural column; indoor/outdoor|\n| 49  | Fence Gate        | Special/Fence     | Cond.    | Passable only when a condition is met          |\n| 50  | Cave Fence        | Special/Fence     | No       | Fence type suited for cave environments        |\n| 51  | Fence Post        | Special/Fence     | No       | Single post; connects fence segments           |\n\nClients may extend this list with custom tile IDs above 100.\n\n### Interactive Object Types\n\n```typescript\ninterface InteractiveObject {\n  type: \"npc\" | \"sign\" | \"warp\" | \"item\" | \"trigger\";\n\n  // For type \"npc\"\n  npc?: string;         // naddr of the NPC event (kind 36011)\n  facing?: \"up\" | \"down\" | \"left\" | \"right\";\n\n  // For type \"sign\"\n  text?: string;        // Text content shown when examined\n\n  // For type \"warp\"\n  // Target map reference. Resolution order:\n  //   1. Full naddr (naddr1…) — unambiguous, preferred for cross-user warps\n  //   2. d-tag slug — resolved against the same author's maps first, then globally\n  target?: string;\n  // Tile coordinates on the target map where the player arrives.\n  // If omitted, the target map's fasttravel-x/fasttravel-y tags are used as fallback.\n  targetX?: number;\n  targetY?: number;\n  direction?: \"both\" | \"one-way\"; // Default: \"both\"\n  condition?: string;   // Script condition (see Script System)\n  visible?: boolean | string; // true/false or script expression\n\n  // For type \"item\"\n  item?: string;        // Item identifier\n  condition?: string;   // Script condition (only show/take if met)\n\n  // For type \"trigger\"\n  script?: string;      // Script executed when player steps on tile\n  triggerOn?: \"step\" | \"action\"; // Default: \"step\"\n}\n```\n\n### Encounter Zone\n\n```typescript\ninterface EncounterZone {\n  // Tiles included in this zone, as array of \"x,y\" coordinates\n  // OR a rect: [x, y, width, height]\n  tiles?: string[];\n  rect?: [number, number, number, number];\n\n  // Encounter rate: 0.0–1.0\n  rate: number;\n\n  // Nostrmon that can appear here\n  nostrmon: EncounterEntry[];\n}\n\ninterface EncounterEntry {\n  // naddr of the Nostrmon event (kind 38267), or its d-tag\n  ref: string;\n\n  // Level range\n  minLevel: number;\n  maxLevel: number;\n\n  // Relative rarity weight (default: 1)\n  weight?: number;\n\n  // Which form index to use (default: 0)\n  formIndex?: number;\n}\n```\n\n### Named Zone\n\n```typescript\ninterface NamedZone {\n  name: string;\n  // Zone type for minimap: \"area\", \"town\", \"city\", \"dungeon\"\n  type: \"area\" | \"town\" | \"city\" | \"dungeon\";\n  // Rectangle: [x, y, width, height] in tiles\n  rect: [number, number, number, number];\n  // Optional hex color for minimap rendering\n  color?: string;\n}\n```\n\n### Script System\n\nThe interactive layer supports a simple scripting language for conditions and triggers. Scripts are plain strings using a minimal expression syntax:\n\n```\n# Variables (set/check flags)\nSET flag_name\nUNSET flag_name\nHAS flag_name         # Check if flag is set\nNOT HAS flag_name\n\n# Item checks\nHAS_ITEM item_id\nNOT HAS_ITEM item_id\nGIVE_ITEM item_id\n\n# Badge/Achievement checks\nHAS_BADGE badge_id\n\n# Dialogue\nSAY \"Line 1\" \"Line 2\" \"Line 3\"\nSAY_CONDITIONAL HAS flag_name \"You already did this.\" \"You haven't done this yet.\"\n\n# Choice boxes\nCHOICE \"Option A\" \"Option B\"\nON_CHOICE 0 SET chose_a\nON_CHOICE 1 SET chose_b\n\n# Warp\nWARP naddr_or_dtag x y\n\n# Battle\nBATTLE naddr_npc\nBATTLE_WILD naddr_nostrmon level\n\n# Control flow\nIF HAS flag_name THEN ... END\n```\n\n---\n\n## Kind 38267 — Nostrmon\n\nA **Nostrmon** is an addressable event defining a creature species, including its stats, types, moves, and sprites.\n\n### Tags\n\n| Tag       | Req. | Description                                                     |\n|-----------|------|-----------------------------------------------------------------|\n| `d`       | ✓    | Unique species identifier (slug, e.g. `flamewulf`)              |\n| `name`    | ✓    | Species name                                                    |\n| `type`    | ✓    | One, two, or three types (repeat tag). e.g. `[\"type\", \"fire\"]`  |\n| `sprite`  | ✓    | URL of the front sprite image                                   |\n| `backsprite` |   | URL of the back sprite (for battle screen)                      |\n| `model3d` |      | URL of a 3D model file (glTF/glb) for 3D clients               |\n| `hp`      | ✓    | Base HP stat (integer string)                                   |\n| `atk`     | ✓    | Base Attack stat                                                |\n| `def`     | ✓    | Base Defense stat                                               |\n| `spatk`   | ✓    | Base Special Attack stat                                        |\n| `spdef`   | ✓    | Base Special Defense stat                                       |\n| `spd`     | ✓    | Base Speed stat                                                 |\n| `move`    | ✓    | Learnable move. Format: `[\"move\", \"move-id\", \"learn-method\", \"level-or-condition\"]` |\n| `t`       |      | `nostrmon` and any other tags                                   |\n| `alt`     | ✓    | NIP-31 description: `\"Nostrmon creature: <name>\"`               |\n\n### Content\n\nThe `content` field is a JSON object:\n\n```typescript\ninterface NostrmonContent {\n  // Flavor text / Pokédex-style description\n  description?: string;\n\n  // Forms (if more than one form exists)\n  forms?: NostrmonForm[];\n}\n\ninterface NostrmonForm {\n  name: string;           // Form name (e.g., \"Mega\", \"Shiny\", \"Winter\")\n  sprite: string;         // Front sprite URL for this form\n  backsprite?: string;    // Back sprite URL for this form\n  model3d?: string;       // 3D model URL for this form\n  types?: string[];       // Override types for this form\n  // Override stats (omitted = use base stats)\n  hp?: number;\n  atk?: number;\n  def?: number;\n  spatk?: number;\n  spdef?: number;\n  spd?: number;\n}\n```\n\n### Move Learn Methods\n\nThe `move` tag's learn method field accepts:\n\n| Method     | Description                                       |\n|------------|---------------------------------------------------|\n| `level`    | Learned at the given level number                 |\n| `tm`       | Taught via Technical Machine item                 |\n| `egg`      | Learned via breeding (egg move)                   |\n| `tutor`    | Taught by a move tutor NPC                        |\n| `evolution`| Learned upon evolution                            |\n\n### Types\n\nStandard Nostrmon types (clients may define custom types):\n\n`normal`, `fire`, `water`, `electric`, `grass`, `ice`, `fighting`, `poison`, `ground`, `flying`, `psychic`, `bug`, `rock`, `ghost`, `dragon`, `dark`, `steel`, `fairy`, `cosmic`, `digital`, `sound`, `nature`\n\n### Example\n\n```json\n{\n  \"kind\": 38267,\n  \"content\": \"{\\\"description\\\":\\\"A canine Nostrmon wreathed in spectral flame. It is said to guard the gates of forgotten servers.\\\",\\\"forms\\\":[]}\",\n  \"tags\": [\n    [\"d\", \"flamewulf\"],\n    [\"name\", \"Flamewulf\"],\n    [\"type\", \"fire\"],\n    [\"type\", \"ghost\"],\n    [\"sprite\", \"https://example.com/flamewulf-front.png\"],\n    [\"backsprite\", \"https://example.com/flamewulf-back.png\"],\n    [\"hp\", \"75\"],\n    [\"atk\", \"90\"],\n    [\"def\", \"60\"],\n    [\"spatk\", \"85\"],\n    [\"spdef\", \"65\"],\n    [\"spd\", \"100\"],\n    [\"move\", \"ember\", \"level\", \"5\"],\n    [\"move\", \"shadow-ball\", \"level\", \"30\"],\n    [\"move\", \"flamethrower\", \"tm\", \"\"],\n    [\"t\", \"nostrmon\"],\n    [\"alt\", \"Nostrmon creature: Flamewulf\"]\n  ]\n}\n```\n\n---\n\n## Kind 36011 — NPC\n\nAn **NPC** (Non-Player Character) is a character that can be placed on maps. NPCs come in two varieties: **Simple** (scripted dialogue) and **AI** (language model driven).\n\n### Tags\n\n| Tag         | Req. | Description                                                            |\n|-------------|------|------------------------------------------------------------------------|\n| `d`         | ✓    | Unique NPC identifier (slug)                                           |\n| `name`      | ✓    | NPC display name                                                       |\n| `npc-type`  | ✓    | `\"simple\"` or `\"ai\"`                                                   |\n| `sprite`    | ✓    | URL of the NPC's sprite image                                          |\n| `nostrmon`  |      | `naddr` of a Nostrmon. Repeat for multiple Nostrmon (used in battles)  |\n| `nostrmon-level` |   | Level for each Nostrmon (paired by index with `nostrmon` tags)         |\n| `trainer-class` |    | Trainer class string (e.g., `\"Bug Catcher\"`, `\"Gym Leader\"`)          |\n| `battle-music` |     | `naddr` of a music event for the battle against this NPC               |\n| `t`         |      | `nostrmon` and discovery tags                                          |\n| `alt`       | ✓    | NIP-31 description: `\"Nostrmon NPC: <name>\"`                           |\n\n### Content\n\nThe `content` field is a JSON object:\n\n```typescript\ninterface NPCContent {\n  // Scripted dialogue (required for simple NPCs, used as fallback for AI NPCs)\n  dialogue: string[];\n\n  // Choice-based dialogue branches (optional)\n  choices?: NPCChoice[];\n\n  // For AI NPCs only\n  ai?: {\n    // Describe the NPC's knowledge, backstory, and behavior in natural language\n    knowledge: string;\n    // NPC personality and behavior description\n    behavior: string;\n    // Preferred languages (English always required)\n    languages?: string[];\n    // Additional freeform properties\n    notes?: string;\n  };\n}\n\ninterface NPCChoice {\n  prompt: string;           // The player's choice text\n  response: string[];       // NPC response dialogue\n  condition?: string;       // Script condition to show this choice\n  effect?: string;          // Script effect when chosen\n}\n```\n\n### Example (Simple NPC)\n\n```json\n{\n  \"kind\": 36011,\n  \"content\": \"{\\\"dialogue\\\":[\\\"Greetings, traveler!\\\",\\\"The Ashfire Caves to the east are dangerous.\\\",\\\"Make sure your Nostrmon are well rested before you go!\\\"]}\",\n  \"tags\": [\n    [\"d\", \"old-hermit-ashfire\"],\n    [\"name\", \"Old Hermit\"],\n    [\"npc-type\", \"simple\"],\n    [\"sprite\", \"https://example.com/hermit-sprite.png\"],\n    [\"t\", \"nostrmon\"],\n    [\"alt\", \"Nostrmon NPC: Old Hermit\"]\n  ]\n}\n```\n\n### Example (AI NPC)\n\n```json\n{\n  \"kind\": 36011,\n  \"content\": \"{\\\"dialogue\\\":[\\\"Hello! I'm Professor Nakamoto. I study Nostrmon across the decentralized world.\\\"],\\\"ai\\\":{\\\"knowledge\\\":\\\"Expert on Nostrmon biology, types, and habitats. Knows all maps in Ashfire Region.\\\",\\\"behavior\\\":\\\"Friendly and enthusiastic. Loves giving hints. Never breaks character.\\\",\\\"languages\\\":[\\\"English\\\",\\\"Japanese\\\"],\\\"notes\\\":\\\"Occasionally quotes Satoshi Nakamoto philosophically.\\\"}}\",\n  \"tags\": [\n    [\"d\", \"professor-nakamoto\"],\n    [\"name\", \"Prof. Nakamoto\"],\n    [\"npc-type\", \"ai\"],\n    [\"sprite\", \"https://example.com/professor-sprite.png\"],\n    [\"t\", \"nostrmon\"],\n    [\"alt\", \"Nostrmon NPC: Prof. Nakamoto\"]\n  ]\n}\n```\n\n---\n\n## Kind 35253 — Game Save\n\nA **Game Save** records a player's progress. It is a replaceable event per `d` tag, allowing players to maintain named save slots. Players may also export/import saves locally.\n\n### Tags\n\n| Tag         | Req. | Description                                                       |\n|-------------|------|-------------------------------------------------------------------|\n| `d`         | ✓    | Save slot identifier (e.g., `\"save-1\"`)                           |\n| `save-name` |      | Human-readable save name                                          |\n| `region`    |      | `naddr` of the current region                                     |\n| `map`       |      | `d` tag of the current map                                        |\n| `playtime`  |      | Total playtime in seconds (integer string)                        |\n| `version`   | ✓    | Protocol version of this save format (e.g., `\"1\"`)               |\n| `alt`       | ✓    | NIP-31 description: `\"Nostrmon game save\"`                        |\n\n### Content\n\nThe `content` field is **NIP-44 encrypted** to the player's own pubkey and contains the full game state as JSON:\n\n```typescript\ninterface GameSaveContent {\n  // Player info\n  playerName: string;\n  badges: string[];           // Badge IDs earned\n\n  // Current position\n  currentMap: string;         // d-tag of current map\n  currentRegion?: string;     // naddr of current region\n  positionX: number;\n  positionY: number;\n\n  // Active team (up to 6 Nostrmon)\n  team: OwnedNostrmon[];\n\n  // PC Storage boxes\n  storage: OwnedNostrmon[][];\n\n  // Inventory\n  inventory: Record<string, number>; // item_id -> quantity\n\n  // World flags (script system state)\n  flags: Record<string, boolean>;\n\n  // Completed NPC battles\n  defeatedTrainers: string[]; // NPC d-tags\n\n  // Timestamps\n  savedAt: number;\n  startedAt: number;\n}\n\ninterface OwnedNostrmon {\n  speciesRef: string;    // naddr or d-tag of species (kind 38267)\n  nickname?: string;\n  level: number;\n  experience: number;\n  formIndex: number;     // Current form (default: 0)\n  hp: number;            // Current HP\n  moves: string[];       // Up to 4 move IDs currently equipped\n  learnedMoves: string[];// All moves ever learned\n  // Individual Values (genetic variation, 0-31 per stat)\n  ivs: { hp: number; atk: number; def: number; spatk: number; spdef: number; spd: number; };\n  // Effort Values (training gains)\n  evs: { hp: number; atk: number; def: number; spatk: number; spdef: number; spd: number; };\n  // Personality traits (affect stat calculations)\n  nature: string;\n  caughtAt: number;      // Unix timestamp\n  caughtMap?: string;    // d-tag of map where caught\n}\n```\n\n---\n\n## Kind 39951 — Item\n\nAn **Item** is an addressable event defining a usable, holdable, or key item that can be found in the world, bought in shops, or given by NPCs. Items from any author can be referenced.\n\n### Tags\n\n| Tag         | Req. | Description                                                              |\n|-------------|------|--------------------------------------------------------------------------|\n| `d`         | ✓    | Unique item identifier (slug, e.g. `potion`, `escape-rope`)              |\n| `name`      | ✓    | Human-readable item name                                                 |\n| `item-type` | ✓    | Category: `consumable`, `hold`, `key`, `tm`, `ball`, `badge`, `misc`     |\n| `sprite`    |      | URL of the item's icon/sprite image                                      |\n| `price`     |      | Default shop buy price in gold (integer string). `\"0\"` = not for sale    |\n| `sell-price`|      | Default sell price (integer string). Omit = half of `price`              |\n| `single-use`|      | `\"true\"` if consumed on use. Default: `\"true\"` for consumables           |\n| `holdable`  |      | `\"true\"` if a Nostrmon can hold this item in battle                      |\n| `t`         |      | `nostrmon` and any additional tags                                       |\n| `alt`       | ✓    | NIP-31 description: `\"Nostrmon item: <name>\"`                            |\n\n### Content\n\nThe `content` field is a JSON object:\n\n```typescript\ninterface ItemContent {\n  // Description shown in the bag/item screen\n  description: string;\n\n  // What happens when this item is used (plain-text script or freeform description)\n  // Clients interpret this to apply effects. Common effect keywords:\n  //   HEAL_HP <amount>          — restore HP to one Nostrmon\n  //   HEAL_HP_ALL <amount>      — restore HP to all team Nostrmon\n  //   HEAL_STATUS               — cure a status condition\n  //   REVIVE                    — revive a fainted Nostrmon to half HP\n  //   REVIVE_FULL               — revive to full HP\n  //   CATCH_RATE <multiplier>   — ball catch-rate multiplier (for ball items)\n  //   TEACH_MOVE <move-id>      — teach a move (for TM items)\n  //   WARP_ESCAPE               — escape from a dungeon to last town\n  //   BADGE <badge-id>          — grants a badge (for badge items)\n  effect?: string;\n}\n```\n\n### Item Categories\n\n| Category    | Description                                                            |\n|-------------|------------------------------------------------------------------------|\n| `consumable`| Used from the bag; disappears after use (e.g. Potion, Antidote)       |\n| `hold`      | Held by a Nostrmon during battle for passive effects                   |\n| `key`       | Key item; never consumed; triggers world events or opens warps         |\n| `tm`        | Technical Machine; teaches a move to a compatible Nostrmon             |\n| `ball`      | Used in battle to catch wild Nostrmon; has a `CATCH_RATE` multiplier   |\n| `badge`     | Proof of a gym/trainer victory; unlocks abilities or areas             |\n| `misc`      | Miscellaneous item with no standard category                           |\n\n### Example\n\n```json\n{\n  \"kind\": 39951,\n  \"content\": \"{\\\"description\\\":\\\"Restores 20 HP to a single Nostrmon.\\\",\\\"effect\\\":\\\"HEAL_HP 20\\\"}\",\n  \"tags\": [\n    [\"d\", \"potion\"],\n    [\"name\", \"Potion\"],\n    [\"item-type\", \"consumable\"],\n    [\"sprite\", \"https://example.com/items/potion.png\"],\n    [\"price\", \"300\"],\n    [\"sell-price\", \"150\"],\n    [\"single-use\", \"true\"],\n    [\"holdable\", \"false\"],\n    [\"t\", \"nostrmon\"],\n    [\"alt\", \"Nostrmon item: Potion\"]\n  ]\n}\n```\n\n---\n\n## Querying Content\n\n### Discover all Nostrmon (any author)\n\n```json\n[{ \"kinds\": [38267], \"#t\": [\"nostrmon\"], \"limit\": 50 }]\n```\n\n### Discover all regions (any author)\n\n```json\n[{ \"kinds\": [30597], \"#t\": [\"nostrmon\"], \"limit\": 50 }]\n```\n\n### Get a specific NPC by author and d-tag\n\n```json\n[{ \"kinds\": [36011], \"authors\": [\"<pubkey>\"], \"#d\": [\"old-hermit-ashfire\"] }]\n```\n\n### Discover all items (any author)\n\n```json\n[{ \"kinds\": [39951], \"#t\": [\"nostrmon\"], \"limit\": 100 }]\n```\n\n### Get all maps in a region (by region naddr reference)\n\nMaps reference their region via the `region` tag. Clients should query maps and filter by region reference client-side, or use a relay that supports tag filtering.\n\n---\n\n## Battle Rules\n\n### Wild Battles\n\n- A wild encounter is triggered when the player steps on a tile inside an encounter zone, according to the zone's `rate` (0–1).\n- **Auto-catch rule**: Wild Nostrmon at **level 1–5** are caught automatically at **100% success rate** with no battle required. This ensures new players always get their first Nostrmon.\n- If the player has no Nostrmon in their team, wild encounters at any level trigger auto-catch instead of a battle.\n- For wild Nostrmon above level 5, a full battle takes place. The player may fight, use items, switch Nostrmon, or attempt to flee.\n- **Catching** requires a ball item. Catch rate = `0.3 + (1 − currentHpRatio) × 0.7` modified by the ball's `CATCH_RATE` multiplier.\n- The player can flee from any wild battle without penalty.\n\n### Trainer Battles\n\n- NPCs with one or more `nostrmon` tags initiate trainer battles when the player interacts with them.\n- The player **cannot** catch the Nostrmon of another trainer.\n- The player **cannot** flee a trainer battle.\n- Defeating a trainer stores their `d`-tag in `defeatedTrainers` in the save. Re-interacting with a defeated trainer shows fallback dialogue instead of battle.\n- Trainer battle music uses the NPC's `battle-music` tag if set, otherwise the region's default battle theme.\n\n### Stat & Damage Calculation\n\n- Stats use the standard formula: `floor((2×base + IV + floor(EV/4)) × level / 100) + 5` (or `+level+10` for HP)\n- IVs: random 0–31 per stat, generated at catch/receive time\n- EVs: start at 0, gained from defeating Nostrmon\n- Natures: 25 natures, each raises one stat by 10% and lowers another (or neutral)\n- Level-up: cubic XP formula `XP_needed = (level+1)³ − level³`\n\n### XP & Levelling\n\n- Clients MUST award XP to the active Nostrmon after defeating or catching a wild Nostrmon\n- XP reward: `floor((sum_of_base_stats × enemy_level) / 7)`\n- When a Nostrmon's XP exceeds the threshold, it levels up and its stats recalculate\n- Clients SHOULD check for move learning on level-up (from the species `move` tags with `learn-method: level`)\n\n---\n\n## Multiplayer Presence\n\nOn maps with `multiplayer: \"true\"`, clients SHOULD broadcast the player's position using **ephemeral kind 20001** events (\"Presence Events\").\n\n### Kind 20001 — Presence Event (Ephemeral)\n\n| Field | Value |\n|-------|-------|\n| `kind` | `20001` |\n| `content` | JSON: `{\"x\": <tile_x>, \"y\": <tile_y>, \"name\": \"<display_name>\"}` |\n| `tags` | `[\"d\", \"<map_d_tag>\"]`, `[\"expiration\", \"<unix_timestamp+30>\"]` |\n\n- Clients broadcast their position every ~5 seconds while on a multiplayer map\n- Clients subscribe to kind 20001 events filtered by the current map's `d` tag\n- Players not seen for 20+ seconds should be removed from the display\n- Other players are shown as coloured dots or avatars on the map\n- Position data is **not saved** — it is purely ephemeral\n\n---\n\n## Client Requirements\n\n### MUST\n\n- Clients MUST be able to render and play maps using terrain and interactive layers\n- Clients MUST support Nostrmon battles (wild and trainer)\n- Clients MUST auto-catch wild Nostrmon at level 1–5 at 100% rate without battle\n- Clients MUST prevent catching in trainer battles\n- Clients MUST prevent fleeing in trainer battles\n- Clients MUST support game saves (kind 35253) with NIP-44 encryption\n- Clients MUST persist saves locally (e.g. localStorage) in addition to Nostr\n- Clients MUST treat maps without a `region` tag as belonging to \"Unknown Region\"\n- Clients MUST use `fasttravel-x` / `fasttravel-y` as the spawn position when fast-traveling to a map\n- Clients MUST NOT allow fast-traveling to a map with `prison: \"true\"` unless it belongs to the current user\n- Clients MUST implement an in-game menu with at minimum: team management, bag/inventory, save game\n\n### SHOULD\n\n- Clients SHOULD render a minimap for regions with map type-appropriate icons\n- Clients SHOULD support keyboard navigation and touch controls on mobile\n- Clients SHOULD support gamepad/controller input\n- Clients SHOULD render day/night cycles for maps where `daynight` is `\"true\"`\n- Clients SHOULD handle AI NPCs with configurable AI provider/model\n- Clients SHOULD list entry maps (`entry-map: \"true\"`) from all authors for cross-region warp selection\n- Clients SHOULD broadcast and receive presence events on multiplayer maps (kind 20001)\n- Clients SHOULD show PC box storage for Nostrmon overflow management\n\n### MAY\n\n- Clients MAY render maps in 2.5D or 3D using the height map layer\n- Clients MAY provide editors for regions, maps, Nostrmon, NPCs, and items\n- Clients MAY support custom tilesets beyond the standard tile IDs\n- Clients MAY support NPC shops (using item `price` tags for buy/sell)\n- Clients MAY implement Nostrmon trading between players on multiplayer maps\n\n---\n\n## Interoperability Notes\n\n- All creature references use `naddr` (kind 38267) or the `d` tag — clients should support both\n- Map warps referencing other users' maps are valid and encouraged for cross-region travel\n- Nostrmon from any author may be referenced in encounter zones\n- Music references use kind 36787 (Nostr Music events)\n- The `t: nostrmon` tag is used for all discovery queries — clients SHOULD include it on all published events\n\n---\n\n*This NIP was authored as part of the Nostrmon World client. Feedback welcome.*","sig":"a05e672bebb9da149e8af39383a855233f08c95c0caf7fe4d99df0f016cc197914034f3b50273a4bd29dd66ff02d2df1b55f818f96fa1a38e02204f162f2f00d"}