diff options
| author | workhorse <workhorse@localhost.localdomain> | 2026-06-19 20:24:52 -0400 |
|---|---|---|
| committer | workhorse <workhorse@localhost.localdomain> | 2026-06-19 20:24:52 -0400 |
| commit | 8ee8982b8759bcae116647cc993867f4c8b0a6ce (patch) | |
| tree | ee01f7b1d745cbc94d9981108a1209527487b3e5 | |
| parent | 2bec24859af8f03c80a0a58e3240519942450167 (diff) | |
| download | thehouseoficarus-8ee8982b8759bcae116647cc993867f4c8b0a6ce.tar.gz | |
reorganized items, objects, and rooms in directories. oranized module names. added startup checks.
1048 files changed, 7145 insertions, 6324 deletions
@@ -7,87 +7,52 @@ Set on a terraformed asteroid where technology has regressed. "Technology" repla ## Build & Run ```bash -make build # go build -o tc ./cmd/mud +make build # go build -o thoi ./cmd/mud make run # build + run with DATA_DIR=./data -make test # go test ./... -timeout 60s +make test # DATA_DIR=$(PWD)/data go test ./... -timeout 60s make vet # go vet ./... ``` -Binary accepts `--config <path>` (defaults to `config.yaml`). If no config found, starts telnet on :4000. +Binary accepts `--config <path>` (defaults to `config.yaml`). If no config found it creates one with defaults (telnet :4000, http :8888, tick 600ms). Dependencies: `gopkg.in/yaml.v3`, `github.com/gorilla/websocket`. -Config: -```yaml -game: - tick_length: 600 # ms per game tick (default 600, min 50) -``` - ## Package Map ``` -cmd/mud/main.go Entry point — config loading, multi-listener, tick engine +cmd/mud/main.go Entry point — config loading, multi-listener, tick subscriber registration internal/ - config/ YAML config (telnet, http, https listeners) - net/ Conn interface (tcp + websocket), session states, hub, IAC echo - game/ Login flow, command dispatch, input sanitization, all game logic - action/ Behavior structs (GatherConfig, TalkConfig, etc.), Action, drop tables, SuccessChance - player/ Player struct, skills, inventory, XP (RSC table), name/password validation, accounts - world/ Room, MobDef, MobInstance, ObjState, ground items, wandering, drop tables - combat/ Combat state tracking, OSRS-style combat formulas - object/ ItemDef, ObjectDef, item/object YAML loaders, EquipSlot, WeaponType, ItemStats + config/ YAML config (telnet, telnet_tls, http, https listeners, color targets) + net/ Conn interface (tcpConn, wsConn), Hub, Session, session states, IAC echo + game/ Game struct, HandleSession state machine, command registry, all game logic + hacking/ Minigame interface + 3 implementations (Wumpus, Mastermind, Liar's Dice) + action/ Behavior structs (GatherConfig, TalkConfig, UseConfig), RecipeStore, SuccessChance + player/ Player struct, skills, inventory, bank, equipment, accounts, XP, validation + world/ World, RoomDef, MobDef, MobInstance, ObjState, ground items, wandering + combat/ Combat state tracking, OSRS-style formulas (HitChance, MaxHit, AttackRoll) + object/ ItemDef, ObjectDef, ItemStore, ObjectStore, EquipSlot, WeaponType, ItemStats engine/ Tick scheduler — configurable ms interval, subscriber pattern, ToTicks() - color/ xterm-256 color system with auto ANSI downgrade, numeric palette (0-255), gradients, inline tags + color/ xterm-256 color system with auto ANSI downgrade, gradients, inline tags ``` -`internal/game/` is the largest package. Key files: +`internal/game/` is organized by file name prefix for easy navigation: -| File | Purpose | -|---|---| -| `game.go` | Game struct, HandleSession state machine, command dispatch, ProcessQueuedCommands | -| `login_account.go` | Account auth, creation, password handling, main menu, account rename/purge | -| `login_char.go` | Character creation, connection, rename, delete | -| `cmd_*.go` | Command handlers for each command (see Commands section) | -| `action.go` | StartAction, CancelAction, AdvanceActions, checkCondition, verbAliases, verbSkill | -| `action_*.go` | Action lifecycle per type (gather, talk, use, production) | -| `action_burn.go` | Burn/stoke firemaking (standalone, not behavior-YAML-driven) | -| `action_search.go` | Search bird's nests for loot | -| `action_room.go` | RunEnterSteps (on_enter scripts), BroadcastRespawns | -| `action_state.go` | ActionType consts, ActionState struct, Description() for look display | -| `action_default_target.go` | Smart auto-selection for gather/attack | -| `tick.go` | DisconnectTick, RegenTick, WanderTick, SharedDepletionTick, MoveTick, VisualTick, TechTick | -| `map.go` | BFS graph builder, tiny map, full map, display utilities (strip, trim) | -| `types.go` | EquipSlots, itemMatch, xpGain, deathDrop | -| `utils.go` | Helper functions (plural, parseQty, parseChoiceIndex, formatPickupList, etc.) | -| `help.go` | Help topic YAML loading and display | -| `color.go` | colorMode(), colorize(), colorTag() helpers | -| `table.go` | Unicode/ASCII table rendering for score/option/help/crafting menus | -| `tech.go` | TechDef struct, 25 hardcoded tech definitions, techLevelBonus, applyTechProtection, totalTechBonus | -| `cmd_tech.go` | doTech, toggleTech, doTechList, doTechQuick — technology command handlers | -| `cmd_stats.go` | doStats — equipment bonus totals, attack roll, max hit display | -| `cmd_clean.go` | doClean — background herb cleaning (Pharmacy) | -| `cmd_mix.go` | doMix — potion mixing via production system (Pharmacy) | -| `cmd_shop.go` | handleShopInput — buy/sell/browse/leave in shop interface | -| `action_steal.go` | doSteal, startSteal, advanceSteal — thieving action lifecycle | -| `cmd_sneak.go` | doSneak, SneakTick — sneak toggle + guard watch notifications | -| `action_clean.go` | advanceClean — background clean action lifecycle | -| `equip_stats.go` | playerEquipBonuses — sums all equipped items into one ItemStats | -| `aggro.go` | checkAggro — aggressive mob attack on room enter | -| `cmd_bank.go` | handleBankInput — deposit/withdraw/browse in bank interface | -| `cmd_construct.go` | doConstruct — construction production command at workbench | -| `cmd_estate_directory.go` | startEstateDirectory, lookEstateDirectory — player house directory, homeowner scanning, teleport | -| `course.go` | CourseStore, CourseConfig, ObstacleDef, ObstacleInfo — agility course YAML loader, room-to-obstacle lookup, obstacleVerbs | -| `cmd_agility.go` | doObstacle — agility obstacle command handler | -| `action_agility.go` | startObstacle, advanceObstacle, obstacleFail, calcFailChance — 3-phase obstacle lifecycle | -| `hacking.go` | HackingMinigame interface, HackingSession, terminalDefs, handleHackingInput, endHacking, hackingXP | -| `hacking_wumpus.go` | WumpusGame — Hunt the Rogue AI (20-node dodecahedron, probes, hazards) | -| `hacking_mastermind.go` | MastermindGame — Code Breaker (4-digit cipher, 10 guesses, feedback) | -| `hacking_liars_dice.go` | LiarsDiceGame — Signal Bluff (hidden dice bidding vs AI, wilds, exact calls) | -| `cmd_jack.go` | doJack, findTerminalInRoom — jack into terminals command handler | +| Prefix | Purpose | Count | +|---|---|---| +| `game.go`, `cmd_registry.go`, `tick.go` | Core state machine, command dispatch, tick callbacks | 3 | +| `core_*.go` | Infrastructure — types, utils, login, production engine, skill XP, flags, courses, equipment, stations, messages, startup validation | 13 | +| `action_*.go` | Tick-based action lifecycles — gather, firemaking, talk, use, search, thieving, farming, agility, scavenging, assassin, fletching, cleaning, room scripts, targeting | 16 | +| `cmd_*.go` | Command handlers — one file per command or command group | 49 | +| `sys_*.go` | Game subsystems — technology, science, combat (death + aggro), assassin tasks, buffs, construction | 6 | +| `ui_*.go` | Display/output — color, prompt, table, map, help | 5 | +| `hacking/` | Hacking sub-package — Minigame interface, TerminalDef, CalcXP, WumpusGame, MastermindGame, LiarsDiceGame | 4 | + +**To add a new command:** create `cmd_<name>.go` with the handler, add one line to `cmd_registry.go`. +**To add a new skill:** create `action_<skill>.go` with `start*`/`advance*` methods dispatched from `action.go`. ## Key Conventions -**YAML-driven.** Rooms, items, objects, mobs, behaviors, drops are YAML files under `data/`. Read from disk on every access — edit a room description and it takes effect immediately, no restart. +**YAML-driven.** Rooms, items, objects, mobs, drops, recipes, modules, courses are YAML files under `data/`. Read from disk on every access — edit and it takes effect immediately, no restart. Items, rooms, and recipes are organized into subdirectories by category (items: `equipment/`, `tools/`, etc.; rooms: `town/`, `wilderness/`, etc.; recipes: `smithing/`, `crafting/`, etc.). All IDs remain globally unique across subdirectories via path-indexed loading. **Live state.** Player data (characters, accounts) is written to YAML on every state change. Ground items, mob instances, and object states live in memory only and are lost on restart. @@ -95,11 +60,11 @@ internal/ **Transport-agnostic.** The `Conn` interface (`internal/net/conn.go`) abstracts the transport layer. `tcpConn` wraps a raw `net.Conn` for telnet. `wsConn` wraps `gorilla/websocket.Conn` for the web client. Game code works with `*Session` regardless of transport. -**Input sanitization.** `HandleSession` strips Unicode control characters from every input line via `player.StripControlCharacters` before dispatch. Account/character names validated to `[A-Za-z0-9 ]{1,30}`. Input truncated to 1024 bytes. Password echo suppressed via IAC ECHO (telnet) and OSC sequences (web). WebSocket origin checked against host header + loopback. +**Input sanitization.** `HandleSession` strips Unicode control characters from every input line via `player.StripControlCharacters`. Account/character names validated to `[A-Za-z0-9 ]{1,30}`. Input truncated to 1024 bytes. Password echo suppressed via IAC ECHO (telnet) and OSC sequences (web). WebSocket origin checked against host header + loopback. -**Tick-driven.** The world runs on a configurable tick (default 600ms). Combat, gathering, regen, wandering, respawns, shared depletion, fire ticks all advance per tick. +**Tick-driven.** The world runs on a configurable tick (default 600ms, min 50ms). All game advancement happens per tick. -**Fractional ticks.** All YAML timer fields (tool_speed, speed, base_wait, deplete_timer, etc.) accept `float64` values. `engine.ToTicks(base)` probabilistically rounds to an integer — a tool_speed of 4.5 means each action cycle has a 50% chance of 4 ticks and 50% of 5 ticks. +**Fractional ticks.** All YAML timer fields accept `float64` values. `engine.ToTicks(base)` probabilistically rounds to an integer — a tool_speed of 4.5 means each action cycle has a 50% chance of 4 ticks and 50% of 5 ticks. **Concurrency.** Every state-bearing package uses its own `sync.Mutex`: - `world.World` — groundItems, objStates, seeded, objMoves @@ -119,181 +84,163 @@ The pattern is: lock, snapshot/unmarshal, unlock, then process. The engine creat ## Data Files ``` -data/rooms/<id>.yaml Room definitions (exits, objects, mobs, spawns, on_enter) +data/rooms/<id>.yaml Room definitions (exits, objects, mobs, item_spawns, on_enter) +data/rooms/player_housing/ Player house rooms data/items/<id>.yaml Item definitions (stats, equip_slot, tool_type, burn_ticks, search_table, etc.) -data/mobs/<id>.yaml Mob definitions (combat stats, drops, behavior — NO wander config) -data/objects/<id>.yaml Object definitions (name, behavior, hidden, inroom_description, removal_item, props) -data/behaviors/<id>.yaml Behaviors (gather, talk, use) -data/drops/<id>.yaml Shared drop tables (weighted item lists) +data/mobs/<id>.yaml Mob definitions (combat stats, drops, behavior, steal config) +data/objects/<id>.yaml Object definitions (name, behavior, hidden, inroom_description, removal_item) +data/drops/<id>.yaml Shared drop tables (weighted item lists, sub-table references) data/help/<id>.yaml Help topics -data/recipes/<id>.yaml Recipe definitions (cooking, crafting, smithing, etc.) +data/recipes/<id>.yaml Recipe definitions (cooking, smithing, crafting, fletching, etc.) +data/modules/<id>.yaml Science module definitions (id, level, max_hit, base_xp, junk_cost, category) +data/courses/<id>.yaml Agility course definitions (name, required_level, start_room, obstacles) data/players/accounts/ Account YAML (gitignored) data/players/characters/ Character YAML (gitignored) ``` -Wander config (`wander_rooms`, `wander_interval`) is set per-instance in room YAML — mob defs are generic. Mobs wander via legal (unconditioned) room exits; objects teleport between rooms in their list. +Wander config (`wander_rooms`, `wander_interval`) is set per-instance in room YAML — mob defs are generic. Mobs wander via legal (unconditioned) room exits; objects teleport between rooms in their assigned list. See `worldbuilding_guide/` for full YAML format reference with examples. +## Startup Validation + +At startup, the server runs comprehensive integrity checks on all data files. Errors cause the server to exit; warnings are informational. + +**Duplicate ID checks** across all data directories (items, rooms, mobs, objects, drops, recipes, courses, modules, help). Detects collision from two files with the same ID in different subdirectories. + +**Referential integrity checks:** +- Room exits → target rooms exist +- Room mobs/objects/spawns → mob defs/object defs/items exist +- Mob drops, steal tables, finishing blow items → referenced items/drop tables exist +- Object removal items, steal tables, guard mobs, use_interaction items → exist +- Object gather config drops → items/tables exist; bait items exist +- Object talk config node actions (give_item, take_item, teleport, shop items) → exist +- Item search tables, made_from items/byproducts, farm_product → exist +- Recipe consume items, output, fail product → exist +- Drop table sub-references → exist +- Course start_room and obstacle rooms → exist + +**World wiring checks** (config-driven): +- Orphan rooms (no exit from any room leads to them) + +### Config: `startup_validation` + +```yaml +game: + tick_length: 600 + startup_validation: + check_sources: [1] # rooms to start reachability walk from + ignore_unreachable: [] # suppress "no exit leads here" for these rooms +``` + +Defaults: `check_sources: [1]`, ignore list empty. Set `check_sources` to include rooms accessible only via teleport (e.g., `[1, 1000]`) to suppress false orphan warnings. Use `ignore_unreachable_to` for rooms that are intentionally isolated. + ## Inline Color Tags -Room descriptions (and prompts) support inline color tags using `{spec}text{/}` syntax. Untagged text in room descriptions uses the `room_desc` color target. +Room descriptions and prompts support inline color tags using `{spec}text{/}` syntax. ```yaml description: "On the table lies a {182 bold}mysterious vase{/} with a rose in it." ``` -Tag spec format matches the color command: `{<0-255> [bold] [dim] [underline]}text{/}`. +Tag spec format: `{<0-255> [bold] [dim] [underline]}text{/}`. -Gradients are supported: `{g:196,82}gradient text{/}`. Multi-stop: `{g:45,39,59}three stops{/}`. +Gradients: `{g:196,82}gradient text{/}`. Multi-stop: `{g:45,39,59}three stops{/}`. Item and object YAML `color` fields also support gradient syntax: `color: "g:196,208,226"`. Gradients interpolate in RGB space across the xterm-256 palette. In ANSI mode, each character maps to the nearest ANSI color. -Item and object YAML `color` fields also support gradient syntax: `color: "g:196,208,226"`. - -## Commands - -### Instant (execute immediately, no queue) -| Command | Description | -|---------|-------------| -| `say <text>` | Room chat (preserves case from raw input) | -| `score` / `sc` | Character stats and skills | -| `inventory` / `i` / `inv` | Inventory contents (28 slots) | -| `equip` / `eq` / `equipment` / `wear` / `wield` | View or change equipped items (no args = view, with args = equip) | -| `look` / `l` | Room view (mobs, objects, ground items, exits, players) | -| `look <target>` / `l <target>` | Examine mobs, objects, items, players, directions | -| `exits` | List available exits | -| `help [topic]` | Help topics from data/help/ | -| `map` | BFS ASCII map centered on player | -| `option` / `options [name] [value]` | Account-wide settings (see Option System) | -| `alias <name> <cmd>` | Account-wide command alias with arg passthrough | -| `unalias <name>` | Remove an alias | -| `description` / `desc` | Set custom player description | -| `prompt <value>` | Set custom per-character command prompt | -| `queued` | Show pending tick actions | -| `color` / `colors [target] [value]` | Customize display colors (account-wide) | -| `color reset <target>` | Reset a color target to server default | -| `color <target> off` | Disable color for a specific target | -| `colortable` | Display xterm-256 color reference chart | -| `style <name>` | Set combat style: accurate, aggressive, defensive, balanced (prefix match) | -| `stats` | Show total equipment bonuses, attack type, attack roll, max hit | -| `tech [name]` / `t` | Toggle tech on/off, `tech list` shows all, `tech quick <name>` sets quick tech | - -### Free (stackable, execute before active) -| Command | Description | -|---------|-------------| -| `equip` / `wear` / `wield <item>` | Equip item to correct slot. `equip all` auto-equips best per slot | -| `remove` / `unwear` / `unwield <item>` | Unequip item back to inventory. `remove all` unequips everything | -| `eat <item>` | Eat food to heal (3-tick cooldown, can eat during combat) | -| `fletch [item]` | Fletch logs/items into bows, arrows, etc. (background action) | -| `clean [herb]` | Clean grimy herbs (background action, Pharmacy skill) | - -### Active (replaces previous active, queued per tick) -| Command | Description | -|---------|-------------| -| `n` / `s` / `e` / `w` / `u` / `d` | Movement (multi-tick, equipment-dependent speed, flee during combat) | -| `get` / `take` / `grab` / `pick <item>` | Pick up item from ground (reservation-aware) | -| `get all` / `get all <name>` | Pick up all (or matching) items | -| `drop <item>` | Drop item to ground | -| `drop all` / `drop all <name>` | Drop all (or matching) items | -| `attack` / `kill <mob>` | Combat with numbered targeting and smart default | -| `mine` / `chop` / `cut` / `fish <object>` | Gathering with smart default (verbAliases map to "gather") | -| `use <item> [on/with] <target>` | Universal item interaction: recipes, crafting, gathering shortcuts | -| `cook <item>` | Cook raw food on a fire or cooking range (Cooking skill) | -| `smelt [item]` | Smelt ore into bars at a furnace (Smithing skill) | -| `smith [item]` | Smith bars into items at an anvil with a hammer (Smithing skill) | -| `mix [item]` | Mix potions from unfinished potions and reagents (Pharmacy skill) | -| `talk` / `speak` / `ask <target>` | NPC conversations (objects or mobs with behavior) | -| `pull` / `push <object>` | Interact with objects (shortcut for use) | -| `search <item>` | Search bird's nests / searchable items (rolls on search_table) | -| `burn [item]` | Start a fire (smart default: auto-select single log type) | -| `stoke [item]` | Add logs to existing fire for XP | -| `walk <room_number>` | BFS pathfinding to a room by number | -| `walk <directions>` | Direction sequence like `3n2e1u` (capped by agility level) | -| `construct` / `make [item]` | Construction: make planks or furniture at a workbench (Active, production system) | -| `bank` / `use bank` | Open bank interface at a bank booth (deposit, withdraw, browse, leave) | -| `scramble` / `jump` / `swing` / `balance` / `climb` / `crawl` / `vault` / `leap` / `slide` | Agility obstacle verbs (Active, per-room validation) | -| `jack` / `jackin [terminal]` | Jack into a terminal for hacking minigames (Active) | -| `quit` | 10-tick rest sequence, then return to menu (blocked during combat) | - ## Command Dispatch -`handleGameCommand()` in `internal/game/game.go`: -1. Cancel rest timer -2. Resolve account aliases (alias expansion BEFORE command lookup — can shadow built-ins) -3. Classify command (Instant / Free / Active / Unknown) -4. Instant runs immediately; Free/Active queue for next tick +`handleGameCommand()` in `game.go`: +1. Expands account aliases (aliases can shadow built-in commands) +2. Splits input, lowercases the command word +3. Special-cases `equip`/`wear`/`wield` with no args → display equipment directly +4. Calls `classifyCommand(cmd)` from `cmd_registry.go` → `ClassInstant` / `ClassFree` / `ClassActive` / `ClassUnknown` +5. ClassInstant executes `executeCommand()` immediately + writes prompt +6. ClassFree appends to `freeQueue[playerName]` for next tick +7. ClassActive replaces entry in `activeQueue[playerName]`, sorted by timestamp on execution +8. ClassUnknown falls through to `verbAliases` and `obstacleVerbs` maps, then prints error ## Tick-Based Action Queue -`ProcessQueuedCommands` runs each tick: -1. Clears stale ActionState from one-tick actions (move, get, drop) +`ProcessQueuedCommands()` runs each tick: +1. Clears stale `ActionState` from one-tick actions (move, get, drop) 2. Executes all free commands per player in queued order 3. Executes all active commands sorted globally by timestamp (first-to-queue wins conflicts) 4. Advances walk sequences (one step per tick) 5. Flushes pending shared depletions -**Conflict resolution:** multi-player attack on same mob or get on same item — first to queue wins (timestamp-order). Shared depletion defers to award all successful gatherers on depletion tick. +**Conflict resolution:** multi-player attack on same mob, get on same item, etc. — first to queue wins (timestamp-order). Shared depletion awards all successful gatherers on depletion tick. -**ActionState** tracks player activity for `look` display. Timed actions (gather, combat, burn, stoke, use, rest, walk) persist until interrupted. One-tick actions (move, get, drop) clear after one tick. +**ActionState** tracks player activity for `look` display. Timed actions persist until interrupted; one-tick actions (move, get, drop) clear after one tick. -Queue feedback controlled by `queue_silently` option (default on). +Queue feedback is suppressed by default via the `queue_silently` option. ## Action System -Actions that interact with objects/mobs route through `StartAction()` in `action.go`: +Actions that interact with objects/mobs route through `startAction()` in `action.go`: 1. Normalizes verb via `verbAliases` map (mine/chop/fish/cut → gather, talk/speak/ask → talk) 2. Multiple object types → "That's ambiguous, which one?" 3. Searches object instances in room (numbered targeting via `N.name`) 4. Falls back to mob instances if no object matches 5. Loads the behavior from YAML -6. Routes to type-specific handler (startGather, startTalk, startUse) +6. Routes to type-specific handler (startGather, startMobTalk, startTalk, startUse) The `verbSkill` map maps verb → skill name for default target resolution: - mine → mining, chop/cut → woodcutting, fish → fishing -### Action Types +### Action Types (from action_state.go) -| ActionType | Trigger | Description | +| ActionType | Trigger | Type | |---|---|---| -| `gathering` | mine/chop/cut/fish | Resource gathering with skill checks, tool reqs, depletion | -| `combating` | attack/kill | Combat with attack/defense rolls | -| `using` | use | Crafting — consume items, produce output | -| `talking` | talk/speak/ask | NPC conversation trees with choices/conditions/actions | -| `burning` | burn | Firemaking startup (3 phases) | -| `stoking` | stoke | Adding logs to existing fire | -| `searching` | search | Search bird's nests / items with search_table | -| `resting` | quit | 10-tick rest before disconnect | -| `walking` | walk | Multi-step movement (one dir per tick) | -| `moving` | n/s/e/w/u/d | Multi-tick movement state | -| `picking_up` | get | One-tick pickup state | -| `dropping` | drop | One-tick drop state | -| `cooking` | cook | Cooking food on fire/range | -| `smelting` | smelt | Smelting ore into bars at furnace | -| `smithing` | smith | Smithing bars into items at anvil | -| `cleaning` | clean | Cleaning grimy herbs (background action) | -| `mixing` | mix | Mixing potions (Pharmacy) | -| `constructing` | construct/make | Construction via production system (workbench) | - -### Behavior Types (YAML-driven) - -| Type | Verbs | Use | +| `gathering` | mine/chop/cut/fish | Active | +| `combating` | attack/kill | Active | +| `using` | use / pull / push | Active | +| `talking` | talk/speak/ask | Active | +| `burning` | burn | Active | +| `stoking` | stoke | Active | +| `searching` | search | Active | +| `resting` | quit | Active | +| `walking` | walk | Active | +| `moving` | n/s/e/w/u/d | Active | +| `picking_up` | get | Active | +| `dropping` | drop | Active | +| `producing` | cook/smelt/smith/craft/mix/construct | Active | +| `fletching` | fletch | Free (background) | +| `eating` | eat | Free | +| `cleaning` | clean | Free (background) | +| `identifying` | identify/id | Active | +| `stealing` | steal/thieve | Active | +| `planting` | plant | Active | +| `harvesting_crop` | harvest | Active | +| `raking` | rake | Active | +| `watering` | water | Active | +| `curing` | cure | Active | +| `traversing` | obstacle verbs (scramble/jump/etc.) | Active | +| `hacking` | jack/jackin | Active | + +### Behavior Types (YAML-driven in behavior.go) + +| Type | Verbs | Description | |---|---|---| | `gather` | mine, chop, cut, fish | Resource gathering with skill checks, tool requirements, depletion/respawn | | `use` | use | Crafting stations — consume items, produce output, optional skill checks | -| `talk` | talk, speak, ask | NPC conversation trees with choices, conditions, actions | +| `talk` | talk, speak, ask | NPC conversation trees with choices, conditions, node actions | -### Behaviors Not in YAML (hardcoded) +### Hardcoded Actions (not YAML-driven) | Action | File | Description | |---|---|---| -| burn | `action_burn.go` | 3-phase firemaking: drop log → try burn → skill check → create fire object | -| stoke | `action_burn.go` | Add logs to fire, XP per log, increments fire quality | +| burn/stoke | `action_burn.go` | 3-phase firemaking: drop log → try → skill check → create fire. Stoke adds logs. | | search | `action_search.go` | Search items with search_table, consumes one, rolls on drop table | -| cook | `action_production.go` | Recipe-driven cooking on fire/range stations | -| smelt | `action_production.go` | Recipe-driven smelting of ore into bars at furnace | -| smith | `action_production.go` | Recipe-driven smithing of bars into items at anvil (requires hammer) | -| steal | `action_steal.go` | Thieving: pickpocket mobs, steal from objects, guard watching, sneak mode | +| cook/smelt/smith/craft/mix | `production_core.go` | Unified recipe-driven production — station checks, timed loops, success/fail, XP, byproducts | +| fletch | `action_fletch.go` | Background fletching — instant or timed, stackable output | +| clean | `action_clean.go` | Background herb cleaning via recipe matching | +| steal | `action_steal.go` | Thieving — pickpocket, stall stealing, guard watching, sneak mode | +| agility | `action_agility.go` | 3-phase obstacle traversal with fail chance, course lap tracking | +| farm | `action_farm.go` | Planting, growth stages (500-tick), watering, disease, harvesting | +| identify | `action_identify.go` | Scavenging — scrap_metal → junk at altars | +| finishing blow | `action_finishing_blow.go` | Assassin special item on mob at 1 HP | ### GatherConfig Fields @@ -305,7 +252,7 @@ The `verbSkill` map maps verb → skill name for default target resolution: | `base_wait` | Base ticks per action cycle | | `tools` | Required tool_type list | | `bait` | Required bait item | -| `success` | SuccessFormula (base + per_level, capped) | +| `success` | SuccessFormula (base + per_level * (level - required), capped) | | `drops` | Weighted drop entries (item_id, table ref, depletes, quantity, message, level, xp) | | `respawn_timer` | Ticks until depleted object respawns | | `deplete_timer` | Ticks for shared depletion (trees) | @@ -318,8 +265,7 @@ The `verbSkill` map maps verb → skill name for default target resolution: ### SuccessChance Formula -`SuccessChance(cfg SuccessFormula, level int, requiredLevel int) float64`: -``` +```go chance = cfg.Base + (level - requiredLevel) * cfg.PerLevel clamped to [0, cfg.Cap] ``` @@ -335,7 +281,9 @@ clamped to [0, cfg.Cap] | `teleport` | Moves player to a room ID | | `heal` | Restores hitpoints | | `cost` | Deducts credits from player | -| `shop` | Opens a buy/sell interface (see Shop section) | +| `shop` | Opens a buy/sell interface | +| `assign_task` / `skip_task` / `extend_task` | Assassin task management | +| `sawmill` | Opens sawmill interface (construction) | ### Condition System @@ -343,80 +291,96 @@ Used by exits, talk options, on-enter scripts, and use_interactions checks: | Field | Scope | Example | |---|---|---| -| `flag` | World (shared by all players) | `flag: gate_open` | -| `player_flag` | Per-character (quest progress) | `player_flag: finished_tutorial` | -| `has_item` | Player inventory check | `has_item: bronze_key` | -| `all_of` | All sub-conditions must pass | Nested list | +| `flag` | World (shared by all) | `flag: gate_open` | +| `player_flag` | Per-character | `player_flag: finished_tutorial` | +| `has_item` | Player inventory | `has_item: bronze_key` | +| `min_credits` | Player credits | `min_credits: 100` | +| `all_of` | All sub-conditions pass | Nested list | | `any_of` | Any sub-condition passes | Nested list | | `not` | Invert the check | `not: true` | -### Firemaking (burn/stoke) - -See `internal/game/action_burn.go`. - -**Burn flow (3 phases):** -- Phase 0 (inventory only): Drops 1 log to ground, outputs "You drop the X and begin to make a fire..." -- Phase 1: "You try burning the X on the ground..." (waits tool_speed ticks) -- Phase 2: Skill check (chance = 0.5 + (level - fireLevel) * 0.02, capped [0.05, 0.95]). On success creates `fire` object (quality = log's burn_ticks), gives XP, broadcasts. On fail retries Phase 1. - -**Stoke flow:** 10-tick loop → "You throw X onto the fire", gives XP, adds burn_ticks/2 to fire quality. Ends when out of item. - -**Fire objects:** Created via `World.AddObjInstance()`, tracked by `ObjState.Quality`. Each tick `FireTick()` decrements quality; at 0, `RemoveObjInstance()` cleans up and drops `removal_item` (e.g., ashes). - -**Fire tools:** `matches` (stackable, consumed), `firesteel` (non-consumable), `lighter` (quality-based, `MaxQuality: 100`, decreases per use). Tool search: main hand → inventory. - -**Item fields for firemaking:** `burn_ticks`, `fire_level`, `fire_xp`, `quality`, `max_quality`. - ## Two Depletion Mechanics **Per-drop depletion** (mining, regular trees): Set `depletes: true` on a drop entry. The resource depletes on first successful gather of that drop. -**Shared depletion** (higher-tier trees): Set `deplete_timer: <ticks>` on the behavior. A shared timer counts down while anyone is chopping; when it hits 0, the next successful gather depletes the tree for all players. Timer regenerates when no one is chopping. Managed by `SharedDepletionTick` in `tick.go`. +**Shared depletion** (higher-tier trees): Set `deplete_timer: <ticks>` on the behavior. A shared timer counts down while anyone is chopping; when it hits 0, the next successful gather depletes the tree for all players. Timer regenerates when no one is chopping. Managed by `SharedDepletionTick`. ## Ground Item System - `DropDespawnTicks = 1000` — dropped items despawn after 1000 ticks - `ReserveTicks = 100` — mob loot is reserved for the killer for 100 ticks -- Items with same ID in the same room are NOT merged — each entry has independent despawn timer -- Spawn items respawn after their respawn delay; nearby matching items are merged on respawn +- Items with same ID in the same room are NOT merged — independent despawn timers +- Spawn items respawn after their delay; nearby matching items are merged on respawn - Despawn timers visible via `despawn` option; reserve info via `reserve` option ## Combat System -**Attack types.** Weapons have an `attack_type` field (stab/slash/crush/ranged/science). The attack type determines which of the player's 5 attack bonuses is used for accuracy and which of the mob's 5 defense bonuses is used. Equipment stats use per-type fields: `stab_attack`, `slash_attack`, `crush_attack`, `science_attack`, `ranged_attack` (and matching defense fields). - -**OSRS accuracy formula.** `HitChance(attackRoll, defenseRoll)` uses a continuous probability curve: if `a > d`, chance = `1 - (d+2)/(2*(a+1))`; otherwise `a/(2*(d+1))`. Equal rolls ≈ 50% hit chance. +**Attack types.** Weapons have an `attack_type` field (stab/slash/crush/ranged/science). The attack type determines which player attack bonus and which mob defense bonus to use. -**Ranged combat.** When `weapon_type` is "ranged", uses Ranged level for attack rolls, `ranged_attack` for accuracy, `ranged_strength` from ammo for max hit. Consumes 1 ammo per attack. If ammo runs out, combat ends. XP: 75% Ranged, 25% Hitpoints (all styles). +**OSRS accuracy formula.** `HitChance(a, d)`: if `a > d` → `1 - (d+2)/(2*(a+1))`, else `a/(2*(d+1))`. Equal rolls ≈ 50%. -**Aggressive mobs.** Mobs with `aggressive: true` auto-attack players entering their room (1-tick delay). Only aggros if `playerLevel <= mobLevel * 2` (OSRS rule). Checked on room enter and login via `checkAggro()`. +**Ranged combat.** Weapon type "ranged" uses Ranged level for attack rolls, consumes 1 ammo per attack. If ammo runs out, combat ends. XP: 75% Ranged, 25% Hitpoints. -**Equipment requirements.** Items can have `requirements: { attack: 20, defense: 10 }`. Checked in `doWear` and `doWearAll` before equipping. Displayed when examining items. +**Agile mobs.** Mobs with `aggressive: true` auto-attack players entering their room (1-tick delay) if `playerLevel <= mobLevel * 2`. -**Technology in combat.** Active tech boosts (Clarity, Amplifier, etc.) add percentage-based level bonuses to attack/strength/defense/ranged. Protection techs (Kinetic Barrier, Projectile Screen, Neural Firewall) reduce incoming damage by 40%. Dead Man's Switch deals 25% max HP damage to the mob on player death. +**Equipment requirements.** Items can have `requirements: { attack: 20, defense: 10 }` — checked before equipping. -**Fleeing combat:** Players can move in any direction to attempt to flee. Movement takes the normal tick delay (default 4, reduced by equipment). During the countdown, the mob continues attacking. If the mob lands a hit, the escape fails ("Can't escape!") and combat resumes. If no hit lands, the player escapes. With Cape of Agility, fleeing is instant. The `run_countdown` option shows tick-by-tick countdown messages. +**Fleeing combat:** Movement during combat is a flee attempt. Mobs continue attacking during the movement countdown; a hit aborts the flee ("Can't escape!"). Cape of Agility makes fleeing instant. -**Death mechanic:** Player drops credits to ground. If player has >3 items (inventory + equipment), the 3 most valuable are kept and rest are dropped. Player teleports to room 1 at full HP. All active techs deactivated on death. +**Death mechanic:** Player drops credits to ground. If >3 items total (inventory + equipment), the 3 most valuable are kept, rest dropped. Player teleports to room 1 at full HP. All active techs deactivated. **XP formula:** `baseXP = dmg * 4`, distributed by attack style: -- Accurate: 75% Attack, 25% Hitpoints -- Aggressive: 75% Strength, 25% Hitpoints -- Defensive: 75% Defense, 25% Hitpoints -- Balanced: 25% each Attack/Strength/Defense/Hitpoints -- Ranged (all styles): 75% Ranged, 25% Hitpoints +- Accurate: +3 attack, 75% Attack XP / 25% HP +- Aggressive: +3 strength, 75% Strength XP / 25% HP +- Defensive: +3 defense, 75% Defense XP / 25% HP +- Balanced: +1 each, 25% each Attack/Strength/Defense/HP +- Ranged styles: varied bonus, 75% Ranged XP / 25% HP -**Mob combat level:** `base = (def + hp) / 4`, `offensive = max(melee=(atk+str)/4, ranged=rng*3/8, science=sci*3/8)`, `level = floor(base + offensive)`. +**Mob combat level:** `floor((def+hp)/4 + max((atk+str)/4, rng*3/8, sci*3/8))`. -**Player combat level:** Ranged-or-melee dominant calculation. Includes Technology (0.25) and Science (0.125). - -**Mob respawn:** Default 30 ticks. Broadcasts spawn messages if `mob_spawn` option is on. +**Player combat level:** Ranged-or-melee dominant, includes Technology (0.25) and Science (0.125). **Mob DropTable:** `Remains` (guaranteed drop item), `Loot` (weighted DropEntry table). +## Technology System (tech.go) + +25 hardcoded techs in 4 categories, unlocked by Technology level: +- **Attack/Strength/Defense/Ranged/Science tiers:** I/II/III at 5%/10%/15% level boost +- **Protection techs:** Kinetic Barrier (melee), Projectile Screen (ranged), Neural Firewall (science) — 40% damage reduction each +- **Utility:** Nano Repair (2x HP regen), Rapid Repair (4x), Power Saver (20% drain reduction), Dead Man's Switch (25% max HP retribution on death) +- **Combo:** Overclock (15% atk+str), Fortify (15% def + 2x regen) + +Battery = Technology level (float64). Each tech has a drain rate (0.05–0.25 per tick). Equipment TechnologyBonus reduces drain (capped at 50%). Active techs deactivate when battery hits 0. 1-tick "flicking" grace period supported. + +## Science System (science.go) + +Mods loaded from `data/modules/` — categories: mods, enchant, chip, processing, transport, combat. Junk cost for casting, deck equipment provides junk. Trigger command for casting, autotrigger for automation. Mod list viewable with `mods` command. + +## Hacking System (game/hacking/) + +Minigame interface: `Init(level) string`, `HandleInput(input) (output, done, won)`, `Name() string`. + +Three minigames at 3 terminal levels (1, 20, 40): +- **WumpusGame** — Hunt the Rogue AI: 20-node dodecahedron, probes, hazards +- **MastermindGame** — Code Breaker: 4-digit cipher, 10 guesses, feedback +- **LiarsDiceGame** — Signal Bluff: hidden dice bidding vs AI, wilds, exact calls + +XP scales with Hacking level. + +## Skills (23 total, 1-99, RSC XP table) + +| Category | Skills | +|---|---| +| Combat | Attack, Strength, Defense, Hitpoints, Ranged, Science, Technology, Assassin | +| Gathering | Fishing, Woodcutting, Mining, Hacking, Scavenging, Farming, Thieving | +| Production | Cooking, Smithing, Crafting, Fletching, Pharmacy, Construction, Firemaking | +| Utility | Agility | + +All fully implemented. + ## Option System -Account-wide options set via `option <name> <value>`. Options are stored in the account YAML and shared by all characters on the same account. +Account-wide options set via `option <name> <value>`. Stored in account YAML, shared by all characters on the account. | Option | Type | Default | Description | |---|---|---|---| @@ -424,34 +388,64 @@ Account-wide options set via `option <name> <value>`. Options are stored in the | `tiny_map` | string | "right" | off/right/left — mini-map display | | `xp_drops` | bool | true | XP drop messages | | `exits` | bool | true | Long exit display in look | -| `mob_enter` | bool | true | Messages when mobs enter the room | -| `mob_leave` | bool | true | Messages when mobs leave the room | +| `mob_enter` | bool | true | Messages when mobs enter | +| `mob_leave` | bool | true | Messages when mobs leave | | `mob_spawn` | bool | true | Messages when mobs spawn | | `reserve` | bool | true | Show full reserved item details | -| `depletion` | bool | false | Show depletion and despawn timers | +| `depletion` | bool | false | Show depletion timers | | `despawn` | bool | false | Show ground item despawn timers | | `color` | string | "xterm256" | none/ansi/xterm256 — color output mode | | `mapwidth` | int | 30 | Map viewport width | | `mapheight` | int | 20 | Map viewport height | | `mappadding` | string | "none" | none/x/y/xy — blank-row stripping | -| `automap` | bool | false | Show map automatically after moving | +| `automap` | bool | false | Auto-show map after moving | | `queue_silently` | bool | true | Suppress queue messages | | `room_desc_width` | int | 70 | Room desc line wrap width | | `unicode` | bool | true | Unicode box-drawing characters | -| `run_countdown` | bool | false | Show countdown messages when fleeing combat | -| `visual_ticks` | bool | false | Display a tick marker every game tick | -| `visual_tick_count` | int | 0 | Cycle length for tick counter (0 = no counter) | -| `visual_tick_text` | string | "TICK" | Text displayed for visual ticks | - -Prompt is NOT an option — it is a per-character setting via the `prompt` command. Default: `"> "`. `prompt none` sets it to blank. Stored in character YAML as `prompt:`. +| `run_countdown` | bool | false | Flee countdown messages | +| `visual_ticks` | bool | false | Tick marker display | +| `visual_tick_count` | int | 0 | Tick counter cycle length | +| `visual_tick_text` | string | "Tick" | Text for visual tick marker | +| `fletch_all` | bool | false | Auto-start fletching | +| `smith_all` | bool | false | Auto-start smithing | +| `cook_all` | bool | false | Auto-start cooking | +| `smelt_all` | bool | false | Auto-start smelting | +| `mix_all` | bool | false | Auto-start mixing | +| `construct_all` | bool | false | Auto-start constructing | +| `craft_all` | bool | false | Auto-start crafting | + +Prompt is NOT an option — per-character via the `prompt` command. Default: `"> "`. `prompt none` sets it to blank. Prompt variables: `%h` (HP), `%H` (max HP), `%b` (battery), `%B` (max battery), `%c` (credits), `%i` (free slots), `%s` (style short), `%S` (style long), `%m` (mob HP), `%M` (mob max HP), `%X_<skill>` (XP), `%x_<skill>` (XP to next). -New accounts are asked "Should I disable color? [y/N]" after password creation. Pressing enter defaults to No (xterm256 enabled). Choosing Y sets color to "none". +## Session States (net/server.go) -## ItemDef Fields +| State | Purpose | +|---|---| +| `StateAccountName` | Entering account name | +| `StatePassword` | Entering password | +| `StateNewAccountPass` | Setting password for new account | +| `StateNewAccountConfirm` | Confirming password | +| `StateColorChoice` | New account: "Should I disable color?" | +| `StateMenu` | Main menu | +| `StateNewCharName` | Naming new character or selecting for connection | +| `StateRenameAccount` | Renaming account | +| `StateRenameChar` | Selecting character to rename | +| `StateRenameCharName` | Entering new character name | +| `StateDeleteChar` | Confirming character deletion | +| `StatePurgeAccount` | Confirming account purge | +| `StateGame` | In-game command mode | +| `StateChangeDescription` | Setting player description | +| `StateTalk` | NPC conversation input | +| `StateDropAllConfirm` | Confirming `drop all` | +| `StateRecipeChoice` | Recipe/product selection (by number or name) | +| `StateHowMany` | "How many?" production count | +| `StateSmithProduct` / `StateFletchProduct` / `StateCraftProduct` / `StateProductChoice` | Product selection table menus | +| `StateShop` | Shop interface (buy, sell, browse, leave) | +| `StateBank` | Bank interface (deposit, withdraw, browse, leave) | +| `StateHacking` | Jacked into a terminal running a minigame | -From `internal/object/item.go`: +## ItemDef Fields (object/item.go) | Field | Description | |---|---| @@ -462,88 +456,41 @@ From `internal/object/item.go`: | `value` | Credit value | | `stackable` | Can stack in inventory | | `equip_slot` | head/neck/torso/legs/hands/feet/back/ammo/main_hand/off_hand/ring | -| `weapon_type` | "melee" / "ranged" / "science" | -| `attack_type` | "stab" / "slash" / "crush" / "ranged" / "science" | -| `stats` | Per-type attack/defense bonuses, strength, ranged strength, science damage, technology bonus | -| `speed` | Attack speed | -| `requirements` | Skill level requirements to equip (e.g., `{attack: 20, defense: 10}`) | +| `weapon_type` | melee / ranged / science | +| `attack_type` | stab / slash / crush / ranged / science | +| `stats` | Per-type attack/defense bonuses, strength, ranged_strength, science_damage, technology_bonus | +| `speed` | Attack speed in ticks | +| `requirements` | Skill level requirements to equip | | `tool_type` | Tool type string for gather requirements | | `tool_speed` | Speed bonus for gathering | | `burn_ticks` | Burn duration for firemaking | | `fire_level` | Required firemaking level | | `fire_xp` | XP for burning | -| `quality` | Default quality (e.g., lighter butane) | -| `max_quality` | Maximum quality | -| `search_table` | Drop table for searching this item | -| `search_misc_table` | Secondary drop table | +| `quality` / `max_quality` | Default and maximum quality | +| `search_table` / `search_misc_table` | Drop tables for searching this item | | `search_ticks` | Ticks per search action | | `search_message` | Custom search message | -| `made_from` | MadeFrom entries for item-on-item combinations (byproducts supported) | +| `made_from` | MadeFrom entries for item-on-item combinations (with byproducts) | | `ticks` | Ticks per production cycle for MadeFrom combines (default 2) | +| `farming` | Farming-related fields (seed type, patch, yield, level, xp) | +| `potion` | Potion properties (buff levels for attack/strength/defense/agility) | -## ObjectDef Fields - -From `internal/object/object.go`: - -| Field | Description | -|---|---| -| `id` | Unique identifier | -| `name` | Display name | -| `behavior` | Behavior ID for interaction | -| `hidden` | Interactable but not shown in room listing | -| `inroom_description` | Custom "A X is here." text | -| `removal_item` | Item dropped when instance is removed (fire → ashes) | -| `description` | Text shown when examining the object (supports `{quality}` placeholder for quality-based objects) | -| `use_interactions` | List of item-on-object interactions with conditions and actions (see worldbuilding guide) | - -## World ObjState Fields - -From `internal/world/world.go`: - -| Field | Description | -|---|---| -| `DefID` | Object definition ID | -| `Name` | Display name | -| `Index` | Index for duplicate objects in same room | -| `RoomID` | Current room | -| `Depleted` | Resource is depleted | -| `DepleteTimer` | Ticks until respawn | -| `SharedMax` | Max shared depletion timer | -| `SharedTimer` | Current shared timer value | -| `WanderRooms` | Rooms for object wandering | -| `WanderInterval` | Ticks between wanders | -| `Quality` | Fire quality, resource health, etc. | -| `JustRespawned` | Flag for respawn broadcast | - -## Session States - -From `internal/net/server.go`: +## Places to Be Careful -| State | Purpose | -|---|---| -| `StateAccountName` | Entering account name | -| `StatePassword` | Entering password | -| `StateNewAccountPass` | Setting password for new account | -| `StateNewAccountConfirm` | Confirming password | -| `StateColorChoice` | New account: "Should I disable color?" | -| `StateMenu` | Main menu | -| `StateNewCharName` | Naming new character | -| `StateRenameAccount` | Renaming account | -| `StateRenameChar` | Selecting character to rename | -| `StateRenameCharName` | Entering new character name | -| `StateDeleteChar` | Confirming character deletion | -| `StatePurgeAccount` | Confirming account purge | -| `StateGame` | In-game command mode | -| `StateChangeDescription` | Setting player description | -| `StateTalk` | NPC conversation input | -| `StateDropAllConfirm` | Confirming `drop all` | -| `StateRecipeChoice` | Recipe/product selection table menu (number or name input, enter cancels) | -| `StateHowMany` | "How many?" production count prompt | -| `StateSmithProduct` | Smith product selection with numbered table (#, name, or partial name input) | -| `StateShop` | Buy/sell/browse in shop (buy, sell, browse, leave commands) | -| `StateBank` | Bank interface (deposit, withdraw, browse, leave commands) | -| `StateHacking` | Jacked into a terminal running a minigame | -| `StateColorChoice` | New account color preference | +- `startAction` searches objects first, then mobs. A mob must have `behavior:` set on its YAML def to be interactable. +- Exits changed from `map[ExitDir]int` to `map[ExitDir]ExitDef` — old `north: 2` still works via custom `UnmarshalYAML`. Same pattern for `RoomMob`. +- `checkCondition` is the single condition evaluator — used by exits, talk options, on-enter scripts, and use_interactions. +- Object `hidden: true` means the object doesn't appear in room listings but is still interactable. +- Alias expansion happens before command dispatch and can shadow built-in commands. +- `say` preserves case from raw input. +- `get`, `drop`, and `quit` cancel the player's active action. +- `findGroundMatches` and `findInventoryMatches` support bidirectional prefix matching — `"iron ax"` matches `"iron axe"`. +- Mob wander config is per-instance in room YAML via `RoomMob`, not on `MobDef`. +- Walk distance capped by agility level. +- `wear all` equips the highest-value item per slot; `remove all` unequips everything. +- Cape of Agility makes movement instant (1 tick). Graceful pieces each reduce by 0.25 ticks; full set +0.5 bonus for 2 ticks total. Cape overrides Graceful. +- During combat, movement is a flee attempt. Mob hits during countdown abort the flee. +- Level-up messages output `*** You are now level N <skill>! ***` across all skills that gain XP. ## Adding a New Skill @@ -554,54 +501,20 @@ From `internal/net/server.go`: 5. Place the object in a room YAML in `data/rooms/` 6. Create any resource items in `data/items/` -Set `xp` on the behavior to award XP on successful gathers. Set `deplete_timer` for tree-style depletion, or use per-drop `depletes: true` for rock-style depletion. - ## Adding a New Production Skill -Production skills (cooking, smelting, smithing) share a unified system in `action_production.go`: +Production skills share a unified system in `core_production.go`: -1. Create recipe YAMLs in `data/recipes/` with the new `type` (e.g., `type: fletching`) +1. Create recipe YAMLs in `data/recipes/` with the new `type` 2. Create a station object in `data/objects/` if needed -3. Add a `cmd_<skill>.go` command handler following the `cmd_cook.go` pattern -4. Add the command to `classifyCommand()` and `executeCommand()` in `game.go` -5. Add the action type string to `AdvanceActions` in `action.go` -6. Add a case in `startProductionFromRecipe()` for default messages +3. Add a `cmd_<skill>.go` command handler following existing patterns +4. Add the command to `commandRegistry` in `cmd_registry.go` with the appropriate class +5. Wire up the `auto_start` option if desired -The unified production cycle handles: "How many?" prompt, start message, timed loops, success/fail rolls, XP, output quantity, stackable stacking, byproducts, and end message. Tool requirements (e.g., hammer for smithing, needle for crafting) are checked in the command handler before calling `promptHowMany`. +The unified production cycle handles: HowMany prompt, start message, timed loops, success/fail rolls, XP, output quantity, stackable stacking, byproducts, and end message. Tool requirements are checked in the command handler before calling `promptHowMany`. ## Adding a New Command -1. Add a `cmd_*.go` file in `internal/game/` with the handler -2. Add a case in `handleGameCommand()` and entry in `classifyCommand()` in `internal/game/game.go` +1. Add a `cmd_*.go` file in `internal/game/` with the handler function `func (g *Game) executeXxx(sess *net.Session, args []string, rawInput string)` +2. Add the command to `commandRegistry` in `cmd_registry.go` with the appropriate `CommandClass` 3. Update `data/help/` YAML files - -## Skills (23 total, 1-99, RSC XP table) - -| Category | Skills | -|---|---| -| Combat | Attack, Strength, Defense, Hitpoints, Ranged, Science, Technology, Assassin | -| Gathering | Fishing, Woodcutting, Mining, Hacking, Scavenging, Farming, Thieving | -| Production | Cooking, Smithing, Crafting, Fletching, Pharmacy, Construction, Firemaking | -| Utility | Agility | - -Implemented: Mining, Fishing, Woodcutting, Firemaking, Cooking, Smithing (smelting + smithing), Fletching, Pharmacy (herb cleaning + potion mixing), Technology (25 techs, battery drain, 1-tick flicking, combat integration), Construction (planks, furniture, player houses), Agility (3 obstacle courses, 9 verbs, lap tracking), Hacking (3 minigames, terminals, StateHacking). The rest are stubs (skill defined, XP tracked, but no behaviors/objects/items yet). - -## Places to Be Careful - -- `StartAction` searches objects first, then mobs. A mob must have `behavior:` set on its YAML def to be interactable. -- Exits changed from `map[ExitDir]int` to `map[ExitDir]ExitDef` — old `north: 2` still works via custom `UnmarshalYAML`. Same pattern for `RoomMob`. -- `checkCondition` is the single condition evaluator — used by exits, talk options, on-enter scripts, and use_interactions checks. -- Object `Hidden: true` means the object doesn't appear in room listings but is still interactable. -- Alias expansion happens before command dispatch and can shadow built-in commands. -- `say` preserves case (alias expansion preserves case, dispatch extracts original input text). -- `get`, `drop`, and `quit` cancel the player's active action (gathering, use, etc.). -- `findGroundMatches` and `findInventoryMatches` support bidirectional prefix matching — `"iron ax"` matches `"iron axe"`. -- Mob wander config is per-instance in room YAML via `RoomMob`, not on `MobDef`. -- Walk distance capped by agility level (`len(dirs) > agilityLevel`). -- `wear all` auto-equips the highest-value item per slot from inventory. -- `remove all` unequips everything if inventory has room. -- Movement takes multiple ticks (default 4, reduced by Graceful set and Cape of Agility). Cape of Agility makes movement instant (1 tick). Graceful pieces each reduce by 0.25 ticks; full set bonus adds 0.5 for 2 ticks total. Cape overrides Graceful. -- During combat, movement is a flee attempt. Mob hits during the countdown abort the flee ("Can't escape!"). -- Level-up messages output `*** You are now level N <skill>! ***` across all skills that gain XP. - -Skills provide specialized instructions and workflows for specific tasks. diff --git a/cmd/mud/main.go b/cmd/mud/main.go index 497f427..ef4a560 100644 --- a/cmd/mud/main.go +++ b/cmd/mud/main.go @@ -35,7 +35,7 @@ func main() { } } - g := game.New(dataDir, &cfg.Colors) + g := game.New(dataDir, &cfg.Colors, cfg.Game.StartupValidation) g.Ticks.Start(cfg.Game.TickLength) defer g.Ticks.Stop() diff --git a/data/items/adamant_arrow.yaml b/data/items/ammo/adamant_arrow.yaml index bbcdcab..bbcdcab 100644 --- a/data/items/adamant_arrow.yaml +++ b/data/items/ammo/adamant_arrow.yaml diff --git a/data/items/adamant_arrowtips.yaml b/data/items/ammo/adamant_arrowtips.yaml index 49ddb57..49ddb57 100644 --- a/data/items/adamant_arrowtips.yaml +++ b/data/items/ammo/adamant_arrowtips.yaml diff --git a/data/items/adamant_bolts.yaml b/data/items/ammo/adamant_bolts.yaml index 47d088f..47d088f 100644 --- a/data/items/adamant_bolts.yaml +++ b/data/items/ammo/adamant_bolts.yaml diff --git a/data/items/adamant_bolts_unf.yaml b/data/items/ammo/adamant_bolts_unf.yaml index db709db..db709db 100644 --- a/data/items/adamant_bolts_unf.yaml +++ b/data/items/ammo/adamant_bolts_unf.yaml diff --git a/data/items/arrow_shaft.yaml b/data/items/ammo/arrow_shaft.yaml index 715a3e6..715a3e6 100644 --- a/data/items/arrow_shaft.yaml +++ b/data/items/ammo/arrow_shaft.yaml diff --git a/data/items/bronze_arrow.yaml b/data/items/ammo/bronze_arrow.yaml index eb73a48..eb73a48 100644 --- a/data/items/bronze_arrow.yaml +++ b/data/items/ammo/bronze_arrow.yaml diff --git a/data/items/bronze_arrowtips.yaml b/data/items/ammo/bronze_arrowtips.yaml index df42e59..df42e59 100644 --- a/data/items/bronze_arrowtips.yaml +++ b/data/items/ammo/bronze_arrowtips.yaml diff --git a/data/items/bronze_bolts.yaml b/data/items/ammo/bronze_bolts.yaml index 0d3afae..0d3afae 100644 --- a/data/items/bronze_bolts.yaml +++ b/data/items/ammo/bronze_bolts.yaml diff --git a/data/items/bronze_bolts_unf.yaml b/data/items/ammo/bronze_bolts_unf.yaml index 538d8ab..538d8ab 100644 --- a/data/items/bronze_bolts_unf.yaml +++ b/data/items/ammo/bronze_bolts_unf.yaml diff --git a/data/items/diamond_bolt_tips.yaml b/data/items/ammo/diamond_bolt_tips.yaml index 1529b11..1529b11 100644 --- a/data/items/diamond_bolt_tips.yaml +++ b/data/items/ammo/diamond_bolt_tips.yaml diff --git a/data/items/diamond_bolts.yaml b/data/items/ammo/diamond_bolts.yaml index efe8013..efe8013 100644 --- a/data/items/diamond_bolts.yaml +++ b/data/items/ammo/diamond_bolts.yaml diff --git a/data/items/diamond_bolts_e.yaml b/data/items/ammo/diamond_bolts_e.yaml index 93ade4c..93ade4c 100644 --- a/data/items/diamond_bolts_e.yaml +++ b/data/items/ammo/diamond_bolts_e.yaml diff --git a/data/items/emerald_bolt_tips.yaml b/data/items/ammo/emerald_bolt_tips.yaml index afd285b..afd285b 100644 --- a/data/items/emerald_bolt_tips.yaml +++ b/data/items/ammo/emerald_bolt_tips.yaml diff --git a/data/items/emerald_bolts.yaml b/data/items/ammo/emerald_bolts.yaml index 1afdcd0..1afdcd0 100644 --- a/data/items/emerald_bolts.yaml +++ b/data/items/ammo/emerald_bolts.yaml diff --git a/data/items/emerald_bolts_e.yaml b/data/items/ammo/emerald_bolts_e.yaml index 4cb7cbd..4cb7cbd 100644 --- a/data/items/emerald_bolts_e.yaml +++ b/data/items/ammo/emerald_bolts_e.yaml diff --git a/data/items/headless_arrow.yaml b/data/items/ammo/headless_arrow.yaml index acf1384..acf1384 100644 --- a/data/items/headless_arrow.yaml +++ b/data/items/ammo/headless_arrow.yaml diff --git a/data/items/iron_arrow.yaml b/data/items/ammo/iron_arrow.yaml index ebadaec..ebadaec 100644 --- a/data/items/iron_arrow.yaml +++ b/data/items/ammo/iron_arrow.yaml diff --git a/data/items/iron_arrowtips.yaml b/data/items/ammo/iron_arrowtips.yaml index 54ffd11..54ffd11 100644 --- a/data/items/iron_arrowtips.yaml +++ b/data/items/ammo/iron_arrowtips.yaml diff --git a/data/items/iron_bolts.yaml b/data/items/ammo/iron_bolts.yaml index ed81578..ed81578 100644 --- a/data/items/iron_bolts.yaml +++ b/data/items/ammo/iron_bolts.yaml diff --git a/data/items/iron_bolts_unf.yaml b/data/items/ammo/iron_bolts_unf.yaml index 0a51ca0..0a51ca0 100644 --- a/data/items/iron_bolts_unf.yaml +++ b/data/items/ammo/iron_bolts_unf.yaml diff --git a/data/items/mithril_arrow.yaml b/data/items/ammo/mithril_arrow.yaml index 23464e9..23464e9 100644 --- a/data/items/mithril_arrow.yaml +++ b/data/items/ammo/mithril_arrow.yaml diff --git a/data/items/mithril_arrowtips.yaml b/data/items/ammo/mithril_arrowtips.yaml index 8f68a34..8f68a34 100644 --- a/data/items/mithril_arrowtips.yaml +++ b/data/items/ammo/mithril_arrowtips.yaml diff --git a/data/items/mithril_bolts.yaml b/data/items/ammo/mithril_bolts.yaml index e160065..e160065 100644 --- a/data/items/mithril_bolts.yaml +++ b/data/items/ammo/mithril_bolts.yaml diff --git a/data/items/mithril_bolts_unf.yaml b/data/items/ammo/mithril_bolts_unf.yaml index 8015f1a..8015f1a 100644 --- a/data/items/mithril_bolts_unf.yaml +++ b/data/items/ammo/mithril_bolts_unf.yaml diff --git a/data/items/ruby_bolt_tips.yaml b/data/items/ammo/ruby_bolt_tips.yaml index 6ebe1a0..6ebe1a0 100644 --- a/data/items/ruby_bolt_tips.yaml +++ b/data/items/ammo/ruby_bolt_tips.yaml diff --git a/data/items/ruby_bolts.yaml b/data/items/ammo/ruby_bolts.yaml index b83bec2..b83bec2 100644 --- a/data/items/ruby_bolts.yaml +++ b/data/items/ammo/ruby_bolts.yaml diff --git a/data/items/ruby_bolts_e.yaml b/data/items/ammo/ruby_bolts_e.yaml index 14954c2..14954c2 100644 --- a/data/items/ruby_bolts_e.yaml +++ b/data/items/ammo/ruby_bolts_e.yaml diff --git a/data/items/rune_arrow.yaml b/data/items/ammo/rune_arrow.yaml index b00e922..b00e922 100644 --- a/data/items/rune_arrow.yaml +++ b/data/items/ammo/rune_arrow.yaml diff --git a/data/items/rune_arrowtips.yaml b/data/items/ammo/rune_arrowtips.yaml index c2d80e0..c2d80e0 100644 --- a/data/items/rune_arrowtips.yaml +++ b/data/items/ammo/rune_arrowtips.yaml diff --git a/data/items/rune_bolts.yaml b/data/items/ammo/rune_bolts.yaml index 82ac597..82ac597 100644 --- a/data/items/rune_bolts.yaml +++ b/data/items/ammo/rune_bolts.yaml diff --git a/data/items/rune_bolts_unf.yaml b/data/items/ammo/rune_bolts_unf.yaml index ecaf494..ecaf494 100644 --- a/data/items/rune_bolts_unf.yaml +++ b/data/items/ammo/rune_bolts_unf.yaml diff --git a/data/items/sapphire_bolt_tips.yaml b/data/items/ammo/sapphire_bolt_tips.yaml index 7513fd3..7513fd3 100644 --- a/data/items/sapphire_bolt_tips.yaml +++ b/data/items/ammo/sapphire_bolt_tips.yaml diff --git a/data/items/sapphire_bolts.yaml b/data/items/ammo/sapphire_bolts.yaml index a7102c9..a7102c9 100644 --- a/data/items/sapphire_bolts.yaml +++ b/data/items/ammo/sapphire_bolts.yaml diff --git a/data/items/sapphire_bolts_e.yaml b/data/items/ammo/sapphire_bolts_e.yaml index dc378cc..dc378cc 100644 --- a/data/items/sapphire_bolts_e.yaml +++ b/data/items/ammo/sapphire_bolts_e.yaml diff --git a/data/items/steel_arrow.yaml b/data/items/ammo/steel_arrow.yaml index e14171f..e14171f 100644 --- a/data/items/steel_arrow.yaml +++ b/data/items/ammo/steel_arrow.yaml diff --git a/data/items/steel_arrowtips.yaml b/data/items/ammo/steel_arrowtips.yaml index 49000d2..49000d2 100644 --- a/data/items/steel_arrowtips.yaml +++ b/data/items/ammo/steel_arrowtips.yaml diff --git a/data/items/steel_bolts.yaml b/data/items/ammo/steel_bolts.yaml index 7dfadf1..7dfadf1 100644 --- a/data/items/steel_bolts.yaml +++ b/data/items/ammo/steel_bolts.yaml diff --git a/data/items/steel_bolts_unf.yaml b/data/items/ammo/steel_bolts_unf.yaml index b65d5fa..b65d5fa 100644 --- a/data/items/steel_bolts_unf.yaml +++ b/data/items/ammo/steel_bolts_unf.yaml diff --git a/data/items/avantoe_potion_unf.yaml b/data/items/avantoe_potion_unf.yaml deleted file mode 100644 index 8b23f35..0000000 --- a/data/items/avantoe_potion_unf.yaml +++ /dev/null @@ -1,12 +0,0 @@ -id: avantoe_potion_unf -name: "avantoe potion (unf)" -color: "48" -description: "An unfinished potion with avantoe floating in water." -value: 50 -stackable: false -made_from: - - items: [avantoe] - qty: 1 - - items: [vial_of_water] - qty: 1 -ticks: 0 diff --git a/data/items/bread_dough.yaml b/data/items/bread_dough.yaml deleted file mode 100644 index 98ab297..0000000 --- a/data/items/bread_dough.yaml +++ /dev/null @@ -1,14 +0,0 @@ -id: bread_dough -name: bread dough -color: "222" -description: "A ball of uncooked bread dough. It needs to be baked." -value: 3 -stackable: false -ticks: 2 -made_from: - - items: [pot_of_flour] - qty: 1 - byproducts: [empty_pot] - - items: [bucket_of_water, jug_of_water] - qty: 1 - byproducts: [empty_bucket, empty_jug] diff --git a/data/items/cadantine_potion_unf.yaml b/data/items/cadantine_potion_unf.yaml deleted file mode 100644 index 416d938..0000000 --- a/data/items/cadantine_potion_unf.yaml +++ /dev/null @@ -1,12 +0,0 @@ -id: cadantine_potion_unf -name: "cadantine potion (unf)" -color: "48" -description: "An unfinished potion with cadantine floating in water." -value: 72 -stackable: false -made_from: - - items: [cadantine] - qty: 1 - - items: [vial_of_water] - qty: 1 -ticks: 0 diff --git a/data/items/acid_vial.yaml b/data/items/consumables/acid_vial.yaml index 7a49e2d..7a49e2d 100644 --- a/data/items/acid_vial.yaml +++ b/data/items/consumables/acid_vial.yaml diff --git a/data/items/amp_potion.yaml b/data/items/consumables/amp_potion.yaml index 8167932..8167932 100644 --- a/data/items/amp_potion.yaml +++ b/data/items/consumables/amp_potion.yaml diff --git a/data/items/anchovies.yaml b/data/items/consumables/anchovies.yaml index 0abd846..0abd846 100644 --- a/data/items/anchovies.yaml +++ b/data/items/consumables/anchovies.yaml diff --git a/data/items/antitoxin_powder.yaml b/data/items/consumables/antitoxin_powder.yaml index dedba43..dedba43 100644 --- a/data/items/antitoxin_powder.yaml +++ b/data/items/consumables/antitoxin_powder.yaml diff --git a/data/items/apple.yaml b/data/items/consumables/apple.yaml index 10c09c1..10c09c1 100644 --- a/data/items/apple.yaml +++ b/data/items/consumables/apple.yaml diff --git a/data/items/consumables/avantoe_potion_unf.yaml b/data/items/consumables/avantoe_potion_unf.yaml new file mode 100644 index 0000000..62f2218 --- /dev/null +++ b/data/items/consumables/avantoe_potion_unf.yaml @@ -0,0 +1,12 @@ +id: avantoe_potion_unf +name: "avantoe potion (unf)" +color: "48" +description: "An unfinished potion with avantoe floating in water." +value: 50 +stackable: false +made_from: + - items: [avantoe] + quantity: 1 + - items: [vial_of_water] + quantity: 1 +ticks: 0 diff --git a/data/items/bio_serum.yaml b/data/items/consumables/bio_serum.yaml index b397e46..b397e46 100644 --- a/data/items/bio_serum.yaml +++ b/data/items/consumables/bio_serum.yaml diff --git a/data/items/blight_spore.yaml b/data/items/consumables/blight_spore.yaml index add0f6e..add0f6e 100644 --- a/data/items/blight_spore.yaml +++ b/data/items/consumables/blight_spore.yaml diff --git a/data/items/bread.yaml b/data/items/consumables/bread.yaml index 68cefdc..68cefdc 100644 --- a/data/items/bread.yaml +++ b/data/items/consumables/bread.yaml diff --git a/data/items/consumables/bread_dough.yaml b/data/items/consumables/bread_dough.yaml new file mode 100644 index 0000000..73ac998 --- /dev/null +++ b/data/items/consumables/bread_dough.yaml @@ -0,0 +1,14 @@ +id: bread_dough +name: bread dough +color: "222" +description: "A ball of uncooked bread dough. It needs to be baked." +value: 3 +stackable: false +ticks: 2 +made_from: + - items: [pot_of_flour] + quantity: 1 + byproducts: [empty_pot] + - items: [bucket_of_water, jug_of_water] + quantity: 1 + byproducts: [empty_bucket, empty_jug] diff --git a/data/items/bucket_of_water.yaml b/data/items/consumables/bucket_of_water.yaml index 3449cdd..3449cdd 100644 --- a/data/items/bucket_of_water.yaml +++ b/data/items/consumables/bucket_of_water.yaml diff --git a/data/items/burnt_fish.yaml b/data/items/consumables/burnt_fish.yaml index 7af9f03..7af9f03 100644 --- a/data/items/burnt_fish.yaml +++ b/data/items/consumables/burnt_fish.yaml diff --git a/data/items/burnt_meat.yaml b/data/items/consumables/burnt_meat.yaml index 92c339c..92c339c 100644 --- a/data/items/burnt_meat.yaml +++ b/data/items/consumables/burnt_meat.yaml diff --git a/data/items/cabbage.yaml b/data/items/consumables/cabbage.yaml index c04fd4e..c04fd4e 100644 --- a/data/items/cabbage.yaml +++ b/data/items/consumables/cabbage.yaml diff --git a/data/items/consumables/cadantine_potion_unf.yaml b/data/items/consumables/cadantine_potion_unf.yaml new file mode 100644 index 0000000..d1f13c6 --- /dev/null +++ b/data/items/consumables/cadantine_potion_unf.yaml @@ -0,0 +1,12 @@ +id: cadantine_potion_unf +name: "cadantine potion (unf)" +color: "48" +description: "An unfinished potion with cadantine floating in water." +value: 72 +stackable: false +made_from: + - items: [cadantine] + quantity: 1 + - items: [vial_of_water] + quantity: 1 +ticks: 0 diff --git a/data/items/catalyst_wine.yaml b/data/items/consumables/catalyst_wine.yaml index fcfe1a0..fcfe1a0 100644 --- a/data/items/catalyst_wine.yaml +++ b/data/items/consumables/catalyst_wine.yaml diff --git a/data/items/cheese.yaml b/data/items/consumables/cheese.yaml index 79d9fe8..79d9fe8 100644 --- a/data/items/cheese.yaml +++ b/data/items/consumables/cheese.yaml diff --git a/data/items/consumables/dwarf_weed_potion_unf.yaml b/data/items/consumables/dwarf_weed_potion_unf.yaml new file mode 100644 index 0000000..64f7faa --- /dev/null +++ b/data/items/consumables/dwarf_weed_potion_unf.yaml @@ -0,0 +1,12 @@ +id: dwarf_weed_potion_unf +name: "dwarf weed potion (unf)" +color: "48" +description: "An unfinished potion with dwarf weed floating in water." +value: 88 +stackable: false +made_from: + - items: [dwarf_weed] + quantity: 1 + - items: [vial_of_water] + quantity: 1 +ticks: 0 diff --git a/data/items/full_restore.yaml b/data/items/consumables/full_restore.yaml index 96f6036..96f6036 100644 --- a/data/items/full_restore.yaml +++ b/data/items/consumables/full_restore.yaml diff --git a/data/items/consumables/guam_potion_unf.yaml b/data/items/consumables/guam_potion_unf.yaml new file mode 100644 index 0000000..ba81e93 --- /dev/null +++ b/data/items/consumables/guam_potion_unf.yaml @@ -0,0 +1,12 @@ +id: guam_potion_unf +name: "guam potion (unf)" +color: "48" +description: "An unfinished potion with guam floating in water." +value: 5 +stackable: false +made_from: + - items: [guam] + quantity: 1 + - items: [vial_of_water] + quantity: 1 +ticks: 0 diff --git a/data/items/consumables/harralander_potion_unf.yaml b/data/items/consumables/harralander_potion_unf.yaml new file mode 100644 index 0000000..522f8ea --- /dev/null +++ b/data/items/consumables/harralander_potion_unf.yaml @@ -0,0 +1,12 @@ +id: harralander_potion_unf +name: "harralander potion (unf)" +color: "48" +description: "An unfinished potion with harralander floating in water." +value: 18 +stackable: false +made_from: + - items: [harralander] + quantity: 1 + - items: [vial_of_water] + quantity: 1 +ticks: 0 diff --git a/data/items/herring.yaml b/data/items/consumables/herring.yaml index adbbd95..adbbd95 100644 --- a/data/items/herring.yaml +++ b/data/items/consumables/herring.yaml diff --git a/data/items/consumables/irit_potion_unf.yaml b/data/items/consumables/irit_potion_unf.yaml new file mode 100644 index 0000000..76a8577 --- /dev/null +++ b/data/items/consumables/irit_potion_unf.yaml @@ -0,0 +1,12 @@ +id: irit_potion_unf +name: "irit potion (unf)" +color: "48" +description: "An unfinished potion with irit floating in water." +value: 42 +stackable: false +made_from: + - items: [irit] + quantity: 1 + - items: [vial_of_water] + quantity: 1 +ticks: 0 diff --git a/data/items/jug_of_water.yaml b/data/items/consumables/jug_of_water.yaml index 04d3b8f..04d3b8f 100644 --- a/data/items/jug_of_water.yaml +++ b/data/items/consumables/jug_of_water.yaml diff --git a/data/items/consumables/kwuarm_potion_unf.yaml b/data/items/consumables/kwuarm_potion_unf.yaml new file mode 100644 index 0000000..0448145 --- /dev/null +++ b/data/items/consumables/kwuarm_potion_unf.yaml @@ -0,0 +1,12 @@ +id: kwuarm_potion_unf +name: "kwuarm potion (unf)" +color: "48" +description: "An unfinished potion with kwuarm floating in water." +value: 56 +stackable: false +made_from: + - items: [kwuarm] + quantity: 1 + - items: [vial_of_water] + quantity: 1 +ticks: 0 diff --git a/data/items/consumables/lantadyme_potion_unf.yaml b/data/items/consumables/lantadyme_potion_unf.yaml new file mode 100644 index 0000000..3460a18 --- /dev/null +++ b/data/items/consumables/lantadyme_potion_unf.yaml @@ -0,0 +1,12 @@ +id: lantadyme_potion_unf +name: "lantadyme potion (unf)" +color: "48" +description: "An unfinished potion with lantadyme floating in water." +value: 80 +stackable: false +made_from: + - items: [lantadyme] + quantity: 1 + - items: [vial_of_water] + quantity: 1 +ticks: 0 diff --git a/data/items/consumables/marrentill_potion_unf.yaml b/data/items/consumables/marrentill_potion_unf.yaml new file mode 100644 index 0000000..4424e5e --- /dev/null +++ b/data/items/consumables/marrentill_potion_unf.yaml @@ -0,0 +1,12 @@ +id: marrentill_potion_unf +name: "marrentill potion (unf)" +color: "48" +description: "An unfinished potion with marrentill floating in water." +value: 8 +stackable: false +made_from: + - items: [marrentill] + quantity: 1 + - items: [vial_of_water] + quantity: 1 +ticks: 0 diff --git a/data/items/nano_restore.yaml b/data/items/consumables/nano_restore.yaml index e430b49..e430b49 100644 --- a/data/items/nano_restore.yaml +++ b/data/items/consumables/nano_restore.yaml diff --git a/data/items/onion.yaml b/data/items/consumables/onion.yaml index 0d0aca7..0d0aca7 100644 --- a/data/items/onion.yaml +++ b/data/items/consumables/onion.yaml diff --git a/data/items/consumables/pastry_dough.yaml b/data/items/consumables/pastry_dough.yaml new file mode 100644 index 0000000..b607c83 --- /dev/null +++ b/data/items/consumables/pastry_dough.yaml @@ -0,0 +1,11 @@ +id: pastry_dough +name: pastry dough +color: "222" +description: "A ball of uncooked pastry dough. It needs to be baked." +value: 3 +stackable: false +made_from: + - items: [pot_of_flour] + quantity: 1 + - items: [bucket_of_water] + quantity: 1 diff --git a/data/items/pie_dish.yaml b/data/items/consumables/pie_dish.yaml index bd6100b..bd6100b 100644 --- a/data/items/pie_dish.yaml +++ b/data/items/consumables/pie_dish.yaml diff --git a/data/items/consumables/pizza_dough.yaml b/data/items/consumables/pizza_dough.yaml new file mode 100644 index 0000000..12d8b14 --- /dev/null +++ b/data/items/consumables/pizza_dough.yaml @@ -0,0 +1,11 @@ +id: pizza_dough +name: pizza dough +color: "222" +description: "A ball of uncooked pizza dough. It needs to be baked." +value: 3 +stackable: false +made_from: + - items: [pot_of_flour] + quantity: 1 + - items: [bucket_of_water] + quantity: 1 diff --git a/data/items/plant_cure.yaml b/data/items/consumables/plant_cure.yaml index 64ebe91..64ebe91 100644 --- a/data/items/plant_cure.yaml +++ b/data/items/consumables/plant_cure.yaml diff --git a/data/items/pot_of_flour.yaml b/data/items/consumables/pot_of_flour.yaml index c05c065..c05c065 100644 --- a/data/items/pot_of_flour.yaml +++ b/data/items/consumables/pot_of_flour.yaml diff --git a/data/items/potato.yaml b/data/items/consumables/potato.yaml index d9f521a..d9f521a 100644 --- a/data/items/potato.yaml +++ b/data/items/consumables/potato.yaml diff --git a/data/items/consumables/ranarr_potion_unf.yaml b/data/items/consumables/ranarr_potion_unf.yaml new file mode 100644 index 0000000..d2c475d --- /dev/null +++ b/data/items/consumables/ranarr_potion_unf.yaml @@ -0,0 +1,12 @@ +id: ranarr_potion_unf +name: "ranarr potion (unf)" +color: "48" +description: "An unfinished potion with ranarr floating in water." +value: 38 +stackable: false +made_from: + - items: [ranarr] + quantity: 1 + - items: [vial_of_water] + quantity: 1 +ticks: 0 diff --git a/data/items/raw_anchovies.yaml b/data/items/consumables/raw_anchovies.yaml index cf5b75f..cf5b75f 100644 --- a/data/items/raw_anchovies.yaml +++ b/data/items/consumables/raw_anchovies.yaml diff --git a/data/items/raw_anglerfish.yaml b/data/items/consumables/raw_anglerfish.yaml index b1c7262..b1c7262 100644 --- a/data/items/raw_anglerfish.yaml +++ b/data/items/consumables/raw_anglerfish.yaml diff --git a/data/items/raw_bass.yaml b/data/items/consumables/raw_bass.yaml index 34dddc1..34dddc1 100644 --- a/data/items/raw_bass.yaml +++ b/data/items/consumables/raw_bass.yaml diff --git a/data/items/raw_beef.yaml b/data/items/consumables/raw_beef.yaml index 59695b0..59695b0 100644 --- a/data/items/raw_beef.yaml +++ b/data/items/consumables/raw_beef.yaml diff --git a/data/items/raw_cave_eel.yaml b/data/items/consumables/raw_cave_eel.yaml index 000f93c..000f93c 100644 --- a/data/items/raw_cave_eel.yaml +++ b/data/items/consumables/raw_cave_eel.yaml diff --git a/data/items/raw_cod.yaml b/data/items/consumables/raw_cod.yaml index fe94f35..fe94f35 100644 --- a/data/items/raw_cod.yaml +++ b/data/items/consumables/raw_cod.yaml diff --git a/data/items/raw_herring.yaml b/data/items/consumables/raw_herring.yaml index 730eca5..730eca5 100644 --- a/data/items/raw_herring.yaml +++ b/data/items/consumables/raw_herring.yaml diff --git a/data/items/raw_lobster.yaml b/data/items/consumables/raw_lobster.yaml index 908c931..908c931 100644 --- a/data/items/raw_lobster.yaml +++ b/data/items/consumables/raw_lobster.yaml diff --git a/data/items/raw_mackerel.yaml b/data/items/consumables/raw_mackerel.yaml index 42e1d09..42e1d09 100644 --- a/data/items/raw_mackerel.yaml +++ b/data/items/consumables/raw_mackerel.yaml diff --git a/data/items/raw_pike.yaml b/data/items/consumables/raw_pike.yaml index 625c019..625c019 100644 --- a/data/items/raw_pike.yaml +++ b/data/items/consumables/raw_pike.yaml diff --git a/data/items/raw_rainbow_fish.yaml b/data/items/consumables/raw_rainbow_fish.yaml index 311c9f1..311c9f1 100644 --- a/data/items/raw_rainbow_fish.yaml +++ b/data/items/consumables/raw_rainbow_fish.yaml diff --git a/data/items/raw_salmon.yaml b/data/items/consumables/raw_salmon.yaml index d5ae9bd..d5ae9bd 100644 --- a/data/items/raw_salmon.yaml +++ b/data/items/consumables/raw_salmon.yaml diff --git a/data/items/raw_sardine.yaml b/data/items/consumables/raw_sardine.yaml index d27a155..d27a155 100644 --- a/data/items/raw_sardine.yaml +++ b/data/items/consumables/raw_sardine.yaml diff --git a/data/items/raw_shark.yaml b/data/items/consumables/raw_shark.yaml index 999ccb9..999ccb9 100644 --- a/data/items/raw_shark.yaml +++ b/data/items/consumables/raw_shark.yaml diff --git a/data/items/raw_shrimps.yaml b/data/items/consumables/raw_shrimps.yaml index 1127fda..1127fda 100644 --- a/data/items/raw_shrimps.yaml +++ b/data/items/consumables/raw_shrimps.yaml diff --git a/data/items/raw_slimy_eel.yaml b/data/items/consumables/raw_slimy_eel.yaml index 40820e5..40820e5 100644 --- a/data/items/raw_slimy_eel.yaml +++ b/data/items/consumables/raw_slimy_eel.yaml diff --git a/data/items/raw_swordfish.yaml b/data/items/consumables/raw_swordfish.yaml index e162460..e162460 100644 --- a/data/items/raw_swordfish.yaml +++ b/data/items/consumables/raw_swordfish.yaml diff --git a/data/items/raw_trout.yaml b/data/items/consumables/raw_trout.yaml index c1d98aa..c1d98aa 100644 --- a/data/items/raw_trout.yaml +++ b/data/items/consumables/raw_trout.yaml diff --git a/data/items/raw_tuna.yaml b/data/items/consumables/raw_tuna.yaml index 6079f92..6079f92 100644 --- a/data/items/raw_tuna.yaml +++ b/data/items/consumables/raw_tuna.yaml diff --git a/data/items/restoration_compound.yaml b/data/items/consumables/restoration_compound.yaml index 913153f..913153f 100644 --- a/data/items/restoration_compound.yaml +++ b/data/items/consumables/restoration_compound.yaml diff --git a/data/items/salmon.yaml b/data/items/consumables/salmon.yaml index 59b8237..59b8237 100644 --- a/data/items/salmon.yaml +++ b/data/items/consumables/salmon.yaml diff --git a/data/items/sardine.yaml b/data/items/consumables/sardine.yaml index c11b42b..c11b42b 100644 --- a/data/items/sardine.yaml +++ b/data/items/consumables/sardine.yaml diff --git a/data/items/science_serum.yaml b/data/items/consumables/science_serum.yaml index e78f915..e78f915 100644 --- a/data/items/science_serum.yaml +++ b/data/items/consumables/science_serum.yaml diff --git a/data/items/shield_potion.yaml b/data/items/consumables/shield_potion.yaml index 4cd91e8..4cd91e8 100644 --- a/data/items/shield_potion.yaml +++ b/data/items/consumables/shield_potion.yaml diff --git a/data/items/shrimps.yaml b/data/items/consumables/shrimps.yaml index 9c280c8..9c280c8 100644 --- a/data/items/shrimps.yaml +++ b/data/items/consumables/shrimps.yaml diff --git a/data/items/consumables/snapdragon_potion_unf.yaml b/data/items/consumables/snapdragon_potion_unf.yaml new file mode 100644 index 0000000..ee8e366 --- /dev/null +++ b/data/items/consumables/snapdragon_potion_unf.yaml @@ -0,0 +1,12 @@ +id: snapdragon_potion_unf +name: "snapdragon potion (unf)" +color: "48" +description: "An unfinished potion with snapdragon floating in water." +value: 68 +stackable: false +made_from: + - items: [snapdragon] + quantity: 1 + - items: [vial_of_water] + quantity: 1 +ticks: 0 diff --git a/data/items/stim_potion.yaml b/data/items/consumables/stim_potion.yaml index de51291..de51291 100644 --- a/data/items/stim_potion.yaml +++ b/data/items/consumables/stim_potion.yaml diff --git a/data/items/strawberry.yaml b/data/items/consumables/strawberry.yaml index 337a65e..337a65e 100644 --- a/data/items/strawberry.yaml +++ b/data/items/consumables/strawberry.yaml diff --git a/data/items/super_amp.yaml b/data/items/consumables/super_amp.yaml index 3bea59b..3bea59b 100644 --- a/data/items/super_amp.yaml +++ b/data/items/consumables/super_amp.yaml diff --git a/data/items/super_bio_serum.yaml b/data/items/consumables/super_bio_serum.yaml index fbc5ebe..fbc5ebe 100644 --- a/data/items/super_bio_serum.yaml +++ b/data/items/consumables/super_bio_serum.yaml diff --git a/data/items/super_shield.yaml b/data/items/consumables/super_shield.yaml index 7545b2e..7545b2e 100644 --- a/data/items/super_shield.yaml +++ b/data/items/consumables/super_shield.yaml diff --git a/data/items/super_stim.yaml b/data/items/consumables/super_stim.yaml index c290c5f..c290c5f 100644 --- a/data/items/super_stim.yaml +++ b/data/items/consumables/super_stim.yaml diff --git a/data/items/super_stim_cell.yaml b/data/items/consumables/super_stim_cell.yaml index 1f25597..1f25597 100644 --- a/data/items/super_stim_cell.yaml +++ b/data/items/consumables/super_stim_cell.yaml diff --git a/data/items/sweetcorn.yaml b/data/items/consumables/sweetcorn.yaml index 32f5a70..32f5a70 100644 --- a/data/items/sweetcorn.yaml +++ b/data/items/consumables/sweetcorn.yaml diff --git a/data/items/targeting_serum.yaml b/data/items/consumables/targeting_serum.yaml index b10ebc5..b10ebc5 100644 --- a/data/items/targeting_serum.yaml +++ b/data/items/consumables/targeting_serum.yaml diff --git a/data/items/consumables/tarromin_potion_unf.yaml b/data/items/consumables/tarromin_potion_unf.yaml new file mode 100644 index 0000000..abc6438 --- /dev/null +++ b/data/items/consumables/tarromin_potion_unf.yaml @@ -0,0 +1,12 @@ +id: tarromin_potion_unf +name: "tarromin potion (unf)" +color: "48" +description: "An unfinished potion with tarromin floating in water." +value: 12 +stackable: false +made_from: + - items: [tarromin] + quantity: 1 + - items: [vial_of_water] + quantity: 1 +ticks: 0 diff --git a/data/items/tech_serum.yaml b/data/items/consumables/tech_serum.yaml index aac3fdc..aac3fdc 100644 --- a/data/items/tech_serum.yaml +++ b/data/items/consumables/tech_serum.yaml diff --git a/data/items/consumables/toadflax_potion_unf.yaml b/data/items/consumables/toadflax_potion_unf.yaml new file mode 100644 index 0000000..f05b406 --- /dev/null +++ b/data/items/consumables/toadflax_potion_unf.yaml @@ -0,0 +1,12 @@ +id: toadflax_potion_unf +name: "toadflax potion (unf)" +color: "48" +description: "An unfinished potion with toadflax floating in water." +value: 28 +stackable: false +made_from: + - items: [toadflax] + quantity: 1 + - items: [vial_of_water] + quantity: 1 +ticks: 0 diff --git a/data/items/tomato.yaml b/data/items/consumables/tomato.yaml index d2ad349..d2ad349 100644 --- a/data/items/tomato.yaml +++ b/data/items/consumables/tomato.yaml diff --git a/data/items/consumables/torstol_potion_unf.yaml b/data/items/consumables/torstol_potion_unf.yaml new file mode 100644 index 0000000..cf551df --- /dev/null +++ b/data/items/consumables/torstol_potion_unf.yaml @@ -0,0 +1,12 @@ +id: torstol_potion_unf +name: "torstol potion (unf)" +color: "48" +description: "An unfinished potion with torstol floating in water." +value: 102 +stackable: false +made_from: + - items: [torstol] + quantity: 1 + - items: [vial_of_water] + quantity: 1 +ticks: 0 diff --git a/data/items/trout.yaml b/data/items/consumables/trout.yaml index df6cdcc..df6cdcc 100644 --- a/data/items/trout.yaml +++ b/data/items/consumables/trout.yaml diff --git a/data/items/vial_of_water.yaml b/data/items/consumables/vial_of_water.yaml index c3e2995..c3e2995 100644 --- a/data/items/vial_of_water.yaml +++ b/data/items/consumables/vial_of_water.yaml diff --git a/data/items/watermelon.yaml b/data/items/consumables/watermelon.yaml index 3374687..3374687 100644 --- a/data/items/watermelon.yaml +++ b/data/items/consumables/watermelon.yaml diff --git a/data/items/advanced_bio_deck.yaml b/data/items/decks/advanced_bio_deck.yaml index 1411a16..1411a16 100644 --- a/data/items/advanced_bio_deck.yaml +++ b/data/items/decks/advanced_bio_deck.yaml diff --git a/data/items/advanced_eco_deck.yaml b/data/items/decks/advanced_eco_deck.yaml index c844f47..c844f47 100644 --- a/data/items/advanced_eco_deck.yaml +++ b/data/items/decks/advanced_eco_deck.yaml diff --git a/data/items/advanced_hydro_deck.yaml b/data/items/decks/advanced_hydro_deck.yaml index 2910931..2910931 100644 --- a/data/items/advanced_hydro_deck.yaml +++ b/data/items/decks/advanced_hydro_deck.yaml diff --git a/data/items/advanced_solar_deck.yaml b/data/items/decks/advanced_solar_deck.yaml index 002845c..002845c 100644 --- a/data/items/advanced_solar_deck.yaml +++ b/data/items/decks/advanced_solar_deck.yaml diff --git a/data/items/basic_deck.yaml b/data/items/decks/basic_deck.yaml index ef2549a..ef2549a 100644 --- a/data/items/basic_deck.yaml +++ b/data/items/decks/basic_deck.yaml diff --git a/data/items/bio_deck.yaml b/data/items/decks/bio_deck.yaml index 8de2036..8de2036 100644 --- a/data/items/bio_deck.yaml +++ b/data/items/decks/bio_deck.yaml diff --git a/data/items/bio_identifier.yaml b/data/items/decks/bio_identifier.yaml index 1b5a941..1b5a941 100644 --- a/data/items/bio_identifier.yaml +++ b/data/items/decks/bio_identifier.yaml diff --git a/data/items/biojunk.yaml b/data/items/decks/biojunk.yaml index 8832a20..8832a20 100644 --- a/data/items/biojunk.yaml +++ b/data/items/decks/biojunk.yaml diff --git a/data/items/blood_identifier.yaml b/data/items/decks/blood_identifier.yaml index 3540179..3540179 100644 --- a/data/items/blood_identifier.yaml +++ b/data/items/decks/blood_identifier.yaml diff --git a/data/items/bloodjunk.yaml b/data/items/decks/bloodjunk.yaml index b837137..b837137 100644 --- a/data/items/bloodjunk.yaml +++ b/data/items/decks/bloodjunk.yaml diff --git a/data/items/chaos_identifier.yaml b/data/items/decks/chaos_identifier.yaml index 82a7ccf..82a7ccf 100644 --- a/data/items/chaos_identifier.yaml +++ b/data/items/decks/chaos_identifier.yaml diff --git a/data/items/chaosjunk.yaml b/data/items/decks/chaosjunk.yaml index 99515df..99515df 100644 --- a/data/items/chaosjunk.yaml +++ b/data/items/decks/chaosjunk.yaml diff --git a/data/items/cosmic_identifier.yaml b/data/items/decks/cosmic_identifier.yaml index 97cb89a..97cb89a 100644 --- a/data/items/cosmic_identifier.yaml +++ b/data/items/decks/cosmic_identifier.yaml diff --git a/data/items/cosmicjunk.yaml b/data/items/decks/cosmicjunk.yaml index d9acc21..d9acc21 100644 --- a/data/items/cosmicjunk.yaml +++ b/data/items/decks/cosmicjunk.yaml diff --git a/data/items/death_identifier.yaml b/data/items/decks/death_identifier.yaml index 778bca5..778bca5 100644 --- a/data/items/death_identifier.yaml +++ b/data/items/decks/death_identifier.yaml diff --git a/data/items/deathjunk.yaml b/data/items/decks/deathjunk.yaml index 7dcaba8..7dcaba8 100644 --- a/data/items/deathjunk.yaml +++ b/data/items/decks/deathjunk.yaml diff --git a/data/items/eco_deck.yaml b/data/items/decks/eco_deck.yaml index ef1a991..ef1a991 100644 --- a/data/items/eco_deck.yaml +++ b/data/items/decks/eco_deck.yaml diff --git a/data/items/eco_identifier.yaml b/data/items/decks/eco_identifier.yaml index d0af516..d0af516 100644 --- a/data/items/eco_identifier.yaml +++ b/data/items/decks/eco_identifier.yaml diff --git a/data/items/ecojunk.yaml b/data/items/decks/ecojunk.yaml index c050049..c050049 100644 --- a/data/items/ecojunk.yaml +++ b/data/items/decks/ecojunk.yaml diff --git a/data/items/hydro_deck.yaml b/data/items/decks/hydro_deck.yaml index 0e417a2..0e417a2 100644 --- a/data/items/hydro_deck.yaml +++ b/data/items/decks/hydro_deck.yaml diff --git a/data/items/hydro_identifier.yaml b/data/items/decks/hydro_identifier.yaml index 3eb7d98..3eb7d98 100644 --- a/data/items/hydro_identifier.yaml +++ b/data/items/decks/hydro_identifier.yaml diff --git a/data/items/hydrojunk.yaml b/data/items/decks/hydrojunk.yaml index bfcd64a..bfcd64a 100644 --- a/data/items/hydrojunk.yaml +++ b/data/items/decks/hydrojunk.yaml diff --git a/data/items/law_identifier.yaml b/data/items/decks/law_identifier.yaml index 25700e1..25700e1 100644 --- a/data/items/law_identifier.yaml +++ b/data/items/decks/law_identifier.yaml diff --git a/data/items/lawjunk.yaml b/data/items/decks/lawjunk.yaml index b46bf9e..b46bf9e 100644 --- a/data/items/lawjunk.yaml +++ b/data/items/decks/lawjunk.yaml diff --git a/data/items/nature_identifier.yaml b/data/items/decks/nature_identifier.yaml index dc441cf..dc441cf 100644 --- a/data/items/nature_identifier.yaml +++ b/data/items/decks/nature_identifier.yaml diff --git a/data/items/naturejunk.yaml b/data/items/decks/naturejunk.yaml index 49ed1ff..49ed1ff 100644 --- a/data/items/naturejunk.yaml +++ b/data/items/decks/naturejunk.yaml diff --git a/data/items/solar_deck.yaml b/data/items/decks/solar_deck.yaml index 72b7e9e..72b7e9e 100644 --- a/data/items/solar_deck.yaml +++ b/data/items/decks/solar_deck.yaml diff --git a/data/items/solar_identifier.yaml b/data/items/decks/solar_identifier.yaml index 663bd9f..663bd9f 100644 --- a/data/items/solar_identifier.yaml +++ b/data/items/decks/solar_identifier.yaml diff --git a/data/items/solarjunk.yaml b/data/items/decks/solarjunk.yaml index ab4d5d5..ab4d5d5 100644 --- a/data/items/solarjunk.yaml +++ b/data/items/decks/solarjunk.yaml diff --git a/data/items/dwarf_weed_potion_unf.yaml b/data/items/dwarf_weed_potion_unf.yaml deleted file mode 100644 index 1a9516e..0000000 --- a/data/items/dwarf_weed_potion_unf.yaml +++ /dev/null @@ -1,12 +0,0 @@ -id: dwarf_weed_potion_unf -name: "dwarf weed potion (unf)" -color: "48" -description: "An unfinished potion with dwarf weed floating in water." -value: 88 -stackable: false -made_from: - - items: [dwarf_weed] - qty: 1 - - items: [vial_of_water] - qty: 1 -ticks: 0 diff --git a/data/items/abyssal_bracelet.yaml b/data/items/equipment/abyssal_bracelet.yaml index 3b424c3..3b424c3 100644 --- a/data/items/abyssal_bracelet.yaml +++ b/data/items/equipment/abyssal_bracelet.yaml diff --git a/data/items/adamant_dagger.yaml b/data/items/equipment/adamant_dagger.yaml index d78ecdc..d78ecdc 100644 --- a/data/items/adamant_dagger.yaml +++ b/data/items/equipment/adamant_dagger.yaml diff --git a/data/items/adamant_full_helm.yaml b/data/items/equipment/adamant_full_helm.yaml index 3c36c62..3c36c62 100644 --- a/data/items/adamant_full_helm.yaml +++ b/data/items/equipment/adamant_full_helm.yaml diff --git a/data/items/adamant_med_helm.yaml b/data/items/equipment/adamant_med_helm.yaml index 1fb6785..1fb6785 100644 --- a/data/items/adamant_med_helm.yaml +++ b/data/items/equipment/adamant_med_helm.yaml diff --git a/data/items/adamant_platebody.yaml b/data/items/equipment/adamant_platebody.yaml index a37b781..a37b781 100644 --- a/data/items/adamant_platebody.yaml +++ b/data/items/equipment/adamant_platebody.yaml diff --git a/data/items/adamant_sword.yaml b/data/items/equipment/adamant_sword.yaml index 035b615..035b615 100644 --- a/data/items/adamant_sword.yaml +++ b/data/items/equipment/adamant_sword.yaml diff --git a/data/items/binding_necklace.yaml b/data/items/equipment/binding_necklace.yaml index e9e7559..e9e7559 100644 --- a/data/items/binding_necklace.yaml +++ b/data/items/equipment/binding_necklace.yaml diff --git a/data/items/black_axe.yaml b/data/items/equipment/black_axe.yaml index e708645..e708645 100644 --- a/data/items/black_axe.yaml +++ b/data/items/equipment/black_axe.yaml diff --git a/data/items/bracelet_of_clay.yaml b/data/items/equipment/bracelet_of_clay.yaml index d8cd881..d8cd881 100644 --- a/data/items/bracelet_of_clay.yaml +++ b/data/items/equipment/bracelet_of_clay.yaml diff --git a/data/items/bracelet_of_slaughter.yaml b/data/items/equipment/bracelet_of_slaughter.yaml index 2bbbbec..2bbbbec 100644 --- a/data/items/bracelet_of_slaughter.yaml +++ b/data/items/equipment/bracelet_of_slaughter.yaml diff --git a/data/items/bronze_dagger.yaml b/data/items/equipment/bronze_dagger.yaml index 95ec968..95ec968 100644 --- a/data/items/bronze_dagger.yaml +++ b/data/items/equipment/bronze_dagger.yaml diff --git a/data/items/bronze_full_helm.yaml b/data/items/equipment/bronze_full_helm.yaml index ed006a8..ed006a8 100644 --- a/data/items/bronze_full_helm.yaml +++ b/data/items/equipment/bronze_full_helm.yaml diff --git a/data/items/bronze_med_helm.yaml b/data/items/equipment/bronze_med_helm.yaml index c9635cf..c9635cf 100644 --- a/data/items/bronze_med_helm.yaml +++ b/data/items/equipment/bronze_med_helm.yaml diff --git a/data/items/bronze_platebody.yaml b/data/items/equipment/bronze_platebody.yaml index 8e6dd2c..8e6dd2c 100644 --- a/data/items/bronze_platebody.yaml +++ b/data/items/equipment/bronze_platebody.yaml diff --git a/data/items/bronze_sword.yaml b/data/items/equipment/bronze_sword.yaml index 0cfdd0e..0cfdd0e 100644 --- a/data/items/bronze_sword.yaml +++ b/data/items/equipment/bronze_sword.yaml diff --git a/data/items/capacitor_gloves.yaml b/data/items/equipment/capacitor_gloves.yaml index e5af9ed..e5af9ed 100644 --- a/data/items/capacitor_gloves.yaml +++ b/data/items/equipment/capacitor_gloves.yaml diff --git a/data/items/cape_of_agility.yaml b/data/items/equipment/cape_of_agility.yaml index 5567e73..5567e73 100644 --- a/data/items/cape_of_agility.yaml +++ b/data/items/equipment/cape_of_agility.yaml diff --git a/data/items/chitin_plate.yaml b/data/items/equipment/chitin_plate.yaml index 4148a2a..4148a2a 100644 --- a/data/items/chitin_plate.yaml +++ b/data/items/equipment/chitin_plate.yaml diff --git a/data/items/coif.yaml b/data/items/equipment/coif.yaml index 8d910d7..8d910d7 100644 --- a/data/items/coif.yaml +++ b/data/items/equipment/coif.yaml diff --git a/data/items/diamond_amulet_u.yaml b/data/items/equipment/diamond_amulet_u.yaml index 55eaf45..55eaf45 100644 --- a/data/items/diamond_amulet_u.yaml +++ b/data/items/equipment/diamond_amulet_u.yaml diff --git a/data/items/diamond_bracelet.yaml b/data/items/equipment/diamond_bracelet.yaml index 5ba5778..5ba5778 100644 --- a/data/items/diamond_bracelet.yaml +++ b/data/items/equipment/diamond_bracelet.yaml diff --git a/data/items/diamond_necklace.yaml b/data/items/equipment/diamond_necklace.yaml index 5629b8c..5629b8c 100644 --- a/data/items/diamond_necklace.yaml +++ b/data/items/equipment/diamond_necklace.yaml diff --git a/data/items/diamond_ring.yaml b/data/items/equipment/diamond_ring.yaml index 54023c3..54023c3 100644 --- a/data/items/diamond_ring.yaml +++ b/data/items/equipment/diamond_ring.yaml diff --git a/data/items/digsite_pendant.yaml b/data/items/equipment/digsite_pendant.yaml index b28e3e3..b28e3e3 100644 --- a/data/items/digsite_pendant.yaml +++ b/data/items/equipment/digsite_pendant.yaml diff --git a/data/items/dragon_axe.yaml b/data/items/equipment/dragon_axe.yaml index ddc9758..ddc9758 100644 --- a/data/items/dragon_axe.yaml +++ b/data/items/equipment/dragon_axe.yaml diff --git a/data/items/emerald_amulet_u.yaml b/data/items/equipment/emerald_amulet_u.yaml index 87261d4..87261d4 100644 --- a/data/items/emerald_amulet_u.yaml +++ b/data/items/equipment/emerald_amulet_u.yaml diff --git a/data/items/emerald_bracelet.yaml b/data/items/equipment/emerald_bracelet.yaml index 04e4979..04e4979 100644 --- a/data/items/emerald_bracelet.yaml +++ b/data/items/equipment/emerald_bracelet.yaml diff --git a/data/items/emerald_necklace.yaml b/data/items/equipment/emerald_necklace.yaml index 2107ca4..2107ca4 100644 --- a/data/items/emerald_necklace.yaml +++ b/data/items/equipment/emerald_necklace.yaml diff --git a/data/items/emerald_ring.yaml b/data/items/equipment/emerald_ring.yaml index 253f872..253f872 100644 --- a/data/items/emerald_ring.yaml +++ b/data/items/equipment/emerald_ring.yaml diff --git a/data/items/gold_amulet_u.yaml b/data/items/equipment/gold_amulet_u.yaml index 8671941..8671941 100644 --- a/data/items/gold_amulet_u.yaml +++ b/data/items/equipment/gold_amulet_u.yaml diff --git a/data/items/gold_bracelet.yaml b/data/items/equipment/gold_bracelet.yaml index 2c4534f..2c4534f 100644 --- a/data/items/gold_bracelet.yaml +++ b/data/items/equipment/gold_bracelet.yaml diff --git a/data/items/gold_necklace.yaml b/data/items/equipment/gold_necklace.yaml index 4a22ac1..4a22ac1 100644 --- a/data/items/gold_necklace.yaml +++ b/data/items/equipment/gold_necklace.yaml diff --git a/data/items/gold_ring.yaml b/data/items/equipment/gold_ring.yaml index 1a39165..1a39165 100644 --- a/data/items/gold_ring.yaml +++ b/data/items/equipment/gold_ring.yaml diff --git a/data/items/graceful_boots.yaml b/data/items/equipment/graceful_boots.yaml index 71e8f84..71e8f84 100644 --- a/data/items/graceful_boots.yaml +++ b/data/items/equipment/graceful_boots.yaml diff --git a/data/items/graceful_cape.yaml b/data/items/equipment/graceful_cape.yaml index 1d7c8f0..1d7c8f0 100644 --- a/data/items/graceful_cape.yaml +++ b/data/items/equipment/graceful_cape.yaml diff --git a/data/items/graceful_gloves.yaml b/data/items/equipment/graceful_gloves.yaml index 311ded5..311ded5 100644 --- a/data/items/graceful_gloves.yaml +++ b/data/items/equipment/graceful_gloves.yaml diff --git a/data/items/graceful_hat.yaml b/data/items/equipment/graceful_hat.yaml index faec1e3..faec1e3 100644 --- a/data/items/graceful_hat.yaml +++ b/data/items/equipment/graceful_hat.yaml diff --git a/data/items/graceful_legs.yaml b/data/items/equipment/graceful_legs.yaml index 31eeebf..31eeebf 100644 --- a/data/items/graceful_legs.yaml +++ b/data/items/equipment/graceful_legs.yaml diff --git a/data/items/graceful_torso.yaml b/data/items/equipment/graceful_torso.yaml index ec1edb7..ec1edb7 100644 --- a/data/items/graceful_torso.yaml +++ b/data/items/equipment/graceful_torso.yaml diff --git a/data/items/hard_leather_body.yaml b/data/items/equipment/hard_leather_body.yaml index a5fe30f..a5fe30f 100644 --- a/data/items/hard_leather_body.yaml +++ b/data/items/equipment/hard_leather_body.yaml diff --git a/data/items/hard_leather_shield.yaml b/data/items/equipment/hard_leather_shield.yaml index fd7dabf..fd7dabf 100644 --- a/data/items/hard_leather_shield.yaml +++ b/data/items/equipment/hard_leather_shield.yaml diff --git a/data/items/inoculation_bracelet.yaml b/data/items/equipment/inoculation_bracelet.yaml index 9a3a149..9a3a149 100644 --- a/data/items/inoculation_bracelet.yaml +++ b/data/items/equipment/inoculation_bracelet.yaml diff --git a/data/items/insulated_gloves.yaml b/data/items/equipment/insulated_gloves.yaml index 3e53614..3e53614 100644 --- a/data/items/insulated_gloves.yaml +++ b/data/items/equipment/insulated_gloves.yaml diff --git a/data/items/iron_dagger.yaml b/data/items/equipment/iron_dagger.yaml index 8fa645c..8fa645c 100644 --- a/data/items/iron_dagger.yaml +++ b/data/items/equipment/iron_dagger.yaml diff --git a/data/items/iron_full_helm.yaml b/data/items/equipment/iron_full_helm.yaml index 3a2fc0c..3a2fc0c 100644 --- a/data/items/iron_full_helm.yaml +++ b/data/items/equipment/iron_full_helm.yaml diff --git a/data/items/iron_med_helm.yaml b/data/items/equipment/iron_med_helm.yaml index 6956283..6956283 100644 --- a/data/items/iron_med_helm.yaml +++ b/data/items/equipment/iron_med_helm.yaml diff --git a/data/items/iron_platebody.yaml b/data/items/equipment/iron_platebody.yaml index 3c0be80..3c0be80 100644 --- a/data/items/iron_platebody.yaml +++ b/data/items/equipment/iron_platebody.yaml diff --git a/data/items/iron_sword.yaml b/data/items/equipment/iron_sword.yaml index a5711fc..a5711fc 100644 --- a/data/items/iron_sword.yaml +++ b/data/items/equipment/iron_sword.yaml diff --git a/data/items/leather_body.yaml b/data/items/equipment/leather_body.yaml index e69342c..e69342c 100644 --- a/data/items/leather_body.yaml +++ b/data/items/equipment/leather_body.yaml diff --git a/data/items/leather_boots.yaml b/data/items/equipment/leather_boots.yaml index 7716e95..7716e95 100644 --- a/data/items/leather_boots.yaml +++ b/data/items/equipment/leather_boots.yaml diff --git a/data/items/leather_chaps.yaml b/data/items/equipment/leather_chaps.yaml index 1a17c16..1a17c16 100644 --- a/data/items/leather_chaps.yaml +++ b/data/items/equipment/leather_chaps.yaml diff --git a/data/items/leather_cowl.yaml b/data/items/equipment/leather_cowl.yaml index aa5965a..aa5965a 100644 --- a/data/items/leather_cowl.yaml +++ b/data/items/equipment/leather_cowl.yaml diff --git a/data/items/leather_gloves.yaml b/data/items/equipment/leather_gloves.yaml index 7590fee..7590fee 100644 --- a/data/items/leather_gloves.yaml +++ b/data/items/equipment/leather_gloves.yaml diff --git a/data/items/leather_vambraces.yaml b/data/items/equipment/leather_vambraces.yaml index fa59aa9..fa59aa9 100644 --- a/data/items/leather_vambraces.yaml +++ b/data/items/equipment/leather_vambraces.yaml diff --git a/data/items/longbow.yaml b/data/items/equipment/longbow.yaml index f40c96d..f40c96d 100644 --- a/data/items/longbow.yaml +++ b/data/items/equipment/longbow.yaml diff --git a/data/items/longbow_u.yaml b/data/items/equipment/longbow_u.yaml index 93e5ff0..93e5ff0 100644 --- a/data/items/longbow_u.yaml +++ b/data/items/equipment/longbow_u.yaml diff --git a/data/items/magic_longbow.yaml b/data/items/equipment/magic_longbow.yaml index 07797fb..07797fb 100644 --- a/data/items/magic_longbow.yaml +++ b/data/items/equipment/magic_longbow.yaml diff --git a/data/items/magic_longbow_u.yaml b/data/items/equipment/magic_longbow_u.yaml index 65682ed..65682ed 100644 --- a/data/items/magic_longbow_u.yaml +++ b/data/items/equipment/magic_longbow_u.yaml diff --git a/data/items/magic_shortbow.yaml b/data/items/equipment/magic_shortbow.yaml index 893b287..893b287 100644 --- a/data/items/magic_shortbow.yaml +++ b/data/items/equipment/magic_shortbow.yaml diff --git a/data/items/magic_shortbow_u.yaml b/data/items/equipment/magic_shortbow_u.yaml index 2075bd1..2075bd1 100644 --- a/data/items/magic_shortbow_u.yaml +++ b/data/items/equipment/magic_shortbow_u.yaml diff --git a/data/items/maple_longbow.yaml b/data/items/equipment/maple_longbow.yaml index 1c86128..1c86128 100644 --- a/data/items/maple_longbow.yaml +++ b/data/items/equipment/maple_longbow.yaml diff --git a/data/items/maple_longbow_u.yaml b/data/items/equipment/maple_longbow_u.yaml index 120bf1d..120bf1d 100644 --- a/data/items/maple_longbow_u.yaml +++ b/data/items/equipment/maple_longbow_u.yaml diff --git a/data/items/maple_shortbow.yaml b/data/items/equipment/maple_shortbow.yaml index 38c27b5..38c27b5 100644 --- a/data/items/maple_shortbow.yaml +++ b/data/items/equipment/maple_shortbow.yaml diff --git a/data/items/maple_shortbow_u.yaml b/data/items/equipment/maple_shortbow_u.yaml index 6fc6b84..6fc6b84 100644 --- a/data/items/maple_shortbow_u.yaml +++ b/data/items/equipment/maple_shortbow_u.yaml diff --git a/data/items/mithril_dagger.yaml b/data/items/equipment/mithril_dagger.yaml index 8ffe595..8ffe595 100644 --- a/data/items/mithril_dagger.yaml +++ b/data/items/equipment/mithril_dagger.yaml diff --git a/data/items/mithril_full_helm.yaml b/data/items/equipment/mithril_full_helm.yaml index d317705..d317705 100644 --- a/data/items/mithril_full_helm.yaml +++ b/data/items/equipment/mithril_full_helm.yaml diff --git a/data/items/mithril_med_helm.yaml b/data/items/equipment/mithril_med_helm.yaml index f244a7c..f244a7c 100644 --- a/data/items/mithril_med_helm.yaml +++ b/data/items/equipment/mithril_med_helm.yaml diff --git a/data/items/mithril_platebody.yaml b/data/items/equipment/mithril_platebody.yaml index 50e8ea0..50e8ea0 100644 --- a/data/items/mithril_platebody.yaml +++ b/data/items/equipment/mithril_platebody.yaml diff --git a/data/items/mithril_sword.yaml b/data/items/equipment/mithril_sword.yaml index 1824f5b..1824f5b 100644 --- a/data/items/mithril_sword.yaml +++ b/data/items/equipment/mithril_sword.yaml diff --git a/data/items/necklace_of_passage.yaml b/data/items/equipment/necklace_of_passage.yaml index b5630ed..b5630ed 100644 --- a/data/items/necklace_of_passage.yaml +++ b/data/items/equipment/necklace_of_passage.yaml diff --git a/data/items/neural_headband.yaml b/data/items/equipment/neural_headband.yaml index e01e57d..e01e57d 100644 --- a/data/items/neural_headband.yaml +++ b/data/items/equipment/neural_headband.yaml diff --git a/data/items/oak_longbow.yaml b/data/items/equipment/oak_longbow.yaml index 71e7c7c..71e7c7c 100644 --- a/data/items/oak_longbow.yaml +++ b/data/items/equipment/oak_longbow.yaml diff --git a/data/items/oak_longbow_u.yaml b/data/items/equipment/oak_longbow_u.yaml index 6df0dab..6df0dab 100644 --- a/data/items/oak_longbow_u.yaml +++ b/data/items/equipment/oak_longbow_u.yaml diff --git a/data/items/oak_shortbow.yaml b/data/items/equipment/oak_shortbow.yaml index 30ebbce..30ebbce 100644 --- a/data/items/oak_shortbow.yaml +++ b/data/items/equipment/oak_shortbow.yaml diff --git a/data/items/oak_shortbow_u.yaml b/data/items/equipment/oak_shortbow_u.yaml index 5bebc38..5bebc38 100644 --- a/data/items/oak_shortbow_u.yaml +++ b/data/items/equipment/oak_shortbow_u.yaml diff --git a/data/items/party_hat_blue.yaml b/data/items/equipment/party_hat_blue.yaml index 42d6bb5..42d6bb5 100644 --- a/data/items/party_hat_blue.yaml +++ b/data/items/equipment/party_hat_blue.yaml diff --git a/data/items/party_hat_green.yaml b/data/items/equipment/party_hat_green.yaml index 82c3bc7..82c3bc7 100644 --- a/data/items/party_hat_green.yaml +++ b/data/items/equipment/party_hat_green.yaml diff --git a/data/items/party_hat_pink.yaml b/data/items/equipment/party_hat_pink.yaml index 006e261..006e261 100644 --- a/data/items/party_hat_pink.yaml +++ b/data/items/equipment/party_hat_pink.yaml diff --git a/data/items/party_hat_red.yaml b/data/items/equipment/party_hat_red.yaml index 005b3dd..005b3dd 100644 --- a/data/items/party_hat_red.yaml +++ b/data/items/equipment/party_hat_red.yaml diff --git a/data/items/party_hat_white.yaml b/data/items/equipment/party_hat_white.yaml index c8e8f86..c8e8f86 100644 --- a/data/items/party_hat_white.yaml +++ b/data/items/equipment/party_hat_white.yaml diff --git a/data/items/party_hat_yellow.yaml b/data/items/equipment/party_hat_yellow.yaml index 33a85f8..33a85f8 100644 --- a/data/items/party_hat_yellow.yaml +++ b/data/items/equipment/party_hat_yellow.yaml diff --git a/data/items/phoenix_necklace.yaml b/data/items/equipment/phoenix_necklace.yaml index b53fafb..b53fafb 100644 --- a/data/items/phoenix_necklace.yaml +++ b/data/items/equipment/phoenix_necklace.yaml diff --git a/data/items/power_amulet.yaml b/data/items/equipment/power_amulet.yaml index bd136a4..bd136a4 100644 --- a/data/items/power_amulet.yaml +++ b/data/items/equipment/power_amulet.yaml diff --git a/data/items/ring_of_dueling.yaml b/data/items/equipment/ring_of_dueling.yaml index 0c11e87..0c11e87 100644 --- a/data/items/ring_of_dueling.yaml +++ b/data/items/equipment/ring_of_dueling.yaml diff --git a/data/items/ring_of_forging.yaml b/data/items/equipment/ring_of_forging.yaml index d0792a1..d0792a1 100644 --- a/data/items/ring_of_forging.yaml +++ b/data/items/equipment/ring_of_forging.yaml diff --git a/data/items/ring_of_life.yaml b/data/items/equipment/ring_of_life.yaml index ab0b6e3..ab0b6e3 100644 --- a/data/items/ring_of_life.yaml +++ b/data/items/equipment/ring_of_life.yaml diff --git a/data/items/ring_of_recoil.yaml b/data/items/equipment/ring_of_recoil.yaml index c143f68..c143f68 100644 --- a/data/items/ring_of_recoil.yaml +++ b/data/items/equipment/ring_of_recoil.yaml diff --git a/data/items/ruby_amulet_u.yaml b/data/items/equipment/ruby_amulet_u.yaml index 031bf8b..031bf8b 100644 --- a/data/items/ruby_amulet_u.yaml +++ b/data/items/equipment/ruby_amulet_u.yaml diff --git a/data/items/ruby_bracelet.yaml b/data/items/equipment/ruby_bracelet.yaml index e5f3f70..e5f3f70 100644 --- a/data/items/ruby_bracelet.yaml +++ b/data/items/equipment/ruby_bracelet.yaml diff --git a/data/items/ruby_necklace.yaml b/data/items/equipment/ruby_necklace.yaml index e181777..e181777 100644 --- a/data/items/ruby_necklace.yaml +++ b/data/items/equipment/ruby_necklace.yaml diff --git a/data/items/ruby_ring.yaml b/data/items/equipment/ruby_ring.yaml index cb0cfde..cb0cfde 100644 --- a/data/items/ruby_ring.yaml +++ b/data/items/equipment/ruby_ring.yaml diff --git a/data/items/rune_dagger.yaml b/data/items/equipment/rune_dagger.yaml index 9e8507b..9e8507b 100644 --- a/data/items/rune_dagger.yaml +++ b/data/items/equipment/rune_dagger.yaml diff --git a/data/items/rune_full_helm.yaml b/data/items/equipment/rune_full_helm.yaml index 87d6973..87d6973 100644 --- a/data/items/rune_full_helm.yaml +++ b/data/items/equipment/rune_full_helm.yaml diff --git a/data/items/rune_med_helm.yaml b/data/items/equipment/rune_med_helm.yaml index 895d257..895d257 100644 --- a/data/items/rune_med_helm.yaml +++ b/data/items/equipment/rune_med_helm.yaml diff --git a/data/items/rune_platebody.yaml b/data/items/equipment/rune_platebody.yaml index d1e5fb1..d1e5fb1 100644 --- a/data/items/rune_platebody.yaml +++ b/data/items/equipment/rune_platebody.yaml diff --git a/data/items/rune_sword.yaml b/data/items/equipment/rune_sword.yaml index e0bfb74..e0bfb74 100644 --- a/data/items/rune_sword.yaml +++ b/data/items/equipment/rune_sword.yaml diff --git a/data/items/sapphire_amulet_u.yaml b/data/items/equipment/sapphire_amulet_u.yaml index 22ef39c..22ef39c 100644 --- a/data/items/sapphire_amulet_u.yaml +++ b/data/items/equipment/sapphire_amulet_u.yaml diff --git a/data/items/sapphire_bracelet.yaml b/data/items/equipment/sapphire_bracelet.yaml index a2996eb..a2996eb 100644 --- a/data/items/sapphire_bracelet.yaml +++ b/data/items/equipment/sapphire_bracelet.yaml diff --git a/data/items/sapphire_necklace.yaml b/data/items/equipment/sapphire_necklace.yaml index e553973..e553973 100644 --- a/data/items/sapphire_necklace.yaml +++ b/data/items/equipment/sapphire_necklace.yaml diff --git a/data/items/sapphire_ring.yaml b/data/items/equipment/sapphire_ring.yaml index 40e8cc5..40e8cc5 100644 --- a/data/items/sapphire_ring.yaml +++ b/data/items/equipment/sapphire_ring.yaml diff --git a/data/items/shortbow.yaml b/data/items/equipment/shortbow.yaml index ecd3630..ecd3630 100644 --- a/data/items/shortbow.yaml +++ b/data/items/equipment/shortbow.yaml diff --git a/data/items/shortbow_u.yaml b/data/items/equipment/shortbow_u.yaml index 6ffcafc..6ffcafc 100644 --- a/data/items/shortbow_u.yaml +++ b/data/items/equipment/shortbow_u.yaml diff --git a/data/items/spectral_visor.yaml b/data/items/equipment/spectral_visor.yaml index 851a929..851a929 100644 --- a/data/items/spectral_visor.yaml +++ b/data/items/equipment/spectral_visor.yaml diff --git a/data/items/steel_dagger.yaml b/data/items/equipment/steel_dagger.yaml index e52b882..e52b882 100644 --- a/data/items/steel_dagger.yaml +++ b/data/items/equipment/steel_dagger.yaml diff --git a/data/items/steel_full_helm.yaml b/data/items/equipment/steel_full_helm.yaml index 7152ded..7152ded 100644 --- a/data/items/steel_full_helm.yaml +++ b/data/items/equipment/steel_full_helm.yaml diff --git a/data/items/steel_med_helm.yaml b/data/items/equipment/steel_med_helm.yaml index 9e15fdd..9e15fdd 100644 --- a/data/items/steel_med_helm.yaml +++ b/data/items/equipment/steel_med_helm.yaml diff --git a/data/items/steel_platebody.yaml b/data/items/equipment/steel_platebody.yaml index f44dfa3..f44dfa3 100644 --- a/data/items/steel_platebody.yaml +++ b/data/items/equipment/steel_platebody.yaml diff --git a/data/items/steel_sword.yaml b/data/items/equipment/steel_sword.yaml index e096dc9..e096dc9 100644 --- a/data/items/steel_sword.yaml +++ b/data/items/equipment/steel_sword.yaml diff --git a/data/items/willow_longbow.yaml b/data/items/equipment/willow_longbow.yaml index e30528c..e30528c 100644 --- a/data/items/willow_longbow.yaml +++ b/data/items/equipment/willow_longbow.yaml diff --git a/data/items/willow_longbow_u.yaml b/data/items/equipment/willow_longbow_u.yaml index 5e4e9da..5e4e9da 100644 --- a/data/items/willow_longbow_u.yaml +++ b/data/items/equipment/willow_longbow_u.yaml diff --git a/data/items/willow_shortbow.yaml b/data/items/equipment/willow_shortbow.yaml index f75cfe9..f75cfe9 100644 --- a/data/items/willow_shortbow.yaml +++ b/data/items/equipment/willow_shortbow.yaml diff --git a/data/items/willow_shortbow_u.yaml b/data/items/equipment/willow_shortbow_u.yaml index b467455..b467455 100644 --- a/data/items/willow_shortbow_u.yaml +++ b/data/items/equipment/willow_shortbow_u.yaml diff --git a/data/items/yew_longbow.yaml b/data/items/equipment/yew_longbow.yaml index 1e7c0f5..1e7c0f5 100644 --- a/data/items/yew_longbow.yaml +++ b/data/items/equipment/yew_longbow.yaml diff --git a/data/items/yew_longbow_u.yaml b/data/items/equipment/yew_longbow_u.yaml index ac4fdb2..ac4fdb2 100644 --- a/data/items/yew_longbow_u.yaml +++ b/data/items/equipment/yew_longbow_u.yaml diff --git a/data/items/yew_shortbow.yaml b/data/items/equipment/yew_shortbow.yaml index c302a38..c302a38 100644 --- a/data/items/yew_shortbow.yaml +++ b/data/items/equipment/yew_shortbow.yaml diff --git a/data/items/yew_shortbow_u.yaml b/data/items/equipment/yew_shortbow_u.yaml index 4c2124b..4c2124b 100644 --- a/data/items/yew_shortbow_u.yaml +++ b/data/items/equipment/yew_shortbow_u.yaml diff --git a/data/items/guam_potion_unf.yaml b/data/items/guam_potion_unf.yaml deleted file mode 100644 index 970a9d2..0000000 --- a/data/items/guam_potion_unf.yaml +++ /dev/null @@ -1,12 +0,0 @@ -id: guam_potion_unf -name: "guam potion (unf)" -color: "48" -description: "An unfinished potion with guam floating in water." -value: 5 -stackable: false -made_from: - - items: [guam] - qty: 1 - - items: [vial_of_water] - qty: 1 -ticks: 0 diff --git a/data/items/harralander_potion_unf.yaml b/data/items/harralander_potion_unf.yaml deleted file mode 100644 index bd578c2..0000000 --- a/data/items/harralander_potion_unf.yaml +++ /dev/null @@ -1,12 +0,0 @@ -id: harralander_potion_unf -name: "harralander potion (unf)" -color: "48" -description: "An unfinished potion with harralander floating in water." -value: 18 -stackable: false -made_from: - - items: [harralander] - qty: 1 - - items: [vial_of_water] - qty: 1 -ticks: 0 diff --git a/data/items/irit_potion_unf.yaml b/data/items/irit_potion_unf.yaml deleted file mode 100644 index d10a19a..0000000 --- a/data/items/irit_potion_unf.yaml +++ /dev/null @@ -1,12 +0,0 @@ -id: irit_potion_unf -name: "irit potion (unf)" -color: "48" -description: "An unfinished potion with irit floating in water." -value: 42 -stackable: false -made_from: - - items: [irit] - qty: 1 - - items: [vial_of_water] - qty: 1 -ticks: 0 diff --git a/data/items/kwuarm_potion_unf.yaml b/data/items/kwuarm_potion_unf.yaml deleted file mode 100644 index 750a47a..0000000 --- a/data/items/kwuarm_potion_unf.yaml +++ /dev/null @@ -1,12 +0,0 @@ -id: kwuarm_potion_unf -name: "kwuarm potion (unf)" -color: "48" -description: "An unfinished potion with kwuarm floating in water." -value: 56 -stackable: false -made_from: - - items: [kwuarm] - qty: 1 - - items: [vial_of_water] - qty: 1 -ticks: 0 diff --git a/data/items/lantadyme_potion_unf.yaml b/data/items/lantadyme_potion_unf.yaml deleted file mode 100644 index bc66c3c..0000000 --- a/data/items/lantadyme_potion_unf.yaml +++ /dev/null @@ -1,12 +0,0 @@ -id: lantadyme_potion_unf -name: "lantadyme potion (unf)" -color: "48" -description: "An unfinished potion with lantadyme floating in water." -value: 80 -stackable: false -made_from: - - items: [lantadyme] - qty: 1 - - items: [vial_of_water] - qty: 1 -ticks: 0 diff --git a/data/items/marrentill_potion_unf.yaml b/data/items/marrentill_potion_unf.yaml deleted file mode 100644 index e7b3817..0000000 --- a/data/items/marrentill_potion_unf.yaml +++ /dev/null @@ -1,12 +0,0 @@ -id: marrentill_potion_unf -name: "marrentill potion (unf)" -color: "48" -description: "An unfinished potion with marrentill floating in water." -value: 8 -stackable: false -made_from: - - items: [marrentill] - qty: 1 - - items: [vial_of_water] - qty: 1 -ticks: 0 diff --git a/data/items/adamant_nails.yaml b/data/items/materials/adamant_nails.yaml index c40d228..c40d228 100644 --- a/data/items/adamant_nails.yaml +++ b/data/items/materials/adamant_nails.yaml diff --git a/data/items/adamantite_bar.yaml b/data/items/materials/adamantite_bar.yaml index 5a9b827..5a9b827 100644 --- a/data/items/adamantite_bar.yaml +++ b/data/items/materials/adamantite_bar.yaml diff --git a/data/items/adamantite_ore.yaml b/data/items/materials/adamantite_ore.yaml index fabe0da..fabe0da 100644 --- a/data/items/adamantite_ore.yaml +++ b/data/items/materials/adamantite_ore.yaml diff --git a/data/items/arachnid_enzyme.yaml b/data/items/materials/arachnid_enzyme.yaml index 4be2f65..4be2f65 100644 --- a/data/items/arachnid_enzyme.yaml +++ b/data/items/materials/arachnid_enzyme.yaml diff --git a/data/items/ashes.yaml b/data/items/materials/ashes.yaml index 0b83f77..0b83f77 100644 --- a/data/items/ashes.yaml +++ b/data/items/materials/ashes.yaml diff --git a/data/items/avantoe.yaml b/data/items/materials/avantoe.yaml index d596096..d596096 100644 --- a/data/items/avantoe.yaml +++ b/data/items/materials/avantoe.yaml diff --git a/data/items/ball_of_wool.yaml b/data/items/materials/ball_of_wool.yaml index 1a680a4..1a680a4 100644 --- a/data/items/ball_of_wool.yaml +++ b/data/items/materials/ball_of_wool.yaml diff --git a/data/items/bones.yaml b/data/items/materials/bones.yaml index 25097d3..25097d3 100644 --- a/data/items/bones.yaml +++ b/data/items/materials/bones.yaml diff --git a/data/items/bowstring.yaml b/data/items/materials/bowstring.yaml index a180081..a180081 100644 --- a/data/items/bowstring.yaml +++ b/data/items/materials/bowstring.yaml diff --git a/data/items/bronze_bar.yaml b/data/items/materials/bronze_bar.yaml index 053cfe8..053cfe8 100644 --- a/data/items/bronze_bar.yaml +++ b/data/items/materials/bronze_bar.yaml diff --git a/data/items/bronze_nails.yaml b/data/items/materials/bronze_nails.yaml index 513e9c4..513e9c4 100644 --- a/data/items/bronze_nails.yaml +++ b/data/items/materials/bronze_nails.yaml diff --git a/data/items/cadantine.yaml b/data/items/materials/cadantine.yaml index f684f0d..f684f0d 100644 --- a/data/items/cadantine.yaml +++ b/data/items/materials/cadantine.yaml diff --git a/data/items/chocolate_dust.yaml b/data/items/materials/chocolate_dust.yaml index 56a6666..56a6666 100644 --- a/data/items/chocolate_dust.yaml +++ b/data/items/materials/chocolate_dust.yaml diff --git a/data/items/clay.yaml b/data/items/materials/clay.yaml index 55c9b2b..55c9b2b 100644 --- a/data/items/clay.yaml +++ b/data/items/materials/clay.yaml diff --git a/data/items/coal.yaml b/data/items/materials/coal.yaml index 7b79f08..7b79f08 100644 --- a/data/items/coal.yaml +++ b/data/items/materials/coal.yaml diff --git a/data/items/copper_ore.yaml b/data/items/materials/copper_ore.yaml index 392879a..392879a 100644 --- a/data/items/copper_ore.yaml +++ b/data/items/materials/copper_ore.yaml diff --git a/data/items/cowhide.yaml b/data/items/materials/cowhide.yaml index 2cb192e..2cb192e 100644 --- a/data/items/cowhide.yaml +++ b/data/items/materials/cowhide.yaml diff --git a/data/items/crushed_nest.yaml b/data/items/materials/crushed_nest.yaml index 533d942..533d942 100644 --- a/data/items/crushed_nest.yaml +++ b/data/items/materials/crushed_nest.yaml diff --git a/data/items/diamond.yaml b/data/items/materials/diamond.yaml index 2ec703f..2ec703f 100644 --- a/data/items/diamond.yaml +++ b/data/items/materials/diamond.yaml diff --git a/data/items/dwarf_weed.yaml b/data/items/materials/dwarf_weed.yaml index 559edf3..559edf3 100644 --- a/data/items/dwarf_weed.yaml +++ b/data/items/materials/dwarf_weed.yaml diff --git a/data/items/ectoplasm.yaml b/data/items/materials/ectoplasm.yaml index 8417e2d..8417e2d 100644 --- a/data/items/ectoplasm.yaml +++ b/data/items/materials/ectoplasm.yaml diff --git a/data/items/emerald.yaml b/data/items/materials/emerald.yaml index 9a0c71d..9a0c71d 100644 --- a/data/items/emerald.yaml +++ b/data/items/materials/emerald.yaml diff --git a/data/items/eye_of_newt.yaml b/data/items/materials/eye_of_newt.yaml index baf5ebe..baf5ebe 100644 --- a/data/items/eye_of_newt.yaml +++ b/data/items/materials/eye_of_newt.yaml diff --git a/data/items/feather.yaml b/data/items/materials/feather.yaml index 25afc2a..25afc2a 100644 --- a/data/items/feather.yaml +++ b/data/items/materials/feather.yaml diff --git a/data/items/flax.yaml b/data/items/materials/flax.yaml index 36f7082..36f7082 100644 --- a/data/items/flax.yaml +++ b/data/items/materials/flax.yaml diff --git a/data/items/gold_bar.yaml b/data/items/materials/gold_bar.yaml index 3272b04..3272b04 100644 --- a/data/items/gold_bar.yaml +++ b/data/items/materials/gold_bar.yaml diff --git a/data/items/gold_ore.yaml b/data/items/materials/gold_ore.yaml index e45ca03..e45ca03 100644 --- a/data/items/gold_ore.yaml +++ b/data/items/materials/gold_ore.yaml diff --git a/data/items/grimy_avantoe.yaml b/data/items/materials/grimy_avantoe.yaml index 4f84679..4f84679 100644 --- a/data/items/grimy_avantoe.yaml +++ b/data/items/materials/grimy_avantoe.yaml diff --git a/data/items/grimy_cadantine.yaml b/data/items/materials/grimy_cadantine.yaml index 0eb88f8..0eb88f8 100644 --- a/data/items/grimy_cadantine.yaml +++ b/data/items/materials/grimy_cadantine.yaml diff --git a/data/items/grimy_dwarf_weed.yaml b/data/items/materials/grimy_dwarf_weed.yaml index 8f24595..8f24595 100644 --- a/data/items/grimy_dwarf_weed.yaml +++ b/data/items/materials/grimy_dwarf_weed.yaml diff --git a/data/items/grimy_guam.yaml b/data/items/materials/grimy_guam.yaml index fb408af..fb408af 100644 --- a/data/items/grimy_guam.yaml +++ b/data/items/materials/grimy_guam.yaml diff --git a/data/items/grimy_harralander.yaml b/data/items/materials/grimy_harralander.yaml index deea973..deea973 100644 --- a/data/items/grimy_harralander.yaml +++ b/data/items/materials/grimy_harralander.yaml diff --git a/data/items/grimy_irit.yaml b/data/items/materials/grimy_irit.yaml index 54f66f8..54f66f8 100644 --- a/data/items/grimy_irit.yaml +++ b/data/items/materials/grimy_irit.yaml diff --git a/data/items/grimy_kwuarm.yaml b/data/items/materials/grimy_kwuarm.yaml index 88630f8..88630f8 100644 --- a/data/items/grimy_kwuarm.yaml +++ b/data/items/materials/grimy_kwuarm.yaml diff --git a/data/items/grimy_lantadyme.yaml b/data/items/materials/grimy_lantadyme.yaml index 8003931..8003931 100644 --- a/data/items/grimy_lantadyme.yaml +++ b/data/items/materials/grimy_lantadyme.yaml diff --git a/data/items/grimy_marrentill.yaml b/data/items/materials/grimy_marrentill.yaml index 7548fe5..7548fe5 100644 --- a/data/items/grimy_marrentill.yaml +++ b/data/items/materials/grimy_marrentill.yaml diff --git a/data/items/grimy_ranarr.yaml b/data/items/materials/grimy_ranarr.yaml index 1f82277..1f82277 100644 --- a/data/items/grimy_ranarr.yaml +++ b/data/items/materials/grimy_ranarr.yaml diff --git a/data/items/grimy_snapdragon.yaml b/data/items/materials/grimy_snapdragon.yaml index f15c604..f15c604 100644 --- a/data/items/grimy_snapdragon.yaml +++ b/data/items/materials/grimy_snapdragon.yaml diff --git a/data/items/grimy_tarromin.yaml b/data/items/materials/grimy_tarromin.yaml index 712061c..712061c 100644 --- a/data/items/grimy_tarromin.yaml +++ b/data/items/materials/grimy_tarromin.yaml diff --git a/data/items/grimy_toadflax.yaml b/data/items/materials/grimy_toadflax.yaml index c489566..c489566 100644 --- a/data/items/grimy_toadflax.yaml +++ b/data/items/materials/grimy_toadflax.yaml diff --git a/data/items/grimy_torstol.yaml b/data/items/materials/grimy_torstol.yaml index 47db8d7..47db8d7 100644 --- a/data/items/grimy_torstol.yaml +++ b/data/items/materials/grimy_torstol.yaml diff --git a/data/items/guam.yaml b/data/items/materials/guam.yaml index 8fe7972..8fe7972 100644 --- a/data/items/guam.yaml +++ b/data/items/materials/guam.yaml diff --git a/data/items/hard_leather.yaml b/data/items/materials/hard_leather.yaml index e04030c..e04030c 100644 --- a/data/items/hard_leather.yaml +++ b/data/items/materials/hard_leather.yaml diff --git a/data/items/harralander.yaml b/data/items/materials/harralander.yaml index 08e66ed..08e66ed 100644 --- a/data/items/harralander.yaml +++ b/data/items/materials/harralander.yaml diff --git a/data/items/irit.yaml b/data/items/materials/irit.yaml index 40f1956..40f1956 100644 --- a/data/items/irit.yaml +++ b/data/items/materials/irit.yaml diff --git a/data/items/iron_bar.yaml b/data/items/materials/iron_bar.yaml index 26c8352..26c8352 100644 --- a/data/items/iron_bar.yaml +++ b/data/items/materials/iron_bar.yaml diff --git a/data/items/iron_nails.yaml b/data/items/materials/iron_nails.yaml index 77323c9..77323c9 100644 --- a/data/items/iron_nails.yaml +++ b/data/items/materials/iron_nails.yaml diff --git a/data/items/iron_ore.yaml b/data/items/materials/iron_ore.yaml index 78e82a5..78e82a5 100644 --- a/data/items/iron_ore.yaml +++ b/data/items/materials/iron_ore.yaml diff --git a/data/items/kwuarm.yaml b/data/items/materials/kwuarm.yaml index ab0d7ff..ab0d7ff 100644 --- a/data/items/kwuarm.yaml +++ b/data/items/materials/kwuarm.yaml diff --git a/data/items/lantadyme.yaml b/data/items/materials/lantadyme.yaml index d38b7da..d38b7da 100644 --- a/data/items/lantadyme.yaml +++ b/data/items/materials/lantadyme.yaml diff --git a/data/items/leather.yaml b/data/items/materials/leather.yaml index 82d0696..82d0696 100644 --- a/data/items/leather.yaml +++ b/data/items/materials/leather.yaml diff --git a/data/items/limpwurt_root.yaml b/data/items/materials/limpwurt_root.yaml index 49dd0dc..49dd0dc 100644 --- a/data/items/limpwurt_root.yaml +++ b/data/items/materials/limpwurt_root.yaml diff --git a/data/items/logs.yaml b/data/items/materials/logs.yaml index 1395d94..1395d94 100644 --- a/data/items/logs.yaml +++ b/data/items/materials/logs.yaml diff --git a/data/items/magic_logs.yaml b/data/items/materials/magic_logs.yaml index 01a804e..01a804e 100644 --- a/data/items/magic_logs.yaml +++ b/data/items/materials/magic_logs.yaml diff --git a/data/items/mahogany_logs.yaml b/data/items/materials/mahogany_logs.yaml index 67b9a6c..67b9a6c 100644 --- a/data/items/mahogany_logs.yaml +++ b/data/items/materials/mahogany_logs.yaml diff --git a/data/items/mahogany_planks.yaml b/data/items/materials/mahogany_planks.yaml index d551321..d551321 100644 --- a/data/items/mahogany_planks.yaml +++ b/data/items/materials/mahogany_planks.yaml diff --git a/data/items/maple_logs.yaml b/data/items/materials/maple_logs.yaml index 6b081e1..6b081e1 100644 --- a/data/items/maple_logs.yaml +++ b/data/items/materials/maple_logs.yaml diff --git a/data/items/marrentill.yaml b/data/items/materials/marrentill.yaml index 4bd492d..4bd492d 100644 --- a/data/items/marrentill.yaml +++ b/data/items/materials/marrentill.yaml diff --git a/data/items/mithril_bar.yaml b/data/items/materials/mithril_bar.yaml index 00e97a4..00e97a4 100644 --- a/data/items/mithril_bar.yaml +++ b/data/items/materials/mithril_bar.yaml diff --git a/data/items/mithril_nails.yaml b/data/items/materials/mithril_nails.yaml index aeb0544..aeb0544 100644 --- a/data/items/mithril_nails.yaml +++ b/data/items/materials/mithril_nails.yaml diff --git a/data/items/mithril_ore.yaml b/data/items/materials/mithril_ore.yaml index 55d8d2c..55d8d2c 100644 --- a/data/items/mithril_ore.yaml +++ b/data/items/materials/mithril_ore.yaml diff --git a/data/items/oak_logs.yaml b/data/items/materials/oak_logs.yaml index 840ebfd..840ebfd 100644 --- a/data/items/oak_logs.yaml +++ b/data/items/materials/oak_logs.yaml diff --git a/data/items/oak_planks.yaml b/data/items/materials/oak_planks.yaml index 29376c6..29376c6 100644 --- a/data/items/oak_planks.yaml +++ b/data/items/materials/oak_planks.yaml diff --git a/data/items/planks.yaml b/data/items/materials/planks.yaml index 67de72e..67de72e 100644 --- a/data/items/planks.yaml +++ b/data/items/materials/planks.yaml diff --git a/data/items/potato_cactus.yaml b/data/items/materials/potato_cactus.yaml index 1178727..1178727 100644 --- a/data/items/potato_cactus.yaml +++ b/data/items/materials/potato_cactus.yaml diff --git a/data/items/ranarr.yaml b/data/items/materials/ranarr.yaml index 683cce6..683cce6 100644 --- a/data/items/ranarr.yaml +++ b/data/items/materials/ranarr.yaml diff --git a/data/items/redwood_logs.yaml b/data/items/materials/redwood_logs.yaml index 5ea1ab0..5ea1ab0 100644 --- a/data/items/redwood_logs.yaml +++ b/data/items/materials/redwood_logs.yaml diff --git a/data/items/ruby.yaml b/data/items/materials/ruby.yaml index 644e1bf..644e1bf 100644 --- a/data/items/ruby.yaml +++ b/data/items/materials/ruby.yaml diff --git a/data/items/rune_nails.yaml b/data/items/materials/rune_nails.yaml index 5d2dfc5..5d2dfc5 100644 --- a/data/items/rune_nails.yaml +++ b/data/items/materials/rune_nails.yaml diff --git a/data/items/runite_bar.yaml b/data/items/materials/runite_bar.yaml index 1faff69..1faff69 100644 --- a/data/items/runite_bar.yaml +++ b/data/items/materials/runite_bar.yaml diff --git a/data/items/runite_ore.yaml b/data/items/materials/runite_ore.yaml index 05d3248..05d3248 100644 --- a/data/items/runite_ore.yaml +++ b/data/items/materials/runite_ore.yaml diff --git a/data/items/sacred_eel.yaml b/data/items/materials/sacred_eel.yaml index 9a03940..9a03940 100644 --- a/data/items/sacred_eel.yaml +++ b/data/items/materials/sacred_eel.yaml diff --git a/data/items/salt.yaml b/data/items/materials/salt.yaml index d9c1b2a..d9c1b2a 100644 --- a/data/items/salt.yaml +++ b/data/items/materials/salt.yaml diff --git a/data/items/sapphire.yaml b/data/items/materials/sapphire.yaml index 9710d45..9710d45 100644 --- a/data/items/sapphire.yaml +++ b/data/items/materials/sapphire.yaml diff --git a/data/items/silver_bar.yaml b/data/items/materials/silver_bar.yaml index eccb25f..eccb25f 100644 --- a/data/items/silver_bar.yaml +++ b/data/items/materials/silver_bar.yaml diff --git a/data/items/silver_ore.yaml b/data/items/materials/silver_ore.yaml index 5b40ff0..5b40ff0 100644 --- a/data/items/silver_ore.yaml +++ b/data/items/materials/silver_ore.yaml diff --git a/data/items/slug_mucus.yaml b/data/items/materials/slug_mucus.yaml index 620038a..620038a 100644 --- a/data/items/slug_mucus.yaml +++ b/data/items/materials/slug_mucus.yaml diff --git a/data/items/snapdragon.yaml b/data/items/materials/snapdragon.yaml index 0c3ba2f..0c3ba2f 100644 --- a/data/items/snapdragon.yaml +++ b/data/items/materials/snapdragon.yaml diff --git a/data/items/snape_grass.yaml b/data/items/materials/snape_grass.yaml index 59a9b30..59a9b30 100644 --- a/data/items/snape_grass.yaml +++ b/data/items/materials/snape_grass.yaml diff --git a/data/items/materials/soft_clay.yaml b/data/items/materials/soft_clay.yaml new file mode 100644 index 0000000..018e5ef --- /dev/null +++ b/data/items/materials/soft_clay.yaml @@ -0,0 +1,13 @@ +id: soft_clay +name: soft clay +color: "173" +description: "Soft, workable clay ready for shaping on a pottery wheel." +value: 2 +stackable: false +ticks: 2 +made_from: + - items: [clay] + quantity: 1 + - items: [bucket_of_water, jug_of_water] + quantity: 1 + byproducts: [empty_bucket, empty_jug] diff --git a/data/items/steel_bar.yaml b/data/items/materials/steel_bar.yaml index 450fd5c..450fd5c 100644 --- a/data/items/steel_bar.yaml +++ b/data/items/materials/steel_bar.yaml diff --git a/data/items/steel_nails.yaml b/data/items/materials/steel_nails.yaml index 4890d18..4890d18 100644 --- a/data/items/steel_nails.yaml +++ b/data/items/materials/steel_nails.yaml diff --git a/data/items/stim_cell.yaml b/data/items/materials/stim_cell.yaml index b431532..b431532 100644 --- a/data/items/stim_cell.yaml +++ b/data/items/materials/stim_cell.yaml diff --git a/data/items/tarromin.yaml b/data/items/materials/tarromin.yaml index 5af2573..5af2573 100644 --- a/data/items/tarromin.yaml +++ b/data/items/materials/tarromin.yaml diff --git a/data/items/teak_logs.yaml b/data/items/materials/teak_logs.yaml index c69f807..c69f807 100644 --- a/data/items/teak_logs.yaml +++ b/data/items/materials/teak_logs.yaml diff --git a/data/items/teak_planks.yaml b/data/items/materials/teak_planks.yaml index f0a0642..f0a0642 100644 --- a/data/items/teak_planks.yaml +++ b/data/items/materials/teak_planks.yaml diff --git a/data/items/thread.yaml b/data/items/materials/thread.yaml index 3a9a4f7..3a9a4f7 100644 --- a/data/items/thread.yaml +++ b/data/items/materials/thread.yaml diff --git a/data/items/tin_ore.yaml b/data/items/materials/tin_ore.yaml index 0ae1cd0..0ae1cd0 100644 --- a/data/items/tin_ore.yaml +++ b/data/items/materials/tin_ore.yaml diff --git a/data/items/toadflax.yaml b/data/items/materials/toadflax.yaml index 0de8f01..0de8f01 100644 --- a/data/items/toadflax.yaml +++ b/data/items/materials/toadflax.yaml diff --git a/data/items/torstol.yaml b/data/items/materials/torstol.yaml index a8b8fbb..a8b8fbb 100644 --- a/data/items/torstol.yaml +++ b/data/items/materials/torstol.yaml diff --git a/data/items/uncut_diamond.yaml b/data/items/materials/uncut_diamond.yaml index cf41d70..cf41d70 100644 --- a/data/items/uncut_diamond.yaml +++ b/data/items/materials/uncut_diamond.yaml diff --git a/data/items/uncut_emerald.yaml b/data/items/materials/uncut_emerald.yaml index 1ea217a..1ea217a 100644 --- a/data/items/uncut_emerald.yaml +++ b/data/items/materials/uncut_emerald.yaml diff --git a/data/items/uncut_ruby.yaml b/data/items/materials/uncut_ruby.yaml index dfa8188..dfa8188 100644 --- a/data/items/uncut_ruby.yaml +++ b/data/items/materials/uncut_ruby.yaml diff --git a/data/items/uncut_sapphire.yaml b/data/items/materials/uncut_sapphire.yaml index bf073fa..bf073fa 100644 --- a/data/items/uncut_sapphire.yaml +++ b/data/items/materials/uncut_sapphire.yaml diff --git a/data/items/vial.yaml b/data/items/materials/vial.yaml index 2a5260a..2a5260a 100644 --- a/data/items/vial.yaml +++ b/data/items/materials/vial.yaml diff --git a/data/items/white_berries.yaml b/data/items/materials/white_berries.yaml index bdaa993..bdaa993 100644 --- a/data/items/white_berries.yaml +++ b/data/items/materials/white_berries.yaml diff --git a/data/items/willow_logs.yaml b/data/items/materials/willow_logs.yaml index dbd315b..dbd315b 100644 --- a/data/items/willow_logs.yaml +++ b/data/items/materials/willow_logs.yaml diff --git a/data/items/wool.yaml b/data/items/materials/wool.yaml index f557aaf..f557aaf 100644 --- a/data/items/wool.yaml +++ b/data/items/materials/wool.yaml diff --git a/data/items/yew_logs.yaml b/data/items/materials/yew_logs.yaml index a5a86a2..a5a86a2 100644 --- a/data/items/yew_logs.yaml +++ b/data/items/materials/yew_logs.yaml diff --git a/data/items/birds_nest.yaml b/data/items/misc/birds_nest.yaml index 1366b5d..1366b5d 100644 --- a/data/items/birds_nest.yaml +++ b/data/items/misc/birds_nest.yaml diff --git a/data/items/christmas_cracker.yaml b/data/items/misc/christmas_cracker.yaml index c296443..c296443 100644 --- a/data/items/christmas_cracker.yaml +++ b/data/items/misc/christmas_cracker.yaml diff --git a/data/items/circuit_board.yaml b/data/items/misc/circuit_board.yaml index 5b4db83..5b4db83 100644 --- a/data/items/circuit_board.yaml +++ b/data/items/misc/circuit_board.yaml diff --git a/data/items/credit_stick.yaml b/data/items/misc/credit_stick.yaml index 46b3050..46b3050 100644 --- a/data/items/credit_stick.yaml +++ b/data/items/misc/credit_stick.yaml diff --git a/data/items/credits.yaml b/data/items/misc/credits.yaml index 7e2de10..7e2de10 100644 --- a/data/items/credits.yaml +++ b/data/items/misc/credits.yaml diff --git a/data/items/mahogany_table.yaml b/data/items/misc/mahogany_table.yaml index 245b929..245b929 100644 --- a/data/items/mahogany_table.yaml +++ b/data/items/misc/mahogany_table.yaml diff --git a/data/items/nutrient_bar.yaml b/data/items/misc/nutrient_bar.yaml index d33d7de..d33d7de 100644 --- a/data/items/nutrient_bar.yaml +++ b/data/items/misc/nutrient_bar.yaml diff --git a/data/items/oak_shelf.yaml b/data/items/misc/oak_shelf.yaml index 0f08fa5..0f08fa5 100644 --- a/data/items/oak_shelf.yaml +++ b/data/items/misc/oak_shelf.yaml diff --git a/data/items/oak_table.yaml b/data/items/misc/oak_table.yaml index e94b372..e94b372 100644 --- a/data/items/oak_table.yaml +++ b/data/items/misc/oak_table.yaml diff --git a/data/items/pass_stub.yaml b/data/items/misc/pass_stub.yaml index 1068190..1068190 100644 --- a/data/items/pass_stub.yaml +++ b/data/items/misc/pass_stub.yaml diff --git a/data/items/scrap_metal.yaml b/data/items/misc/scrap_metal.yaml index d9b805e..d9b805e 100644 --- a/data/items/scrap_metal.yaml +++ b/data/items/misc/scrap_metal.yaml diff --git a/data/items/teak_table.yaml b/data/items/misc/teak_table.yaml index 5c2c5c5..5c2c5c5 100644 --- a/data/items/teak_table.yaml +++ b/data/items/misc/teak_table.yaml diff --git a/data/items/wooden_chair.yaml b/data/items/misc/wooden_chair.yaml index 16220ef..16220ef 100644 --- a/data/items/wooden_chair.yaml +++ b/data/items/misc/wooden_chair.yaml diff --git a/data/items/wooden_shelf.yaml b/data/items/misc/wooden_shelf.yaml index 3b0d97d..3b0d97d 100644 --- a/data/items/wooden_shelf.yaml +++ b/data/items/misc/wooden_shelf.yaml diff --git a/data/items/wooden_table.yaml b/data/items/misc/wooden_table.yaml index 171a9bb..171a9bb 100644 --- a/data/items/wooden_table.yaml +++ b/data/items/misc/wooden_table.yaml diff --git a/data/items/pastry_dough.yaml b/data/items/pastry_dough.yaml deleted file mode 100644 index c08c0ae..0000000 --- a/data/items/pastry_dough.yaml +++ /dev/null @@ -1,11 +0,0 @@ -id: pastry_dough -name: pastry dough -color: "222" -description: "A ball of uncooked pastry dough. It needs to be baked." -value: 3 -stackable: false -made_from: - - items: [pot_of_flour] - qty: 1 - - items: [bucket_of_water] - qty: 1 diff --git a/data/items/pizza_dough.yaml b/data/items/pizza_dough.yaml deleted file mode 100644 index 1105c60..0000000 --- a/data/items/pizza_dough.yaml +++ /dev/null @@ -1,11 +0,0 @@ -id: pizza_dough -name: pizza dough -color: "222" -description: "A ball of uncooked pizza dough. It needs to be baked." -value: 3 -stackable: false -made_from: - - items: [pot_of_flour] - qty: 1 - - items: [bucket_of_water] - qty: 1 diff --git a/data/items/ranarr_potion_unf.yaml b/data/items/ranarr_potion_unf.yaml deleted file mode 100644 index 373abb6..0000000 --- a/data/items/ranarr_potion_unf.yaml +++ /dev/null @@ -1,12 +0,0 @@ -id: ranarr_potion_unf -name: "ranarr potion (unf)" -color: "48" -description: "An unfinished potion with ranarr floating in water." -value: 38 -stackable: false -made_from: - - items: [ranarr] - qty: 1 - - items: [vial_of_water] - qty: 1 -ticks: 0 diff --git a/data/items/avantoe_seed.yaml b/data/items/seeds/avantoe_seed.yaml index fb7b427..fb7b427 100644 --- a/data/items/avantoe_seed.yaml +++ b/data/items/seeds/avantoe_seed.yaml diff --git a/data/items/cabbage_seed.yaml b/data/items/seeds/cabbage_seed.yaml index 8a6db33..8a6db33 100644 --- a/data/items/cabbage_seed.yaml +++ b/data/items/seeds/cabbage_seed.yaml diff --git a/data/items/cadantine_seed.yaml b/data/items/seeds/cadantine_seed.yaml index 8326033..8326033 100644 --- a/data/items/cadantine_seed.yaml +++ b/data/items/seeds/cadantine_seed.yaml diff --git a/data/items/dwarf_weed_seed.yaml b/data/items/seeds/dwarf_weed_seed.yaml index c8ba6f2..c8ba6f2 100644 --- a/data/items/dwarf_weed_seed.yaml +++ b/data/items/seeds/dwarf_weed_seed.yaml diff --git a/data/items/guam_seed.yaml b/data/items/seeds/guam_seed.yaml index b55e1a8..b55e1a8 100644 --- a/data/items/guam_seed.yaml +++ b/data/items/seeds/guam_seed.yaml diff --git a/data/items/harralander_seed.yaml b/data/items/seeds/harralander_seed.yaml index 5be3571..5be3571 100644 --- a/data/items/harralander_seed.yaml +++ b/data/items/seeds/harralander_seed.yaml diff --git a/data/items/irit_seed.yaml b/data/items/seeds/irit_seed.yaml index 4b8bad2..4b8bad2 100644 --- a/data/items/irit_seed.yaml +++ b/data/items/seeds/irit_seed.yaml diff --git a/data/items/kwuarm_seed.yaml b/data/items/seeds/kwuarm_seed.yaml index 053c2f3..053c2f3 100644 --- a/data/items/kwuarm_seed.yaml +++ b/data/items/seeds/kwuarm_seed.yaml diff --git a/data/items/lantadyme_seed.yaml b/data/items/seeds/lantadyme_seed.yaml index f4be89c..f4be89c 100644 --- a/data/items/lantadyme_seed.yaml +++ b/data/items/seeds/lantadyme_seed.yaml diff --git a/data/items/marrentill_seed.yaml b/data/items/seeds/marrentill_seed.yaml index 4b42353..4b42353 100644 --- a/data/items/marrentill_seed.yaml +++ b/data/items/seeds/marrentill_seed.yaml diff --git a/data/items/onion_seed.yaml b/data/items/seeds/onion_seed.yaml index a1231ad..a1231ad 100644 --- a/data/items/onion_seed.yaml +++ b/data/items/seeds/onion_seed.yaml diff --git a/data/items/potato_seed.yaml b/data/items/seeds/potato_seed.yaml index 9daee8a..9daee8a 100644 --- a/data/items/potato_seed.yaml +++ b/data/items/seeds/potato_seed.yaml diff --git a/data/items/ranarr_seed.yaml b/data/items/seeds/ranarr_seed.yaml index ef54c0d..ef54c0d 100644 --- a/data/items/ranarr_seed.yaml +++ b/data/items/seeds/ranarr_seed.yaml diff --git a/data/items/snapdragon_seed.yaml b/data/items/seeds/snapdragon_seed.yaml index 06f2a9e..06f2a9e 100644 --- a/data/items/snapdragon_seed.yaml +++ b/data/items/seeds/snapdragon_seed.yaml diff --git a/data/items/strawberry_seed.yaml b/data/items/seeds/strawberry_seed.yaml index 8b2f45c..8b2f45c 100644 --- a/data/items/strawberry_seed.yaml +++ b/data/items/seeds/strawberry_seed.yaml diff --git a/data/items/sweetcorn_seed.yaml b/data/items/seeds/sweetcorn_seed.yaml index d85b35b..d85b35b 100644 --- a/data/items/sweetcorn_seed.yaml +++ b/data/items/seeds/sweetcorn_seed.yaml diff --git a/data/items/tarromin_seed.yaml b/data/items/seeds/tarromin_seed.yaml index c10483a..c10483a 100644 --- a/data/items/tarromin_seed.yaml +++ b/data/items/seeds/tarromin_seed.yaml diff --git a/data/items/toadflax_seed.yaml b/data/items/seeds/toadflax_seed.yaml index 1ef6cb2..1ef6cb2 100644 --- a/data/items/toadflax_seed.yaml +++ b/data/items/seeds/toadflax_seed.yaml diff --git a/data/items/tomato_seed.yaml b/data/items/seeds/tomato_seed.yaml index c1db131..c1db131 100644 --- a/data/items/tomato_seed.yaml +++ b/data/items/seeds/tomato_seed.yaml diff --git a/data/items/torstol_seed.yaml b/data/items/seeds/torstol_seed.yaml index 2dfd60c..2dfd60c 100644 --- a/data/items/torstol_seed.yaml +++ b/data/items/seeds/torstol_seed.yaml diff --git a/data/items/watermelon_seed.yaml b/data/items/seeds/watermelon_seed.yaml index 7ea59c6..7ea59c6 100644 --- a/data/items/watermelon_seed.yaml +++ b/data/items/seeds/watermelon_seed.yaml diff --git a/data/items/snapdragon_potion_unf.yaml b/data/items/snapdragon_potion_unf.yaml deleted file mode 100644 index ac3aba3..0000000 --- a/data/items/snapdragon_potion_unf.yaml +++ /dev/null @@ -1,12 +0,0 @@ -id: snapdragon_potion_unf -name: "snapdragon potion (unf)" -color: "48" -description: "An unfinished potion with snapdragon floating in water." -value: 68 -stackable: false -made_from: - - items: [snapdragon] - qty: 1 - - items: [vial_of_water] - qty: 1 -ticks: 0 diff --git a/data/items/soft_clay.yaml b/data/items/soft_clay.yaml deleted file mode 100644 index 1ba07e3..0000000 --- a/data/items/soft_clay.yaml +++ /dev/null @@ -1,13 +0,0 @@ -id: soft_clay -name: soft clay -color: "173" -description: "Soft, workable clay ready for shaping on a pottery wheel." -value: 2 -stackable: false -ticks: 2 -made_from: - - items: [clay] - qty: 1 - - items: [bucket_of_water, jug_of_water] - qty: 1 - byproducts: [empty_bucket, empty_jug] diff --git a/data/items/tarromin_potion_unf.yaml b/data/items/tarromin_potion_unf.yaml deleted file mode 100644 index 6a3fab6..0000000 --- a/data/items/tarromin_potion_unf.yaml +++ /dev/null @@ -1,12 +0,0 @@ -id: tarromin_potion_unf -name: "tarromin potion (unf)" -color: "48" -description: "An unfinished potion with tarromin floating in water." -value: 12 -stackable: false -made_from: - - items: [tarromin] - qty: 1 - - items: [vial_of_water] - qty: 1 -ticks: 0 diff --git a/data/items/toadflax_potion_unf.yaml b/data/items/toadflax_potion_unf.yaml deleted file mode 100644 index ca2a123..0000000 --- a/data/items/toadflax_potion_unf.yaml +++ /dev/null @@ -1,12 +0,0 @@ -id: toadflax_potion_unf -name: "toadflax potion (unf)" -color: "48" -description: "An unfinished potion with toadflax floating in water." -value: 28 -stackable: false -made_from: - - items: [toadflax] - qty: 1 - - items: [vial_of_water] - qty: 1 -ticks: 0 diff --git a/data/items/adamant_axe.yaml b/data/items/tools/adamant_axe.yaml index 81232fe..81232fe 100644 --- a/data/items/adamant_axe.yaml +++ b/data/items/tools/adamant_axe.yaml diff --git a/data/items/adamant_pickaxe.yaml b/data/items/tools/adamant_pickaxe.yaml index 4296b0d..4296b0d 100644 --- a/data/items/adamant_pickaxe.yaml +++ b/data/items/tools/adamant_pickaxe.yaml diff --git a/data/items/amulet_mould.yaml b/data/items/tools/amulet_mould.yaml index a8153cb..a8153cb 100644 --- a/data/items/amulet_mould.yaml +++ b/data/items/tools/amulet_mould.yaml diff --git a/data/items/big_fishing_net.yaml b/data/items/tools/big_fishing_net.yaml index a8b5352..a8b5352 100644 --- a/data/items/big_fishing_net.yaml +++ b/data/items/tools/big_fishing_net.yaml diff --git a/data/items/black_pickaxe.yaml b/data/items/tools/black_pickaxe.yaml index c3df955..c3df955 100644 --- a/data/items/black_pickaxe.yaml +++ b/data/items/tools/black_pickaxe.yaml diff --git a/data/items/bracelet_mould.yaml b/data/items/tools/bracelet_mould.yaml index 78bc099..78bc099 100644 --- a/data/items/bracelet_mould.yaml +++ b/data/items/tools/bracelet_mould.yaml diff --git a/data/items/bronze_axe.yaml b/data/items/tools/bronze_axe.yaml index 84b2762..84b2762 100644 --- a/data/items/bronze_axe.yaml +++ b/data/items/tools/bronze_axe.yaml diff --git a/data/items/bronze_pickaxe.yaml b/data/items/tools/bronze_pickaxe.yaml index b581fc0..b581fc0 100644 --- a/data/items/bronze_pickaxe.yaml +++ b/data/items/tools/bronze_pickaxe.yaml diff --git a/data/items/chisel.yaml b/data/items/tools/chisel.yaml index a99c828..a99c828 100644 --- a/data/items/chisel.yaml +++ b/data/items/tools/chisel.yaml diff --git a/data/items/dragon_pickaxe.yaml b/data/items/tools/dragon_pickaxe.yaml index 6f187b8..6f187b8 100644 --- a/data/items/dragon_pickaxe.yaml +++ b/data/items/tools/dragon_pickaxe.yaml diff --git a/data/items/empty_bucket.yaml b/data/items/tools/empty_bucket.yaml index 6debb02..6debb02 100644 --- a/data/items/empty_bucket.yaml +++ b/data/items/tools/empty_bucket.yaml diff --git a/data/items/empty_jug.yaml b/data/items/tools/empty_jug.yaml index c6774a5..c6774a5 100644 --- a/data/items/empty_jug.yaml +++ b/data/items/tools/empty_jug.yaml diff --git a/data/items/empty_pot.yaml b/data/items/tools/empty_pot.yaml index a57b441..a57b441 100644 --- a/data/items/empty_pot.yaml +++ b/data/items/tools/empty_pot.yaml diff --git a/data/items/firesteel.yaml b/data/items/tools/firesteel.yaml index b3f9302..b3f9302 100644 --- a/data/items/firesteel.yaml +++ b/data/items/tools/firesteel.yaml diff --git a/data/items/fishing_bait.yaml b/data/items/tools/fishing_bait.yaml index 2336a7d..2336a7d 100644 --- a/data/items/fishing_bait.yaml +++ b/data/items/tools/fishing_bait.yaml diff --git a/data/items/fishing_rod.yaml b/data/items/tools/fishing_rod.yaml index a48c0a1..a48c0a1 100644 --- a/data/items/fishing_rod.yaml +++ b/data/items/tools/fishing_rod.yaml diff --git a/data/items/fly_fishing_rod.yaml b/data/items/tools/fly_fishing_rod.yaml index c0f3f78..c0f3f78 100644 --- a/data/items/fly_fishing_rod.yaml +++ b/data/items/tools/fly_fishing_rod.yaml diff --git a/data/items/hammer.yaml b/data/items/tools/hammer.yaml index 74302a4..74302a4 100644 --- a/data/items/hammer.yaml +++ b/data/items/tools/hammer.yaml diff --git a/data/items/harpoon.yaml b/data/items/tools/harpoon.yaml index 1412d5c..1412d5c 100644 --- a/data/items/harpoon.yaml +++ b/data/items/tools/harpoon.yaml diff --git a/data/items/iron_axe.yaml b/data/items/tools/iron_axe.yaml index 3f989ca..3f989ca 100644 --- a/data/items/iron_axe.yaml +++ b/data/items/tools/iron_axe.yaml diff --git a/data/items/iron_pickaxe.yaml b/data/items/tools/iron_pickaxe.yaml index d120fde..d120fde 100644 --- a/data/items/iron_pickaxe.yaml +++ b/data/items/tools/iron_pickaxe.yaml diff --git a/data/items/knife.yaml b/data/items/tools/knife.yaml index fddf120..fddf120 100644 --- a/data/items/knife.yaml +++ b/data/items/tools/knife.yaml diff --git a/data/items/lighter.yaml b/data/items/tools/lighter.yaml index 567f42e..567f42e 100644 --- a/data/items/lighter.yaml +++ b/data/items/tools/lighter.yaml diff --git a/data/items/lobster_pot.yaml b/data/items/tools/lobster_pot.yaml index 79771c1..79771c1 100644 --- a/data/items/lobster_pot.yaml +++ b/data/items/tools/lobster_pot.yaml diff --git a/data/items/matches.yaml b/data/items/tools/matches.yaml index d816cbc..d816cbc 100644 --- a/data/items/matches.yaml +++ b/data/items/tools/matches.yaml diff --git a/data/items/mithril_axe.yaml b/data/items/tools/mithril_axe.yaml index ca18195..ca18195 100644 --- a/data/items/mithril_axe.yaml +++ b/data/items/tools/mithril_axe.yaml diff --git a/data/items/mithril_pickaxe.yaml b/data/items/tools/mithril_pickaxe.yaml index 5da6937..5da6937 100644 --- a/data/items/mithril_pickaxe.yaml +++ b/data/items/tools/mithril_pickaxe.yaml diff --git a/data/items/necklace_mould.yaml b/data/items/tools/necklace_mould.yaml index bc4df45..bc4df45 100644 --- a/data/items/necklace_mould.yaml +++ b/data/items/tools/necklace_mould.yaml diff --git a/data/items/needle.yaml b/data/items/tools/needle.yaml index 5f53bf3..5f53bf3 100644 --- a/data/items/needle.yaml +++ b/data/items/tools/needle.yaml diff --git a/data/items/plant_pot.yaml b/data/items/tools/plant_pot.yaml index 2f81e08..2f81e08 100644 --- a/data/items/plant_pot.yaml +++ b/data/items/tools/plant_pot.yaml diff --git a/data/items/rake.yaml b/data/items/tools/rake.yaml index 5949626..5949626 100644 --- a/data/items/rake.yaml +++ b/data/items/tools/rake.yaml diff --git a/data/items/ring_mould.yaml b/data/items/tools/ring_mould.yaml index d7846c8..d7846c8 100644 --- a/data/items/ring_mould.yaml +++ b/data/items/tools/ring_mould.yaml diff --git a/data/items/rune_axe.yaml b/data/items/tools/rune_axe.yaml index a694bdf..a694bdf 100644 --- a/data/items/rune_axe.yaml +++ b/data/items/tools/rune_axe.yaml diff --git a/data/items/rune_pickaxe.yaml b/data/items/tools/rune_pickaxe.yaml index 265231d..265231d 100644 --- a/data/items/rune_pickaxe.yaml +++ b/data/items/tools/rune_pickaxe.yaml diff --git a/data/items/saw.yaml b/data/items/tools/saw.yaml index 4a7ad6a..4a7ad6a 100644 --- a/data/items/saw.yaml +++ b/data/items/tools/saw.yaml diff --git a/data/items/shears.yaml b/data/items/tools/shears.yaml index 4166be3..4166be3 100644 --- a/data/items/shears.yaml +++ b/data/items/tools/shears.yaml diff --git a/data/items/small_fishing_net.yaml b/data/items/tools/small_fishing_net.yaml index 9e91f8f..9e91f8f 100644 --- a/data/items/small_fishing_net.yaml +++ b/data/items/tools/small_fishing_net.yaml diff --git a/data/items/spade.yaml b/data/items/tools/spade.yaml index 7d0b465..7d0b465 100644 --- a/data/items/spade.yaml +++ b/data/items/tools/spade.yaml diff --git a/data/items/steel_axe.yaml b/data/items/tools/steel_axe.yaml index 6f2ac99..6f2ac99 100644 --- a/data/items/steel_axe.yaml +++ b/data/items/tools/steel_axe.yaml diff --git a/data/items/steel_pickaxe.yaml b/data/items/tools/steel_pickaxe.yaml index cc048a1..cc048a1 100644 --- a/data/items/steel_pickaxe.yaml +++ b/data/items/tools/steel_pickaxe.yaml diff --git a/data/items/unfired_pie_dish.yaml b/data/items/tools/unfired_pie_dish.yaml index fddc4d1..fddc4d1 100644 --- a/data/items/unfired_pie_dish.yaml +++ b/data/items/tools/unfired_pie_dish.yaml diff --git a/data/items/unfired_plant_pot.yaml b/data/items/tools/unfired_plant_pot.yaml index c088242..c088242 100644 --- a/data/items/unfired_plant_pot.yaml +++ b/data/items/tools/unfired_plant_pot.yaml diff --git a/data/items/unfired_pot.yaml b/data/items/tools/unfired_pot.yaml index 265a19f..265a19f 100644 --- a/data/items/unfired_pot.yaml +++ b/data/items/tools/unfired_pot.yaml diff --git a/data/items/watering_can.yaml b/data/items/tools/watering_can.yaml index 4a75de9..4a75de9 100644 --- a/data/items/watering_can.yaml +++ b/data/items/tools/watering_can.yaml diff --git a/data/items/torstol_potion_unf.yaml b/data/items/torstol_potion_unf.yaml deleted file mode 100644 index f5816d2..0000000 --- a/data/items/torstol_potion_unf.yaml +++ /dev/null @@ -1,12 +0,0 @@ -id: torstol_potion_unf -name: "torstol potion (unf)" -color: "48" -description: "An unfinished potion with torstol floating in water." -value: 102 -stackable: false -made_from: - - items: [torstol] - qty: 1 - - items: [vial_of_water] - qty: 1 -ticks: 0 diff --git a/data/mobs/estate_broker.yaml b/data/mobs/estate_broker.yaml index 6698730..a8b3ed7 100644 --- a/data/mobs/estate_broker.yaml +++ b/data/mobs/estate_broker.yaml @@ -20,8 +20,8 @@ talk: set_player_flags: owns_house_local_neighborhood: local_neighborhood condition: - not: - player_flag: owns_house_local_neighborhood + not: true + player_flag: owns_house_local_neighborhood next: purchased text: Sounds great! I'll buy one. - next: goodbye @@ -39,8 +39,8 @@ talk: set_player_flags: owns_house_local_neighborhood: local_neighborhood condition: - not: - player_flag: owns_house_local_neighborhood + not: true + player_flag: owns_house_local_neighborhood next: purchased text: Yes, I'd like to buy a house. - condition: diff --git a/data/objects/anvil.yaml b/data/objects/anvil.yaml index 22725c1..ab5a79f 100644 --- a/data/objects/anvil.yaml +++ b/data/objects/anvil.yaml @@ -3,7 +3,7 @@ name: anvil color: "250" description: "A heavy iron anvil for hammering metal into shape." use_interactions: - - item: silver_bar + - item_id: silver_bar message: "You should use this with a mold at a furnace." - - item: gold_bar + - item_id: gold_bar message: "You should use this with a mold at a furnace." diff --git a/data/recipes/clean/clean_avantoe.yaml b/data/recipes/clean/clean_avantoe.yaml new file mode 100644 index 0000000..61f8f87 --- /dev/null +++ b/data/recipes/clean/clean_avantoe.yaml @@ -0,0 +1,11 @@ +id: clean_avantoe +type: clean +skill: pharmacy +level: 48 +xp: 10 +wait: 2 +consume: + - items: [grimy_avantoe] + quantity: 1 +output: avantoe +message: "You clean the grimy avantoe leaf." diff --git a/data/recipes/clean/clean_cadantine.yaml b/data/recipes/clean/clean_cadantine.yaml new file mode 100644 index 0000000..a013b5d --- /dev/null +++ b/data/recipes/clean/clean_cadantine.yaml @@ -0,0 +1,11 @@ +id: clean_cadantine +type: clean +skill: pharmacy +level: 65 +xp: 13 +wait: 2 +consume: + - items: [grimy_cadantine] + quantity: 1 +output: cadantine +message: "You clean the grimy cadantine leaf." diff --git a/data/recipes/clean/clean_dwarf_weed.yaml b/data/recipes/clean/clean_dwarf_weed.yaml new file mode 100644 index 0000000..4ea9bb7 --- /dev/null +++ b/data/recipes/clean/clean_dwarf_weed.yaml @@ -0,0 +1,11 @@ +id: clean_dwarf_weed +type: clean +skill: pharmacy +level: 70 +xp: 14 +wait: 2 +consume: + - items: [grimy_dwarf_weed] + quantity: 1 +output: dwarf_weed +message: "You clean the grimy dwarf weed leaf." diff --git a/data/recipes/clean/clean_guam.yaml b/data/recipes/clean/clean_guam.yaml new file mode 100644 index 0000000..d8bb492 --- /dev/null +++ b/data/recipes/clean/clean_guam.yaml @@ -0,0 +1,11 @@ +id: clean_guam +type: clean +skill: pharmacy +level: 3 +xp: 3 +wait: 2 +consume: + - items: [grimy_guam] + quantity: 1 +output: guam +message: "You clean the grimy guam leaf." diff --git a/data/recipes/clean/clean_harralander.yaml b/data/recipes/clean/clean_harralander.yaml new file mode 100644 index 0000000..15d9d22 --- /dev/null +++ b/data/recipes/clean/clean_harralander.yaml @@ -0,0 +1,11 @@ +id: clean_harralander +type: clean +skill: pharmacy +level: 20 +xp: 6 +wait: 2 +consume: + - items: [grimy_harralander] + quantity: 1 +output: harralander +message: "You clean the grimy harralander leaf." diff --git a/data/recipes/clean/clean_irit.yaml b/data/recipes/clean/clean_irit.yaml new file mode 100644 index 0000000..f75603b --- /dev/null +++ b/data/recipes/clean/clean_irit.yaml @@ -0,0 +1,11 @@ +id: clean_irit +type: clean +skill: pharmacy +level: 40 +xp: 9 +wait: 2 +consume: + - items: [grimy_irit] + quantity: 1 +output: irit +message: "You clean the grimy irit leaf." diff --git a/data/recipes/clean/clean_kwuarm.yaml b/data/recipes/clean/clean_kwuarm.yaml new file mode 100644 index 0000000..1a11a84 --- /dev/null +++ b/data/recipes/clean/clean_kwuarm.yaml @@ -0,0 +1,11 @@ +id: clean_kwuarm +type: clean +skill: pharmacy +level: 54 +xp: 11 +wait: 2 +consume: + - items: [grimy_kwuarm] + quantity: 1 +output: kwuarm +message: "You clean the grimy kwuarm leaf." diff --git a/data/recipes/clean/clean_lantadyme.yaml b/data/recipes/clean/clean_lantadyme.yaml new file mode 100644 index 0000000..076f20d --- /dev/null +++ b/data/recipes/clean/clean_lantadyme.yaml @@ -0,0 +1,11 @@ +id: clean_lantadyme +type: clean +skill: pharmacy +level: 67 +xp: 13 +wait: 2 +consume: + - items: [grimy_lantadyme] + quantity: 1 +output: lantadyme +message: "You clean the grimy lantadyme leaf." diff --git a/data/recipes/clean/clean_marrentill.yaml b/data/recipes/clean/clean_marrentill.yaml new file mode 100644 index 0000000..f1565dd --- /dev/null +++ b/data/recipes/clean/clean_marrentill.yaml @@ -0,0 +1,11 @@ +id: clean_marrentill +type: clean +skill: pharmacy +level: 5 +xp: 4 +wait: 2 +consume: + - items: [grimy_marrentill] + quantity: 1 +output: marrentill +message: "You clean the grimy marrentill leaf." diff --git a/data/recipes/clean/clean_ranarr.yaml b/data/recipes/clean/clean_ranarr.yaml new file mode 100644 index 0000000..2e639d8 --- /dev/null +++ b/data/recipes/clean/clean_ranarr.yaml @@ -0,0 +1,11 @@ +id: clean_ranarr +type: clean +skill: pharmacy +level: 25 +xp: 8 +wait: 2 +consume: + - items: [grimy_ranarr] + quantity: 1 +output: ranarr +message: "You clean the grimy ranarr leaf." diff --git a/data/recipes/clean/clean_snapdragon.yaml b/data/recipes/clean/clean_snapdragon.yaml new file mode 100644 index 0000000..995ac8f --- /dev/null +++ b/data/recipes/clean/clean_snapdragon.yaml @@ -0,0 +1,11 @@ +id: clean_snapdragon +type: clean +skill: pharmacy +level: 59 +xp: 12 +wait: 2 +consume: + - items: [grimy_snapdragon] + quantity: 1 +output: snapdragon +message: "You clean the grimy snapdragon leaf." diff --git a/data/recipes/clean/clean_tarromin.yaml b/data/recipes/clean/clean_tarromin.yaml new file mode 100644 index 0000000..1ad55e1 --- /dev/null +++ b/data/recipes/clean/clean_tarromin.yaml @@ -0,0 +1,11 @@ +id: clean_tarromin +type: clean +skill: pharmacy +level: 11 +xp: 5 +wait: 2 +consume: + - items: [grimy_tarromin] + quantity: 1 +output: tarromin +message: "You clean the grimy tarromin leaf." diff --git a/data/recipes/clean/clean_toadflax.yaml b/data/recipes/clean/clean_toadflax.yaml new file mode 100644 index 0000000..11aafca --- /dev/null +++ b/data/recipes/clean/clean_toadflax.yaml @@ -0,0 +1,11 @@ +id: clean_toadflax +type: clean +skill: pharmacy +level: 30 +xp: 8 +wait: 2 +consume: + - items: [grimy_toadflax] + quantity: 1 +output: toadflax +message: "You clean the grimy toadflax leaf." diff --git a/data/recipes/clean/clean_torstol.yaml b/data/recipes/clean/clean_torstol.yaml new file mode 100644 index 0000000..c9bac28 --- /dev/null +++ b/data/recipes/clean/clean_torstol.yaml @@ -0,0 +1,11 @@ +id: clean_torstol +type: clean +skill: pharmacy +level: 75 +xp: 15 +wait: 2 +consume: + - items: [grimy_torstol] + quantity: 1 +output: torstol +message: "You clean the grimy torstol leaf." diff --git a/data/recipes/clean_avantoe.yaml b/data/recipes/clean_avantoe.yaml deleted file mode 100644 index 6903718..0000000 --- a/data/recipes/clean_avantoe.yaml +++ /dev/null @@ -1,11 +0,0 @@ -id: clean_avantoe -type: clean -skill: pharmacy -level: 48 -xp: 10 -wait: 2 -consume: - - items: [grimy_avantoe] - qty: 1 -output: avantoe -message: "You clean the grimy avantoe leaf." diff --git a/data/recipes/clean_cadantine.yaml b/data/recipes/clean_cadantine.yaml deleted file mode 100644 index 0a84f1f..0000000 --- a/data/recipes/clean_cadantine.yaml +++ /dev/null @@ -1,11 +0,0 @@ -id: clean_cadantine -type: clean -skill: pharmacy -level: 65 -xp: 13 -wait: 2 -consume: - - items: [grimy_cadantine] - qty: 1 -output: cadantine -message: "You clean the grimy cadantine leaf." diff --git a/data/recipes/clean_dwarf_weed.yaml b/data/recipes/clean_dwarf_weed.yaml deleted file mode 100644 index 4843036..0000000 --- a/data/recipes/clean_dwarf_weed.yaml +++ /dev/null @@ -1,11 +0,0 @@ -id: clean_dwarf_weed -type: clean -skill: pharmacy -level: 70 -xp: 14 -wait: 2 -consume: - - items: [grimy_dwarf_weed] - qty: 1 -output: dwarf_weed -message: "You clean the grimy dwarf weed leaf." diff --git a/data/recipes/clean_guam.yaml b/data/recipes/clean_guam.yaml deleted file mode 100644 index faa1e0f..0000000 --- a/data/recipes/clean_guam.yaml +++ /dev/null @@ -1,11 +0,0 @@ -id: clean_guam -type: clean -skill: pharmacy -level: 3 -xp: 3 -wait: 2 -consume: - - items: [grimy_guam] - qty: 1 -output: guam -message: "You clean the grimy guam leaf." diff --git a/data/recipes/clean_harralander.yaml b/data/recipes/clean_harralander.yaml deleted file mode 100644 index 42aca32..0000000 --- a/data/recipes/clean_harralander.yaml +++ /dev/null @@ -1,11 +0,0 @@ -id: clean_harralander -type: clean -skill: pharmacy -level: 20 -xp: 6 -wait: 2 -consume: - - items: [grimy_harralander] - qty: 1 -output: harralander -message: "You clean the grimy harralander leaf." diff --git a/data/recipes/clean_irit.yaml b/data/recipes/clean_irit.yaml deleted file mode 100644 index 1524c20..0000000 --- a/data/recipes/clean_irit.yaml +++ /dev/null @@ -1,11 +0,0 @@ -id: clean_irit -type: clean -skill: pharmacy -level: 40 -xp: 9 -wait: 2 -consume: - - items: [grimy_irit] - qty: 1 -output: irit -message: "You clean the grimy irit leaf." diff --git a/data/recipes/clean_kwuarm.yaml b/data/recipes/clean_kwuarm.yaml deleted file mode 100644 index 178dec4..0000000 --- a/data/recipes/clean_kwuarm.yaml +++ /dev/null @@ -1,11 +0,0 @@ -id: clean_kwuarm -type: clean -skill: pharmacy -level: 54 -xp: 11 -wait: 2 -consume: - - items: [grimy_kwuarm] - qty: 1 -output: kwuarm -message: "You clean the grimy kwuarm leaf." diff --git a/data/recipes/clean_lantadyme.yaml b/data/recipes/clean_lantadyme.yaml deleted file mode 100644 index 05c4f98..0000000 --- a/data/recipes/clean_lantadyme.yaml +++ /dev/null @@ -1,11 +0,0 @@ -id: clean_lantadyme -type: clean -skill: pharmacy -level: 67 -xp: 13 -wait: 2 -consume: - - items: [grimy_lantadyme] - qty: 1 -output: lantadyme -message: "You clean the grimy lantadyme leaf." diff --git a/data/recipes/clean_marrentill.yaml b/data/recipes/clean_marrentill.yaml deleted file mode 100644 index 55959c5..0000000 --- a/data/recipes/clean_marrentill.yaml +++ /dev/null @@ -1,11 +0,0 @@ -id: clean_marrentill -type: clean -skill: pharmacy -level: 5 -xp: 4 -wait: 2 -consume: - - items: [grimy_marrentill] - qty: 1 -output: marrentill -message: "You clean the grimy marrentill leaf." diff --git a/data/recipes/clean_ranarr.yaml b/data/recipes/clean_ranarr.yaml deleted file mode 100644 index 712c88b..0000000 --- a/data/recipes/clean_ranarr.yaml +++ /dev/null @@ -1,11 +0,0 @@ -id: clean_ranarr -type: clean -skill: pharmacy -level: 25 -xp: 8 -wait: 2 -consume: - - items: [grimy_ranarr] - qty: 1 -output: ranarr -message: "You clean the grimy ranarr leaf." diff --git a/data/recipes/clean_snapdragon.yaml b/data/recipes/clean_snapdragon.yaml deleted file mode 100644 index d90c775..0000000 --- a/data/recipes/clean_snapdragon.yaml +++ /dev/null @@ -1,11 +0,0 @@ -id: clean_snapdragon -type: clean -skill: pharmacy -level: 59 -xp: 12 -wait: 2 -consume: - - items: [grimy_snapdragon] - qty: 1 -output: snapdragon -message: "You clean the grimy snapdragon leaf." diff --git a/data/recipes/clean_tarromin.yaml b/data/recipes/clean_tarromin.yaml deleted file mode 100644 index 1752b7c..0000000 --- a/data/recipes/clean_tarromin.yaml +++ /dev/null @@ -1,11 +0,0 @@ -id: clean_tarromin -type: clean -skill: pharmacy -level: 11 -xp: 5 -wait: 2 -consume: - - items: [grimy_tarromin] - qty: 1 -output: tarromin -message: "You clean the grimy tarromin leaf." diff --git a/data/recipes/clean_toadflax.yaml b/data/recipes/clean_toadflax.yaml deleted file mode 100644 index 4124576..0000000 --- a/data/recipes/clean_toadflax.yaml +++ /dev/null @@ -1,11 +0,0 @@ -id: clean_toadflax -type: clean -skill: pharmacy -level: 30 -xp: 8 -wait: 2 -consume: - - items: [grimy_toadflax] - qty: 1 -output: toadflax -message: "You clean the grimy toadflax leaf." diff --git a/data/recipes/clean_torstol.yaml b/data/recipes/clean_torstol.yaml deleted file mode 100644 index 7ce0017..0000000 --- a/data/recipes/clean_torstol.yaml +++ /dev/null @@ -1,11 +0,0 @@ -id: clean_torstol -type: clean -skill: pharmacy -level: 75 -xp: 15 -wait: 2 -consume: - - items: [grimy_torstol] - qty: 1 -output: torstol -message: "You clean the grimy torstol leaf." diff --git a/data/recipes/construct_mahogany_planks.yaml b/data/recipes/construct_mahogany_planks.yaml deleted file mode 100644 index 07e0f40..0000000 --- a/data/recipes/construct_mahogany_planks.yaml +++ /dev/null @@ -1,12 +0,0 @@ -id: construct_mahogany_planks -type: construction -level: 50 -xp: 30 -wait: 20 -station: [workbench] -tool: saw -consume: - - items: [mahogany_logs] - qty: 1 -output: mahogany_planks -message: "You saw the mahogany logs into luxurious mahogany planks." diff --git a/data/recipes/construct_mahogany_table.yaml b/data/recipes/construct_mahogany_table.yaml deleted file mode 100644 index 252736f..0000000 --- a/data/recipes/construct_mahogany_table.yaml +++ /dev/null @@ -1,11 +0,0 @@ -id: construct_mahogany_table -type: construction -level: 52 -xp: 120 -wait: 6 -station: [workbench] -consume: - - items: [mahogany_planks] - qty: 3 -output: mahogany_table -message: "You build a luxurious mahogany table." diff --git a/data/recipes/construct_oak_planks.yaml b/data/recipes/construct_oak_planks.yaml deleted file mode 100644 index 5858208..0000000 --- a/data/recipes/construct_oak_planks.yaml +++ /dev/null @@ -1,12 +0,0 @@ -id: construct_oak_planks -type: construction -level: 15 -xp: 10 -wait: 20 -station: [workbench] -tool: saw -consume: - - items: [oak_logs] - qty: 1 -output: oak_planks -message: "You saw the oak logs into sturdy oak planks." diff --git a/data/recipes/construct_oak_shelf.yaml b/data/recipes/construct_oak_shelf.yaml deleted file mode 100644 index 8661679..0000000 --- a/data/recipes/construct_oak_shelf.yaml +++ /dev/null @@ -1,11 +0,0 @@ -id: construct_oak_shelf -type: construction -level: 18 -xp: 40 -wait: 6 -station: [workbench] -consume: - - items: [oak_planks] - qty: 2 -output: oak_shelf -message: "You assemble the oak planks into a sturdy shelf." diff --git a/data/recipes/construct_oak_table.yaml b/data/recipes/construct_oak_table.yaml deleted file mode 100644 index e8eff24..0000000 --- a/data/recipes/construct_oak_table.yaml +++ /dev/null @@ -1,11 +0,0 @@ -id: construct_oak_table -type: construction -level: 20 -xp: 50 -wait: 6 -station: [workbench] -consume: - - items: [oak_planks] - qty: 3 -output: oak_table -message: "You build a fine oak table." diff --git a/data/recipes/construct_planks.yaml b/data/recipes/construct_planks.yaml deleted file mode 100644 index 4a2a363..0000000 --- a/data/recipes/construct_planks.yaml +++ /dev/null @@ -1,12 +0,0 @@ -id: construct_planks -type: construction -level: 1 -xp: 5 -wait: 20 -station: [workbench] -tool: saw -consume: - - items: [logs] - qty: 1 -output: planks -message: "You saw the logs into some regular planks." diff --git a/data/recipes/construct_teak_planks.yaml b/data/recipes/construct_teak_planks.yaml deleted file mode 100644 index 022ff7f..0000000 --- a/data/recipes/construct_teak_planks.yaml +++ /dev/null @@ -1,12 +0,0 @@ -id: construct_teak_planks -type: construction -level: 35 -xp: 20 -wait: 20 -station: [workbench] -tool: saw -consume: - - items: [teak_logs] - qty: 1 -output: teak_planks -message: "You saw the teak logs into fine teak planks." diff --git a/data/recipes/construct_teak_table.yaml b/data/recipes/construct_teak_table.yaml deleted file mode 100644 index db926b8..0000000 --- a/data/recipes/construct_teak_table.yaml +++ /dev/null @@ -1,11 +0,0 @@ -id: construct_teak_table -type: construction -level: 38 -xp: 80 -wait: 6 -station: [workbench] -consume: - - items: [teak_planks] - qty: 3 -output: teak_table -message: "You build an elegant teak table." diff --git a/data/recipes/construct_wooden_chair.yaml b/data/recipes/construct_wooden_chair.yaml deleted file mode 100644 index cad6200..0000000 --- a/data/recipes/construct_wooden_chair.yaml +++ /dev/null @@ -1,11 +0,0 @@ -id: construct_wooden_chair -type: construction -level: 8 -xp: 30 -wait: 6 -station: [workbench] -consume: - - items: [planks] - qty: 2 -output: wooden_chair -message: "You craft a comfortable wooden chair." diff --git a/data/recipes/construct_wooden_shelf.yaml b/data/recipes/construct_wooden_shelf.yaml deleted file mode 100644 index f09a199..0000000 --- a/data/recipes/construct_wooden_shelf.yaml +++ /dev/null @@ -1,11 +0,0 @@ -id: construct_wooden_shelf -type: construction -level: 4 -xp: 20 -wait: 6 -station: [workbench] -consume: - - items: [planks] - qty: 2 -output: wooden_shelf -message: "You assemble the planks into a wooden shelf." diff --git a/data/recipes/construct_wooden_table.yaml b/data/recipes/construct_wooden_table.yaml deleted file mode 100644 index 8451f31..0000000 --- a/data/recipes/construct_wooden_table.yaml +++ /dev/null @@ -1,11 +0,0 @@ -id: construct_wooden_table -type: construction -level: 6 -xp: 25 -wait: 6 -station: [workbench] -consume: - - items: [planks] - qty: 3 -output: wooden_table -message: "You build a sturdy wooden table." diff --git a/data/recipes/construction/construct_mahogany_planks.yaml b/data/recipes/construction/construct_mahogany_planks.yaml new file mode 100644 index 0000000..6634f78 --- /dev/null +++ b/data/recipes/construction/construct_mahogany_planks.yaml @@ -0,0 +1,12 @@ +id: construct_mahogany_planks +type: construction +level: 50 +xp: 30 +wait: 20 +station: [workbench] +tool: saw +consume: + - items: [mahogany_logs] + quantity: 1 +output: mahogany_planks +message: "You saw the mahogany logs into luxurious mahogany planks." diff --git a/data/recipes/construction/construct_mahogany_table.yaml b/data/recipes/construction/construct_mahogany_table.yaml new file mode 100644 index 0000000..89d08e4 --- /dev/null +++ b/data/recipes/construction/construct_mahogany_table.yaml @@ -0,0 +1,11 @@ +id: construct_mahogany_table +type: construction +level: 52 +xp: 120 +wait: 6 +station: [workbench] +consume: + - items: [mahogany_planks] + quantity: 3 +output: mahogany_table +message: "You build a luxurious mahogany table." diff --git a/data/recipes/construction/construct_oak_planks.yaml b/data/recipes/construction/construct_oak_planks.yaml new file mode 100644 index 0000000..77c2fcb --- /dev/null +++ b/data/recipes/construction/construct_oak_planks.yaml @@ -0,0 +1,12 @@ +id: construct_oak_planks +type: construction +level: 15 +xp: 10 +wait: 20 +station: [workbench] +tool: saw +consume: + - items: [oak_logs] + quantity: 1 +output: oak_planks +message: "You saw the oak logs into sturdy oak planks." diff --git a/data/recipes/construction/construct_oak_shelf.yaml b/data/recipes/construction/construct_oak_shelf.yaml new file mode 100644 index 0000000..042e64f --- /dev/null +++ b/data/recipes/construction/construct_oak_shelf.yaml @@ -0,0 +1,11 @@ +id: construct_oak_shelf +type: construction +level: 18 +xp: 40 +wait: 6 +station: [workbench] +consume: + - items: [oak_planks] + quantity: 2 +output: oak_shelf +message: "You assemble the oak planks into a sturdy shelf." diff --git a/data/recipes/construction/construct_oak_table.yaml b/data/recipes/construction/construct_oak_table.yaml new file mode 100644 index 0000000..8eafe15 --- /dev/null +++ b/data/recipes/construction/construct_oak_table.yaml @@ -0,0 +1,11 @@ +id: construct_oak_table +type: construction +level: 20 +xp: 50 +wait: 6 +station: [workbench] +consume: + - items: [oak_planks] + quantity: 3 +output: oak_table +message: "You build a fine oak table." diff --git a/data/recipes/construction/construct_planks.yaml b/data/recipes/construction/construct_planks.yaml new file mode 100644 index 0000000..3ed8058 --- /dev/null +++ b/data/recipes/construction/construct_planks.yaml @@ -0,0 +1,12 @@ +id: construct_planks +type: construction +level: 1 +xp: 5 +wait: 20 +station: [workbench] +tool: saw +consume: + - items: [logs] + quantity: 1 +output: planks +message: "You saw the logs into some regular planks." diff --git a/data/recipes/construction/construct_teak_planks.yaml b/data/recipes/construction/construct_teak_planks.yaml new file mode 100644 index 0000000..aec0888 --- /dev/null +++ b/data/recipes/construction/construct_teak_planks.yaml @@ -0,0 +1,12 @@ +id: construct_teak_planks +type: construction +level: 35 +xp: 20 +wait: 20 +station: [workbench] +tool: saw +consume: + - items: [teak_logs] + quantity: 1 +output: teak_planks +message: "You saw the teak logs into fine teak planks." diff --git a/data/recipes/construction/construct_teak_table.yaml b/data/recipes/construction/construct_teak_table.yaml new file mode 100644 index 0000000..88d4a2a --- /dev/null +++ b/data/recipes/construction/construct_teak_table.yaml @@ -0,0 +1,11 @@ +id: construct_teak_table +type: construction +level: 38 +xp: 80 +wait: 6 +station: [workbench] +consume: + - items: [teak_planks] + quantity: 3 +output: teak_table +message: "You build an elegant teak table." diff --git a/data/recipes/construction/construct_wooden_chair.yaml b/data/recipes/construction/construct_wooden_chair.yaml new file mode 100644 index 0000000..3a9120d --- /dev/null +++ b/data/recipes/construction/construct_wooden_chair.yaml @@ -0,0 +1,11 @@ +id: construct_wooden_chair +type: construction +level: 8 +xp: 30 +wait: 6 +station: [workbench] +consume: + - items: [planks] + quantity: 2 +output: wooden_chair +message: "You craft a comfortable wooden chair." diff --git a/data/recipes/construction/construct_wooden_shelf.yaml b/data/recipes/construction/construct_wooden_shelf.yaml new file mode 100644 index 0000000..c8ea836 --- /dev/null +++ b/data/recipes/construction/construct_wooden_shelf.yaml @@ -0,0 +1,11 @@ +id: construct_wooden_shelf +type: construction +level: 4 +xp: 20 +wait: 6 +station: [workbench] +consume: + - items: [planks] + quantity: 2 +output: wooden_shelf +message: "You assemble the planks into a wooden shelf." diff --git a/data/recipes/construction/construct_wooden_table.yaml b/data/recipes/construction/construct_wooden_table.yaml new file mode 100644 index 0000000..21d6c53 --- /dev/null +++ b/data/recipes/construction/construct_wooden_table.yaml @@ -0,0 +1,11 @@ +id: construct_wooden_table +type: construction +level: 6 +xp: 25 +wait: 6 +station: [workbench] +consume: + - items: [planks] + quantity: 3 +output: wooden_table +message: "You build a sturdy wooden table." diff --git a/data/recipes/cook_anchovies.yaml b/data/recipes/cook_anchovies.yaml deleted file mode 100644 index 07d3f62..0000000 --- a/data/recipes/cook_anchovies.yaml +++ /dev/null @@ -1,13 +0,0 @@ -id: cook_anchovies -type: cooking -level: 1 -xp: 30 -wait: 6 -station: [fire, cooking_range] -consume: - - items: [raw_anchovies] - qty: 1 -output: anchovies -fail: burnt_fish -message: "Cooked to perfection. It looks great!" -fail_message: "You accidentally burn the anchovies." diff --git a/data/recipes/cook_bread.yaml b/data/recipes/cook_bread.yaml deleted file mode 100644 index c76cedc..0000000 --- a/data/recipes/cook_bread.yaml +++ /dev/null @@ -1,13 +0,0 @@ -id: cook_bread -type: cooking -level: 1 -xp: 40 -wait: 6 -station: [cooking_range] -consume: - - items: [bread_dough] - qty: 1 -output: bread -fail: burnt_meat -message: "You bake the dough into a fresh loaf of bread." -fail_message: "You burn the bread to a crisp." diff --git a/data/recipes/cook_herring.yaml b/data/recipes/cook_herring.yaml deleted file mode 100644 index 05d10eb..0000000 --- a/data/recipes/cook_herring.yaml +++ /dev/null @@ -1,13 +0,0 @@ -id: cook_herring -type: cooking -level: 5 -xp: 50 -wait: 6 -station: [fire, cooking_range] -consume: - - items: [raw_herring] - qty: 1 -output: herring -fail: burnt_fish -message: "Cooked to perfection. It looks great!" -fail_message: "You accidentally burn the herring." diff --git a/data/recipes/cook_salmon.yaml b/data/recipes/cook_salmon.yaml deleted file mode 100644 index ab086fb..0000000 --- a/data/recipes/cook_salmon.yaml +++ /dev/null @@ -1,13 +0,0 @@ -id: cook_salmon -type: cooking -level: 25 -xp: 90 -wait: 6 -station: [fire, cooking_range] -consume: - - items: [raw_salmon] - qty: 1 -output: salmon -fail: burnt_fish -message: "Cooked to perfection. It looks great!" -fail_message: "You accidentally burn the salmon." diff --git a/data/recipes/cook_sardine.yaml b/data/recipes/cook_sardine.yaml deleted file mode 100644 index f7e8389..0000000 --- a/data/recipes/cook_sardine.yaml +++ /dev/null @@ -1,13 +0,0 @@ -id: cook_sardine -type: cooking -level: 1 -xp: 40 -wait: 6 -station: [fire, cooking_range] -consume: - - items: [raw_sardine] - qty: 1 -output: sardine -fail: burnt_fish -message: "Cooked to perfection. It looks great!" -fail_message: "You accidentally burn the sardine." diff --git a/data/recipes/cook_shrimps.yaml b/data/recipes/cook_shrimps.yaml deleted file mode 100644 index 8755b68..0000000 --- a/data/recipes/cook_shrimps.yaml +++ /dev/null @@ -1,13 +0,0 @@ -id: cook_shrimps -type: cooking -level: 1 -xp: 30 -wait: 6 -station: [fire, cooking_range] -consume: - - items: [raw_shrimps] - qty: 1 -output: shrimps -fail: burnt_fish -message: "Cooked to perfection. It looks great!" -fail_message: "You accidentally burn the shrimps." diff --git a/data/recipes/cook_trout.yaml b/data/recipes/cook_trout.yaml deleted file mode 100644 index a392e3d..0000000 --- a/data/recipes/cook_trout.yaml +++ /dev/null @@ -1,13 +0,0 @@ -id: cook_trout -type: cooking -level: 15 -xp: 70 -wait: 6 -station: [fire, cooking_range] -consume: - - items: [raw_trout] - qty: 1 -output: trout -fail: burnt_fish -message: "Cooked to perfection. It looks great!" -fail_message: "You accidentally burn the trout." diff --git a/data/recipes/cooking/cook_anchovies.yaml b/data/recipes/cooking/cook_anchovies.yaml new file mode 100644 index 0000000..bd4ea41 --- /dev/null +++ b/data/recipes/cooking/cook_anchovies.yaml @@ -0,0 +1,13 @@ +id: cook_anchovies +type: cooking +level: 1 +xp: 30 +wait: 6 +station: [fire, cooking_range] +consume: + - items: [raw_anchovies] + quantity: 1 +output: anchovies +fail: burnt_fish +message: "Cooked to perfection. It looks great!" +fail_message: "You accidentally burn the anchovies." diff --git a/data/recipes/cooking/cook_bread.yaml b/data/recipes/cooking/cook_bread.yaml new file mode 100644 index 0000000..d1c68bf --- /dev/null +++ b/data/recipes/cooking/cook_bread.yaml @@ -0,0 +1,13 @@ +id: cook_bread +type: cooking +level: 1 +xp: 40 +wait: 6 +station: [cooking_range] +consume: + - items: [bread_dough] + quantity: 1 +output: bread +fail: burnt_meat +message: "You bake the dough into a fresh loaf of bread." +fail_message: "You burn the bread to a crisp." diff --git a/data/recipes/cooking/cook_herring.yaml b/data/recipes/cooking/cook_herring.yaml new file mode 100644 index 0000000..3113092 --- /dev/null +++ b/data/recipes/cooking/cook_herring.yaml @@ -0,0 +1,13 @@ +id: cook_herring +type: cooking +level: 5 +xp: 50 +wait: 6 +station: [fire, cooking_range] +consume: + - items: [raw_herring] + quantity: 1 +output: herring +fail: burnt_fish +message: "Cooked to perfection. It looks great!" +fail_message: "You accidentally burn the herring." diff --git a/data/recipes/cooking/cook_salmon.yaml b/data/recipes/cooking/cook_salmon.yaml new file mode 100644 index 0000000..32c0fb0 --- /dev/null +++ b/data/recipes/cooking/cook_salmon.yaml @@ -0,0 +1,13 @@ +id: cook_salmon +type: cooking +level: 25 +xp: 90 +wait: 6 +station: [fire, cooking_range] +consume: + - items: [raw_salmon] + quantity: 1 +output: salmon +fail: burnt_fish +message: "Cooked to perfection. It looks great!" +fail_message: "You accidentally burn the salmon." diff --git a/data/recipes/cooking/cook_sardine.yaml b/data/recipes/cooking/cook_sardine.yaml new file mode 100644 index 0000000..fcda9b5 --- /dev/null +++ b/data/recipes/cooking/cook_sardine.yaml @@ -0,0 +1,13 @@ +id: cook_sardine +type: cooking +level: 1 +xp: 40 +wait: 6 +station: [fire, cooking_range] +consume: + - items: [raw_sardine] + quantity: 1 +output: sardine +fail: burnt_fish +message: "Cooked to perfection. It looks great!" +fail_message: "You accidentally burn the sardine." diff --git a/data/recipes/cooking/cook_shrimps.yaml b/data/recipes/cooking/cook_shrimps.yaml new file mode 100644 index 0000000..feb4506 --- /dev/null +++ b/data/recipes/cooking/cook_shrimps.yaml @@ -0,0 +1,13 @@ +id: cook_shrimps +type: cooking +level: 1 +xp: 30 +wait: 6 +station: [fire, cooking_range] +consume: + - items: [raw_shrimps] + quantity: 1 +output: shrimps +fail: burnt_fish +message: "Cooked to perfection. It looks great!" +fail_message: "You accidentally burn the shrimps." diff --git a/data/recipes/cooking/cook_trout.yaml b/data/recipes/cooking/cook_trout.yaml new file mode 100644 index 0000000..cec6cd4 --- /dev/null +++ b/data/recipes/cooking/cook_trout.yaml @@ -0,0 +1,13 @@ +id: cook_trout +type: cooking +level: 15 +xp: 70 +wait: 6 +station: [fire, cooking_range] +consume: + - items: [raw_trout] + quantity: 1 +output: trout +fail: burnt_fish +message: "Cooked to perfection. It looks great!" +fail_message: "You accidentally burn the trout." diff --git a/data/recipes/craft_ball_of_wool.yaml b/data/recipes/craft_ball_of_wool.yaml deleted file mode 100644 index 2f8f4f9..0000000 --- a/data/recipes/craft_ball_of_wool.yaml +++ /dev/null @@ -1,11 +0,0 @@ -id: craft_ball_of_wool -type: crafting -level: 1 -xp: 3 -wait: 3 -station: [spinning_wheel] -consume: - - items: [wool] - qty: 1 -output: ball_of_wool -message: "You spin the wool into a ball." diff --git a/data/recipes/craft_bowstring.yaml b/data/recipes/craft_bowstring.yaml deleted file mode 100644 index 1df6aba..0000000 --- a/data/recipes/craft_bowstring.yaml +++ /dev/null @@ -1,11 +0,0 @@ -id: craft_bowstring -type: crafting -level: 1 -xp: 15 -wait: 3 -station: [spinning_wheel] -consume: - - items: [flax] - qty: 1 -output: bowstring -message: "You spin the flax into a bowstring." diff --git a/data/recipes/craft_coif.yaml b/data/recipes/craft_coif.yaml deleted file mode 100644 index 49fc4c3..0000000 --- a/data/recipes/craft_coif.yaml +++ /dev/null @@ -1,13 +0,0 @@ -id: craft_coif -type: crafting -level: 38 -xp: 37 -wait: 4 -tool: needle -consume: - - items: [hard_leather] - qty: 1 - - items: [thread] - qty: 1 -output: coif -message: "You craft a coif." diff --git a/data/recipes/craft_cut_diamond.yaml b/data/recipes/craft_cut_diamond.yaml deleted file mode 100644 index b0187a8..0000000 --- a/data/recipes/craft_cut_diamond.yaml +++ /dev/null @@ -1,11 +0,0 @@ -id: craft_cut_diamond -type: crafting -level: 43 -xp: 108 -wait: 3 -tool: chisel -consume: - - items: [uncut_diamond] - qty: 1 -output: diamond -message: "You cut the diamond into a beautiful gem." diff --git a/data/recipes/craft_cut_emerald.yaml b/data/recipes/craft_cut_emerald.yaml deleted file mode 100644 index 69fdd19..0000000 --- a/data/recipes/craft_cut_emerald.yaml +++ /dev/null @@ -1,11 +0,0 @@ -id: craft_cut_emerald -type: crafting -level: 27 -xp: 68 -wait: 3 -tool: chisel -consume: - - items: [uncut_emerald] - qty: 1 -output: emerald -message: "You cut the emerald into a beautiful gem." diff --git a/data/recipes/craft_cut_ruby.yaml b/data/recipes/craft_cut_ruby.yaml deleted file mode 100644 index 6cc402c..0000000 --- a/data/recipes/craft_cut_ruby.yaml +++ /dev/null @@ -1,11 +0,0 @@ -id: craft_cut_ruby -type: crafting -level: 63 -xp: 85 -wait: 3 -tool: chisel -consume: - - items: [uncut_ruby] - qty: 1 -output: ruby -message: "You cut the ruby into a beautiful gem." diff --git a/data/recipes/craft_cut_sapphire.yaml b/data/recipes/craft_cut_sapphire.yaml deleted file mode 100644 index 6f3bb65..0000000 --- a/data/recipes/craft_cut_sapphire.yaml +++ /dev/null @@ -1,11 +0,0 @@ -id: craft_cut_sapphire -type: crafting -level: 20 -xp: 50 -wait: 3 -tool: chisel -consume: - - items: [uncut_sapphire] - qty: 1 -output: sapphire -message: "You cut the sapphire into a beautiful gem." diff --git a/data/recipes/craft_diamond_amulet_u.yaml b/data/recipes/craft_diamond_amulet_u.yaml deleted file mode 100644 index 053c409..0000000 --- a/data/recipes/craft_diamond_amulet_u.yaml +++ /dev/null @@ -1,16 +0,0 @@ -id: craft_diamond_amulet_u -type: crafting -level: 70 -xp: 100 -wait: 4 -station: [furnace] -consume: - - items: [gold_bar] - qty: 1 - - items: [diamond] - qty: 1 - - items: [amulet_mould] - qty: 1 - byproducts: [amulet_mould] -output: diamond_amulet_u -message: "You cast a diamond amulet." diff --git a/data/recipes/craft_diamond_bracelet.yaml b/data/recipes/craft_diamond_bracelet.yaml deleted file mode 100644 index 17ac23e..0000000 --- a/data/recipes/craft_diamond_bracelet.yaml +++ /dev/null @@ -1,16 +0,0 @@ -id: craft_diamond_bracelet -type: crafting -level: 58 -xp: 95 -wait: 4 -station: [furnace] -consume: - - items: [gold_bar] - qty: 1 - - items: [diamond] - qty: 1 - - items: [bracelet_mould] - qty: 1 - byproducts: [bracelet_mould] -output: diamond_bracelet -message: "You cast a diamond bracelet." diff --git a/data/recipes/craft_diamond_necklace.yaml b/data/recipes/craft_diamond_necklace.yaml deleted file mode 100644 index cebbec1..0000000 --- a/data/recipes/craft_diamond_necklace.yaml +++ /dev/null @@ -1,16 +0,0 @@ -id: craft_diamond_necklace -type: crafting -level: 56 -xp: 90 -wait: 4 -station: [furnace] -consume: - - items: [gold_bar] - qty: 1 - - items: [diamond] - qty: 1 - - items: [necklace_mould] - qty: 1 - byproducts: [necklace_mould] -output: diamond_necklace -message: "You cast a diamond necklace." diff --git a/data/recipes/craft_diamond_ring.yaml b/data/recipes/craft_diamond_ring.yaml deleted file mode 100644 index aacce0e..0000000 --- a/data/recipes/craft_diamond_ring.yaml +++ /dev/null @@ -1,16 +0,0 @@ -id: craft_diamond_ring -type: crafting -level: 43 -xp: 85 -wait: 4 -station: [furnace] -consume: - - items: [gold_bar] - qty: 1 - - items: [diamond] - qty: 1 - - items: [ring_mould] - qty: 1 - byproducts: [ring_mould] -output: diamond_ring -message: "You cast a diamond ring." diff --git a/data/recipes/craft_emerald_amulet_u.yaml b/data/recipes/craft_emerald_amulet_u.yaml deleted file mode 100644 index dbf8b8a..0000000 --- a/data/recipes/craft_emerald_amulet_u.yaml +++ /dev/null @@ -1,16 +0,0 @@ -id: craft_emerald_amulet_u -type: crafting -level: 31 -xp: 70 -wait: 4 -station: [furnace] -consume: - - items: [gold_bar] - qty: 1 - - items: [emerald] - qty: 1 - - items: [amulet_mould] - qty: 1 - byproducts: [amulet_mould] -output: emerald_amulet_u -message: "You cast a emerald amulet." diff --git a/data/recipes/craft_emerald_bracelet.yaml b/data/recipes/craft_emerald_bracelet.yaml deleted file mode 100644 index b3dd83e..0000000 --- a/data/recipes/craft_emerald_bracelet.yaml +++ /dev/null @@ -1,16 +0,0 @@ -id: craft_emerald_bracelet -type: crafting -level: 30 -xp: 65 -wait: 4 -station: [furnace] -consume: - - items: [gold_bar] - qty: 1 - - items: [emerald] - qty: 1 - - items: [bracelet_mould] - qty: 1 - byproducts: [bracelet_mould] -output: emerald_bracelet -message: "You cast a emerald bracelet." diff --git a/data/recipes/craft_emerald_necklace.yaml b/data/recipes/craft_emerald_necklace.yaml deleted file mode 100644 index cd0a94b..0000000 --- a/data/recipes/craft_emerald_necklace.yaml +++ /dev/null @@ -1,16 +0,0 @@ -id: craft_emerald_necklace -type: crafting -level: 29 -xp: 60 -wait: 4 -station: [furnace] -consume: - - items: [gold_bar] - qty: 1 - - items: [emerald] - qty: 1 - - items: [necklace_mould] - qty: 1 - byproducts: [necklace_mould] -output: emerald_necklace -message: "You cast a emerald necklace." diff --git a/data/recipes/craft_emerald_ring.yaml b/data/recipes/craft_emerald_ring.yaml deleted file mode 100644 index ebbe473..0000000 --- a/data/recipes/craft_emerald_ring.yaml +++ /dev/null @@ -1,16 +0,0 @@ -id: craft_emerald_ring -type: crafting -level: 27 -xp: 55 -wait: 4 -station: [furnace] -consume: - - items: [gold_bar] - qty: 1 - - items: [emerald] - qty: 1 - - items: [ring_mould] - qty: 1 - byproducts: [ring_mould] -output: emerald_ring -message: "You cast a emerald ring." diff --git a/data/recipes/craft_gold_amulet_u.yaml b/data/recipes/craft_gold_amulet_u.yaml deleted file mode 100644 index 3701320..0000000 --- a/data/recipes/craft_gold_amulet_u.yaml +++ /dev/null @@ -1,14 +0,0 @@ -id: craft_gold_amulet_u -type: crafting -level: 8 -xp: 30 -wait: 4 -station: [furnace] -consume: - - items: [gold_bar] - qty: 1 - - items: [amulet_mould] - qty: 1 - byproducts: [amulet_mould] -output: gold_amulet_u -message: "You cast a gold amulet." diff --git a/data/recipes/craft_gold_bracelet.yaml b/data/recipes/craft_gold_bracelet.yaml deleted file mode 100644 index 630b8de..0000000 --- a/data/recipes/craft_gold_bracelet.yaml +++ /dev/null @@ -1,14 +0,0 @@ -id: craft_gold_bracelet -type: crafting -level: 7 -xp: 25 -wait: 4 -station: [furnace] -consume: - - items: [gold_bar] - qty: 1 - - items: [bracelet_mould] - qty: 1 - byproducts: [bracelet_mould] -output: gold_bracelet -message: "You cast a gold bracelet." diff --git a/data/recipes/craft_gold_necklace.yaml b/data/recipes/craft_gold_necklace.yaml deleted file mode 100644 index 6879338..0000000 --- a/data/recipes/craft_gold_necklace.yaml +++ /dev/null @@ -1,14 +0,0 @@ -id: craft_gold_necklace -type: crafting -level: 6 -xp: 20 -wait: 4 -station: [furnace] -consume: - - items: [gold_bar] - qty: 1 - - items: [necklace_mould] - qty: 1 - byproducts: [necklace_mould] -output: gold_necklace -message: "You cast a gold necklace." diff --git a/data/recipes/craft_gold_ring.yaml b/data/recipes/craft_gold_ring.yaml deleted file mode 100644 index 4e2c13f..0000000 --- a/data/recipes/craft_gold_ring.yaml +++ /dev/null @@ -1,14 +0,0 @@ -id: craft_gold_ring -type: crafting -level: 5 -xp: 15 -wait: 4 -station: [furnace] -consume: - - items: [gold_bar] - qty: 1 - - items: [ring_mould] - qty: 1 - byproducts: [ring_mould] -output: gold_ring -message: "You cast a gold ring." diff --git a/data/recipes/craft_hard_leather_body.yaml b/data/recipes/craft_hard_leather_body.yaml deleted file mode 100644 index 088553e..0000000 --- a/data/recipes/craft_hard_leather_body.yaml +++ /dev/null @@ -1,13 +0,0 @@ -id: craft_hard_leather_body -type: crafting -level: 28 -xp: 35 -wait: 4 -tool: needle -consume: - - items: [hard_leather] - qty: 1 - - items: [thread] - qty: 1 -output: hard_leather_body -message: "You craft a hard leather body." diff --git a/data/recipes/craft_hard_leather_shield.yaml b/data/recipes/craft_hard_leather_shield.yaml deleted file mode 100644 index b41e5b4..0000000 --- a/data/recipes/craft_hard_leather_shield.yaml +++ /dev/null @@ -1,13 +0,0 @@ -id: craft_hard_leather_shield -type: crafting -level: 41 -xp: 40 -wait: 4 -tool: needle -consume: - - items: [hard_leather] - qty: 1 - - items: [thread] - qty: 1 -output: hard_leather_shield -message: "You craft a hard leather shield." diff --git a/data/recipes/craft_leather_body.yaml b/data/recipes/craft_leather_body.yaml deleted file mode 100644 index b01eefa..0000000 --- a/data/recipes/craft_leather_body.yaml +++ /dev/null @@ -1,13 +0,0 @@ -id: craft_leather_body -type: crafting -level: 14 -xp: 25 -wait: 4 -tool: needle -consume: - - items: [leather] - qty: 1 - - items: [thread] - qty: 1 -output: leather_body -message: "You craft a leather body." diff --git a/data/recipes/craft_leather_boots.yaml b/data/recipes/craft_leather_boots.yaml deleted file mode 100644 index df86ae9..0000000 --- a/data/recipes/craft_leather_boots.yaml +++ /dev/null @@ -1,13 +0,0 @@ -id: craft_leather_boots -type: crafting -level: 7 -xp: 16 -wait: 4 -tool: needle -consume: - - items: [leather] - qty: 1 - - items: [thread] - qty: 1 -output: leather_boots -message: "You craft a pair of leather boots." diff --git a/data/recipes/craft_leather_chaps.yaml b/data/recipes/craft_leather_chaps.yaml deleted file mode 100644 index bfbb832..0000000 --- a/data/recipes/craft_leather_chaps.yaml +++ /dev/null @@ -1,13 +0,0 @@ -id: craft_leather_chaps -type: crafting -level: 18 -xp: 27 -wait: 4 -tool: needle -consume: - - items: [leather] - qty: 1 - - items: [thread] - qty: 1 -output: leather_chaps -message: "You craft a pair of leather chaps." diff --git a/data/recipes/craft_leather_cowl.yaml b/data/recipes/craft_leather_cowl.yaml deleted file mode 100644 index 7f018bf..0000000 --- a/data/recipes/craft_leather_cowl.yaml +++ /dev/null @@ -1,13 +0,0 @@ -id: craft_leather_cowl -type: crafting -level: 9 -xp: 19 -wait: 4 -tool: needle -consume: - - items: [leather] - qty: 1 - - items: [thread] - qty: 1 -output: leather_cowl -message: "You craft a leather cowl." diff --git a/data/recipes/craft_leather_gloves.yaml b/data/recipes/craft_leather_gloves.yaml deleted file mode 100644 index 4f6b27c..0000000 --- a/data/recipes/craft_leather_gloves.yaml +++ /dev/null @@ -1,13 +0,0 @@ -id: craft_leather_gloves -type: crafting -level: 1 -xp: 14 -wait: 4 -tool: needle -consume: - - items: [leather] - qty: 1 - - items: [thread] - qty: 1 -output: leather_gloves -message: "You craft a pair of leather gloves." diff --git a/data/recipes/craft_leather_vambraces.yaml b/data/recipes/craft_leather_vambraces.yaml deleted file mode 100644 index 44624c9..0000000 --- a/data/recipes/craft_leather_vambraces.yaml +++ /dev/null @@ -1,13 +0,0 @@ -id: craft_leather_vambraces -type: crafting -level: 11 -xp: 22 -wait: 4 -tool: needle -consume: - - items: [leather] - qty: 1 - - items: [thread] - qty: 1 -output: leather_vambraces -message: "You craft a pair of leather vambraces." diff --git a/data/recipes/craft_pie_dish.yaml b/data/recipes/craft_pie_dish.yaml deleted file mode 100644 index 0648dd5..0000000 --- a/data/recipes/craft_pie_dish.yaml +++ /dev/null @@ -1,16 +0,0 @@ -id: craft_pie_dish -type: crafting -level: 7 -xp: 10 -wait: 4 -station: [pottery_oven] -consume: - - items: [unfired_pie_dish] - qty: 1 -output: pie_dish -message: "You fire the pie dish in the oven successfully." -fail_message: "The pie dish cracks in the oven and is ruined." -success: - base: 0.40 - per_level: 0.02 - cap: 0.95 diff --git a/data/recipes/craft_plant_pot.yaml b/data/recipes/craft_plant_pot.yaml deleted file mode 100644 index efa353c..0000000 --- a/data/recipes/craft_plant_pot.yaml +++ /dev/null @@ -1,16 +0,0 @@ -id: craft_plant_pot -type: crafting -level: 19 -xp: 18 -wait: 4 -station: [pottery_oven] -consume: - - items: [unfired_plant_pot] - qty: 1 -output: plant_pot -message: "You fire the plant pot in the oven successfully." -fail_message: "The plant pot cracks in the oven and is ruined." -success: - base: 0.30 - per_level: 0.02 - cap: 0.95 diff --git a/data/recipes/craft_pot.yaml b/data/recipes/craft_pot.yaml deleted file mode 100644 index 4e7a5ce..0000000 --- a/data/recipes/craft_pot.yaml +++ /dev/null @@ -1,16 +0,0 @@ -id: craft_pot -type: crafting -level: 1 -xp: 6 -wait: 4 -station: [pottery_oven] -consume: - - items: [unfired_pot] - qty: 1 -output: empty_pot -message: "You fire the pot in the oven successfully." -fail_message: "The pot cracks in the oven and is ruined." -success: - base: 0.50 - per_level: 0.02 - cap: 0.95 diff --git a/data/recipes/craft_ruby_amulet_u.yaml b/data/recipes/craft_ruby_amulet_u.yaml deleted file mode 100644 index 4f1fbea..0000000 --- a/data/recipes/craft_ruby_amulet_u.yaml +++ /dev/null @@ -1,16 +0,0 @@ -id: craft_ruby_amulet_u -type: crafting -level: 50 -xp: 85 -wait: 4 -station: [furnace] -consume: - - items: [gold_bar] - qty: 1 - - items: [ruby] - qty: 1 - - items: [amulet_mould] - qty: 1 - byproducts: [amulet_mould] -output: ruby_amulet_u -message: "You cast a ruby amulet." diff --git a/data/recipes/craft_ruby_bracelet.yaml b/data/recipes/craft_ruby_bracelet.yaml deleted file mode 100644 index c5e0027..0000000 --- a/data/recipes/craft_ruby_bracelet.yaml +++ /dev/null @@ -1,16 +0,0 @@ -id: craft_ruby_bracelet -type: crafting -level: 42 -xp: 80 -wait: 4 -station: [furnace] -consume: - - items: [gold_bar] - qty: 1 - - items: [ruby] - qty: 1 - - items: [bracelet_mould] - qty: 1 - byproducts: [bracelet_mould] -output: ruby_bracelet -message: "You cast a ruby bracelet." diff --git a/data/recipes/craft_ruby_necklace.yaml b/data/recipes/craft_ruby_necklace.yaml deleted file mode 100644 index 4504f7b..0000000 --- a/data/recipes/craft_ruby_necklace.yaml +++ /dev/null @@ -1,16 +0,0 @@ -id: craft_ruby_necklace -type: crafting -level: 40 -xp: 75 -wait: 4 -station: [furnace] -consume: - - items: [gold_bar] - qty: 1 - - items: [ruby] - qty: 1 - - items: [necklace_mould] - qty: 1 - byproducts: [necklace_mould] -output: ruby_necklace -message: "You cast a ruby necklace." diff --git a/data/recipes/craft_ruby_ring.yaml b/data/recipes/craft_ruby_ring.yaml deleted file mode 100644 index e38a490..0000000 --- a/data/recipes/craft_ruby_ring.yaml +++ /dev/null @@ -1,16 +0,0 @@ -id: craft_ruby_ring -type: crafting -level: 63 -xp: 70 -wait: 4 -station: [furnace] -consume: - - items: [gold_bar] - qty: 1 - - items: [ruby] - qty: 1 - - items: [ring_mould] - qty: 1 - byproducts: [ring_mould] -output: ruby_ring -message: "You cast a ruby ring." diff --git a/data/recipes/craft_sapphire_amulet_u.yaml b/data/recipes/craft_sapphire_amulet_u.yaml deleted file mode 100644 index a15a484..0000000 --- a/data/recipes/craft_sapphire_amulet_u.yaml +++ /dev/null @@ -1,16 +0,0 @@ -id: craft_sapphire_amulet_u -type: crafting -level: 24 -xp: 65 -wait: 4 -station: [furnace] -consume: - - items: [gold_bar] - qty: 1 - - items: [sapphire] - qty: 1 - - items: [amulet_mould] - qty: 1 - byproducts: [amulet_mould] -output: sapphire_amulet_u -message: "You cast a sapphire amulet." diff --git a/data/recipes/craft_sapphire_bracelet.yaml b/data/recipes/craft_sapphire_bracelet.yaml deleted file mode 100644 index ee5d1a7..0000000 --- a/data/recipes/craft_sapphire_bracelet.yaml +++ /dev/null @@ -1,16 +0,0 @@ -id: craft_sapphire_bracelet -type: crafting -level: 23 -xp: 60 -wait: 4 -station: [furnace] -consume: - - items: [gold_bar] - qty: 1 - - items: [sapphire] - qty: 1 - - items: [bracelet_mould] - qty: 1 - byproducts: [bracelet_mould] -output: sapphire_bracelet -message: "You cast a sapphire bracelet." diff --git a/data/recipes/craft_sapphire_necklace.yaml b/data/recipes/craft_sapphire_necklace.yaml deleted file mode 100644 index 1dfd112..0000000 --- a/data/recipes/craft_sapphire_necklace.yaml +++ /dev/null @@ -1,16 +0,0 @@ -id: craft_sapphire_necklace -type: crafting -level: 22 -xp: 55 -wait: 4 -station: [furnace] -consume: - - items: [gold_bar] - qty: 1 - - items: [sapphire] - qty: 1 - - items: [necklace_mould] - qty: 1 - byproducts: [necklace_mould] -output: sapphire_necklace -message: "You cast a sapphire necklace." diff --git a/data/recipes/craft_sapphire_ring.yaml b/data/recipes/craft_sapphire_ring.yaml deleted file mode 100644 index dd793ac..0000000 --- a/data/recipes/craft_sapphire_ring.yaml +++ /dev/null @@ -1,16 +0,0 @@ -id: craft_sapphire_ring -type: crafting -level: 20 -xp: 40 -wait: 4 -station: [furnace] -consume: - - items: [gold_bar] - qty: 1 - - items: [sapphire] - qty: 1 - - items: [ring_mould] - qty: 1 - byproducts: [ring_mould] -output: sapphire_ring -message: "You cast a sapphire ring." diff --git a/data/recipes/craft_unfired_pie_dish.yaml b/data/recipes/craft_unfired_pie_dish.yaml deleted file mode 100644 index e55d47e..0000000 --- a/data/recipes/craft_unfired_pie_dish.yaml +++ /dev/null @@ -1,11 +0,0 @@ -id: craft_unfired_pie_dish -type: crafting -level: 7 -xp: 15 -wait: 4 -station: [pottery_wheel] -consume: - - items: [soft_clay] - qty: 1 -output: unfired_pie_dish -message: "You shape the clay into a pie dish." diff --git a/data/recipes/craft_unfired_plant_pot.yaml b/data/recipes/craft_unfired_plant_pot.yaml deleted file mode 100644 index 6dbd8ef..0000000 --- a/data/recipes/craft_unfired_plant_pot.yaml +++ /dev/null @@ -1,11 +0,0 @@ -id: craft_unfired_plant_pot -type: crafting -level: 19 -xp: 18 -wait: 4 -station: [pottery_wheel] -consume: - - items: [soft_clay] - qty: 1 -output: unfired_plant_pot -message: "You shape the clay into a plant pot." diff --git a/data/recipes/craft_unfired_pot.yaml b/data/recipes/craft_unfired_pot.yaml deleted file mode 100644 index 8d72be0..0000000 --- a/data/recipes/craft_unfired_pot.yaml +++ /dev/null @@ -1,11 +0,0 @@ -id: craft_unfired_pot -type: crafting -level: 1 -xp: 6 -wait: 4 -station: [pottery_wheel] -consume: - - items: [soft_clay] - qty: 1 -output: unfired_pot -message: "You shape the clay into a pot." diff --git a/data/recipes/crafting/craft_ball_of_wool.yaml b/data/recipes/crafting/craft_ball_of_wool.yaml new file mode 100644 index 0000000..ef25972 --- /dev/null +++ b/data/recipes/crafting/craft_ball_of_wool.yaml @@ -0,0 +1,11 @@ +id: craft_ball_of_wool +type: crafting +level: 1 +xp: 3 +wait: 3 +station: [spinning_wheel] +consume: + - items: [wool] + quantity: 1 +output: ball_of_wool +message: "You spin the wool into a ball." diff --git a/data/recipes/crafting/craft_bowstring.yaml b/data/recipes/crafting/craft_bowstring.yaml new file mode 100644 index 0000000..caca1a4 --- /dev/null +++ b/data/recipes/crafting/craft_bowstring.yaml @@ -0,0 +1,11 @@ +id: craft_bowstring +type: crafting +level: 1 +xp: 15 +wait: 3 +station: [spinning_wheel] +consume: + - items: [flax] + quantity: 1 +output: bowstring +message: "You spin the flax into a bowstring." diff --git a/data/recipes/crafting/craft_coif.yaml b/data/recipes/crafting/craft_coif.yaml new file mode 100644 index 0000000..4aa914a --- /dev/null +++ b/data/recipes/crafting/craft_coif.yaml @@ -0,0 +1,13 @@ +id: craft_coif +type: crafting +level: 38 +xp: 37 +wait: 4 +tool: needle +consume: + - items: [hard_leather] + quantity: 1 + - items: [thread] + quantity: 1 +output: coif +message: "You craft a coif." diff --git a/data/recipes/crafting/craft_cut_diamond.yaml b/data/recipes/crafting/craft_cut_diamond.yaml new file mode 100644 index 0000000..175a518 --- /dev/null +++ b/data/recipes/crafting/craft_cut_diamond.yaml @@ -0,0 +1,11 @@ +id: craft_cut_diamond +type: crafting +level: 43 +xp: 108 +wait: 3 +tool: chisel +consume: + - items: [uncut_diamond] + quantity: 1 +output: diamond +message: "You cut the diamond into a beautiful gem." diff --git a/data/recipes/crafting/craft_cut_emerald.yaml b/data/recipes/crafting/craft_cut_emerald.yaml new file mode 100644 index 0000000..f725103 --- /dev/null +++ b/data/recipes/crafting/craft_cut_emerald.yaml @@ -0,0 +1,11 @@ +id: craft_cut_emerald +type: crafting +level: 27 +xp: 68 +wait: 3 +tool: chisel +consume: + - items: [uncut_emerald] + quantity: 1 +output: emerald +message: "You cut the emerald into a beautiful gem." diff --git a/data/recipes/crafting/craft_cut_ruby.yaml b/data/recipes/crafting/craft_cut_ruby.yaml new file mode 100644 index 0000000..bfc5e88 --- /dev/null +++ b/data/recipes/crafting/craft_cut_ruby.yaml @@ -0,0 +1,11 @@ +id: craft_cut_ruby +type: crafting +level: 63 +xp: 85 +wait: 3 +tool: chisel +consume: + - items: [uncut_ruby] + quantity: 1 +output: ruby +message: "You cut the ruby into a beautiful gem." diff --git a/data/recipes/crafting/craft_cut_sapphire.yaml b/data/recipes/crafting/craft_cut_sapphire.yaml new file mode 100644 index 0000000..bfd9a00 --- /dev/null +++ b/data/recipes/crafting/craft_cut_sapphire.yaml @@ -0,0 +1,11 @@ +id: craft_cut_sapphire +type: crafting +level: 20 +xp: 50 +wait: 3 +tool: chisel +consume: + - items: [uncut_sapphire] + quantity: 1 +output: sapphire +message: "You cut the sapphire into a beautiful gem." diff --git a/data/recipes/crafting/craft_diamond_amulet_u.yaml b/data/recipes/crafting/craft_diamond_amulet_u.yaml new file mode 100644 index 0000000..533ce2e --- /dev/null +++ b/data/recipes/crafting/craft_diamond_amulet_u.yaml @@ -0,0 +1,16 @@ +id: craft_diamond_amulet_u +type: crafting +level: 70 +xp: 100 +wait: 4 +station: [furnace] +consume: + - items: [gold_bar] + quantity: 1 + - items: [diamond] + quantity: 1 + - items: [amulet_mould] + quantity: 1 + byproducts: [amulet_mould] +output: diamond_amulet_u +message: "You cast a diamond amulet." diff --git a/data/recipes/crafting/craft_diamond_bracelet.yaml b/data/recipes/crafting/craft_diamond_bracelet.yaml new file mode 100644 index 0000000..f9486d3 --- /dev/null +++ b/data/recipes/crafting/craft_diamond_bracelet.yaml @@ -0,0 +1,16 @@ +id: craft_diamond_bracelet +type: crafting +level: 58 +xp: 95 +wait: 4 +station: [furnace] +consume: + - items: [gold_bar] + quantity: 1 + - items: [diamond] + quantity: 1 + - items: [bracelet_mould] + quantity: 1 + byproducts: [bracelet_mould] +output: diamond_bracelet +message: "You cast a diamond bracelet." diff --git a/data/recipes/crafting/craft_diamond_necklace.yaml b/data/recipes/crafting/craft_diamond_necklace.yaml new file mode 100644 index 0000000..bdd4425 --- /dev/null +++ b/data/recipes/crafting/craft_diamond_necklace.yaml @@ -0,0 +1,16 @@ +id: craft_diamond_necklace +type: crafting +level: 56 +xp: 90 +wait: 4 +station: [furnace] +consume: + - items: [gold_bar] + quantity: 1 + - items: [diamond] + quantity: 1 + - items: [necklace_mould] + quantity: 1 + byproducts: [necklace_mould] +output: diamond_necklace +message: "You cast a diamond necklace." diff --git a/data/recipes/crafting/craft_diamond_ring.yaml b/data/recipes/crafting/craft_diamond_ring.yaml new file mode 100644 index 0000000..eaf3a59 --- /dev/null +++ b/data/recipes/crafting/craft_diamond_ring.yaml @@ -0,0 +1,16 @@ +id: craft_diamond_ring +type: crafting +level: 43 +xp: 85 +wait: 4 +station: [furnace] +consume: + - items: [gold_bar] + quantity: 1 + - items: [diamond] + quantity: 1 + - items: [ring_mould] + quantity: 1 + byproducts: [ring_mould] +output: diamond_ring +message: "You cast a diamond ring." diff --git a/data/recipes/crafting/craft_emerald_amulet_u.yaml b/data/recipes/crafting/craft_emerald_amulet_u.yaml new file mode 100644 index 0000000..82773fb --- /dev/null +++ b/data/recipes/crafting/craft_emerald_amulet_u.yaml @@ -0,0 +1,16 @@ +id: craft_emerald_amulet_u +type: crafting +level: 31 +xp: 70 +wait: 4 +station: [furnace] +consume: + - items: [gold_bar] + quantity: 1 + - items: [emerald] + quantity: 1 + - items: [amulet_mould] + quantity: 1 + byproducts: [amulet_mould] +output: emerald_amulet_u +message: "You cast a emerald amulet." diff --git a/data/recipes/crafting/craft_emerald_bracelet.yaml b/data/recipes/crafting/craft_emerald_bracelet.yaml new file mode 100644 index 0000000..3c2f7b4 --- /dev/null +++ b/data/recipes/crafting/craft_emerald_bracelet.yaml @@ -0,0 +1,16 @@ +id: craft_emerald_bracelet +type: crafting +level: 30 +xp: 65 +wait: 4 +station: [furnace] +consume: + - items: [gold_bar] + quantity: 1 + - items: [emerald] + quantity: 1 + - items: [bracelet_mould] + quantity: 1 + byproducts: [bracelet_mould] +output: emerald_bracelet +message: "You cast a emerald bracelet." diff --git a/data/recipes/crafting/craft_emerald_necklace.yaml b/data/recipes/crafting/craft_emerald_necklace.yaml new file mode 100644 index 0000000..7815c16 --- /dev/null +++ b/data/recipes/crafting/craft_emerald_necklace.yaml @@ -0,0 +1,16 @@ +id: craft_emerald_necklace +type: crafting +level: 29 +xp: 60 +wait: 4 +station: [furnace] +consume: + - items: [gold_bar] + quantity: 1 + - items: [emerald] + quantity: 1 + - items: [necklace_mould] + quantity: 1 + byproducts: [necklace_mould] +output: emerald_necklace +message: "You cast a emerald necklace." diff --git a/data/recipes/crafting/craft_emerald_ring.yaml b/data/recipes/crafting/craft_emerald_ring.yaml new file mode 100644 index 0000000..2590490 --- /dev/null +++ b/data/recipes/crafting/craft_emerald_ring.yaml @@ -0,0 +1,16 @@ +id: craft_emerald_ring +type: crafting +level: 27 +xp: 55 +wait: 4 +station: [furnace] +consume: + - items: [gold_bar] + quantity: 1 + - items: [emerald] + quantity: 1 + - items: [ring_mould] + quantity: 1 + byproducts: [ring_mould] +output: emerald_ring +message: "You cast a emerald ring." diff --git a/data/recipes/crafting/craft_gold_amulet_u.yaml b/data/recipes/crafting/craft_gold_amulet_u.yaml new file mode 100644 index 0000000..69daa89 --- /dev/null +++ b/data/recipes/crafting/craft_gold_amulet_u.yaml @@ -0,0 +1,14 @@ +id: craft_gold_amulet_u +type: crafting +level: 8 +xp: 30 +wait: 4 +station: [furnace] +consume: + - items: [gold_bar] + quantity: 1 + - items: [amulet_mould] + quantity: 1 + byproducts: [amulet_mould] +output: gold_amulet_u +message: "You cast a gold amulet." diff --git a/data/recipes/crafting/craft_gold_bracelet.yaml b/data/recipes/crafting/craft_gold_bracelet.yaml new file mode 100644 index 0000000..e3de6d0 --- /dev/null +++ b/data/recipes/crafting/craft_gold_bracelet.yaml @@ -0,0 +1,14 @@ +id: craft_gold_bracelet +type: crafting +level: 7 +xp: 25 +wait: 4 +station: [furnace] +consume: + - items: [gold_bar] + quantity: 1 + - items: [bracelet_mould] + quantity: 1 + byproducts: [bracelet_mould] +output: gold_bracelet +message: "You cast a gold bracelet." diff --git a/data/recipes/crafting/craft_gold_necklace.yaml b/data/recipes/crafting/craft_gold_necklace.yaml new file mode 100644 index 0000000..ab52bef --- /dev/null +++ b/data/recipes/crafting/craft_gold_necklace.yaml @@ -0,0 +1,14 @@ +id: craft_gold_necklace +type: crafting +level: 6 +xp: 20 +wait: 4 +station: [furnace] +consume: + - items: [gold_bar] + quantity: 1 + - items: [necklace_mould] + quantity: 1 + byproducts: [necklace_mould] +output: gold_necklace +message: "You cast a gold necklace." diff --git a/data/recipes/crafting/craft_gold_ring.yaml b/data/recipes/crafting/craft_gold_ring.yaml new file mode 100644 index 0000000..943c31d --- /dev/null +++ b/data/recipes/crafting/craft_gold_ring.yaml @@ -0,0 +1,14 @@ +id: craft_gold_ring +type: crafting +level: 5 +xp: 15 +wait: 4 +station: [furnace] +consume: + - items: [gold_bar] + quantity: 1 + - items: [ring_mould] + quantity: 1 + byproducts: [ring_mould] +output: gold_ring +message: "You cast a gold ring." diff --git a/data/recipes/crafting/craft_hard_leather_body.yaml b/data/recipes/crafting/craft_hard_leather_body.yaml new file mode 100644 index 0000000..d1287df --- /dev/null +++ b/data/recipes/crafting/craft_hard_leather_body.yaml @@ -0,0 +1,13 @@ +id: craft_hard_leather_body +type: crafting +level: 28 +xp: 35 +wait: 4 +tool: needle +consume: + - items: [hard_leather] + quantity: 1 + - items: [thread] + quantity: 1 +output: hard_leather_body +message: "You craft a hard leather body." diff --git a/data/recipes/crafting/craft_hard_leather_shield.yaml b/data/recipes/crafting/craft_hard_leather_shield.yaml new file mode 100644 index 0000000..7dbd66a --- /dev/null +++ b/data/recipes/crafting/craft_hard_leather_shield.yaml @@ -0,0 +1,13 @@ +id: craft_hard_leather_shield +type: crafting +level: 41 +xp: 40 +wait: 4 +tool: needle +consume: + - items: [hard_leather] + quantity: 1 + - items: [thread] + quantity: 1 +output: hard_leather_shield +message: "You craft a hard leather shield." diff --git a/data/recipes/crafting/craft_leather_body.yaml b/data/recipes/crafting/craft_leather_body.yaml new file mode 100644 index 0000000..0f9774e --- /dev/null +++ b/data/recipes/crafting/craft_leather_body.yaml @@ -0,0 +1,13 @@ +id: craft_leather_body +type: crafting +level: 14 +xp: 25 +wait: 4 +tool: needle +consume: + - items: [leather] + quantity: 1 + - items: [thread] + quantity: 1 +output: leather_body +message: "You craft a leather body." diff --git a/data/recipes/crafting/craft_leather_boots.yaml b/data/recipes/crafting/craft_leather_boots.yaml new file mode 100644 index 0000000..b935a08 --- /dev/null +++ b/data/recipes/crafting/craft_leather_boots.yaml @@ -0,0 +1,13 @@ +id: craft_leather_boots +type: crafting +level: 7 +xp: 16 +wait: 4 +tool: needle +consume: + - items: [leather] + quantity: 1 + - items: [thread] + quantity: 1 +output: leather_boots +message: "You craft a pair of leather boots." diff --git a/data/recipes/crafting/craft_leather_chaps.yaml b/data/recipes/crafting/craft_leather_chaps.yaml new file mode 100644 index 0000000..fac2a9d --- /dev/null +++ b/data/recipes/crafting/craft_leather_chaps.yaml @@ -0,0 +1,13 @@ +id: craft_leather_chaps +type: crafting +level: 18 +xp: 27 +wait: 4 +tool: needle +consume: + - items: [leather] + quantity: 1 + - items: [thread] + quantity: 1 +output: leather_chaps +message: "You craft a pair of leather chaps." diff --git a/data/recipes/crafting/craft_leather_cowl.yaml b/data/recipes/crafting/craft_leather_cowl.yaml new file mode 100644 index 0000000..9e5de25 --- /dev/null +++ b/data/recipes/crafting/craft_leather_cowl.yaml @@ -0,0 +1,13 @@ +id: craft_leather_cowl +type: crafting +level: 9 +xp: 19 +wait: 4 +tool: needle +consume: + - items: [leather] + quantity: 1 + - items: [thread] + quantity: 1 +output: leather_cowl +message: "You craft a leather cowl." diff --git a/data/recipes/crafting/craft_leather_gloves.yaml b/data/recipes/crafting/craft_leather_gloves.yaml new file mode 100644 index 0000000..4b4fdfc --- /dev/null +++ b/data/recipes/crafting/craft_leather_gloves.yaml @@ -0,0 +1,13 @@ +id: craft_leather_gloves +type: crafting +level: 1 +xp: 14 +wait: 4 +tool: needle +consume: + - items: [leather] + quantity: 1 + - items: [thread] + quantity: 1 +output: leather_gloves +message: "You craft a pair of leather gloves." diff --git a/data/recipes/crafting/craft_leather_vambraces.yaml b/data/recipes/crafting/craft_leather_vambraces.yaml new file mode 100644 index 0000000..1227271 --- /dev/null +++ b/data/recipes/crafting/craft_leather_vambraces.yaml @@ -0,0 +1,13 @@ +id: craft_leather_vambraces +type: crafting +level: 11 +xp: 22 +wait: 4 +tool: needle +consume: + - items: [leather] + quantity: 1 + - items: [thread] + quantity: 1 +output: leather_vambraces +message: "You craft a pair of leather vambraces." diff --git a/data/recipes/crafting/craft_pie_dish.yaml b/data/recipes/crafting/craft_pie_dish.yaml new file mode 100644 index 0000000..2b31d17 --- /dev/null +++ b/data/recipes/crafting/craft_pie_dish.yaml @@ -0,0 +1,16 @@ +id: craft_pie_dish +type: crafting +level: 7 +xp: 10 +wait: 4 +station: [pottery_oven] +consume: + - items: [unfired_pie_dish] + quantity: 1 +output: pie_dish +message: "You fire the pie dish in the oven successfully." +fail_message: "The pie dish cracks in the oven and is ruined." +success: + base: 0.40 + per_level: 0.02 + cap: 0.95 diff --git a/data/recipes/crafting/craft_plant_pot.yaml b/data/recipes/crafting/craft_plant_pot.yaml new file mode 100644 index 0000000..ddfcefa --- /dev/null +++ b/data/recipes/crafting/craft_plant_pot.yaml @@ -0,0 +1,16 @@ +id: craft_plant_pot +type: crafting +level: 19 +xp: 18 +wait: 4 +station: [pottery_oven] +consume: + - items: [unfired_plant_pot] + quantity: 1 +output: plant_pot +message: "You fire the plant pot in the oven successfully." +fail_message: "The plant pot cracks in the oven and is ruined." +success: + base: 0.30 + per_level: 0.02 + cap: 0.95 diff --git a/data/recipes/crafting/craft_pot.yaml b/data/recipes/crafting/craft_pot.yaml new file mode 100644 index 0000000..1b80eef --- /dev/null +++ b/data/recipes/crafting/craft_pot.yaml @@ -0,0 +1,16 @@ +id: craft_pot +type: crafting +level: 1 +xp: 6 +wait: 4 +station: [pottery_oven] +consume: + - items: [unfired_pot] + quantity: 1 +output: empty_pot +message: "You fire the pot in the oven successfully." +fail_message: "The pot cracks in the oven and is ruined." +success: + base: 0.50 + per_level: 0.02 + cap: 0.95 diff --git a/data/recipes/crafting/craft_ruby_amulet_u.yaml b/data/recipes/crafting/craft_ruby_amulet_u.yaml new file mode 100644 index 0000000..38a864e --- /dev/null +++ b/data/recipes/crafting/craft_ruby_amulet_u.yaml @@ -0,0 +1,16 @@ +id: craft_ruby_amulet_u +type: crafting +level: 50 +xp: 85 +wait: 4 +station: [furnace] +consume: + - items: [gold_bar] + quantity: 1 + - items: [ruby] + quantity: 1 + - items: [amulet_mould] + quantity: 1 + byproducts: [amulet_mould] +output: ruby_amulet_u +message: "You cast a ruby amulet." diff --git a/data/recipes/crafting/craft_ruby_bracelet.yaml b/data/recipes/crafting/craft_ruby_bracelet.yaml new file mode 100644 index 0000000..bcc963e --- /dev/null +++ b/data/recipes/crafting/craft_ruby_bracelet.yaml @@ -0,0 +1,16 @@ +id: craft_ruby_bracelet +type: crafting +level: 42 +xp: 80 +wait: 4 +station: [furnace] +consume: + - items: [gold_bar] + quantity: 1 + - items: [ruby] + quantity: 1 + - items: [bracelet_mould] + quantity: 1 + byproducts: [bracelet_mould] +output: ruby_bracelet +message: "You cast a ruby bracelet." diff --git a/data/recipes/crafting/craft_ruby_necklace.yaml b/data/recipes/crafting/craft_ruby_necklace.yaml new file mode 100644 index 0000000..60e47a3 --- /dev/null +++ b/data/recipes/crafting/craft_ruby_necklace.yaml @@ -0,0 +1,16 @@ +id: craft_ruby_necklace +type: crafting +level: 40 +xp: 75 +wait: 4 +station: [furnace] +consume: + - items: [gold_bar] + quantity: 1 + - items: [ruby] + quantity: 1 + - items: [necklace_mould] + quantity: 1 + byproducts: [necklace_mould] +output: ruby_necklace +message: "You cast a ruby necklace." diff --git a/data/recipes/crafting/craft_ruby_ring.yaml b/data/recipes/crafting/craft_ruby_ring.yaml new file mode 100644 index 0000000..61d2b46 --- /dev/null +++ b/data/recipes/crafting/craft_ruby_ring.yaml @@ -0,0 +1,16 @@ +id: craft_ruby_ring +type: crafting +level: 63 +xp: 70 +wait: 4 +station: [furnace] +consume: + - items: [gold_bar] + quantity: 1 + - items: [ruby] + quantity: 1 + - items: [ring_mould] + quantity: 1 + byproducts: [ring_mould] +output: ruby_ring +message: "You cast a ruby ring." diff --git a/data/recipes/crafting/craft_sapphire_amulet_u.yaml b/data/recipes/crafting/craft_sapphire_amulet_u.yaml new file mode 100644 index 0000000..07ef6bf --- /dev/null +++ b/data/recipes/crafting/craft_sapphire_amulet_u.yaml @@ -0,0 +1,16 @@ +id: craft_sapphire_amulet_u +type: crafting +level: 24 +xp: 65 +wait: 4 +station: [furnace] +consume: + - items: [gold_bar] + quantity: 1 + - items: [sapphire] + quantity: 1 + - items: [amulet_mould] + quantity: 1 + byproducts: [amulet_mould] +output: sapphire_amulet_u +message: "You cast a sapphire amulet." diff --git a/data/recipes/crafting/craft_sapphire_bracelet.yaml b/data/recipes/crafting/craft_sapphire_bracelet.yaml new file mode 100644 index 0000000..3bc1067 --- /dev/null +++ b/data/recipes/crafting/craft_sapphire_bracelet.yaml @@ -0,0 +1,16 @@ +id: craft_sapphire_bracelet +type: crafting +level: 23 +xp: 60 +wait: 4 +station: [furnace] +consume: + - items: [gold_bar] + quantity: 1 + - items: [sapphire] + quantity: 1 + - items: [bracelet_mould] + quantity: 1 + byproducts: [bracelet_mould] +output: sapphire_bracelet +message: "You cast a sapphire bracelet." diff --git a/data/recipes/crafting/craft_sapphire_necklace.yaml b/data/recipes/crafting/craft_sapphire_necklace.yaml new file mode 100644 index 0000000..8006bf7 --- /dev/null +++ b/data/recipes/crafting/craft_sapphire_necklace.yaml @@ -0,0 +1,16 @@ +id: craft_sapphire_necklace +type: crafting +level: 22 +xp: 55 +wait: 4 +station: [furnace] +consume: + - items: [gold_bar] + quantity: 1 + - items: [sapphire] + quantity: 1 + - items: [necklace_mould] + quantity: 1 + byproducts: [necklace_mould] +output: sapphire_necklace +message: "You cast a sapphire necklace." diff --git a/data/recipes/crafting/craft_sapphire_ring.yaml b/data/recipes/crafting/craft_sapphire_ring.yaml new file mode 100644 index 0000000..cc67b73 --- /dev/null +++ b/data/recipes/crafting/craft_sapphire_ring.yaml @@ -0,0 +1,16 @@ +id: craft_sapphire_ring +type: crafting +level: 20 +xp: 40 +wait: 4 +station: [furnace] +consume: + - items: [gold_bar] + quantity: 1 + - items: [sapphire] + quantity: 1 + - items: [ring_mould] + quantity: 1 + byproducts: [ring_mould] +output: sapphire_ring +message: "You cast a sapphire ring." diff --git a/data/recipes/crafting/craft_unfired_pie_dish.yaml b/data/recipes/crafting/craft_unfired_pie_dish.yaml new file mode 100644 index 0000000..7ba5032 --- /dev/null +++ b/data/recipes/crafting/craft_unfired_pie_dish.yaml @@ -0,0 +1,11 @@ +id: craft_unfired_pie_dish +type: crafting +level: 7 +xp: 15 +wait: 4 +station: [pottery_wheel] +consume: + - items: [soft_clay] + quantity: 1 +output: unfired_pie_dish +message: "You shape the clay into a pie dish." diff --git a/data/recipes/crafting/craft_unfired_plant_pot.yaml b/data/recipes/crafting/craft_unfired_plant_pot.yaml new file mode 100644 index 0000000..db7a38e --- /dev/null +++ b/data/recipes/crafting/craft_unfired_plant_pot.yaml @@ -0,0 +1,11 @@ +id: craft_unfired_plant_pot +type: crafting +level: 19 +xp: 18 +wait: 4 +station: [pottery_wheel] +consume: + - items: [soft_clay] + quantity: 1 +output: unfired_plant_pot +message: "You shape the clay into a plant pot." diff --git a/data/recipes/crafting/craft_unfired_pot.yaml b/data/recipes/crafting/craft_unfired_pot.yaml new file mode 100644 index 0000000..5b2762d --- /dev/null +++ b/data/recipes/crafting/craft_unfired_pot.yaml @@ -0,0 +1,11 @@ +id: craft_unfired_pot +type: crafting +level: 1 +xp: 6 +wait: 4 +station: [pottery_wheel] +consume: + - items: [soft_clay] + quantity: 1 +output: unfired_pot +message: "You shape the clay into a pot." diff --git a/data/recipes/fletch_adamant_arrow.yaml b/data/recipes/fletch_adamant_arrow.yaml deleted file mode 100644 index 0166c99..0000000 --- a/data/recipes/fletch_adamant_arrow.yaml +++ /dev/null @@ -1,13 +0,0 @@ -id: fletch_adamant_arrow -type: fletching -level: 60 -xp: 10 -wait: 2 -consume: - - items: [headless_arrow] - qty: 15 - - items: [adamant_arrowtips] - qty: 15 -output: adamant_arrow -output_qty: 15 -message: "You attach the adamant arrowtips to the headless arrows." diff --git a/data/recipes/fletch_adamant_bolts.yaml b/data/recipes/fletch_adamant_bolts.yaml deleted file mode 100644 index 46aa57f..0000000 --- a/data/recipes/fletch_adamant_bolts.yaml +++ /dev/null @@ -1,13 +0,0 @@ -id: fletch_adamant_bolts -type: fletching -level: 61 -xp: 70 -wait: 0 -consume: - - items: [adamant_bolts_unf] - qty: 10 - - items: [feather] - qty: 10 -output: adamant_bolts -output_qty: 10 -message: "You attach feathers to the adamant bolts." diff --git a/data/recipes/fletch_arrow_shaft.yaml b/data/recipes/fletch_arrow_shaft.yaml deleted file mode 100644 index b2d3c81..0000000 --- a/data/recipes/fletch_arrow_shaft.yaml +++ /dev/null @@ -1,12 +0,0 @@ -id: fletch_arrow_shaft -type: fletching -tool: knife -level: 1 -xp: 5 -wait: 5 -consume: - - items: [logs] - qty: 1 -output: arrow_shaft -output_qty: 15 -message: "You carefully cut the logs into arrow shafts." diff --git a/data/recipes/fletch_arrow_shaft_magic.yaml b/data/recipes/fletch_arrow_shaft_magic.yaml deleted file mode 100644 index b72c4b8..0000000 --- a/data/recipes/fletch_arrow_shaft_magic.yaml +++ /dev/null @@ -1,12 +0,0 @@ -id: fletch_arrow_shaft_magic -type: fletching -tool: knife -level: 75 -xp: 30 -wait: 5 -consume: - - items: [magic_logs] - qty: 1 -output: arrow_shaft -output_qty: 40 -message: "You carefully cut the magic logs into arrow shafts." diff --git a/data/recipes/fletch_arrow_shaft_maple.yaml b/data/recipes/fletch_arrow_shaft_maple.yaml deleted file mode 100644 index aa9fea6..0000000 --- a/data/recipes/fletch_arrow_shaft_maple.yaml +++ /dev/null @@ -1,12 +0,0 @@ -id: fletch_arrow_shaft_maple -type: fletching -tool: knife -level: 45 -xp: 20 -wait: 5 -consume: - - items: [maple_logs] - qty: 1 -output: arrow_shaft -output_qty: 30 -message: "You carefully cut the maple logs into arrow shafts." diff --git a/data/recipes/fletch_arrow_shaft_oak.yaml b/data/recipes/fletch_arrow_shaft_oak.yaml deleted file mode 100644 index 1940e87..0000000 --- a/data/recipes/fletch_arrow_shaft_oak.yaml +++ /dev/null @@ -1,12 +0,0 @@ -id: fletch_arrow_shaft_oak -type: fletching -tool: knife -level: 15 -xp: 10 -wait: 5 -consume: - - items: [oak_logs] - qty: 1 -output: arrow_shaft -output_qty: 20 -message: "You carefully cut the oak logs into arrow shafts." diff --git a/data/recipes/fletch_arrow_shaft_willow.yaml b/data/recipes/fletch_arrow_shaft_willow.yaml deleted file mode 100644 index 986ffae..0000000 --- a/data/recipes/fletch_arrow_shaft_willow.yaml +++ /dev/null @@ -1,12 +0,0 @@ -id: fletch_arrow_shaft_willow -type: fletching -tool: knife -level: 30 -xp: 15 -wait: 5 -consume: - - items: [willow_logs] - qty: 1 -output: arrow_shaft -output_qty: 25 -message: "You carefully cut the willow logs into arrow shafts." diff --git a/data/recipes/fletch_arrow_shaft_yew.yaml b/data/recipes/fletch_arrow_shaft_yew.yaml deleted file mode 100644 index bc7775e..0000000 --- a/data/recipes/fletch_arrow_shaft_yew.yaml +++ /dev/null @@ -1,12 +0,0 @@ -id: fletch_arrow_shaft_yew -type: fletching -tool: knife -level: 60 -xp: 25 -wait: 5 -consume: - - items: [yew_logs] - qty: 1 -output: arrow_shaft -output_qty: 35 -message: "You carefully cut the yew logs into arrow shafts." diff --git a/data/recipes/fletch_bronze_arrow.yaml b/data/recipes/fletch_bronze_arrow.yaml deleted file mode 100644 index 4cc7aca..0000000 --- a/data/recipes/fletch_bronze_arrow.yaml +++ /dev/null @@ -1,13 +0,0 @@ -id: fletch_bronze_arrow -type: fletching -level: 1 -xp: 1 -wait: 2 -consume: - - items: [headless_arrow] - qty: 15 - - items: [bronze_arrowtips] - qty: 15 -output: bronze_arrow -output_qty: 15 -message: "You attach the bronze arrowtips to the headless arrows." diff --git a/data/recipes/fletch_bronze_bolts.yaml b/data/recipes/fletch_bronze_bolts.yaml deleted file mode 100644 index f10595a..0000000 --- a/data/recipes/fletch_bronze_bolts.yaml +++ /dev/null @@ -1,13 +0,0 @@ -id: fletch_bronze_bolts -type: fletching -level: 9 -xp: 5 -wait: 0 -consume: - - items: [bronze_bolts_unf] - qty: 10 - - items: [feather] - qty: 10 -output: bronze_bolts -output_qty: 10 -message: "You attach feathers to the bronze bolts." diff --git a/data/recipes/fletch_diamond_bolt_tips.yaml b/data/recipes/fletch_diamond_bolt_tips.yaml deleted file mode 100644 index dc57964..0000000 --- a/data/recipes/fletch_diamond_bolt_tips.yaml +++ /dev/null @@ -1,12 +0,0 @@ -id: fletch_diamond_bolt_tips -type: fletching -tool: chisel -level: 65 -xp: 7 -wait: 5 -consume: - - items: [uncut_diamond] - qty: 1 -output: diamond_bolt_tips -output_qty: 12 -message: "You cut the diamond into bolt tips." diff --git a/data/recipes/fletch_diamond_bolts.yaml b/data/recipes/fletch_diamond_bolts.yaml deleted file mode 100644 index 7b0a460..0000000 --- a/data/recipes/fletch_diamond_bolts.yaml +++ /dev/null @@ -1,13 +0,0 @@ -id: fletch_diamond_bolts -type: fletching -level: 65 -xp: 7 -wait: 2 -consume: - - items: [adamant_bolts] - qty: 10 - - items: [diamond_bolt_tips] - qty: 10 -output: diamond_bolts -output_qty: 10 -message: "You tip the adamant bolts with diamond." diff --git a/data/recipes/fletch_emerald_bolt_tips.yaml b/data/recipes/fletch_emerald_bolt_tips.yaml deleted file mode 100644 index b7d78a5..0000000 --- a/data/recipes/fletch_emerald_bolt_tips.yaml +++ /dev/null @@ -1,12 +0,0 @@ -id: fletch_emerald_bolt_tips -type: fletching -tool: chisel -level: 66 -xp: 5 -wait: 5 -consume: - - items: [uncut_emerald] - qty: 1 -output: emerald_bolt_tips -output_qty: 12 -message: "You cut the emerald into bolt tips." diff --git a/data/recipes/fletch_emerald_bolts.yaml b/data/recipes/fletch_emerald_bolts.yaml deleted file mode 100644 index 353432a..0000000 --- a/data/recipes/fletch_emerald_bolts.yaml +++ /dev/null @@ -1,13 +0,0 @@ -id: fletch_emerald_bolts -type: fletching -level: 66 -xp: 5 -wait: 2 -consume: - - items: [mithril_bolts] - qty: 10 - - items: [emerald_bolt_tips] - qty: 10 -output: emerald_bolts -output_qty: 10 -message: "You tip the mithril bolts with emerald." diff --git a/data/recipes/fletch_headless_arrow.yaml b/data/recipes/fletch_headless_arrow.yaml deleted file mode 100644 index 3016430..0000000 --- a/data/recipes/fletch_headless_arrow.yaml +++ /dev/null @@ -1,13 +0,0 @@ -id: fletch_headless_arrow -type: fletching -level: 1 -xp: 1 -wait: 2 -consume: - - items: [arrow_shaft] - qty: 15 - - items: [feather] - qty: 15 -output: headless_arrow -output_qty: 15 -message: "You attach feathers to the arrow shafts." diff --git a/data/recipes/fletch_iron_arrow.yaml b/data/recipes/fletch_iron_arrow.yaml deleted file mode 100644 index 2727ca1..0000000 --- a/data/recipes/fletch_iron_arrow.yaml +++ /dev/null @@ -1,13 +0,0 @@ -id: fletch_iron_arrow -type: fletching -level: 15 -xp: 2 -wait: 2 -consume: - - items: [headless_arrow] - qty: 15 - - items: [iron_arrowtips] - qty: 15 -output: iron_arrow -output_qty: 15 -message: "You attach the iron arrowtips to the headless arrows." diff --git a/data/recipes/fletch_iron_bolts.yaml b/data/recipes/fletch_iron_bolts.yaml deleted file mode 100644 index 44a623f..0000000 --- a/data/recipes/fletch_iron_bolts.yaml +++ /dev/null @@ -1,13 +0,0 @@ -id: fletch_iron_bolts -type: fletching -level: 39 -xp: 15 -wait: 0 -consume: - - items: [iron_bolts_unf] - qty: 10 - - items: [feather] - qty: 10 -output: iron_bolts -output_qty: 10 -message: "You attach feathers to the iron bolts." diff --git a/data/recipes/fletch_longbow.yaml b/data/recipes/fletch_longbow.yaml deleted file mode 100644 index 392ccfb..0000000 --- a/data/recipes/fletch_longbow.yaml +++ /dev/null @@ -1,12 +0,0 @@ -id: fletch_longbow -type: fletching -level: 10 -xp: 10 -wait: 2 -consume: - - items: [longbow_u] - qty: 1 - - items: [bowstring] - qty: 1 -output: longbow -message: "You string the longbow." diff --git a/data/recipes/fletch_longbow_u.yaml b/data/recipes/fletch_longbow_u.yaml deleted file mode 100644 index e836a9e..0000000 --- a/data/recipes/fletch_longbow_u.yaml +++ /dev/null @@ -1,11 +0,0 @@ -id: fletch_longbow_u -type: fletching -tool: knife -level: 10 -xp: 10 -wait: 3 -consume: - - items: [logs] - qty: 1 -output: longbow_u -message: "You carefully carve the log into a longbow." diff --git a/data/recipes/fletch_magic_longbow.yaml b/data/recipes/fletch_magic_longbow.yaml deleted file mode 100644 index c8cc0d4..0000000 --- a/data/recipes/fletch_magic_longbow.yaml +++ /dev/null @@ -1,12 +0,0 @@ -id: fletch_magic_longbow -type: fletching -level: 85 -xp: 91 -wait: 2 -consume: - - items: [magic_longbow_u] - qty: 1 - - items: [bowstring] - qty: 1 -output: magic_longbow -message: "You string the magic longbow." diff --git a/data/recipes/fletch_magic_longbow_u.yaml b/data/recipes/fletch_magic_longbow_u.yaml deleted file mode 100644 index 19eddc8..0000000 --- a/data/recipes/fletch_magic_longbow_u.yaml +++ /dev/null @@ -1,11 +0,0 @@ -id: fletch_magic_longbow_u -type: fletching -tool: knife -level: 85 -xp: 91 -wait: 3 -consume: - - items: [magic_logs] - qty: 1 -output: magic_longbow_u -message: "You carefully carve the magic log into a longbow." diff --git a/data/recipes/fletch_magic_shortbow.yaml b/data/recipes/fletch_magic_shortbow.yaml deleted file mode 100644 index b9b3bb2..0000000 --- a/data/recipes/fletch_magic_shortbow.yaml +++ /dev/null @@ -1,12 +0,0 @@ -id: fletch_magic_shortbow -type: fletching -level: 80 -xp: 83 -wait: 2 -consume: - - items: [magic_shortbow_u] - qty: 1 - - items: [bowstring] - qty: 1 -output: magic_shortbow -message: "You string the magic shortbow." diff --git a/data/recipes/fletch_magic_shortbow_u.yaml b/data/recipes/fletch_magic_shortbow_u.yaml deleted file mode 100644 index e9f2e38..0000000 --- a/data/recipes/fletch_magic_shortbow_u.yaml +++ /dev/null @@ -1,11 +0,0 @@ -id: fletch_magic_shortbow_u -type: fletching -tool: knife -level: 80 -xp: 83 -wait: 3 -consume: - - items: [magic_logs] - qty: 1 -output: magic_shortbow_u -message: "You carefully carve the magic log into a shortbow." diff --git a/data/recipes/fletch_maple_longbow.yaml b/data/recipes/fletch_maple_longbow.yaml deleted file mode 100644 index 1ecfb74..0000000 --- a/data/recipes/fletch_maple_longbow.yaml +++ /dev/null @@ -1,12 +0,0 @@ -id: fletch_maple_longbow -type: fletching -level: 55 -xp: 58 -wait: 2 -consume: - - items: [maple_longbow_u] - qty: 1 - - items: [bowstring] - qty: 1 -output: maple_longbow -message: "You string the maple longbow." diff --git a/data/recipes/fletch_maple_longbow_u.yaml b/data/recipes/fletch_maple_longbow_u.yaml deleted file mode 100644 index 981c6e0..0000000 --- a/data/recipes/fletch_maple_longbow_u.yaml +++ /dev/null @@ -1,11 +0,0 @@ -id: fletch_maple_longbow_u -type: fletching -tool: knife -level: 55 -xp: 58 -wait: 3 -consume: - - items: [maple_logs] - qty: 1 -output: maple_longbow_u -message: "You carefully carve the maple log into a longbow." diff --git a/data/recipes/fletch_maple_shortbow.yaml b/data/recipes/fletch_maple_shortbow.yaml deleted file mode 100644 index 844a080..0000000 --- a/data/recipes/fletch_maple_shortbow.yaml +++ /dev/null @@ -1,12 +0,0 @@ -id: fletch_maple_shortbow -type: fletching -level: 50 -xp: 50 -wait: 2 -consume: - - items: [maple_shortbow_u] - qty: 1 - - items: [bowstring] - qty: 1 -output: maple_shortbow -message: "You string the maple shortbow." diff --git a/data/recipes/fletch_maple_shortbow_u.yaml b/data/recipes/fletch_maple_shortbow_u.yaml deleted file mode 100644 index 56dc15c..0000000 --- a/data/recipes/fletch_maple_shortbow_u.yaml +++ /dev/null @@ -1,11 +0,0 @@ -id: fletch_maple_shortbow_u -type: fletching -tool: knife -level: 50 -xp: 50 -wait: 3 -consume: - - items: [maple_logs] - qty: 1 -output: maple_shortbow_u -message: "You carefully carve the maple log into a shortbow." diff --git a/data/recipes/fletch_mithril_arrow.yaml b/data/recipes/fletch_mithril_arrow.yaml deleted file mode 100644 index 1d03823..0000000 --- a/data/recipes/fletch_mithril_arrow.yaml +++ /dev/null @@ -1,13 +0,0 @@ -id: fletch_mithril_arrow -type: fletching -level: 45 -xp: 7 -wait: 2 -consume: - - items: [headless_arrow] - qty: 15 - - items: [mithril_arrowtips] - qty: 15 -output: mithril_arrow -output_qty: 15 -message: "You attach the mithril arrowtips to the headless arrows." diff --git a/data/recipes/fletch_mithril_bolts.yaml b/data/recipes/fletch_mithril_bolts.yaml deleted file mode 100644 index 90e85a8..0000000 --- a/data/recipes/fletch_mithril_bolts.yaml +++ /dev/null @@ -1,13 +0,0 @@ -id: fletch_mithril_bolts -type: fletching -level: 54 -xp: 50 -wait: 0 -consume: - - items: [mithril_bolts_unf] - qty: 10 - - items: [feather] - qty: 10 -output: mithril_bolts -output_qty: 10 -message: "You attach feathers to the mithril bolts." diff --git a/data/recipes/fletch_oak_longbow.yaml b/data/recipes/fletch_oak_longbow.yaml deleted file mode 100644 index 39b72d8..0000000 --- a/data/recipes/fletch_oak_longbow.yaml +++ /dev/null @@ -1,12 +0,0 @@ -id: fletch_oak_longbow -type: fletching -level: 25 -xp: 25 -wait: 2 -consume: - - items: [oak_longbow_u] - qty: 1 - - items: [bowstring] - qty: 1 -output: oak_longbow -message: "You string the oak longbow." diff --git a/data/recipes/fletch_oak_longbow_u.yaml b/data/recipes/fletch_oak_longbow_u.yaml deleted file mode 100644 index 733c227..0000000 --- a/data/recipes/fletch_oak_longbow_u.yaml +++ /dev/null @@ -1,11 +0,0 @@ -id: fletch_oak_longbow_u -type: fletching -tool: knife -level: 25 -xp: 25 -wait: 3 -consume: - - items: [oak_logs] - qty: 1 -output: oak_longbow_u -message: "You carefully carve the oak log into a longbow." diff --git a/data/recipes/fletch_oak_shortbow.yaml b/data/recipes/fletch_oak_shortbow.yaml deleted file mode 100644 index ade20ff..0000000 --- a/data/recipes/fletch_oak_shortbow.yaml +++ /dev/null @@ -1,12 +0,0 @@ -id: fletch_oak_shortbow -type: fletching -level: 20 -xp: 16 -wait: 2 -consume: - - items: [oak_shortbow_u] - qty: 1 - - items: [bowstring] - qty: 1 -output: oak_shortbow -message: "You string the oak shortbow." diff --git a/data/recipes/fletch_oak_shortbow_u.yaml b/data/recipes/fletch_oak_shortbow_u.yaml deleted file mode 100644 index d994a77..0000000 --- a/data/recipes/fletch_oak_shortbow_u.yaml +++ /dev/null @@ -1,11 +0,0 @@ -id: fletch_oak_shortbow_u -type: fletching -tool: knife -level: 20 -xp: 16 -wait: 3 -consume: - - items: [oak_logs] - qty: 1 -output: oak_shortbow_u -message: "You carefully carve the oak log into a shortbow." diff --git a/data/recipes/fletch_ruby_bolt_tips.yaml b/data/recipes/fletch_ruby_bolt_tips.yaml deleted file mode 100644 index 293a840..0000000 --- a/data/recipes/fletch_ruby_bolt_tips.yaml +++ /dev/null @@ -1,12 +0,0 @@ -id: fletch_ruby_bolt_tips -type: fletching -tool: chisel -level: 73 -xp: 6 -wait: 5 -consume: - - items: [uncut_ruby] - qty: 1 -output: ruby_bolt_tips -output_qty: 12 -message: "You cut the ruby into bolt tips." diff --git a/data/recipes/fletch_ruby_bolts.yaml b/data/recipes/fletch_ruby_bolts.yaml deleted file mode 100644 index 1fdac70..0000000 --- a/data/recipes/fletch_ruby_bolts.yaml +++ /dev/null @@ -1,13 +0,0 @@ -id: fletch_ruby_bolts -type: fletching -level: 73 -xp: 6 -wait: 2 -consume: - - items: [adamant_bolts] - qty: 10 - - items: [ruby_bolt_tips] - qty: 10 -output: ruby_bolts -output_qty: 10 -message: "You tip the adamant bolts with ruby." diff --git a/data/recipes/fletch_rune_arrow.yaml b/data/recipes/fletch_rune_arrow.yaml deleted file mode 100644 index a208bce..0000000 --- a/data/recipes/fletch_rune_arrow.yaml +++ /dev/null @@ -1,13 +0,0 @@ -id: fletch_rune_arrow -type: fletching -level: 75 -xp: 12 -wait: 2 -consume: - - items: [headless_arrow] - qty: 15 - - items: [rune_arrowtips] - qty: 15 -output: rune_arrow -output_qty: 15 -message: "You attach the rune arrowtips to the headless arrows." diff --git a/data/recipes/fletch_rune_bolts.yaml b/data/recipes/fletch_rune_bolts.yaml deleted file mode 100644 index 6073d7f..0000000 --- a/data/recipes/fletch_rune_bolts.yaml +++ /dev/null @@ -1,13 +0,0 @@ -id: fletch_rune_bolts -type: fletching -level: 69 -xp: 100 -wait: 0 -consume: - - items: [rune_bolts_unf] - qty: 10 - - items: [feather] - qty: 10 -output: rune_bolts -output_qty: 10 -message: "You attach feathers to the rune bolts." diff --git a/data/recipes/fletch_sapphire_bolt_tips.yaml b/data/recipes/fletch_sapphire_bolt_tips.yaml deleted file mode 100644 index 353d1de..0000000 --- a/data/recipes/fletch_sapphire_bolt_tips.yaml +++ /dev/null @@ -1,12 +0,0 @@ -id: fletch_sapphire_bolt_tips -type: fletching -tool: chisel -level: 63 -xp: 4 -wait: 5 -consume: - - items: [uncut_sapphire] - qty: 1 -output: sapphire_bolt_tips -output_qty: 12 -message: "You cut the sapphire into bolt tips." diff --git a/data/recipes/fletch_sapphire_bolts.yaml b/data/recipes/fletch_sapphire_bolts.yaml deleted file mode 100644 index 503809a..0000000 --- a/data/recipes/fletch_sapphire_bolts.yaml +++ /dev/null @@ -1,13 +0,0 @@ -id: fletch_sapphire_bolts -type: fletching -level: 63 -xp: 4 -wait: 2 -consume: - - items: [mithril_bolts] - qty: 10 - - items: [sapphire_bolt_tips] - qty: 10 -output: sapphire_bolts -output_qty: 10 -message: "You tip the mithril bolts with sapphire." diff --git a/data/recipes/fletch_shortbow.yaml b/data/recipes/fletch_shortbow.yaml deleted file mode 100644 index 0911aa2..0000000 --- a/data/recipes/fletch_shortbow.yaml +++ /dev/null @@ -1,12 +0,0 @@ -id: fletch_shortbow -type: fletching -level: 5 -xp: 5 -wait: 2 -consume: - - items: [shortbow_u] - qty: 1 - - items: [bowstring] - qty: 1 -output: shortbow -message: "You string the shortbow." diff --git a/data/recipes/fletch_shortbow_u.yaml b/data/recipes/fletch_shortbow_u.yaml deleted file mode 100644 index bda2a93..0000000 --- a/data/recipes/fletch_shortbow_u.yaml +++ /dev/null @@ -1,11 +0,0 @@ -id: fletch_shortbow_u -type: fletching -tool: knife -level: 5 -xp: 5 -wait: 3 -consume: - - items: [logs] - qty: 1 -output: shortbow_u -message: "You carefully carve the log into a shortbow." diff --git a/data/recipes/fletch_steel_arrow.yaml b/data/recipes/fletch_steel_arrow.yaml deleted file mode 100644 index fc28d21..0000000 --- a/data/recipes/fletch_steel_arrow.yaml +++ /dev/null @@ -1,13 +0,0 @@ -id: fletch_steel_arrow -type: fletching -level: 30 -xp: 5 -wait: 2 -consume: - - items: [headless_arrow] - qty: 15 - - items: [steel_arrowtips] - qty: 15 -output: steel_arrow -output_qty: 15 -message: "You attach the steel arrowtips to the headless arrows." diff --git a/data/recipes/fletch_steel_bolts.yaml b/data/recipes/fletch_steel_bolts.yaml deleted file mode 100644 index 156b6e0..0000000 --- a/data/recipes/fletch_steel_bolts.yaml +++ /dev/null @@ -1,13 +0,0 @@ -id: fletch_steel_bolts -type: fletching -level: 46 -xp: 35 -wait: 0 -consume: - - items: [steel_bolts_unf] - qty: 10 - - items: [feather] - qty: 10 -output: steel_bolts -output_qty: 10 -message: "You attach feathers to the steel bolts." diff --git a/data/recipes/fletch_willow_longbow.yaml b/data/recipes/fletch_willow_longbow.yaml deleted file mode 100644 index 6f4a9c0..0000000 --- a/data/recipes/fletch_willow_longbow.yaml +++ /dev/null @@ -1,12 +0,0 @@ -id: fletch_willow_longbow -type: fletching -level: 40 -xp: 41 -wait: 2 -consume: - - items: [willow_longbow_u] - qty: 1 - - items: [bowstring] - qty: 1 -output: willow_longbow -message: "You string the willow longbow." diff --git a/data/recipes/fletch_willow_longbow_u.yaml b/data/recipes/fletch_willow_longbow_u.yaml deleted file mode 100644 index 5afbe89..0000000 --- a/data/recipes/fletch_willow_longbow_u.yaml +++ /dev/null @@ -1,11 +0,0 @@ -id: fletch_willow_longbow_u -type: fletching -tool: knife -level: 40 -xp: 41 -wait: 3 -consume: - - items: [willow_logs] - qty: 1 -output: willow_longbow_u -message: "You carefully carve the willow log into a longbow." diff --git a/data/recipes/fletch_willow_shortbow.yaml b/data/recipes/fletch_willow_shortbow.yaml deleted file mode 100644 index e6d044f..0000000 --- a/data/recipes/fletch_willow_shortbow.yaml +++ /dev/null @@ -1,12 +0,0 @@ -id: fletch_willow_shortbow -type: fletching -level: 35 -xp: 33 -wait: 2 -consume: - - items: [willow_shortbow_u] - qty: 1 - - items: [bowstring] - qty: 1 -output: willow_shortbow -message: "You string the willow shortbow." diff --git a/data/recipes/fletch_willow_shortbow_u.yaml b/data/recipes/fletch_willow_shortbow_u.yaml deleted file mode 100644 index b0fb490..0000000 --- a/data/recipes/fletch_willow_shortbow_u.yaml +++ /dev/null @@ -1,11 +0,0 @@ -id: fletch_willow_shortbow_u -type: fletching -tool: knife -level: 35 -xp: 33 -wait: 3 -consume: - - items: [willow_logs] - qty: 1 -output: willow_shortbow_u -message: "You carefully carve the willow log into a shortbow." diff --git a/data/recipes/fletch_yew_longbow.yaml b/data/recipes/fletch_yew_longbow.yaml deleted file mode 100644 index 34b6a79..0000000 --- a/data/recipes/fletch_yew_longbow.yaml +++ /dev/null @@ -1,12 +0,0 @@ -id: fletch_yew_longbow -type: fletching -level: 65 -xp: 75 -wait: 2 -consume: - - items: [yew_longbow_u] - qty: 1 - - items: [bowstring] - qty: 1 -output: yew_longbow -message: "You string the yew longbow." diff --git a/data/recipes/fletch_yew_longbow_u.yaml b/data/recipes/fletch_yew_longbow_u.yaml deleted file mode 100644 index c5abe34..0000000 --- a/data/recipes/fletch_yew_longbow_u.yaml +++ /dev/null @@ -1,11 +0,0 @@ -id: fletch_yew_longbow_u -type: fletching -tool: knife -level: 65 -xp: 75 -wait: 3 -consume: - - items: [yew_logs] - qty: 1 -output: yew_longbow_u -message: "You carefully carve the yew log into a longbow." diff --git a/data/recipes/fletch_yew_shortbow.yaml b/data/recipes/fletch_yew_shortbow.yaml deleted file mode 100644 index 2dac064..0000000 --- a/data/recipes/fletch_yew_shortbow.yaml +++ /dev/null @@ -1,12 +0,0 @@ -id: fletch_yew_shortbow -type: fletching -level: 60 -xp: 67 -wait: 2 -consume: - - items: [yew_shortbow_u] - qty: 1 - - items: [bowstring] - qty: 1 -output: yew_shortbow -message: "You string the yew shortbow." diff --git a/data/recipes/fletch_yew_shortbow_u.yaml b/data/recipes/fletch_yew_shortbow_u.yaml deleted file mode 100644 index 4b61a38..0000000 --- a/data/recipes/fletch_yew_shortbow_u.yaml +++ /dev/null @@ -1,11 +0,0 @@ -id: fletch_yew_shortbow_u -type: fletching -tool: knife -level: 60 -xp: 67 -wait: 3 -consume: - - items: [yew_logs] - qty: 1 -output: yew_shortbow_u -message: "You carefully carve the yew log into a shortbow." diff --git a/data/recipes/fletching/fletch_adamant_arrow.yaml b/data/recipes/fletching/fletch_adamant_arrow.yaml new file mode 100644 index 0000000..57f899b --- /dev/null +++ b/data/recipes/fletching/fletch_adamant_arrow.yaml @@ -0,0 +1,13 @@ +id: fletch_adamant_arrow +type: fletching +level: 60 +xp: 10 +wait: 2 +consume: + - items: [headless_arrow] + quantity: 15 + - items: [adamant_arrowtips] + quantity: 15 +output: adamant_arrow +output_qty: 15 +message: "You attach the adamant arrowtips to the headless arrows." diff --git a/data/recipes/fletching/fletch_adamant_bolts.yaml b/data/recipes/fletching/fletch_adamant_bolts.yaml new file mode 100644 index 0000000..d96c811 --- /dev/null +++ b/data/recipes/fletching/fletch_adamant_bolts.yaml @@ -0,0 +1,13 @@ +id: fletch_adamant_bolts +type: fletching +level: 61 +xp: 70 +wait: 0 +consume: + - items: [adamant_bolts_unf] + quantity: 10 + - items: [feather] + quantity: 10 +output: adamant_bolts +output_qty: 10 +message: "You attach feathers to the adamant bolts." diff --git a/data/recipes/fletching/fletch_arrow_shaft.yaml b/data/recipes/fletching/fletch_arrow_shaft.yaml new file mode 100644 index 0000000..ebf3861 --- /dev/null +++ b/data/recipes/fletching/fletch_arrow_shaft.yaml @@ -0,0 +1,12 @@ +id: fletch_arrow_shaft +type: fletching +tool: knife +level: 1 +xp: 5 +wait: 5 +consume: + - items: [logs] + quantity: 1 +output: arrow_shaft +output_qty: 15 +message: "You carefully cut the logs into arrow shafts." diff --git a/data/recipes/fletching/fletch_arrow_shaft_magic.yaml b/data/recipes/fletching/fletch_arrow_shaft_magic.yaml new file mode 100644 index 0000000..0621859 --- /dev/null +++ b/data/recipes/fletching/fletch_arrow_shaft_magic.yaml @@ -0,0 +1,12 @@ +id: fletch_arrow_shaft_magic +type: fletching +tool: knife +level: 75 +xp: 30 +wait: 5 +consume: + - items: [magic_logs] + quantity: 1 +output: arrow_shaft +output_qty: 40 +message: "You carefully cut the magic logs into arrow shafts." diff --git a/data/recipes/fletching/fletch_arrow_shaft_maple.yaml b/data/recipes/fletching/fletch_arrow_shaft_maple.yaml new file mode 100644 index 0000000..b6671da --- /dev/null +++ b/data/recipes/fletching/fletch_arrow_shaft_maple.yaml @@ -0,0 +1,12 @@ +id: fletch_arrow_shaft_maple +type: fletching +tool: knife +level: 45 +xp: 20 +wait: 5 +consume: + - items: [maple_logs] + quantity: 1 +output: arrow_shaft +output_qty: 30 +message: "You carefully cut the maple logs into arrow shafts." diff --git a/data/recipes/fletching/fletch_arrow_shaft_oak.yaml b/data/recipes/fletching/fletch_arrow_shaft_oak.yaml new file mode 100644 index 0000000..cf38335 --- /dev/null +++ b/data/recipes/fletching/fletch_arrow_shaft_oak.yaml @@ -0,0 +1,12 @@ +id: fletch_arrow_shaft_oak +type: fletching +tool: knife +level: 15 +xp: 10 +wait: 5 +consume: + - items: [oak_logs] + quantity: 1 +output: arrow_shaft +output_qty: 20 +message: "You carefully cut the oak logs into arrow shafts." diff --git a/data/recipes/fletching/fletch_arrow_shaft_willow.yaml b/data/recipes/fletching/fletch_arrow_shaft_willow.yaml new file mode 100644 index 0000000..0c39a13 --- /dev/null +++ b/data/recipes/fletching/fletch_arrow_shaft_willow.yaml @@ -0,0 +1,12 @@ +id: fletch_arrow_shaft_willow +type: fletching +tool: knife +level: 30 +xp: 15 +wait: 5 +consume: + - items: [willow_logs] + quantity: 1 +output: arrow_shaft +output_qty: 25 +message: "You carefully cut the willow logs into arrow shafts." diff --git a/data/recipes/fletching/fletch_arrow_shaft_yew.yaml b/data/recipes/fletching/fletch_arrow_shaft_yew.yaml new file mode 100644 index 0000000..785325e --- /dev/null +++ b/data/recipes/fletching/fletch_arrow_shaft_yew.yaml @@ -0,0 +1,12 @@ +id: fletch_arrow_shaft_yew +type: fletching +tool: knife +level: 60 +xp: 25 +wait: 5 +consume: + - items: [yew_logs] + quantity: 1 +output: arrow_shaft +output_qty: 35 +message: "You carefully cut the yew logs into arrow shafts." diff --git a/data/recipes/fletching/fletch_bronze_arrow.yaml b/data/recipes/fletching/fletch_bronze_arrow.yaml new file mode 100644 index 0000000..4b9e924 --- /dev/null +++ b/data/recipes/fletching/fletch_bronze_arrow.yaml @@ -0,0 +1,13 @@ +id: fletch_bronze_arrow +type: fletching +level: 1 +xp: 1 +wait: 2 +consume: + - items: [headless_arrow] + quantity: 15 + - items: [bronze_arrowtips] + quantity: 15 +output: bronze_arrow +output_qty: 15 +message: "You attach the bronze arrowtips to the headless arrows." diff --git a/data/recipes/fletching/fletch_bronze_bolts.yaml b/data/recipes/fletching/fletch_bronze_bolts.yaml new file mode 100644 index 0000000..cdcf6db --- /dev/null +++ b/data/recipes/fletching/fletch_bronze_bolts.yaml @@ -0,0 +1,13 @@ +id: fletch_bronze_bolts +type: fletching +level: 9 +xp: 5 +wait: 0 +consume: + - items: [bronze_bolts_unf] + quantity: 10 + - items: [feather] + quantity: 10 +output: bronze_bolts +output_qty: 10 +message: "You attach feathers to the bronze bolts." diff --git a/data/recipes/fletching/fletch_diamond_bolt_tips.yaml b/data/recipes/fletching/fletch_diamond_bolt_tips.yaml new file mode 100644 index 0000000..0ccabe2 --- /dev/null +++ b/data/recipes/fletching/fletch_diamond_bolt_tips.yaml @@ -0,0 +1,12 @@ +id: fletch_diamond_bolt_tips +type: fletching +tool: chisel +level: 65 +xp: 7 +wait: 5 +consume: + - items: [uncut_diamond] + quantity: 1 +output: diamond_bolt_tips +output_qty: 12 +message: "You cut the diamond into bolt tips." diff --git a/data/recipes/fletching/fletch_diamond_bolts.yaml b/data/recipes/fletching/fletch_diamond_bolts.yaml new file mode 100644 index 0000000..8c98fc2 --- /dev/null +++ b/data/recipes/fletching/fletch_diamond_bolts.yaml @@ -0,0 +1,13 @@ +id: fletch_diamond_bolts +type: fletching +level: 65 +xp: 7 +wait: 2 +consume: + - items: [adamant_bolts] + quantity: 10 + - items: [diamond_bolt_tips] + quantity: 10 +output: diamond_bolts +output_qty: 10 +message: "You tip the adamant bolts with diamond." diff --git a/data/recipes/fletching/fletch_emerald_bolt_tips.yaml b/data/recipes/fletching/fletch_emerald_bolt_tips.yaml new file mode 100644 index 0000000..d48cf73 --- /dev/null +++ b/data/recipes/fletching/fletch_emerald_bolt_tips.yaml @@ -0,0 +1,12 @@ +id: fletch_emerald_bolt_tips +type: fletching +tool: chisel +level: 66 +xp: 5 +wait: 5 +consume: + - items: [uncut_emerald] + quantity: 1 +output: emerald_bolt_tips +output_qty: 12 +message: "You cut the emerald into bolt tips." diff --git a/data/recipes/fletching/fletch_emerald_bolts.yaml b/data/recipes/fletching/fletch_emerald_bolts.yaml new file mode 100644 index 0000000..8e7e446 --- /dev/null +++ b/data/recipes/fletching/fletch_emerald_bolts.yaml @@ -0,0 +1,13 @@ +id: fletch_emerald_bolts +type: fletching +level: 66 +xp: 5 +wait: 2 +consume: + - items: [mithril_bolts] + quantity: 10 + - items: [emerald_bolt_tips] + quantity: 10 +output: emerald_bolts +output_qty: 10 +message: "You tip the mithril bolts with emerald." diff --git a/data/recipes/fletching/fletch_headless_arrow.yaml b/data/recipes/fletching/fletch_headless_arrow.yaml new file mode 100644 index 0000000..84d88f5 --- /dev/null +++ b/data/recipes/fletching/fletch_headless_arrow.yaml @@ -0,0 +1,13 @@ +id: fletch_headless_arrow +type: fletching +level: 1 +xp: 1 +wait: 2 +consume: + - items: [arrow_shaft] + quantity: 15 + - items: [feather] + quantity: 15 +output: headless_arrow +output_qty: 15 +message: "You attach feathers to the arrow shafts." diff --git a/data/recipes/fletching/fletch_iron_arrow.yaml b/data/recipes/fletching/fletch_iron_arrow.yaml new file mode 100644 index 0000000..fbb1c2c --- /dev/null +++ b/data/recipes/fletching/fletch_iron_arrow.yaml @@ -0,0 +1,13 @@ +id: fletch_iron_arrow +type: fletching +level: 15 +xp: 2 +wait: 2 +consume: + - items: [headless_arrow] + quantity: 15 + - items: [iron_arrowtips] + quantity: 15 +output: iron_arrow +output_qty: 15 +message: "You attach the iron arrowtips to the headless arrows." diff --git a/data/recipes/fletching/fletch_iron_bolts.yaml b/data/recipes/fletching/fletch_iron_bolts.yaml new file mode 100644 index 0000000..bb90403 --- /dev/null +++ b/data/recipes/fletching/fletch_iron_bolts.yaml @@ -0,0 +1,13 @@ +id: fletch_iron_bolts +type: fletching +level: 39 +xp: 15 +wait: 0 +consume: + - items: [iron_bolts_unf] + quantity: 10 + - items: [feather] + quantity: 10 +output: iron_bolts +output_qty: 10 +message: "You attach feathers to the iron bolts." diff --git a/data/recipes/fletching/fletch_longbow.yaml b/data/recipes/fletching/fletch_longbow.yaml new file mode 100644 index 0000000..fa46921 --- /dev/null +++ b/data/recipes/fletching/fletch_longbow.yaml @@ -0,0 +1,12 @@ +id: fletch_longbow +type: fletching +level: 10 +xp: 10 +wait: 2 +consume: + - items: [longbow_u] + quantity: 1 + - items: [bowstring] + quantity: 1 +output: longbow +message: "You string the longbow." diff --git a/data/recipes/fletching/fletch_longbow_u.yaml b/data/recipes/fletching/fletch_longbow_u.yaml new file mode 100644 index 0000000..a893b49 --- /dev/null +++ b/data/recipes/fletching/fletch_longbow_u.yaml @@ -0,0 +1,11 @@ +id: fletch_longbow_u +type: fletching +tool: knife +level: 10 +xp: 10 +wait: 3 +consume: + - items: [logs] + quantity: 1 +output: longbow_u +message: "You carefully carve the log into a longbow." diff --git a/data/recipes/fletching/fletch_magic_longbow.yaml b/data/recipes/fletching/fletch_magic_longbow.yaml new file mode 100644 index 0000000..8e16b9c --- /dev/null +++ b/data/recipes/fletching/fletch_magic_longbow.yaml @@ -0,0 +1,12 @@ +id: fletch_magic_longbow +type: fletching +level: 85 +xp: 91 +wait: 2 +consume: + - items: [magic_longbow_u] + quantity: 1 + - items: [bowstring] + quantity: 1 +output: magic_longbow +message: "You string the magic longbow." diff --git a/data/recipes/fletching/fletch_magic_longbow_u.yaml b/data/recipes/fletching/fletch_magic_longbow_u.yaml new file mode 100644 index 0000000..ce2e247 --- /dev/null +++ b/data/recipes/fletching/fletch_magic_longbow_u.yaml @@ -0,0 +1,11 @@ +id: fletch_magic_longbow_u +type: fletching +tool: knife +level: 85 +xp: 91 +wait: 3 +consume: + - items: [magic_logs] + quantity: 1 +output: magic_longbow_u +message: "You carefully carve the magic log into a longbow." diff --git a/data/recipes/fletching/fletch_magic_shortbow.yaml b/data/recipes/fletching/fletch_magic_shortbow.yaml new file mode 100644 index 0000000..58abce9 --- /dev/null +++ b/data/recipes/fletching/fletch_magic_shortbow.yaml @@ -0,0 +1,12 @@ +id: fletch_magic_shortbow +type: fletching +level: 80 +xp: 83 +wait: 2 +consume: + - items: [magic_shortbow_u] + quantity: 1 + - items: [bowstring] + quantity: 1 +output: magic_shortbow +message: "You string the magic shortbow." diff --git a/data/recipes/fletching/fletch_magic_shortbow_u.yaml b/data/recipes/fletching/fletch_magic_shortbow_u.yaml new file mode 100644 index 0000000..3fbf6cd --- /dev/null +++ b/data/recipes/fletching/fletch_magic_shortbow_u.yaml @@ -0,0 +1,11 @@ +id: fletch_magic_shortbow_u +type: fletching +tool: knife +level: 80 +xp: 83 +wait: 3 +consume: + - items: [magic_logs] + quantity: 1 +output: magic_shortbow_u +message: "You carefully carve the magic log into a shortbow." diff --git a/data/recipes/fletching/fletch_maple_longbow.yaml b/data/recipes/fletching/fletch_maple_longbow.yaml new file mode 100644 index 0000000..123d531 --- /dev/null +++ b/data/recipes/fletching/fletch_maple_longbow.yaml @@ -0,0 +1,12 @@ +id: fletch_maple_longbow +type: fletching +level: 55 +xp: 58 +wait: 2 +consume: + - items: [maple_longbow_u] + quantity: 1 + - items: [bowstring] + quantity: 1 +output: maple_longbow +message: "You string the maple longbow." diff --git a/data/recipes/fletching/fletch_maple_longbow_u.yaml b/data/recipes/fletching/fletch_maple_longbow_u.yaml new file mode 100644 index 0000000..4c61993 --- /dev/null +++ b/data/recipes/fletching/fletch_maple_longbow_u.yaml @@ -0,0 +1,11 @@ +id: fletch_maple_longbow_u +type: fletching +tool: knife +level: 55 +xp: 58 +wait: 3 +consume: + - items: [maple_logs] + quantity: 1 +output: maple_longbow_u +message: "You carefully carve the maple log into a longbow." diff --git a/data/recipes/fletching/fletch_maple_shortbow.yaml b/data/recipes/fletching/fletch_maple_shortbow.yaml new file mode 100644 index 0000000..aebe50a --- /dev/null +++ b/data/recipes/fletching/fletch_maple_shortbow.yaml @@ -0,0 +1,12 @@ +id: fletch_maple_shortbow +type: fletching +level: 50 +xp: 50 +wait: 2 +consume: + - items: [maple_shortbow_u] + quantity: 1 + - items: [bowstring] + quantity: 1 +output: maple_shortbow +message: "You string the maple shortbow." diff --git a/data/recipes/fletching/fletch_maple_shortbow_u.yaml b/data/recipes/fletching/fletch_maple_shortbow_u.yaml new file mode 100644 index 0000000..36270dd --- /dev/null +++ b/data/recipes/fletching/fletch_maple_shortbow_u.yaml @@ -0,0 +1,11 @@ +id: fletch_maple_shortbow_u +type: fletching +tool: knife +level: 50 +xp: 50 +wait: 3 +consume: + - items: [maple_logs] + quantity: 1 +output: maple_shortbow_u +message: "You carefully carve the maple log into a shortbow." diff --git a/data/recipes/fletching/fletch_mithril_arrow.yaml b/data/recipes/fletching/fletch_mithril_arrow.yaml new file mode 100644 index 0000000..87a46e2 --- /dev/null +++ b/data/recipes/fletching/fletch_mithril_arrow.yaml @@ -0,0 +1,13 @@ +id: fletch_mithril_arrow +type: fletching +level: 45 +xp: 7 +wait: 2 +consume: + - items: [headless_arrow] + quantity: 15 + - items: [mithril_arrowtips] + quantity: 15 +output: mithril_arrow +output_qty: 15 +message: "You attach the mithril arrowtips to the headless arrows." diff --git a/data/recipes/fletching/fletch_mithril_bolts.yaml b/data/recipes/fletching/fletch_mithril_bolts.yaml new file mode 100644 index 0000000..a2afcb8 --- /dev/null +++ b/data/recipes/fletching/fletch_mithril_bolts.yaml @@ -0,0 +1,13 @@ +id: fletch_mithril_bolts +type: fletching +level: 54 +xp: 50 +wait: 0 +consume: + - items: [mithril_bolts_unf] + quantity: 10 + - items: [feather] + quantity: 10 +output: mithril_bolts +output_qty: 10 +message: "You attach feathers to the mithril bolts." diff --git a/data/recipes/fletching/fletch_oak_longbow.yaml b/data/recipes/fletching/fletch_oak_longbow.yaml new file mode 100644 index 0000000..f1c96ba --- /dev/null +++ b/data/recipes/fletching/fletch_oak_longbow.yaml @@ -0,0 +1,12 @@ +id: fletch_oak_longbow +type: fletching +level: 25 +xp: 25 +wait: 2 +consume: + - items: [oak_longbow_u] + quantity: 1 + - items: [bowstring] + quantity: 1 +output: oak_longbow +message: "You string the oak longbow." diff --git a/data/recipes/fletching/fletch_oak_longbow_u.yaml b/data/recipes/fletching/fletch_oak_longbow_u.yaml new file mode 100644 index 0000000..8f0b234 --- /dev/null +++ b/data/recipes/fletching/fletch_oak_longbow_u.yaml @@ -0,0 +1,11 @@ +id: fletch_oak_longbow_u +type: fletching +tool: knife +level: 25 +xp: 25 +wait: 3 +consume: + - items: [oak_logs] + quantity: 1 +output: oak_longbow_u +message: "You carefully carve the oak log into a longbow." diff --git a/data/recipes/fletching/fletch_oak_shortbow.yaml b/data/recipes/fletching/fletch_oak_shortbow.yaml new file mode 100644 index 0000000..198657f --- /dev/null +++ b/data/recipes/fletching/fletch_oak_shortbow.yaml @@ -0,0 +1,12 @@ +id: fletch_oak_shortbow +type: fletching +level: 20 +xp: 16 +wait: 2 +consume: + - items: [oak_shortbow_u] + quantity: 1 + - items: [bowstring] + quantity: 1 +output: oak_shortbow +message: "You string the oak shortbow." diff --git a/data/recipes/fletching/fletch_oak_shortbow_u.yaml b/data/recipes/fletching/fletch_oak_shortbow_u.yaml new file mode 100644 index 0000000..4f96a09 --- /dev/null +++ b/data/recipes/fletching/fletch_oak_shortbow_u.yaml @@ -0,0 +1,11 @@ +id: fletch_oak_shortbow_u +type: fletching +tool: knife +level: 20 +xp: 16 +wait: 3 +consume: + - items: [oak_logs] + quantity: 1 +output: oak_shortbow_u +message: "You carefully carve the oak log into a shortbow." diff --git a/data/recipes/fletching/fletch_ruby_bolt_tips.yaml b/data/recipes/fletching/fletch_ruby_bolt_tips.yaml new file mode 100644 index 0000000..bc9f695 --- /dev/null +++ b/data/recipes/fletching/fletch_ruby_bolt_tips.yaml @@ -0,0 +1,12 @@ +id: fletch_ruby_bolt_tips +type: fletching +tool: chisel +level: 73 +xp: 6 +wait: 5 +consume: + - items: [uncut_ruby] + quantity: 1 +output: ruby_bolt_tips +output_qty: 12 +message: "You cut the ruby into bolt tips." diff --git a/data/recipes/fletching/fletch_ruby_bolts.yaml b/data/recipes/fletching/fletch_ruby_bolts.yaml new file mode 100644 index 0000000..ac1d150 --- /dev/null +++ b/data/recipes/fletching/fletch_ruby_bolts.yaml @@ -0,0 +1,13 @@ +id: fletch_ruby_bolts +type: fletching +level: 73 +xp: 6 +wait: 2 +consume: + - items: [adamant_bolts] + quantity: 10 + - items: [ruby_bolt_tips] + quantity: 10 +output: ruby_bolts +output_qty: 10 +message: "You tip the adamant bolts with ruby." diff --git a/data/recipes/fletching/fletch_rune_arrow.yaml b/data/recipes/fletching/fletch_rune_arrow.yaml new file mode 100644 index 0000000..aa2795e --- /dev/null +++ b/data/recipes/fletching/fletch_rune_arrow.yaml @@ -0,0 +1,13 @@ +id: fletch_rune_arrow +type: fletching +level: 75 +xp: 12 +wait: 2 +consume: + - items: [headless_arrow] + quantity: 15 + - items: [rune_arrowtips] + quantity: 15 +output: rune_arrow +output_qty: 15 +message: "You attach the rune arrowtips to the headless arrows." diff --git a/data/recipes/fletching/fletch_rune_bolts.yaml b/data/recipes/fletching/fletch_rune_bolts.yaml new file mode 100644 index 0000000..20bb7b9 --- /dev/null +++ b/data/recipes/fletching/fletch_rune_bolts.yaml @@ -0,0 +1,13 @@ +id: fletch_rune_bolts +type: fletching +level: 69 +xp: 100 +wait: 0 +consume: + - items: [rune_bolts_unf] + quantity: 10 + - items: [feather] + quantity: 10 +output: rune_bolts +output_qty: 10 +message: "You attach feathers to the rune bolts." diff --git a/data/recipes/fletching/fletch_sapphire_bolt_tips.yaml b/data/recipes/fletching/fletch_sapphire_bolt_tips.yaml new file mode 100644 index 0000000..dca6fef --- /dev/null +++ b/data/recipes/fletching/fletch_sapphire_bolt_tips.yaml @@ -0,0 +1,12 @@ +id: fletch_sapphire_bolt_tips +type: fletching +tool: chisel +level: 63 +xp: 4 +wait: 5 +consume: + - items: [uncut_sapphire] + quantity: 1 +output: sapphire_bolt_tips +output_qty: 12 +message: "You cut the sapphire into bolt tips." diff --git a/data/recipes/fletching/fletch_sapphire_bolts.yaml b/data/recipes/fletching/fletch_sapphire_bolts.yaml new file mode 100644 index 0000000..712578f --- /dev/null +++ b/data/recipes/fletching/fletch_sapphire_bolts.yaml @@ -0,0 +1,13 @@ +id: fletch_sapphire_bolts +type: fletching +level: 63 +xp: 4 +wait: 2 +consume: + - items: [mithril_bolts] + quantity: 10 + - items: [sapphire_bolt_tips] + quantity: 10 +output: sapphire_bolts +output_qty: 10 +message: "You tip the mithril bolts with sapphire." diff --git a/data/recipes/fletching/fletch_shortbow.yaml b/data/recipes/fletching/fletch_shortbow.yaml new file mode 100644 index 0000000..e96317d --- /dev/null +++ b/data/recipes/fletching/fletch_shortbow.yaml @@ -0,0 +1,12 @@ +id: fletch_shortbow +type: fletching +level: 5 +xp: 5 +wait: 2 +consume: + - items: [shortbow_u] + quantity: 1 + - items: [bowstring] + quantity: 1 +output: shortbow +message: "You string the shortbow." diff --git a/data/recipes/fletching/fletch_shortbow_u.yaml b/data/recipes/fletching/fletch_shortbow_u.yaml new file mode 100644 index 0000000..3ab4931 --- /dev/null +++ b/data/recipes/fletching/fletch_shortbow_u.yaml @@ -0,0 +1,11 @@ +id: fletch_shortbow_u +type: fletching +tool: knife +level: 5 +xp: 5 +wait: 3 +consume: + - items: [logs] + quantity: 1 +output: shortbow_u +message: "You carefully carve the log into a shortbow." diff --git a/data/recipes/fletching/fletch_steel_arrow.yaml b/data/recipes/fletching/fletch_steel_arrow.yaml new file mode 100644 index 0000000..9bd229a --- /dev/null +++ b/data/recipes/fletching/fletch_steel_arrow.yaml @@ -0,0 +1,13 @@ +id: fletch_steel_arrow +type: fletching +level: 30 +xp: 5 +wait: 2 +consume: + - items: [headless_arrow] + quantity: 15 + - items: [steel_arrowtips] + quantity: 15 +output: steel_arrow +output_qty: 15 +message: "You attach the steel arrowtips to the headless arrows." diff --git a/data/recipes/fletching/fletch_steel_bolts.yaml b/data/recipes/fletching/fletch_steel_bolts.yaml new file mode 100644 index 0000000..9bfdafe --- /dev/null +++ b/data/recipes/fletching/fletch_steel_bolts.yaml @@ -0,0 +1,13 @@ +id: fletch_steel_bolts +type: fletching +level: 46 +xp: 35 +wait: 0 +consume: + - items: [steel_bolts_unf] + quantity: 10 + - items: [feather] + quantity: 10 +output: steel_bolts +output_qty: 10 +message: "You attach feathers to the steel bolts." diff --git a/data/recipes/fletching/fletch_willow_longbow.yaml b/data/recipes/fletching/fletch_willow_longbow.yaml new file mode 100644 index 0000000..28071ac --- /dev/null +++ b/data/recipes/fletching/fletch_willow_longbow.yaml @@ -0,0 +1,12 @@ +id: fletch_willow_longbow +type: fletching +level: 40 +xp: 41 +wait: 2 +consume: + - items: [willow_longbow_u] + quantity: 1 + - items: [bowstring] + quantity: 1 +output: willow_longbow +message: "You string the willow longbow." diff --git a/data/recipes/fletching/fletch_willow_longbow_u.yaml b/data/recipes/fletching/fletch_willow_longbow_u.yaml new file mode 100644 index 0000000..ef808c0 --- /dev/null +++ b/data/recipes/fletching/fletch_willow_longbow_u.yaml @@ -0,0 +1,11 @@ +id: fletch_willow_longbow_u +type: fletching +tool: knife +level: 40 +xp: 41 +wait: 3 +consume: + - items: [willow_logs] + quantity: 1 +output: willow_longbow_u +message: "You carefully carve the willow log into a longbow." diff --git a/data/recipes/fletching/fletch_willow_shortbow.yaml b/data/recipes/fletching/fletch_willow_shortbow.yaml new file mode 100644 index 0000000..a2b2c2b --- /dev/null +++ b/data/recipes/fletching/fletch_willow_shortbow.yaml @@ -0,0 +1,12 @@ +id: fletch_willow_shortbow +type: fletching +level: 35 +xp: 33 +wait: 2 +consume: + - items: [willow_shortbow_u] + quantity: 1 + - items: [bowstring] + quantity: 1 +output: willow_shortbow +message: "You string the willow shortbow." diff --git a/data/recipes/fletching/fletch_willow_shortbow_u.yaml b/data/recipes/fletching/fletch_willow_shortbow_u.yaml new file mode 100644 index 0000000..95609b3 --- /dev/null +++ b/data/recipes/fletching/fletch_willow_shortbow_u.yaml @@ -0,0 +1,11 @@ +id: fletch_willow_shortbow_u +type: fletching +tool: knife +level: 35 +xp: 33 +wait: 3 +consume: + - items: [willow_logs] + quantity: 1 +output: willow_shortbow_u +message: "You carefully carve the willow log into a shortbow." diff --git a/data/recipes/fletching/fletch_yew_longbow.yaml b/data/recipes/fletching/fletch_yew_longbow.yaml new file mode 100644 index 0000000..208c623 --- /dev/null +++ b/data/recipes/fletching/fletch_yew_longbow.yaml @@ -0,0 +1,12 @@ +id: fletch_yew_longbow +type: fletching +level: 65 +xp: 75 +wait: 2 +consume: + - items: [yew_longbow_u] + quantity: 1 + - items: [bowstring] + quantity: 1 +output: yew_longbow +message: "You string the yew longbow." diff --git a/data/recipes/fletching/fletch_yew_longbow_u.yaml b/data/recipes/fletching/fletch_yew_longbow_u.yaml new file mode 100644 index 0000000..bdce4f8 --- /dev/null +++ b/data/recipes/fletching/fletch_yew_longbow_u.yaml @@ -0,0 +1,11 @@ +id: fletch_yew_longbow_u +type: fletching +tool: knife +level: 65 +xp: 75 +wait: 3 +consume: + - items: [yew_logs] + quantity: 1 +output: yew_longbow_u +message: "You carefully carve the yew log into a longbow." diff --git a/data/recipes/fletching/fletch_yew_shortbow.yaml b/data/recipes/fletching/fletch_yew_shortbow.yaml new file mode 100644 index 0000000..fbe5f62 --- /dev/null +++ b/data/recipes/fletching/fletch_yew_shortbow.yaml @@ -0,0 +1,12 @@ +id: fletch_yew_shortbow +type: fletching +level: 60 +xp: 67 +wait: 2 +consume: + - items: [yew_shortbow_u] + quantity: 1 + - items: [bowstring] + quantity: 1 +output: yew_shortbow +message: "You string the yew shortbow." diff --git a/data/recipes/fletching/fletch_yew_shortbow_u.yaml b/data/recipes/fletching/fletch_yew_shortbow_u.yaml new file mode 100644 index 0000000..774e3a5 --- /dev/null +++ b/data/recipes/fletching/fletch_yew_shortbow_u.yaml @@ -0,0 +1,11 @@ +id: fletch_yew_shortbow_u +type: fletching +tool: knife +level: 60 +xp: 67 +wait: 3 +consume: + - items: [yew_logs] + quantity: 1 +output: yew_shortbow_u +message: "You carefully carve the yew log into a shortbow." diff --git a/data/recipes/mix_amp_potion.yaml b/data/recipes/mix_amp_potion.yaml deleted file mode 100644 index 1a50af9..0000000 --- a/data/recipes/mix_amp_potion.yaml +++ /dev/null @@ -1,13 +0,0 @@ -id: mix_amp_potion -type: pharmacy -skill: pharmacy -level: 12 -xp: 50 -wait: 4 -consume: - - items: [tarromin_potion_unf] - qty: 1 - - items: [limpwurt_root] - qty: 1 -output: amp_potion -message: "You mix an amp potion." diff --git a/data/recipes/mix_bio_serum.yaml b/data/recipes/mix_bio_serum.yaml deleted file mode 100644 index 7f1931a..0000000 --- a/data/recipes/mix_bio_serum.yaml +++ /dev/null @@ -1,13 +0,0 @@ -id: mix_bio_serum -type: pharmacy -skill: pharmacy -level: 5 -xp: 38 -wait: 4 -consume: - - items: [marrentill_potion_unf] - qty: 1 - - items: [antitoxin_powder] - qty: 1 -output: bio_serum -message: "You mix a bio serum." diff --git a/data/recipes/mix_full_restore.yaml b/data/recipes/mix_full_restore.yaml deleted file mode 100644 index 76312cf..0000000 --- a/data/recipes/mix_full_restore.yaml +++ /dev/null @@ -1,13 +0,0 @@ -id: mix_full_restore -type: pharmacy -skill: pharmacy -level: 63 -xp: 143 -wait: 4 -consume: - - items: [snapdragon_potion_unf] - qty: 1 - - items: [arachnid_enzyme] - qty: 1 -output: full_restore -message: "You mix a full restore." diff --git a/data/recipes/mix_nano_restore.yaml b/data/recipes/mix_nano_restore.yaml deleted file mode 100644 index 36bb251..0000000 --- a/data/recipes/mix_nano_restore.yaml +++ /dev/null @@ -1,13 +0,0 @@ -id: mix_nano_restore -type: pharmacy -skill: pharmacy -level: 22 -xp: 63 -wait: 4 -consume: - - items: [harralander_potion_unf] - qty: 1 - - items: [arachnid_enzyme] - qty: 1 -output: nano_restore -message: "You mix a nano restore." diff --git a/data/recipes/mix_restoration_compound.yaml b/data/recipes/mix_restoration_compound.yaml deleted file mode 100644 index 6639784..0000000 --- a/data/recipes/mix_restoration_compound.yaml +++ /dev/null @@ -1,13 +0,0 @@ -id: mix_restoration_compound -type: pharmacy -skill: pharmacy -level: 81 -xp: 180 -wait: 4 -consume: - - items: [toadflax_potion_unf] - qty: 1 - - items: [crushed_nest] - qty: 1 -output: restoration_compound -message: "You mix a restoration compound." diff --git a/data/recipes/mix_science_serum.yaml b/data/recipes/mix_science_serum.yaml deleted file mode 100644 index 5f60945..0000000 --- a/data/recipes/mix_science_serum.yaml +++ /dev/null @@ -1,13 +0,0 @@ -id: mix_science_serum -type: pharmacy -skill: pharmacy -level: 76 -xp: 173 -wait: 4 -consume: - - items: [lantadyme_potion_unf] - qty: 1 - - items: [potato_cactus] - qty: 1 -output: science_serum -message: "You mix a science serum." diff --git a/data/recipes/mix_shield_potion.yaml b/data/recipes/mix_shield_potion.yaml deleted file mode 100644 index 875e870..0000000 --- a/data/recipes/mix_shield_potion.yaml +++ /dev/null @@ -1,13 +0,0 @@ -id: mix_shield_potion -type: pharmacy -skill: pharmacy -level: 30 -xp: 75 -wait: 4 -consume: - - items: [ranarr_potion_unf] - qty: 1 - - items: [white_berries] - qty: 1 -output: shield_potion -message: "You mix a shield potion." diff --git a/data/recipes/mix_stim_cell.yaml b/data/recipes/mix_stim_cell.yaml deleted file mode 100644 index 8915f39..0000000 --- a/data/recipes/mix_stim_cell.yaml +++ /dev/null @@ -1,13 +0,0 @@ -id: mix_stim_cell -type: pharmacy -skill: pharmacy -level: 26 -xp: 68 -wait: 4 -consume: - - items: [harralander_potion_unf] - qty: 1 - - items: [chocolate_dust] - qty: 1 -output: stim_cell -message: "You mix a stim cell." diff --git a/data/recipes/mix_stim_potion.yaml b/data/recipes/mix_stim_potion.yaml deleted file mode 100644 index 67db442..0000000 --- a/data/recipes/mix_stim_potion.yaml +++ /dev/null @@ -1,13 +0,0 @@ -id: mix_stim_potion -type: pharmacy -skill: pharmacy -level: 3 -xp: 25 -wait: 4 -consume: - - items: [guam_potion_unf] - qty: 1 - - items: [eye_of_newt] - qty: 1 -output: stim_potion -message: "You mix a stim potion." diff --git a/data/recipes/mix_super_amp.yaml b/data/recipes/mix_super_amp.yaml deleted file mode 100644 index ea30e35..0000000 --- a/data/recipes/mix_super_amp.yaml +++ /dev/null @@ -1,13 +0,0 @@ -id: mix_super_amp -type: pharmacy -skill: pharmacy -level: 55 -xp: 125 -wait: 4 -consume: - - items: [kwuarm_potion_unf] - qty: 1 - - items: [limpwurt_root] - qty: 1 -output: super_amp -message: "You mix a super amp." diff --git a/data/recipes/mix_super_bio_serum.yaml b/data/recipes/mix_super_bio_serum.yaml deleted file mode 100644 index 808dd31..0000000 --- a/data/recipes/mix_super_bio_serum.yaml +++ /dev/null @@ -1,13 +0,0 @@ -id: mix_super_bio_serum -type: pharmacy -skill: pharmacy -level: 48 -xp: 106 -wait: 4 -consume: - - items: [irit_potion_unf] - qty: 1 - - items: [antitoxin_powder] - qty: 1 -output: super_bio_serum -message: "You mix a super bio serum." diff --git a/data/recipes/mix_super_shield.yaml b/data/recipes/mix_super_shield.yaml deleted file mode 100644 index 07d849b..0000000 --- a/data/recipes/mix_super_shield.yaml +++ /dev/null @@ -1,13 +0,0 @@ -id: mix_super_shield -type: pharmacy -skill: pharmacy -level: 66 -xp: 150 -wait: 4 -consume: - - items: [cadantine_potion_unf] - qty: 1 - - items: [white_berries] - qty: 1 -output: super_shield -message: "You mix a super shield." diff --git a/data/recipes/mix_super_stim.yaml b/data/recipes/mix_super_stim.yaml deleted file mode 100644 index 2382960..0000000 --- a/data/recipes/mix_super_stim.yaml +++ /dev/null @@ -1,13 +0,0 @@ -id: mix_super_stim -type: pharmacy -skill: pharmacy -level: 45 -xp: 100 -wait: 4 -consume: - - items: [irit_potion_unf] - qty: 1 - - items: [eye_of_newt] - qty: 1 -output: super_stim -message: "You mix a super stim." diff --git a/data/recipes/mix_super_stim_cell.yaml b/data/recipes/mix_super_stim_cell.yaml deleted file mode 100644 index 5ed6bd3..0000000 --- a/data/recipes/mix_super_stim_cell.yaml +++ /dev/null @@ -1,13 +0,0 @@ -id: mix_super_stim_cell -type: pharmacy -skill: pharmacy -level: 52 -xp: 118 -wait: 4 -consume: - - items: [avantoe_potion_unf] - qty: 1 - - items: [blight_spore] - qty: 1 -output: super_stim_cell -message: "You mix a super stim cell." diff --git a/data/recipes/mix_targeting_serum.yaml b/data/recipes/mix_targeting_serum.yaml deleted file mode 100644 index 54bd338..0000000 --- a/data/recipes/mix_targeting_serum.yaml +++ /dev/null @@ -1,13 +0,0 @@ -id: mix_targeting_serum -type: pharmacy -skill: pharmacy -level: 72 -xp: 163 -wait: 4 -consume: - - items: [dwarf_weed_potion_unf] - qty: 1 - - items: [catalyst_wine] - qty: 1 -output: targeting_serum -message: "You mix a targeting serum." diff --git a/data/recipes/mix_tech_serum.yaml b/data/recipes/mix_tech_serum.yaml deleted file mode 100644 index ea41efd..0000000 --- a/data/recipes/mix_tech_serum.yaml +++ /dev/null @@ -1,13 +0,0 @@ -id: mix_tech_serum -type: pharmacy -skill: pharmacy -level: 38 -xp: 88 -wait: 4 -consume: - - items: [ranarr_potion_unf] - qty: 1 - - items: [snape_grass] - qty: 1 -output: tech_serum -message: "You mix a tech serum." diff --git a/data/recipes/mixing/mix_amp_potion.yaml b/data/recipes/mixing/mix_amp_potion.yaml new file mode 100644 index 0000000..6145296 --- /dev/null +++ b/data/recipes/mixing/mix_amp_potion.yaml @@ -0,0 +1,13 @@ +id: mix_amp_potion +type: pharmacy +skill: pharmacy +level: 12 +xp: 50 +wait: 4 +consume: + - items: [tarromin_potion_unf] + quantity: 1 + - items: [limpwurt_root] + quantity: 1 +output: amp_potion +message: "You mix an amp potion." diff --git a/data/recipes/mixing/mix_bio_serum.yaml b/data/recipes/mixing/mix_bio_serum.yaml new file mode 100644 index 0000000..6f5a3ea --- /dev/null +++ b/data/recipes/mixing/mix_bio_serum.yaml @@ -0,0 +1,13 @@ +id: mix_bio_serum +type: pharmacy +skill: pharmacy +level: 5 +xp: 38 +wait: 4 +consume: + - items: [marrentill_potion_unf] + quantity: 1 + - items: [antitoxin_powder] + quantity: 1 +output: bio_serum +message: "You mix a bio serum." diff --git a/data/recipes/mixing/mix_full_restore.yaml b/data/recipes/mixing/mix_full_restore.yaml new file mode 100644 index 0000000..b9e320e --- /dev/null +++ b/data/recipes/mixing/mix_full_restore.yaml @@ -0,0 +1,13 @@ +id: mix_full_restore +type: pharmacy +skill: pharmacy +level: 63 +xp: 143 +wait: 4 +consume: + - items: [snapdragon_potion_unf] + quantity: 1 + - items: [arachnid_enzyme] + quantity: 1 +output: full_restore +message: "You mix a full restore." diff --git a/data/recipes/mixing/mix_nano_restore.yaml b/data/recipes/mixing/mix_nano_restore.yaml new file mode 100644 index 0000000..4a5ebb0 --- /dev/null +++ b/data/recipes/mixing/mix_nano_restore.yaml @@ -0,0 +1,13 @@ +id: mix_nano_restore +type: pharmacy +skill: pharmacy +level: 22 +xp: 63 +wait: 4 +consume: + - items: [harralander_potion_unf] + quantity: 1 + - items: [arachnid_enzyme] + quantity: 1 +output: nano_restore +message: "You mix a nano restore." diff --git a/data/recipes/mixing/mix_restoration_compound.yaml b/data/recipes/mixing/mix_restoration_compound.yaml new file mode 100644 index 0000000..c945cac --- /dev/null +++ b/data/recipes/mixing/mix_restoration_compound.yaml @@ -0,0 +1,13 @@ +id: mix_restoration_compound +type: pharmacy +skill: pharmacy +level: 81 +xp: 180 +wait: 4 +consume: + - items: [toadflax_potion_unf] + quantity: 1 + - items: [crushed_nest] + quantity: 1 +output: restoration_compound +message: "You mix a restoration compound." diff --git a/data/recipes/mixing/mix_science_serum.yaml b/data/recipes/mixing/mix_science_serum.yaml new file mode 100644 index 0000000..b65f2d2 --- /dev/null +++ b/data/recipes/mixing/mix_science_serum.yaml @@ -0,0 +1,13 @@ +id: mix_science_serum +type: pharmacy +skill: pharmacy +level: 76 +xp: 173 +wait: 4 +consume: + - items: [lantadyme_potion_unf] + quantity: 1 + - items: [potato_cactus] + quantity: 1 +output: science_serum +message: "You mix a science serum." diff --git a/data/recipes/mixing/mix_shield_potion.yaml b/data/recipes/mixing/mix_shield_potion.yaml new file mode 100644 index 0000000..fc44abf --- /dev/null +++ b/data/recipes/mixing/mix_shield_potion.yaml @@ -0,0 +1,13 @@ +id: mix_shield_potion +type: pharmacy +skill: pharmacy +level: 30 +xp: 75 +wait: 4 +consume: + - items: [ranarr_potion_unf] + quantity: 1 + - items: [white_berries] + quantity: 1 +output: shield_potion +message: "You mix a shield potion." diff --git a/data/recipes/mixing/mix_stim_cell.yaml b/data/recipes/mixing/mix_stim_cell.yaml new file mode 100644 index 0000000..ccca53a --- /dev/null +++ b/data/recipes/mixing/mix_stim_cell.yaml @@ -0,0 +1,13 @@ +id: mix_stim_cell +type: pharmacy +skill: pharmacy +level: 26 +xp: 68 +wait: 4 +consume: + - items: [harralander_potion_unf] + quantity: 1 + - items: [chocolate_dust] + quantity: 1 +output: stim_cell +message: "You mix a stim cell." diff --git a/data/recipes/mixing/mix_stim_potion.yaml b/data/recipes/mixing/mix_stim_potion.yaml new file mode 100644 index 0000000..437b985 --- /dev/null +++ b/data/recipes/mixing/mix_stim_potion.yaml @@ -0,0 +1,13 @@ +id: mix_stim_potion +type: pharmacy +skill: pharmacy +level: 3 +xp: 25 +wait: 4 +consume: + - items: [guam_potion_unf] + quantity: 1 + - items: [eye_of_newt] + quantity: 1 +output: stim_potion +message: "You mix a stim potion." diff --git a/data/recipes/mixing/mix_super_amp.yaml b/data/recipes/mixing/mix_super_amp.yaml new file mode 100644 index 0000000..5e05019 --- /dev/null +++ b/data/recipes/mixing/mix_super_amp.yaml @@ -0,0 +1,13 @@ +id: mix_super_amp +type: pharmacy +skill: pharmacy +level: 55 +xp: 125 +wait: 4 +consume: + - items: [kwuarm_potion_unf] + quantity: 1 + - items: [limpwurt_root] + quantity: 1 +output: super_amp +message: "You mix a super amp." diff --git a/data/recipes/mixing/mix_super_bio_serum.yaml b/data/recipes/mixing/mix_super_bio_serum.yaml new file mode 100644 index 0000000..96e6632 --- /dev/null +++ b/data/recipes/mixing/mix_super_bio_serum.yaml @@ -0,0 +1,13 @@ +id: mix_super_bio_serum +type: pharmacy +skill: pharmacy +level: 48 +xp: 106 +wait: 4 +consume: + - items: [irit_potion_unf] + quantity: 1 + - items: [antitoxin_powder] + quantity: 1 +output: super_bio_serum +message: "You mix a super bio serum." diff --git a/data/recipes/mixing/mix_super_shield.yaml b/data/recipes/mixing/mix_super_shield.yaml new file mode 100644 index 0000000..61b3686 --- /dev/null +++ b/data/recipes/mixing/mix_super_shield.yaml @@ -0,0 +1,13 @@ +id: mix_super_shield +type: pharmacy +skill: pharmacy +level: 66 +xp: 150 +wait: 4 +consume: + - items: [cadantine_potion_unf] + quantity: 1 + - items: [white_berries] + quantity: 1 +output: super_shield +message: "You mix a super shield." diff --git a/data/recipes/mixing/mix_super_stim.yaml b/data/recipes/mixing/mix_super_stim.yaml new file mode 100644 index 0000000..bac9f8f --- /dev/null +++ b/data/recipes/mixing/mix_super_stim.yaml @@ -0,0 +1,13 @@ +id: mix_super_stim +type: pharmacy +skill: pharmacy +level: 45 +xp: 100 +wait: 4 +consume: + - items: [irit_potion_unf] + quantity: 1 + - items: [eye_of_newt] + quantity: 1 +output: super_stim +message: "You mix a super stim." diff --git a/data/recipes/mixing/mix_super_stim_cell.yaml b/data/recipes/mixing/mix_super_stim_cell.yaml new file mode 100644 index 0000000..26640ea --- /dev/null +++ b/data/recipes/mixing/mix_super_stim_cell.yaml @@ -0,0 +1,13 @@ +id: mix_super_stim_cell +type: pharmacy +skill: pharmacy +level: 52 +xp: 118 +wait: 4 +consume: + - items: [avantoe_potion_unf] + quantity: 1 + - items: [blight_spore] + quantity: 1 +output: super_stim_cell +message: "You mix a super stim cell." diff --git a/data/recipes/mixing/mix_targeting_serum.yaml b/data/recipes/mixing/mix_targeting_serum.yaml new file mode 100644 index 0000000..06f8421 --- /dev/null +++ b/data/recipes/mixing/mix_targeting_serum.yaml @@ -0,0 +1,13 @@ +id: mix_targeting_serum +type: pharmacy +skill: pharmacy +level: 72 +xp: 163 +wait: 4 +consume: + - items: [dwarf_weed_potion_unf] + quantity: 1 + - items: [catalyst_wine] + quantity: 1 +output: targeting_serum +message: "You mix a targeting serum." diff --git a/data/recipes/mixing/mix_tech_serum.yaml b/data/recipes/mixing/mix_tech_serum.yaml new file mode 100644 index 0000000..a57d2f9 --- /dev/null +++ b/data/recipes/mixing/mix_tech_serum.yaml @@ -0,0 +1,13 @@ +id: mix_tech_serum +type: pharmacy +skill: pharmacy +level: 38 +xp: 88 +wait: 4 +consume: + - items: [ranarr_potion_unf] + quantity: 1 + - items: [snape_grass] + quantity: 1 +output: tech_serum +message: "You mix a tech serum." diff --git a/data/recipes/smelt_adamantite.yaml b/data/recipes/smelt_adamantite.yaml deleted file mode 100644 index c5a34f7..0000000 --- a/data/recipes/smelt_adamantite.yaml +++ /dev/null @@ -1,15 +0,0 @@ -id: smelt_adamantite -type: smelting -skill: smithing -level: 65 -xp: 37 -wait: 4 -station: [furnace] -consume: - - items: [adamantite_ore] - qty: 1 - - items: [coal] - qty: 6 -output: adamantite_bar -message: "You remove a white hot adamantite bar!" -fail_message: "You fail to smelt a usable bar." diff --git a/data/recipes/smelt_bronze.yaml b/data/recipes/smelt_bronze.yaml deleted file mode 100644 index bb46da5..0000000 --- a/data/recipes/smelt_bronze.yaml +++ /dev/null @@ -1,15 +0,0 @@ -id: smelt_bronze -type: smelting -skill: smithing -level: 1 -xp: 6 -wait: 4 -station: [furnace] -consume: - - items: [copper_ore] - qty: 1 - - items: [tin_ore] - qty: 1 -output: bronze_bar -message: "You remove a white hot bronze bar!" -fail_message: "You fail to smelt a usable bar." diff --git a/data/recipes/smelt_gold.yaml b/data/recipes/smelt_gold.yaml deleted file mode 100644 index 6f30147..0000000 --- a/data/recipes/smelt_gold.yaml +++ /dev/null @@ -1,13 +0,0 @@ -id: smelt_gold -type: smelting -skill: smithing -level: 45 -xp: 22 -wait: 4 -station: [furnace] -consume: - - items: [gold_ore] - qty: 1 -output: gold_bar -message: "You remove a white hot gold bar!" -fail_message: "You fail to smelt a usable bar." diff --git a/data/recipes/smelt_iron.yaml b/data/recipes/smelt_iron.yaml deleted file mode 100644 index 2631b28..0000000 --- a/data/recipes/smelt_iron.yaml +++ /dev/null @@ -1,17 +0,0 @@ -id: smelt_iron -type: smelting -skill: smithing -level: 20 -xp: 12 -wait: 4 -station: [furnace] -consume: - - items: [iron_ore] - qty: 1 -output: iron_bar -message: "You remove a white hot iron bar!" -fail_message: "The iron is too impure to make a workable bar." -success: - base: 0.5 - per_level: 0 - cap: 0.5 diff --git a/data/recipes/smelt_mithril.yaml b/data/recipes/smelt_mithril.yaml deleted file mode 100644 index 0e2856a..0000000 --- a/data/recipes/smelt_mithril.yaml +++ /dev/null @@ -1,15 +0,0 @@ -id: smelt_mithril -type: smelting -skill: smithing -level: 50 -xp: 30 -wait: 4 -station: [furnace] -consume: - - items: [mithril_ore] - qty: 1 - - items: [coal] - qty: 4 -output: mithril_bar -message: "You remove a white hot mithril bar!" -fail_message: "You fail to smelt a usable bar." diff --git a/data/recipes/smelt_runite.yaml b/data/recipes/smelt_runite.yaml deleted file mode 100644 index 1c2935e..0000000 --- a/data/recipes/smelt_runite.yaml +++ /dev/null @@ -1,15 +0,0 @@ -id: smelt_runite -type: smelting -skill: smithing -level: 80 -xp: 50 -wait: 4 -station: [furnace] -consume: - - items: [runite_ore] - qty: 1 - - items: [coal] - qty: 8 -output: runite_bar -message: "You remove a white hot runite bar!" -fail_message: "You fail to smelt a usable bar." diff --git a/data/recipes/smelt_silver.yaml b/data/recipes/smelt_silver.yaml deleted file mode 100644 index 1630452..0000000 --- a/data/recipes/smelt_silver.yaml +++ /dev/null @@ -1,13 +0,0 @@ -id: smelt_silver -type: smelting -skill: smithing -level: 25 -xp: 14 -wait: 4 -station: [furnace] -consume: - - items: [silver_ore] - qty: 1 -output: silver_bar -message: "You remove a white hot silver bar!" -fail_message: "You fail to smelt a usable bar." diff --git a/data/recipes/smelt_steel.yaml b/data/recipes/smelt_steel.yaml deleted file mode 100644 index e3df4b6..0000000 --- a/data/recipes/smelt_steel.yaml +++ /dev/null @@ -1,15 +0,0 @@ -id: smelt_steel -type: smelting -skill: smithing -level: 40 -xp: 17 -wait: 4 -station: [furnace] -consume: - - items: [iron_ore] - qty: 1 - - items: [coal] - qty: 2 -output: steel_bar -message: "You remove a white hot steel bar!" -fail_message: "You fail to smelt a usable bar." diff --git a/data/recipes/smelting/smelt_adamantite.yaml b/data/recipes/smelting/smelt_adamantite.yaml new file mode 100644 index 0000000..5ff675b --- /dev/null +++ b/data/recipes/smelting/smelt_adamantite.yaml @@ -0,0 +1,15 @@ +id: smelt_adamantite +type: smelting +skill: smithing +level: 65 +xp: 37 +wait: 4 +station: [furnace] +consume: + - items: [adamantite_ore] + quantity: 1 + - items: [coal] + quantity: 6 +output: adamantite_bar +message: "You remove a white hot adamantite bar!" +fail_message: "You fail to smelt a usable bar." diff --git a/data/recipes/smelting/smelt_bronze.yaml b/data/recipes/smelting/smelt_bronze.yaml new file mode 100644 index 0000000..bdb33af --- /dev/null +++ b/data/recipes/smelting/smelt_bronze.yaml @@ -0,0 +1,15 @@ +id: smelt_bronze +type: smelting +skill: smithing +level: 1 +xp: 6 +wait: 4 +station: [furnace] +consume: + - items: [copper_ore] + quantity: 1 + - items: [tin_ore] + quantity: 1 +output: bronze_bar +message: "You remove a white hot bronze bar!" +fail_message: "You fail to smelt a usable bar." diff --git a/data/recipes/smelting/smelt_gold.yaml b/data/recipes/smelting/smelt_gold.yaml new file mode 100644 index 0000000..91229e8 --- /dev/null +++ b/data/recipes/smelting/smelt_gold.yaml @@ -0,0 +1,13 @@ +id: smelt_gold +type: smelting +skill: smithing +level: 45 +xp: 22 +wait: 4 +station: [furnace] +consume: + - items: [gold_ore] + quantity: 1 +output: gold_bar +message: "You remove a white hot gold bar!" +fail_message: "You fail to smelt a usable bar." diff --git a/data/recipes/smelting/smelt_iron.yaml b/data/recipes/smelting/smelt_iron.yaml new file mode 100644 index 0000000..ce0ca11 --- /dev/null +++ b/data/recipes/smelting/smelt_iron.yaml @@ -0,0 +1,17 @@ +id: smelt_iron +type: smelting +skill: smithing +level: 20 +xp: 12 +wait: 4 +station: [furnace] +consume: + - items: [iron_ore] + quantity: 1 +output: iron_bar +message: "You remove a white hot iron bar!" +fail_message: "The iron is too impure to make a workable bar." +success: + base: 0.5 + per_level: 0 + cap: 0.5 diff --git a/data/recipes/smelting/smelt_mithril.yaml b/data/recipes/smelting/smelt_mithril.yaml new file mode 100644 index 0000000..6285c1b --- /dev/null +++ b/data/recipes/smelting/smelt_mithril.yaml @@ -0,0 +1,15 @@ +id: smelt_mithril +type: smelting +skill: smithing +level: 50 +xp: 30 +wait: 4 +station: [furnace] +consume: + - items: [mithril_ore] + quantity: 1 + - items: [coal] + quantity: 4 +output: mithril_bar +message: "You remove a white hot mithril bar!" +fail_message: "You fail to smelt a usable bar." diff --git a/data/recipes/smelting/smelt_runite.yaml b/data/recipes/smelting/smelt_runite.yaml new file mode 100644 index 0000000..b683221 --- /dev/null +++ b/data/recipes/smelting/smelt_runite.yaml @@ -0,0 +1,15 @@ +id: smelt_runite +type: smelting +skill: smithing +level: 80 +xp: 50 +wait: 4 +station: [furnace] +consume: + - items: [runite_ore] + quantity: 1 + - items: [coal] + quantity: 8 +output: runite_bar +message: "You remove a white hot runite bar!" +fail_message: "You fail to smelt a usable bar." diff --git a/data/recipes/smelting/smelt_silver.yaml b/data/recipes/smelting/smelt_silver.yaml new file mode 100644 index 0000000..f381bd0 --- /dev/null +++ b/data/recipes/smelting/smelt_silver.yaml @@ -0,0 +1,13 @@ +id: smelt_silver +type: smelting +skill: smithing +level: 25 +xp: 14 +wait: 4 +station: [furnace] +consume: + - items: [silver_ore] + quantity: 1 +output: silver_bar +message: "You remove a white hot silver bar!" +fail_message: "You fail to smelt a usable bar." diff --git a/data/recipes/smelting/smelt_steel.yaml b/data/recipes/smelting/smelt_steel.yaml new file mode 100644 index 0000000..ec1c2df --- /dev/null +++ b/data/recipes/smelting/smelt_steel.yaml @@ -0,0 +1,15 @@ +id: smelt_steel +type: smelting +skill: smithing +level: 40 +xp: 17 +wait: 4 +station: [furnace] +consume: + - items: [iron_ore] + quantity: 1 + - items: [coal] + quantity: 2 +output: steel_bar +message: "You remove a white hot steel bar!" +fail_message: "You fail to smelt a usable bar." diff --git a/data/recipes/smith_adamant_arrowtips.yaml b/data/recipes/smith_adamant_arrowtips.yaml deleted file mode 100644 index 6ad49d7..0000000 --- a/data/recipes/smith_adamant_arrowtips.yaml +++ /dev/null @@ -1,12 +0,0 @@ -id: smith_adamant_arrowtips -type: smithing -level: 75 -xp: 62 -wait: 4 -station: [anvil] -consume: - - items: [adamantite_bar] - qty: 1 -output: adamant_arrowtips -output_qty: 15 -message: "You hammer out some adamant arrowtips." diff --git a/data/recipes/smith_adamant_bolts_unf.yaml b/data/recipes/smith_adamant_bolts_unf.yaml deleted file mode 100644 index 9e71a5c..0000000 --- a/data/recipes/smith_adamant_bolts_unf.yaml +++ /dev/null @@ -1,12 +0,0 @@ -id: smith_adamant_bolts_unf -type: smithing -level: 76 -xp: 62 -wait: 4 -station: [anvil] -consume: - - items: [adamantite_bar] - qty: 1 -output: adamant_bolts_unf -output_qty: 10 -message: "You hammer out some adamant bolts." diff --git a/data/recipes/smith_adamant_dagger.yaml b/data/recipes/smith_adamant_dagger.yaml deleted file mode 100644 index 8d5f6d2..0000000 --- a/data/recipes/smith_adamant_dagger.yaml +++ /dev/null @@ -1,11 +0,0 @@ -id: smith_adamant_dagger -type: smithing -level: 70 -xp: 62 -wait: 4 -station: [anvil] -consume: - - items: [adamantite_bar] - qty: 1 -output: adamant_dagger -message: "You hammer out an adamant dagger." diff --git a/data/recipes/smith_adamant_full_helm.yaml b/data/recipes/smith_adamant_full_helm.yaml deleted file mode 100644 index 61a79b0..0000000 --- a/data/recipes/smith_adamant_full_helm.yaml +++ /dev/null @@ -1,11 +0,0 @@ -id: smith_adamant_full_helm -type: smithing -level: 77 -xp: 125 -wait: 4 -station: [anvil] -consume: - - items: [adamantite_bar] - qty: 2 -output: adamant_full_helm -message: "You hammer out an adamant full helm." diff --git a/data/recipes/smith_adamant_med_helm.yaml b/data/recipes/smith_adamant_med_helm.yaml deleted file mode 100644 index 275adaf..0000000 --- a/data/recipes/smith_adamant_med_helm.yaml +++ /dev/null @@ -1,11 +0,0 @@ -id: smith_adamant_med_helm -type: smithing -level: 73 -xp: 62 -wait: 4 -station: [anvil] -consume: - - items: [adamantite_bar] - qty: 1 -output: adamant_med_helm -message: "You hammer out an adamant med helm." diff --git a/data/recipes/smith_adamant_nails.yaml b/data/recipes/smith_adamant_nails.yaml deleted file mode 100644 index 195cbb1..0000000 --- a/data/recipes/smith_adamant_nails.yaml +++ /dev/null @@ -1,12 +0,0 @@ -id: smith_adamant_nails -type: smithing -level: 74 -xp: 62 -wait: 4 -station: [anvil] -consume: - - items: [adamantite_bar] - qty: 1 -output: adamant_nails -output_qty: 15 -message: "You hammer out some adamant nails." diff --git a/data/recipes/smith_adamant_platebody.yaml b/data/recipes/smith_adamant_platebody.yaml deleted file mode 100644 index abd5284..0000000 --- a/data/recipes/smith_adamant_platebody.yaml +++ /dev/null @@ -1,11 +0,0 @@ -id: smith_adamant_platebody -type: smithing -level: 88 -xp: 312 -wait: 4 -station: [anvil] -consume: - - items: [adamantite_bar] - qty: 5 -output: adamant_platebody -message: "You hammer out an adamant platebody." diff --git a/data/recipes/smith_adamant_sword.yaml b/data/recipes/smith_adamant_sword.yaml deleted file mode 100644 index c973310..0000000 --- a/data/recipes/smith_adamant_sword.yaml +++ /dev/null @@ -1,11 +0,0 @@ -id: smith_adamant_sword -type: smithing -level: 74 -xp: 62 -wait: 4 -station: [anvil] -consume: - - items: [adamantite_bar] - qty: 1 -output: adamant_sword -message: "You hammer out an adamant sword." diff --git a/data/recipes/smith_bronze_arrowtips.yaml b/data/recipes/smith_bronze_arrowtips.yaml deleted file mode 100644 index 4b74869..0000000 --- a/data/recipes/smith_bronze_arrowtips.yaml +++ /dev/null @@ -1,12 +0,0 @@ -id: smith_bronze_arrowtips -type: smithing -level: 5 -xp: 12 -wait: 4 -station: [anvil] -consume: - - items: [bronze_bar] - qty: 1 -output: bronze_arrowtips -output_qty: 15 -message: "You hammer out some bronze arrowtips." diff --git a/data/recipes/smith_bronze_bolts_unf.yaml b/data/recipes/smith_bronze_bolts_unf.yaml deleted file mode 100644 index 349be84..0000000 --- a/data/recipes/smith_bronze_bolts_unf.yaml +++ /dev/null @@ -1,12 +0,0 @@ -id: smith_bronze_bolts_unf -type: smithing -level: 6 -xp: 12 -wait: 4 -station: [anvil] -consume: - - items: [bronze_bar] - qty: 1 -output: bronze_bolts_unf -output_qty: 10 -message: "You hammer out some bronze bolts." diff --git a/data/recipes/smith_bronze_dagger.yaml b/data/recipes/smith_bronze_dagger.yaml deleted file mode 100644 index fc458c8..0000000 --- a/data/recipes/smith_bronze_dagger.yaml +++ /dev/null @@ -1,11 +0,0 @@ -id: smith_bronze_dagger -type: smithing -level: 1 -xp: 12 -wait: 4 -station: [anvil] -consume: - - items: [bronze_bar] - qty: 1 -output: bronze_dagger -message: "You hammer out a bronze dagger." diff --git a/data/recipes/smith_bronze_full_helm.yaml b/data/recipes/smith_bronze_full_helm.yaml deleted file mode 100644 index cd689fd..0000000 --- a/data/recipes/smith_bronze_full_helm.yaml +++ /dev/null @@ -1,11 +0,0 @@ -id: smith_bronze_full_helm -type: smithing -level: 7 -xp: 25 -wait: 4 -station: [anvil] -consume: - - items: [bronze_bar] - qty: 2 -output: bronze_full_helm -message: "You hammer out a bronze full helm." diff --git a/data/recipes/smith_bronze_med_helm.yaml b/data/recipes/smith_bronze_med_helm.yaml deleted file mode 100644 index 60e1353..0000000 --- a/data/recipes/smith_bronze_med_helm.yaml +++ /dev/null @@ -1,11 +0,0 @@ -id: smith_bronze_med_helm -type: smithing -level: 3 -xp: 12 -wait: 4 -station: [anvil] -consume: - - items: [bronze_bar] - qty: 1 -output: bronze_med_helm -message: "You hammer out a bronze med helm." diff --git a/data/recipes/smith_bronze_nails.yaml b/data/recipes/smith_bronze_nails.yaml deleted file mode 100644 index fa3286b..0000000 --- a/data/recipes/smith_bronze_nails.yaml +++ /dev/null @@ -1,12 +0,0 @@ -id: smith_bronze_nails -type: smithing -level: 4 -xp: 12 -wait: 4 -station: [anvil] -consume: - - items: [bronze_bar] - qty: 1 -output: bronze_nails -output_qty: 15 -message: "You hammer out some bronze nails." diff --git a/data/recipes/smith_bronze_platebody.yaml b/data/recipes/smith_bronze_platebody.yaml deleted file mode 100644 index 5e49649..0000000 --- a/data/recipes/smith_bronze_platebody.yaml +++ /dev/null @@ -1,11 +0,0 @@ -id: smith_bronze_platebody -type: smithing -level: 18 -xp: 62 -wait: 4 -station: [anvil] -consume: - - items: [bronze_bar] - qty: 5 -output: bronze_platebody -message: "You hammer out a bronze platebody." diff --git a/data/recipes/smith_bronze_sword.yaml b/data/recipes/smith_bronze_sword.yaml deleted file mode 100644 index 23d3237..0000000 --- a/data/recipes/smith_bronze_sword.yaml +++ /dev/null @@ -1,11 +0,0 @@ -id: smith_bronze_sword -type: smithing -level: 4 -xp: 12 -wait: 4 -station: [anvil] -consume: - - items: [bronze_bar] - qty: 1 -output: bronze_sword -message: "You hammer out a bronze sword." diff --git a/data/recipes/smith_iron_arrowtips.yaml b/data/recipes/smith_iron_arrowtips.yaml deleted file mode 100644 index 9b773ee..0000000 --- a/data/recipes/smith_iron_arrowtips.yaml +++ /dev/null @@ -1,12 +0,0 @@ -id: smith_iron_arrowtips -type: smithing -level: 25 -xp: 25 -wait: 4 -station: [anvil] -consume: - - items: [iron_bar] - qty: 1 -output: iron_arrowtips -output_qty: 15 -message: "You hammer out some iron arrowtips." diff --git a/data/recipes/smith_iron_bolts_unf.yaml b/data/recipes/smith_iron_bolts_unf.yaml deleted file mode 100644 index 564daab..0000000 --- a/data/recipes/smith_iron_bolts_unf.yaml +++ /dev/null @@ -1,12 +0,0 @@ -id: smith_iron_bolts_unf -type: smithing -level: 26 -xp: 25 -wait: 4 -station: [anvil] -consume: - - items: [iron_bar] - qty: 1 -output: iron_bolts_unf -output_qty: 10 -message: "You hammer out some iron bolts." diff --git a/data/recipes/smith_iron_dagger.yaml b/data/recipes/smith_iron_dagger.yaml deleted file mode 100644 index d885717..0000000 --- a/data/recipes/smith_iron_dagger.yaml +++ /dev/null @@ -1,11 +0,0 @@ -id: smith_iron_dagger -type: smithing -level: 20 -xp: 25 -wait: 4 -station: [anvil] -consume: - - items: [iron_bar] - qty: 1 -output: iron_dagger -message: "You hammer out an iron dagger." diff --git a/data/recipes/smith_iron_full_helm.yaml b/data/recipes/smith_iron_full_helm.yaml deleted file mode 100644 index afcd56a..0000000 --- a/data/recipes/smith_iron_full_helm.yaml +++ /dev/null @@ -1,11 +0,0 @@ -id: smith_iron_full_helm -type: smithing -level: 27 -xp: 50 -wait: 4 -station: [anvil] -consume: - - items: [iron_bar] - qty: 2 -output: iron_full_helm -message: "You hammer out an iron full helm." diff --git a/data/recipes/smith_iron_med_helm.yaml b/data/recipes/smith_iron_med_helm.yaml deleted file mode 100644 index 5aabb9e..0000000 --- a/data/recipes/smith_iron_med_helm.yaml +++ /dev/null @@ -1,11 +0,0 @@ -id: smith_iron_med_helm -type: smithing -level: 22 -xp: 25 -wait: 4 -station: [anvil] -consume: - - items: [iron_bar] - qty: 1 -output: iron_med_helm -message: "You hammer out an iron med helm." diff --git a/data/recipes/smith_iron_nails.yaml b/data/recipes/smith_iron_nails.yaml deleted file mode 100644 index 2e6e59f..0000000 --- a/data/recipes/smith_iron_nails.yaml +++ /dev/null @@ -1,12 +0,0 @@ -id: smith_iron_nails -type: smithing -level: 24 -xp: 25 -wait: 4 -station: [anvil] -consume: - - items: [iron_bar] - qty: 1 -output: iron_nails -output_qty: 15 -message: "You hammer out some iron nails." diff --git a/data/recipes/smith_iron_platebody.yaml b/data/recipes/smith_iron_platebody.yaml deleted file mode 100644 index c1fd795..0000000 --- a/data/recipes/smith_iron_platebody.yaml +++ /dev/null @@ -1,11 +0,0 @@ -id: smith_iron_platebody -type: smithing -level: 33 -xp: 125 -wait: 4 -station: [anvil] -consume: - - items: [iron_bar] - qty: 5 -output: iron_platebody -message: "You hammer out an iron platebody." diff --git a/data/recipes/smith_iron_sword.yaml b/data/recipes/smith_iron_sword.yaml deleted file mode 100644 index ab87fdc..0000000 --- a/data/recipes/smith_iron_sword.yaml +++ /dev/null @@ -1,11 +0,0 @@ -id: smith_iron_sword -type: smithing -level: 24 -xp: 25 -wait: 4 -station: [anvil] -consume: - - items: [iron_bar] - qty: 1 -output: iron_sword -message: "You hammer out an iron sword." diff --git a/data/recipes/smith_mithril_arrowtips.yaml b/data/recipes/smith_mithril_arrowtips.yaml deleted file mode 100644 index a61e5f1..0000000 --- a/data/recipes/smith_mithril_arrowtips.yaml +++ /dev/null @@ -1,12 +0,0 @@ -id: smith_mithril_arrowtips -type: smithing -level: 55 -xp: 50 -wait: 4 -station: [anvil] -consume: - - items: [mithril_bar] - qty: 1 -output: mithril_arrowtips -output_qty: 15 -message: "You hammer out some mithril arrowtips." diff --git a/data/recipes/smith_mithril_bolts_unf.yaml b/data/recipes/smith_mithril_bolts_unf.yaml deleted file mode 100644 index eb6da91..0000000 --- a/data/recipes/smith_mithril_bolts_unf.yaml +++ /dev/null @@ -1,12 +0,0 @@ -id: smith_mithril_bolts_unf -type: smithing -level: 56 -xp: 50 -wait: 4 -station: [anvil] -consume: - - items: [mithril_bar] - qty: 1 -output: mithril_bolts_unf -output_qty: 10 -message: "You hammer out some mithril bolts." diff --git a/data/recipes/smith_mithril_dagger.yaml b/data/recipes/smith_mithril_dagger.yaml deleted file mode 100644 index f8aea86..0000000 --- a/data/recipes/smith_mithril_dagger.yaml +++ /dev/null @@ -1,11 +0,0 @@ -id: smith_mithril_dagger -type: smithing -level: 50 -xp: 50 -wait: 4 -station: [anvil] -consume: - - items: [mithril_bar] - qty: 1 -output: mithril_dagger -message: "You hammer out a mithril dagger." diff --git a/data/recipes/smith_mithril_full_helm.yaml b/data/recipes/smith_mithril_full_helm.yaml deleted file mode 100644 index 64b78c4..0000000 --- a/data/recipes/smith_mithril_full_helm.yaml +++ /dev/null @@ -1,11 +0,0 @@ -id: smith_mithril_full_helm -type: smithing -level: 57 -xp: 100 -wait: 4 -station: [anvil] -consume: - - items: [mithril_bar] - qty: 2 -output: mithril_full_helm -message: "You hammer out a mithril full helm." diff --git a/data/recipes/smith_mithril_med_helm.yaml b/data/recipes/smith_mithril_med_helm.yaml deleted file mode 100644 index d8cc14e..0000000 --- a/data/recipes/smith_mithril_med_helm.yaml +++ /dev/null @@ -1,11 +0,0 @@ -id: smith_mithril_med_helm -type: smithing -level: 53 -xp: 50 -wait: 4 -station: [anvil] -consume: - - items: [mithril_bar] - qty: 1 -output: mithril_med_helm -message: "You hammer out a mithril med helm." diff --git a/data/recipes/smith_mithril_nails.yaml b/data/recipes/smith_mithril_nails.yaml deleted file mode 100644 index 5f33c62..0000000 --- a/data/recipes/smith_mithril_nails.yaml +++ /dev/null @@ -1,12 +0,0 @@ -id: smith_mithril_nails -type: smithing -level: 54 -xp: 50 -wait: 4 -station: [anvil] -consume: - - items: [mithril_bar] - qty: 1 -output: mithril_nails -output_qty: 15 -message: "You hammer out some mithril nails." diff --git a/data/recipes/smith_mithril_platebody.yaml b/data/recipes/smith_mithril_platebody.yaml deleted file mode 100644 index 43efb1d..0000000 --- a/data/recipes/smith_mithril_platebody.yaml +++ /dev/null @@ -1,11 +0,0 @@ -id: smith_mithril_platebody -type: smithing -level: 68 -xp: 250 -wait: 4 -station: [anvil] -consume: - - items: [mithril_bar] - qty: 5 -output: mithril_platebody -message: "You hammer out a mithril platebody." diff --git a/data/recipes/smith_mithril_sword.yaml b/data/recipes/smith_mithril_sword.yaml deleted file mode 100644 index 98cf6dc..0000000 --- a/data/recipes/smith_mithril_sword.yaml +++ /dev/null @@ -1,11 +0,0 @@ -id: smith_mithril_sword -type: smithing -level: 54 -xp: 50 -wait: 4 -station: [anvil] -consume: - - items: [mithril_bar] - qty: 1 -output: mithril_sword -message: "You hammer out a mithril sword." diff --git a/data/recipes/smith_rune_arrowtips.yaml b/data/recipes/smith_rune_arrowtips.yaml deleted file mode 100644 index 4d2731e..0000000 --- a/data/recipes/smith_rune_arrowtips.yaml +++ /dev/null @@ -1,12 +0,0 @@ -id: smith_rune_arrowtips -type: smithing -level: 90 -xp: 75 -wait: 4 -station: [anvil] -consume: - - items: [runite_bar] - qty: 1 -output: rune_arrowtips -output_qty: 15 -message: "You hammer out some rune arrowtips." diff --git a/data/recipes/smith_rune_bolts_unf.yaml b/data/recipes/smith_rune_bolts_unf.yaml deleted file mode 100644 index 088871b..0000000 --- a/data/recipes/smith_rune_bolts_unf.yaml +++ /dev/null @@ -1,12 +0,0 @@ -id: smith_rune_bolts_unf -type: smithing -level: 91 -xp: 75 -wait: 4 -station: [anvil] -consume: - - items: [runite_bar] - qty: 1 -output: rune_bolts_unf -output_qty: 10 -message: "You hammer out some rune bolts." diff --git a/data/recipes/smith_rune_dagger.yaml b/data/recipes/smith_rune_dagger.yaml deleted file mode 100644 index 3b76cae..0000000 --- a/data/recipes/smith_rune_dagger.yaml +++ /dev/null @@ -1,11 +0,0 @@ -id: smith_rune_dagger -type: smithing -level: 85 -xp: 75 -wait: 4 -station: [anvil] -consume: - - items: [runite_bar] - qty: 1 -output: rune_dagger -message: "You hammer out a rune dagger." diff --git a/data/recipes/smith_rune_full_helm.yaml b/data/recipes/smith_rune_full_helm.yaml deleted file mode 100644 index 1714afa..0000000 --- a/data/recipes/smith_rune_full_helm.yaml +++ /dev/null @@ -1,11 +0,0 @@ -id: smith_rune_full_helm -type: smithing -level: 92 -xp: 150 -wait: 4 -station: [anvil] -consume: - - items: [runite_bar] - qty: 2 -output: rune_full_helm -message: "You hammer out a rune full helm." diff --git a/data/recipes/smith_rune_med_helm.yaml b/data/recipes/smith_rune_med_helm.yaml deleted file mode 100644 index 0c58be5..0000000 --- a/data/recipes/smith_rune_med_helm.yaml +++ /dev/null @@ -1,11 +0,0 @@ -id: smith_rune_med_helm -type: smithing -level: 88 -xp: 75 -wait: 4 -station: [anvil] -consume: - - items: [runite_bar] - qty: 1 -output: rune_med_helm -message: "You hammer out a rune med helm." diff --git a/data/recipes/smith_rune_nails.yaml b/data/recipes/smith_rune_nails.yaml deleted file mode 100644 index ad99d41..0000000 --- a/data/recipes/smith_rune_nails.yaml +++ /dev/null @@ -1,12 +0,0 @@ -id: smith_rune_nails -type: smithing -level: 89 -xp: 75 -wait: 4 -station: [anvil] -consume: - - items: [runite_bar] - qty: 1 -output: rune_nails -output_qty: 15 -message: "You hammer out some rune nails." diff --git a/data/recipes/smith_rune_platebody.yaml b/data/recipes/smith_rune_platebody.yaml deleted file mode 100644 index 7f27292..0000000 --- a/data/recipes/smith_rune_platebody.yaml +++ /dev/null @@ -1,11 +0,0 @@ -id: smith_rune_platebody -type: smithing -level: 99 -xp: 375 -wait: 4 -station: [anvil] -consume: - - items: [runite_bar] - qty: 5 -output: rune_platebody -message: "You hammer out a rune platebody." diff --git a/data/recipes/smith_rune_sword.yaml b/data/recipes/smith_rune_sword.yaml deleted file mode 100644 index c329102..0000000 --- a/data/recipes/smith_rune_sword.yaml +++ /dev/null @@ -1,11 +0,0 @@ -id: smith_rune_sword -type: smithing -level: 89 -xp: 75 -wait: 4 -station: [anvil] -consume: - - items: [runite_bar] - qty: 1 -output: rune_sword -message: "You hammer out a rune sword." diff --git a/data/recipes/smith_steel_arrowtips.yaml b/data/recipes/smith_steel_arrowtips.yaml deleted file mode 100644 index 0f97327..0000000 --- a/data/recipes/smith_steel_arrowtips.yaml +++ /dev/null @@ -1,12 +0,0 @@ -id: smith_steel_arrowtips -type: smithing -level: 35 -xp: 37 -wait: 4 -station: [anvil] -consume: - - items: [steel_bar] - qty: 1 -output: steel_arrowtips -output_qty: 15 -message: "You hammer out some steel arrowtips." diff --git a/data/recipes/smith_steel_bolts_unf.yaml b/data/recipes/smith_steel_bolts_unf.yaml deleted file mode 100644 index 550dd5e..0000000 --- a/data/recipes/smith_steel_bolts_unf.yaml +++ /dev/null @@ -1,12 +0,0 @@ -id: smith_steel_bolts_unf -type: smithing -level: 36 -xp: 37 -wait: 4 -station: [anvil] -consume: - - items: [steel_bar] - qty: 1 -output: steel_bolts_unf -output_qty: 10 -message: "You hammer out some steel bolts." diff --git a/data/recipes/smith_steel_dagger.yaml b/data/recipes/smith_steel_dagger.yaml deleted file mode 100644 index e569065..0000000 --- a/data/recipes/smith_steel_dagger.yaml +++ /dev/null @@ -1,11 +0,0 @@ -id: smith_steel_dagger -type: smithing -level: 30 -xp: 37 -wait: 4 -station: [anvil] -consume: - - items: [steel_bar] - qty: 1 -output: steel_dagger -message: "You hammer out a steel dagger." diff --git a/data/recipes/smith_steel_full_helm.yaml b/data/recipes/smith_steel_full_helm.yaml deleted file mode 100644 index a23b110..0000000 --- a/data/recipes/smith_steel_full_helm.yaml +++ /dev/null @@ -1,11 +0,0 @@ -id: smith_steel_full_helm -type: smithing -level: 37 -xp: 75 -wait: 4 -station: [anvil] -consume: - - items: [steel_bar] - qty: 2 -output: steel_full_helm -message: "You hammer out a steel full helm." diff --git a/data/recipes/smith_steel_med_helm.yaml b/data/recipes/smith_steel_med_helm.yaml deleted file mode 100644 index 264b487..0000000 --- a/data/recipes/smith_steel_med_helm.yaml +++ /dev/null @@ -1,11 +0,0 @@ -id: smith_steel_med_helm -type: smithing -level: 33 -xp: 37 -wait: 4 -station: [anvil] -consume: - - items: [steel_bar] - qty: 1 -output: steel_med_helm -message: "You hammer out a steel med helm." diff --git a/data/recipes/smith_steel_nails.yaml b/data/recipes/smith_steel_nails.yaml deleted file mode 100644 index 63a5881..0000000 --- a/data/recipes/smith_steel_nails.yaml +++ /dev/null @@ -1,12 +0,0 @@ -id: smith_steel_nails -type: smithing -level: 34 -xp: 37 -wait: 4 -station: [anvil] -consume: - - items: [steel_bar] - qty: 1 -output: steel_nails -output_qty: 15 -message: "You hammer out some steel nails." diff --git a/data/recipes/smith_steel_platebody.yaml b/data/recipes/smith_steel_platebody.yaml deleted file mode 100644 index 5d001b0..0000000 --- a/data/recipes/smith_steel_platebody.yaml +++ /dev/null @@ -1,11 +0,0 @@ -id: smith_steel_platebody -type: smithing -level: 48 -xp: 187 -wait: 4 -station: [anvil] -consume: - - items: [steel_bar] - qty: 5 -output: steel_platebody -message: "You hammer out a steel platebody." diff --git a/data/recipes/smith_steel_sword.yaml b/data/recipes/smith_steel_sword.yaml deleted file mode 100644 index b8c18bd..0000000 --- a/data/recipes/smith_steel_sword.yaml +++ /dev/null @@ -1,11 +0,0 @@ -id: smith_steel_sword -type: smithing -level: 34 -xp: 37 -wait: 4 -station: [anvil] -consume: - - items: [steel_bar] - qty: 1 -output: steel_sword -message: "You hammer out a steel sword." diff --git a/data/recipes/smithing/smith_adamant_arrowtips.yaml b/data/recipes/smithing/smith_adamant_arrowtips.yaml new file mode 100644 index 0000000..466cfa2 --- /dev/null +++ b/data/recipes/smithing/smith_adamant_arrowtips.yaml @@ -0,0 +1,12 @@ +id: smith_adamant_arrowtips +type: smithing +level: 75 +xp: 62 +wait: 4 +station: [anvil] +consume: + - items: [adamantite_bar] + quantity: 1 +output: adamant_arrowtips +output_qty: 15 +message: "You hammer out some adamant arrowtips." diff --git a/data/recipes/smithing/smith_adamant_bolts_unf.yaml b/data/recipes/smithing/smith_adamant_bolts_unf.yaml new file mode 100644 index 0000000..2fe1730 --- /dev/null +++ b/data/recipes/smithing/smith_adamant_bolts_unf.yaml @@ -0,0 +1,12 @@ +id: smith_adamant_bolts_unf +type: smithing +level: 76 +xp: 62 +wait: 4 +station: [anvil] +consume: + - items: [adamantite_bar] + quantity: 1 +output: adamant_bolts_unf +output_qty: 10 +message: "You hammer out some adamant bolts." diff --git a/data/recipes/smithing/smith_adamant_dagger.yaml b/data/recipes/smithing/smith_adamant_dagger.yaml new file mode 100644 index 0000000..fb68dbf --- /dev/null +++ b/data/recipes/smithing/smith_adamant_dagger.yaml @@ -0,0 +1,11 @@ +id: smith_adamant_dagger +type: smithing +level: 70 +xp: 62 +wait: 4 +station: [anvil] +consume: + - items: [adamantite_bar] + quantity: 1 +output: adamant_dagger +message: "You hammer out an adamant dagger." diff --git a/data/recipes/smithing/smith_adamant_full_helm.yaml b/data/recipes/smithing/smith_adamant_full_helm.yaml new file mode 100644 index 0000000..2d849e5 --- /dev/null +++ b/data/recipes/smithing/smith_adamant_full_helm.yaml @@ -0,0 +1,11 @@ +id: smith_adamant_full_helm +type: smithing +level: 77 +xp: 125 +wait: 4 +station: [anvil] +consume: + - items: [adamantite_bar] + quantity: 2 +output: adamant_full_helm +message: "You hammer out an adamant full helm." diff --git a/data/recipes/smithing/smith_adamant_med_helm.yaml b/data/recipes/smithing/smith_adamant_med_helm.yaml new file mode 100644 index 0000000..505691c --- /dev/null +++ b/data/recipes/smithing/smith_adamant_med_helm.yaml @@ -0,0 +1,11 @@ +id: smith_adamant_med_helm +type: smithing +level: 73 +xp: 62 +wait: 4 +station: [anvil] +consume: + - items: [adamantite_bar] + quantity: 1 +output: adamant_med_helm +message: "You hammer out an adamant med helm." diff --git a/data/recipes/smithing/smith_adamant_nails.yaml b/data/recipes/smithing/smith_adamant_nails.yaml new file mode 100644 index 0000000..2273b67 --- /dev/null +++ b/data/recipes/smithing/smith_adamant_nails.yaml @@ -0,0 +1,12 @@ +id: smith_adamant_nails +type: smithing +level: 74 +xp: 62 +wait: 4 +station: [anvil] +consume: + - items: [adamantite_bar] + quantity: 1 +output: adamant_nails +output_qty: 15 +message: "You hammer out some adamant nails." diff --git a/data/recipes/smithing/smith_adamant_platebody.yaml b/data/recipes/smithing/smith_adamant_platebody.yaml new file mode 100644 index 0000000..33dc400 --- /dev/null +++ b/data/recipes/smithing/smith_adamant_platebody.yaml @@ -0,0 +1,11 @@ +id: smith_adamant_platebody +type: smithing +level: 88 +xp: 312 +wait: 4 +station: [anvil] +consume: + - items: [adamantite_bar] + quantity: 5 +output: adamant_platebody +message: "You hammer out an adamant platebody." diff --git a/data/recipes/smithing/smith_adamant_sword.yaml b/data/recipes/smithing/smith_adamant_sword.yaml new file mode 100644 index 0000000..e853ea6 --- /dev/null +++ b/data/recipes/smithing/smith_adamant_sword.yaml @@ -0,0 +1,11 @@ +id: smith_adamant_sword +type: smithing +level: 74 +xp: 62 +wait: 4 +station: [anvil] +consume: + - items: [adamantite_bar] + quantity: 1 +output: adamant_sword +message: "You hammer out an adamant sword." diff --git a/data/recipes/smithing/smith_bronze_arrowtips.yaml b/data/recipes/smithing/smith_bronze_arrowtips.yaml new file mode 100644 index 0000000..77d724f --- /dev/null +++ b/data/recipes/smithing/smith_bronze_arrowtips.yaml @@ -0,0 +1,12 @@ +id: smith_bronze_arrowtips +type: smithing +level: 5 +xp: 12 +wait: 4 +station: [anvil] +consume: + - items: [bronze_bar] + quantity: 1 +output: bronze_arrowtips +output_qty: 15 +message: "You hammer out some bronze arrowtips." diff --git a/data/recipes/smithing/smith_bronze_bolts_unf.yaml b/data/recipes/smithing/smith_bronze_bolts_unf.yaml new file mode 100644 index 0000000..340d14f --- /dev/null +++ b/data/recipes/smithing/smith_bronze_bolts_unf.yaml @@ -0,0 +1,12 @@ +id: smith_bronze_bolts_unf +type: smithing +level: 6 +xp: 12 +wait: 4 +station: [anvil] +consume: + - items: [bronze_bar] + quantity: 1 +output: bronze_bolts_unf +output_qty: 10 +message: "You hammer out some bronze bolts." diff --git a/data/recipes/smithing/smith_bronze_dagger.yaml b/data/recipes/smithing/smith_bronze_dagger.yaml new file mode 100644 index 0000000..4842927 --- /dev/null +++ b/data/recipes/smithing/smith_bronze_dagger.yaml @@ -0,0 +1,11 @@ +id: smith_bronze_dagger +type: smithing +level: 1 +xp: 12 +wait: 4 +station: [anvil] +consume: + - items: [bronze_bar] + quantity: 1 +output: bronze_dagger +message: "You hammer out a bronze dagger." diff --git a/data/recipes/smithing/smith_bronze_full_helm.yaml b/data/recipes/smithing/smith_bronze_full_helm.yaml new file mode 100644 index 0000000..6ef58ed --- /dev/null +++ b/data/recipes/smithing/smith_bronze_full_helm.yaml @@ -0,0 +1,11 @@ +id: smith_bronze_full_helm +type: smithing +level: 7 +xp: 25 +wait: 4 +station: [anvil] +consume: + - items: [bronze_bar] + quantity: 2 +output: bronze_full_helm +message: "You hammer out a bronze full helm." diff --git a/data/recipes/smithing/smith_bronze_med_helm.yaml b/data/recipes/smithing/smith_bronze_med_helm.yaml new file mode 100644 index 0000000..6abbc60 --- /dev/null +++ b/data/recipes/smithing/smith_bronze_med_helm.yaml @@ -0,0 +1,11 @@ +id: smith_bronze_med_helm +type: smithing +level: 3 +xp: 12 +wait: 4 +station: [anvil] +consume: + - items: [bronze_bar] + quantity: 1 +output: bronze_med_helm +message: "You hammer out a bronze med helm." diff --git a/data/recipes/smithing/smith_bronze_nails.yaml b/data/recipes/smithing/smith_bronze_nails.yaml new file mode 100644 index 0000000..c75a957 --- /dev/null +++ b/data/recipes/smithing/smith_bronze_nails.yaml @@ -0,0 +1,12 @@ +id: smith_bronze_nails +type: smithing +level: 4 +xp: 12 +wait: 4 +station: [anvil] +consume: + - items: [bronze_bar] + quantity: 1 +output: bronze_nails +output_qty: 15 +message: "You hammer out some bronze nails." diff --git a/data/recipes/smithing/smith_bronze_platebody.yaml b/data/recipes/smithing/smith_bronze_platebody.yaml new file mode 100644 index 0000000..c9d7d39 --- /dev/null +++ b/data/recipes/smithing/smith_bronze_platebody.yaml @@ -0,0 +1,11 @@ +id: smith_bronze_platebody +type: smithing +level: 18 +xp: 62 +wait: 4 +station: [anvil] +consume: + - items: [bronze_bar] + quantity: 5 +output: bronze_platebody +message: "You hammer out a bronze platebody." diff --git a/data/recipes/smithing/smith_bronze_sword.yaml b/data/recipes/smithing/smith_bronze_sword.yaml new file mode 100644 index 0000000..322ca9f --- /dev/null +++ b/data/recipes/smithing/smith_bronze_sword.yaml @@ -0,0 +1,11 @@ +id: smith_bronze_sword +type: smithing +level: 4 +xp: 12 +wait: 4 +station: [anvil] +consume: + - items: [bronze_bar] + quantity: 1 +output: bronze_sword +message: "You hammer out a bronze sword." diff --git a/data/recipes/smithing/smith_iron_arrowtips.yaml b/data/recipes/smithing/smith_iron_arrowtips.yaml new file mode 100644 index 0000000..d11286e --- /dev/null +++ b/data/recipes/smithing/smith_iron_arrowtips.yaml @@ -0,0 +1,12 @@ +id: smith_iron_arrowtips +type: smithing +level: 25 +xp: 25 +wait: 4 +station: [anvil] +consume: + - items: [iron_bar] + quantity: 1 +output: iron_arrowtips +output_qty: 15 +message: "You hammer out some iron arrowtips." diff --git a/data/recipes/smithing/smith_iron_bolts_unf.yaml b/data/recipes/smithing/smith_iron_bolts_unf.yaml new file mode 100644 index 0000000..9529cab --- /dev/null +++ b/data/recipes/smithing/smith_iron_bolts_unf.yaml @@ -0,0 +1,12 @@ +id: smith_iron_bolts_unf +type: smithing +level: 26 +xp: 25 +wait: 4 +station: [anvil] +consume: + - items: [iron_bar] + quantity: 1 +output: iron_bolts_unf +output_qty: 10 +message: "You hammer out some iron bolts." diff --git a/data/recipes/smithing/smith_iron_dagger.yaml b/data/recipes/smithing/smith_iron_dagger.yaml new file mode 100644 index 0000000..3694ca5 --- /dev/null +++ b/data/recipes/smithing/smith_iron_dagger.yaml @@ -0,0 +1,11 @@ +id: smith_iron_dagger +type: smithing +level: 20 +xp: 25 +wait: 4 +station: [anvil] +consume: + - items: [iron_bar] + quantity: 1 +output: iron_dagger +message: "You hammer out an iron dagger." diff --git a/data/recipes/smithing/smith_iron_full_helm.yaml b/data/recipes/smithing/smith_iron_full_helm.yaml new file mode 100644 index 0000000..cfa27f5 --- /dev/null +++ b/data/recipes/smithing/smith_iron_full_helm.yaml @@ -0,0 +1,11 @@ +id: smith_iron_full_helm +type: smithing +level: 27 +xp: 50 +wait: 4 +station: [anvil] +consume: + - items: [iron_bar] + quantity: 2 +output: iron_full_helm +message: "You hammer out an iron full helm." diff --git a/data/recipes/smithing/smith_iron_med_helm.yaml b/data/recipes/smithing/smith_iron_med_helm.yaml new file mode 100644 index 0000000..54b6654 --- /dev/null +++ b/data/recipes/smithing/smith_iron_med_helm.yaml @@ -0,0 +1,11 @@ +id: smith_iron_med_helm +type: smithing +level: 22 +xp: 25 +wait: 4 +station: [anvil] +consume: + - items: [iron_bar] + quantity: 1 +output: iron_med_helm +message: "You hammer out an iron med helm." diff --git a/data/recipes/smithing/smith_iron_nails.yaml b/data/recipes/smithing/smith_iron_nails.yaml new file mode 100644 index 0000000..cb6ad89 --- /dev/null +++ b/data/recipes/smithing/smith_iron_nails.yaml @@ -0,0 +1,12 @@ +id: smith_iron_nails +type: smithing +level: 24 +xp: 25 +wait: 4 +station: [anvil] +consume: + - items: [iron_bar] + quantity: 1 +output: iron_nails +output_qty: 15 +message: "You hammer out some iron nails." diff --git a/data/recipes/smithing/smith_iron_platebody.yaml b/data/recipes/smithing/smith_iron_platebody.yaml new file mode 100644 index 0000000..dd8a7d6 --- /dev/null +++ b/data/recipes/smithing/smith_iron_platebody.yaml @@ -0,0 +1,11 @@ +id: smith_iron_platebody +type: smithing +level: 33 +xp: 125 +wait: 4 +station: [anvil] +consume: + - items: [iron_bar] + quantity: 5 +output: iron_platebody +message: "You hammer out an iron platebody." diff --git a/data/recipes/smithing/smith_iron_sword.yaml b/data/recipes/smithing/smith_iron_sword.yaml new file mode 100644 index 0000000..c2d4bc5 --- /dev/null +++ b/data/recipes/smithing/smith_iron_sword.yaml @@ -0,0 +1,11 @@ +id: smith_iron_sword +type: smithing +level: 24 +xp: 25 +wait: 4 +station: [anvil] +consume: + - items: [iron_bar] + quantity: 1 +output: iron_sword +message: "You hammer out an iron sword." diff --git a/data/recipes/smithing/smith_mithril_arrowtips.yaml b/data/recipes/smithing/smith_mithril_arrowtips.yaml new file mode 100644 index 0000000..2d27604 --- /dev/null +++ b/data/recipes/smithing/smith_mithril_arrowtips.yaml @@ -0,0 +1,12 @@ +id: smith_mithril_arrowtips +type: smithing +level: 55 +xp: 50 +wait: 4 +station: [anvil] +consume: + - items: [mithril_bar] + quantity: 1 +output: mithril_arrowtips +output_qty: 15 +message: "You hammer out some mithril arrowtips." diff --git a/data/recipes/smithing/smith_mithril_bolts_unf.yaml b/data/recipes/smithing/smith_mithril_bolts_unf.yaml new file mode 100644 index 0000000..03afe7f --- /dev/null +++ b/data/recipes/smithing/smith_mithril_bolts_unf.yaml @@ -0,0 +1,12 @@ +id: smith_mithril_bolts_unf +type: smithing +level: 56 +xp: 50 +wait: 4 +station: [anvil] +consume: + - items: [mithril_bar] + quantity: 1 +output: mithril_bolts_unf +output_qty: 10 +message: "You hammer out some mithril bolts." diff --git a/data/recipes/smithing/smith_mithril_dagger.yaml b/data/recipes/smithing/smith_mithril_dagger.yaml new file mode 100644 index 0000000..a437969 --- /dev/null +++ b/data/recipes/smithing/smith_mithril_dagger.yaml @@ -0,0 +1,11 @@ +id: smith_mithril_dagger +type: smithing +level: 50 +xp: 50 +wait: 4 +station: [anvil] +consume: + - items: [mithril_bar] + quantity: 1 +output: mithril_dagger +message: "You hammer out a mithril dagger." diff --git a/data/recipes/smithing/smith_mithril_full_helm.yaml b/data/recipes/smithing/smith_mithril_full_helm.yaml new file mode 100644 index 0000000..f9d6b74 --- /dev/null +++ b/data/recipes/smithing/smith_mithril_full_helm.yaml @@ -0,0 +1,11 @@ +id: smith_mithril_full_helm +type: smithing +level: 57 +xp: 100 +wait: 4 +station: [anvil] +consume: + - items: [mithril_bar] + quantity: 2 +output: mithril_full_helm +message: "You hammer out a mithril full helm." diff --git a/data/recipes/smithing/smith_mithril_med_helm.yaml b/data/recipes/smithing/smith_mithril_med_helm.yaml new file mode 100644 index 0000000..c4ebc30 --- /dev/null +++ b/data/recipes/smithing/smith_mithril_med_helm.yaml @@ -0,0 +1,11 @@ +id: smith_mithril_med_helm +type: smithing +level: 53 +xp: 50 +wait: 4 +station: [anvil] +consume: + - items: [mithril_bar] + quantity: 1 +output: mithril_med_helm +message: "You hammer out a mithril med helm." diff --git a/data/recipes/smithing/smith_mithril_nails.yaml b/data/recipes/smithing/smith_mithril_nails.yaml new file mode 100644 index 0000000..6c9f225 --- /dev/null +++ b/data/recipes/smithing/smith_mithril_nails.yaml @@ -0,0 +1,12 @@ +id: smith_mithril_nails +type: smithing +level: 54 +xp: 50 +wait: 4 +station: [anvil] +consume: + - items: [mithril_bar] + quantity: 1 +output: mithril_nails +output_qty: 15 +message: "You hammer out some mithril nails." diff --git a/data/recipes/smithing/smith_mithril_platebody.yaml b/data/recipes/smithing/smith_mithril_platebody.yaml new file mode 100644 index 0000000..751a7ea --- /dev/null +++ b/data/recipes/smithing/smith_mithril_platebody.yaml @@ -0,0 +1,11 @@ +id: smith_mithril_platebody +type: smithing +level: 68 +xp: 250 +wait: 4 +station: [anvil] +consume: + - items: [mithril_bar] + quantity: 5 +output: mithril_platebody +message: "You hammer out a mithril platebody." diff --git a/data/recipes/smithing/smith_mithril_sword.yaml b/data/recipes/smithing/smith_mithril_sword.yaml new file mode 100644 index 0000000..fdf96ff --- /dev/null +++ b/data/recipes/smithing/smith_mithril_sword.yaml @@ -0,0 +1,11 @@ +id: smith_mithril_sword +type: smithing +level: 54 +xp: 50 +wait: 4 +station: [anvil] +consume: + - items: [mithril_bar] + quantity: 1 +output: mithril_sword +message: "You hammer out a mithril sword." diff --git a/data/recipes/smithing/smith_rune_arrowtips.yaml b/data/recipes/smithing/smith_rune_arrowtips.yaml new file mode 100644 index 0000000..93554a9 --- /dev/null +++ b/data/recipes/smithing/smith_rune_arrowtips.yaml @@ -0,0 +1,12 @@ +id: smith_rune_arrowtips +type: smithing +level: 90 +xp: 75 +wait: 4 +station: [anvil] +consume: + - items: [runite_bar] + quantity: 1 +output: rune_arrowtips +output_qty: 15 +message: "You hammer out some rune arrowtips." diff --git a/data/recipes/smithing/smith_rune_bolts_unf.yaml b/data/recipes/smithing/smith_rune_bolts_unf.yaml new file mode 100644 index 0000000..93047ce --- /dev/null +++ b/data/recipes/smithing/smith_rune_bolts_unf.yaml @@ -0,0 +1,12 @@ +id: smith_rune_bolts_unf +type: smithing +level: 91 +xp: 75 +wait: 4 +station: [anvil] +consume: + - items: [runite_bar] + quantity: 1 +output: rune_bolts_unf +output_qty: 10 +message: "You hammer out some rune bolts." diff --git a/data/recipes/smithing/smith_rune_dagger.yaml b/data/recipes/smithing/smith_rune_dagger.yaml new file mode 100644 index 0000000..a87b356 --- /dev/null +++ b/data/recipes/smithing/smith_rune_dagger.yaml @@ -0,0 +1,11 @@ +id: smith_rune_dagger +type: smithing +level: 85 +xp: 75 +wait: 4 +station: [anvil] +consume: + - items: [runite_bar] + quantity: 1 +output: rune_dagger +message: "You hammer out a rune dagger." diff --git a/data/recipes/smithing/smith_rune_full_helm.yaml b/data/recipes/smithing/smith_rune_full_helm.yaml new file mode 100644 index 0000000..79ae3b0 --- /dev/null +++ b/data/recipes/smithing/smith_rune_full_helm.yaml @@ -0,0 +1,11 @@ +id: smith_rune_full_helm +type: smithing +level: 92 +xp: 150 +wait: 4 +station: [anvil] +consume: + - items: [runite_bar] + quantity: 2 +output: rune_full_helm +message: "You hammer out a rune full helm." diff --git a/data/recipes/smithing/smith_rune_med_helm.yaml b/data/recipes/smithing/smith_rune_med_helm.yaml new file mode 100644 index 0000000..74e639a --- /dev/null +++ b/data/recipes/smithing/smith_rune_med_helm.yaml @@ -0,0 +1,11 @@ +id: smith_rune_med_helm +type: smithing +level: 88 +xp: 75 +wait: 4 +station: [anvil] +consume: + - items: [runite_bar] + quantity: 1 +output: rune_med_helm +message: "You hammer out a rune med helm." diff --git a/data/recipes/smithing/smith_rune_nails.yaml b/data/recipes/smithing/smith_rune_nails.yaml new file mode 100644 index 0000000..2681a57 --- /dev/null +++ b/data/recipes/smithing/smith_rune_nails.yaml @@ -0,0 +1,12 @@ +id: smith_rune_nails +type: smithing +level: 89 +xp: 75 +wait: 4 +station: [anvil] +consume: + - items: [runite_bar] + quantity: 1 +output: rune_nails +output_qty: 15 +message: "You hammer out some rune nails." diff --git a/data/recipes/smithing/smith_rune_platebody.yaml b/data/recipes/smithing/smith_rune_platebody.yaml new file mode 100644 index 0000000..4a36082 --- /dev/null +++ b/data/recipes/smithing/smith_rune_platebody.yaml @@ -0,0 +1,11 @@ +id: smith_rune_platebody +type: smithing +level: 99 +xp: 375 +wait: 4 +station: [anvil] +consume: + - items: [runite_bar] + quantity: 5 +output: rune_platebody +message: "You hammer out a rune platebody." diff --git a/data/recipes/smithing/smith_rune_sword.yaml b/data/recipes/smithing/smith_rune_sword.yaml new file mode 100644 index 0000000..20f94f6 --- /dev/null +++ b/data/recipes/smithing/smith_rune_sword.yaml @@ -0,0 +1,11 @@ +id: smith_rune_sword +type: smithing +level: 89 +xp: 75 +wait: 4 +station: [anvil] +consume: + - items: [runite_bar] + quantity: 1 +output: rune_sword +message: "You hammer out a rune sword." diff --git a/data/recipes/smithing/smith_steel_arrowtips.yaml b/data/recipes/smithing/smith_steel_arrowtips.yaml new file mode 100644 index 0000000..1ec292f --- /dev/null +++ b/data/recipes/smithing/smith_steel_arrowtips.yaml @@ -0,0 +1,12 @@ +id: smith_steel_arrowtips +type: smithing +level: 35 +xp: 37 +wait: 4 +station: [anvil] +consume: + - items: [steel_bar] + quantity: 1 +output: steel_arrowtips +output_qty: 15 +message: "You hammer out some steel arrowtips." diff --git a/data/recipes/smithing/smith_steel_bolts_unf.yaml b/data/recipes/smithing/smith_steel_bolts_unf.yaml new file mode 100644 index 0000000..cc071ef --- /dev/null +++ b/data/recipes/smithing/smith_steel_bolts_unf.yaml @@ -0,0 +1,12 @@ +id: smith_steel_bolts_unf +type: smithing +level: 36 +xp: 37 +wait: 4 +station: [anvil] +consume: + - items: [steel_bar] + quantity: 1 +output: steel_bolts_unf +output_qty: 10 +message: "You hammer out some steel bolts." diff --git a/data/recipes/smithing/smith_steel_dagger.yaml b/data/recipes/smithing/smith_steel_dagger.yaml new file mode 100644 index 0000000..6e2f1c4 --- /dev/null +++ b/data/recipes/smithing/smith_steel_dagger.yaml @@ -0,0 +1,11 @@ +id: smith_steel_dagger +type: smithing +level: 30 +xp: 37 +wait: 4 +station: [anvil] +consume: + - items: [steel_bar] + quantity: 1 +output: steel_dagger +message: "You hammer out a steel dagger." diff --git a/data/recipes/smithing/smith_steel_full_helm.yaml b/data/recipes/smithing/smith_steel_full_helm.yaml new file mode 100644 index 0000000..c95d0d0 --- /dev/null +++ b/data/recipes/smithing/smith_steel_full_helm.yaml @@ -0,0 +1,11 @@ +id: smith_steel_full_helm +type: smithing +level: 37 +xp: 75 +wait: 4 +station: [anvil] +consume: + - items: [steel_bar] + quantity: 2 +output: steel_full_helm +message: "You hammer out a steel full helm." diff --git a/data/recipes/smithing/smith_steel_med_helm.yaml b/data/recipes/smithing/smith_steel_med_helm.yaml new file mode 100644 index 0000000..3415ec8 --- /dev/null +++ b/data/recipes/smithing/smith_steel_med_helm.yaml @@ -0,0 +1,11 @@ +id: smith_steel_med_helm +type: smithing +level: 33 +xp: 37 +wait: 4 +station: [anvil] +consume: + - items: [steel_bar] + quantity: 1 +output: steel_med_helm +message: "You hammer out a steel med helm." diff --git a/data/recipes/smithing/smith_steel_nails.yaml b/data/recipes/smithing/smith_steel_nails.yaml new file mode 100644 index 0000000..2da69c8 --- /dev/null +++ b/data/recipes/smithing/smith_steel_nails.yaml @@ -0,0 +1,12 @@ +id: smith_steel_nails +type: smithing +level: 34 +xp: 37 +wait: 4 +station: [anvil] +consume: + - items: [steel_bar] + quantity: 1 +output: steel_nails +output_qty: 15 +message: "You hammer out some steel nails." diff --git a/data/recipes/smithing/smith_steel_platebody.yaml b/data/recipes/smithing/smith_steel_platebody.yaml new file mode 100644 index 0000000..da11d11 --- /dev/null +++ b/data/recipes/smithing/smith_steel_platebody.yaml @@ -0,0 +1,11 @@ +id: smith_steel_platebody +type: smithing +level: 48 +xp: 187 +wait: 4 +station: [anvil] +consume: + - items: [steel_bar] + quantity: 5 +output: steel_platebody +message: "You hammer out a steel platebody." diff --git a/data/recipes/smithing/smith_steel_sword.yaml b/data/recipes/smithing/smith_steel_sword.yaml new file mode 100644 index 0000000..63270bc --- /dev/null +++ b/data/recipes/smithing/smith_steel_sword.yaml @@ -0,0 +1,11 @@ +id: smith_steel_sword +type: smithing +level: 34 +xp: 37 +wait: 4 +station: [anvil] +consume: + - items: [steel_bar] + quantity: 1 +output: steel_sword +message: "You hammer out a steel sword." diff --git a/data/rooms/1.yaml b/data/rooms/1.yaml deleted file mode 100644 index c4ec261..0000000 --- a/data/rooms/1.yaml +++ /dev/null @@ -1,38 +0,0 @@ -id: 1 -name: "Town Square" -description: "The central square of Lumbridge. A fountain gurgles peacefully in the center. Paths lead west toward the gathering grounds and east toward the production district." -map_symbol: "S" -exits: - east: 2 - west: 22 - up: 100 - down: 31 -objects: - - id: lumby_fountain - - id: charging_station - - id: bank_booth -mobs: - - "newbie_trainer" - - "general_store_clerk" -spawns: - - item_id: cape_of_agility - quantity: 1 - respawn_ticks: 60 - - item_id: graceful_hat - quantity: 1 - respawn_ticks: 60 - - item_id: graceful_torso - quantity: 1 - respawn_ticks: 60 - - item_id: graceful_legs - quantity: 1 - respawn_ticks: 60 - - item_id: graceful_gloves - quantity: 1 - respawn_ticks: 60 - - item_id: graceful_boots - quantity: 1 - respawn_ticks: 60 - - item_id: graceful_cape - quantity: 1 - respawn_ticks: 60 diff --git a/data/rooms/11.yaml b/data/rooms/11.yaml deleted file mode 100644 index a7b3247..0000000 --- a/data/rooms/11.yaml +++ /dev/null @@ -1,17 +0,0 @@ -id: 11 -name: "Kitchen" -description: "A warm kitchen with a stone hearth and wooden counters. A large iron cooking range dominates one wall, and shelves are stocked with ingredients." -exits: - east: 12 - west: 10 -objects: - - id: cooking_range -mobs: - - id: zombie -spawns: - - item_id: bucket_of_water - quantity: 1 - respawn_ticks: 200 - - item_id: pot_of_flour - quantity: 1 - respawn_ticks: 200 diff --git a/data/rooms/12.yaml b/data/rooms/12.yaml deleted file mode 100644 index 80380b8..0000000 --- a/data/rooms/12.yaml +++ /dev/null @@ -1,28 +0,0 @@ -id: 12 -name: "Forge" -description: "A blazing forge and anvil dominate this smoky workshop. The heat from the furnace is intense." -exits: - east: 13 - west: 11 -mobs: - - "weapons_smith" -objects: - - id: furnace - - id: anvil - - id: bank_booth -spawns: - - item_id: copper_ore - quantity: 3 - respawn_ticks: 30 - - item_id: tin_ore - quantity: 3 - respawn_ticks: 30 - - item_id: iron_ore - quantity: 3 - respawn_ticks: 30 - - item_id: coal - quantity: 5 - respawn_ticks: 30 - - item_id: hammer - quantity: 1 - respawn_ticks: 30 diff --git a/data/rooms/13.yaml b/data/rooms/13.yaml deleted file mode 100644 index 939e751..0000000 --- a/data/rooms/13.yaml +++ /dev/null @@ -1,46 +0,0 @@ -id: 13 -name: "Crafting Workshop" -description: "A bustling workshop filled with crafting stations. A {130}spinning wheel{/} sits in one corner, a {173}pottery wheel{/} and {196}pottery oven{/} in another. Racks of tools and raw materials line the walls. The forge is just to the west." -exits: - east: 14 - west: 12 -objects: - - id: spinning_wheel - - id: pottery_wheel - - id: pottery_oven - - id: sheep - - id: clay_rock - - id: clay_rock -mobs: - - id: tanner - - id: cow - - id: cow - - id: cow -spawns: - - item_id: flax - quantity: 5 - respawn_ticks: 60 - - item_id: thread - quantity: 10 - respawn_ticks: 60 - - item_id: shears - quantity: 1 - respawn_ticks: 60 - - item_id: needle - quantity: 1 - respawn_ticks: 60 - - item_id: chisel - quantity: 1 - respawn_ticks: 60 - - item_id: ring_mould - quantity: 1 - respawn_ticks: 60 - - item_id: necklace_mould - quantity: 1 - respawn_ticks: 60 - - item_id: amulet_mould - quantity: 1 - respawn_ticks: 60 - - item_id: bracelet_mould - quantity: 1 - respawn_ticks: 60 diff --git a/data/rooms/14.yaml b/data/rooms/14.yaml deleted file mode 100644 index 63db344..0000000 --- a/data/rooms/14.yaml +++ /dev/null @@ -1,18 +0,0 @@ -id: 14 -name: "Fletching Bench" -description: "A workbench covered in wood shavings, feathers, and arrowheads. Racks of unfinished bows line the walls, and a pile of bowstrings sits in the corner." -exits: - east: 15 - west: 13 -mobs: - - id: moss_giant -spawns: - - item_id: bowstring - quantity: 5 - respawn_ticks: 50 - - item_id: knife - quantity: 1 - respawn_ticks: 50 - - item_id: chisel - quantity: 1 - respawn_ticks: 50 diff --git a/data/rooms/150.yaml b/data/rooms/150.yaml deleted file mode 100644 index 462a30c..0000000 --- a/data/rooms/150.yaml +++ /dev/null @@ -1,32 +0,0 @@ -id: 150 -name: "Hydroponics Bay" -description: "A large enclosed area with climate-controlled growing stations. {34}Lush green patches{/} of soil are laid out in neat rows under artificial UV lamps. A {94}tool shed{/} stands near the entrance. Exits lead to specialized growing areas." -map_symbol: "H" -exits: - north: 15 - east: 151 - south: 152 -objects: - - id: tool_shed -spawns: - - item_id: rake - quantity: 1 - respawn_ticks: 120 - - item_id: spade - quantity: 1 - respawn_ticks: 120 - - item_id: watering_can - quantity: 1 - respawn_ticks: 120 - - item_id: plant_cure - quantity: 3 - respawn_ticks: 200 - - item_id: guam_seed - quantity: 5 - respawn_ticks: 300 - - item_id: potato_seed - quantity: 10 - respawn_ticks: 300 - - item_id: onion_seed - quantity: 10 - respawn_ticks: 300 diff --git a/data/rooms/2.yaml b/data/rooms/2.yaml deleted file mode 100644 index 39fcb9a..0000000 --- a/data/rooms/2.yaml +++ /dev/null @@ -1,17 +0,0 @@ -id: 2 -name: "Fishing Spot" -description: "A quiet spot along the riverbank. The water is clear and fish can be seen swimming beneath the surface. You can cast a line here with a fishing rod and bait." -map_symbol: "F" -exits: - east: 4 - north: 3 - west: 1 -objects: - - id: bait_fishing_spot -spawns: - - item_id: fishing_rod - quantity: 1 - respawn_ticks: 30 - - item_id: fishing_bait - quantity: 20 - respawn_ticks: 60 diff --git a/data/rooms/3.yaml b/data/rooms/3.yaml deleted file mode 100644 index 8e4d1ed..0000000 --- a/data/rooms/3.yaml +++ /dev/null @@ -1,15 +0,0 @@ -id: 3 -name: "Fly Fishing Pool" -description: "A calm pool where insects hover over the water. Perfect for fly fishing." -map_symbol: "X" -exits: - south: 2 -objects: - - id: fly_fishing_spot -spawns: - - item_id: fly_fishing_rod - quantity: 1 - respawn_ticks: 30 - - item_id: feather - quantity: 15 - respawn_ticks: 60 diff --git a/data/rooms/4.yaml b/data/rooms/4.yaml deleted file mode 100644 index 6a60783..0000000 --- a/data/rooms/4.yaml +++ /dev/null @@ -1,29 +0,0 @@ -id: 4 -name: "Woodcutting Glade" -description: "A sunny glade at the edge of the forest. A sturdy tree stands here, perfect for practicing woodcutting." -map_symbol: "W" -exits: - east: 6 - north: 5 - west: 2 -objects: - - id: tree - - id: tree - - id: tree - - id: tree -mobs: - - id: rat - - id: rat -spawns: - - item_id: bronze_axe - quantity: 1 - respawn_ticks: 60 - - item_id: matches - quantity: 100 - respawn_ticks: 120 - - item_id: firesteel - quantity: 1 - respawn_ticks: 120 - - item_id: lighter - quantity: 1 - respawn_ticks: 120 diff --git a/data/rooms/5.yaml b/data/rooms/5.yaml deleted file mode 100644 index 195c098..0000000 --- a/data/rooms/5.yaml +++ /dev/null @@ -1,12 +0,0 @@ -id: 5 -name: "Oak Grove" -description: "A stand of young oak trees. The wood here is tougher but more valuable." -map_symbol: "O" -exits: - south: 4 -objects: - - id: oak_tree -spawns: - - item_id: iron_axe - quantity: 1 - respawn_ticks: 60 diff --git a/data/rooms/6.yaml b/data/rooms/6.yaml deleted file mode 100644 index 66d8d85..0000000 --- a/data/rooms/6.yaml +++ /dev/null @@ -1,16 +0,0 @@ -id: 6 -name: "Mining Pit" -description: "A small mining pit. The rocky walls glint with veins of copper ore." -map_symbol: "M" -exits: - east: 8 - north: 7 - west: 4 -objects: - - id: copper_rock - - id: copper_rock - - id: copper_rock -spawns: - - item_id: bronze_pickaxe - quantity: 1 - respawn_ticks: 30 diff --git a/data/rooms/9.yaml b/data/rooms/9.yaml deleted file mode 100644 index fe15233..0000000 --- a/data/rooms/9.yaml +++ /dev/null @@ -1,17 +0,0 @@ -id: 9 -name: "Scavenging Post" -description: "A cluttered yard full of {243}scrap metal{/} and discarded technology. Piles of salvageable debris are scattered across the ground. The air smells of ozone and rust." -exits: - east: 10 - west: 8 - north: 150 - south: 151 - northeast: 152 - southeast: 153 - northwest: 154 - southwest: 155 -objects: - - id: scrap_pile - - id: scrap_pile - - id: scrap_pile - - id: solar_altar diff --git a/data/rooms/200.yaml b/data/rooms/agility/200.yaml index 469e214..469e214 100644 --- a/data/rooms/200.yaml +++ b/data/rooms/agility/200.yaml diff --git a/data/rooms/201.yaml b/data/rooms/agility/201.yaml index 2beb2ec..2beb2ec 100644 --- a/data/rooms/201.yaml +++ b/data/rooms/agility/201.yaml diff --git a/data/rooms/202.yaml b/data/rooms/agility/202.yaml index b9c0292..b9c0292 100644 --- a/data/rooms/202.yaml +++ b/data/rooms/agility/202.yaml diff --git a/data/rooms/203.yaml b/data/rooms/agility/203.yaml index 4f5d883..4f5d883 100644 --- a/data/rooms/203.yaml +++ b/data/rooms/agility/203.yaml diff --git a/data/rooms/204.yaml b/data/rooms/agility/204.yaml index 2d82040..2d82040 100644 --- a/data/rooms/204.yaml +++ b/data/rooms/agility/204.yaml diff --git a/data/rooms/205.yaml b/data/rooms/agility/205.yaml index d814f7d..d814f7d 100644 --- a/data/rooms/205.yaml +++ b/data/rooms/agility/205.yaml diff --git a/data/rooms/210.yaml b/data/rooms/agility/210.yaml index 2b86500..2b86500 100644 --- a/data/rooms/210.yaml +++ b/data/rooms/agility/210.yaml diff --git a/data/rooms/211.yaml b/data/rooms/agility/211.yaml index 8b1f069..8b1f069 100644 --- a/data/rooms/211.yaml +++ b/data/rooms/agility/211.yaml diff --git a/data/rooms/212.yaml b/data/rooms/agility/212.yaml index 0393a7e..0393a7e 100644 --- a/data/rooms/212.yaml +++ b/data/rooms/agility/212.yaml diff --git a/data/rooms/213.yaml b/data/rooms/agility/213.yaml index be3b736..be3b736 100644 --- a/data/rooms/213.yaml +++ b/data/rooms/agility/213.yaml diff --git a/data/rooms/214.yaml b/data/rooms/agility/214.yaml index 9f9e081..9f9e081 100644 --- a/data/rooms/214.yaml +++ b/data/rooms/agility/214.yaml diff --git a/data/rooms/215.yaml b/data/rooms/agility/215.yaml index 7ea39f9..7ea39f9 100644 --- a/data/rooms/215.yaml +++ b/data/rooms/agility/215.yaml diff --git a/data/rooms/220.yaml b/data/rooms/agility/220.yaml index d6826a3..d6826a3 100644 --- a/data/rooms/220.yaml +++ b/data/rooms/agility/220.yaml diff --git a/data/rooms/221.yaml b/data/rooms/agility/221.yaml index 936ee65..936ee65 100644 --- a/data/rooms/221.yaml +++ b/data/rooms/agility/221.yaml diff --git a/data/rooms/222.yaml b/data/rooms/agility/222.yaml index 119db01..119db01 100644 --- a/data/rooms/222.yaml +++ b/data/rooms/agility/222.yaml diff --git a/data/rooms/223.yaml b/data/rooms/agility/223.yaml index 0e557f6..0e557f6 100644 --- a/data/rooms/223.yaml +++ b/data/rooms/agility/223.yaml diff --git a/data/rooms/224.yaml b/data/rooms/agility/224.yaml index 4e70f7a..4e70f7a 100644 --- a/data/rooms/224.yaml +++ b/data/rooms/agility/224.yaml diff --git a/data/rooms/225.yaml b/data/rooms/agility/225.yaml index 3413792..3413792 100644 --- a/data/rooms/225.yaml +++ b/data/rooms/agility/225.yaml diff --git a/data/rooms/226.yaml b/data/rooms/agility/226.yaml index 6faa2c1..6faa2c1 100644 --- a/data/rooms/226.yaml +++ b/data/rooms/agility/226.yaml diff --git a/data/rooms/player_housing/200.yaml b/data/rooms/player_housing/200.yaml deleted file mode 100644 index 1781818..0000000 --- a/data/rooms/player_housing/200.yaml +++ /dev/null @@ -1,8 +0,0 @@ -id: 200 -name: "Player House: Entrance Hall" -description: "A cozy entrance hall with polished floors and warm lighting. A welcome mat greets visitors at the door." -exits: - south: 170 - north: 201 -objects: - - id: charging_station diff --git a/data/rooms/player_housing/201.yaml b/data/rooms/player_housing/201.yaml deleted file mode 100644 index dbc1fd9..0000000 --- a/data/rooms/player_housing/201.yaml +++ /dev/null @@ -1,8 +0,0 @@ -id: 201 -name: "Player House: Workshop" -description: "A well-lit workshop with a sturdy workbench covered in tools and blueprints. Wood shavings litter the floor around the bench." -exits: - south: 200 -objects: - - id: workbench - - id: bank_booth diff --git a/data/rooms/player_housing/300.yaml b/data/rooms/player_housing/300.yaml new file mode 100644 index 0000000..06f1a07 --- /dev/null +++ b/data/rooms/player_housing/300.yaml @@ -0,0 +1,8 @@ +id: 300 +name: "Player House: Entrance Hall" +description: "A cozy entrance hall with polished floors and warm lighting. A welcome mat greets visitors at the door." +exits: + south: 170 + north: 301 +objects: + - id: charging_station diff --git a/data/rooms/player_housing/301.yaml b/data/rooms/player_housing/301.yaml new file mode 100644 index 0000000..c2f3e65 --- /dev/null +++ b/data/rooms/player_housing/301.yaml @@ -0,0 +1,8 @@ +id: 301 +name: "Player House: Workshop" +description: "A well-lit workshop with a sturdy workbench covered in tools and blueprints. Wood shavings litter the floor around the bench." +exits: + south: 300 +objects: + - id: workbench + - id: bank_booth diff --git a/data/rooms/town/1.yaml b/data/rooms/town/1.yaml new file mode 100644 index 0000000..ec97af2 --- /dev/null +++ b/data/rooms/town/1.yaml @@ -0,0 +1,38 @@ +id: 1 +name: "Town Square" +description: "The central square of Lumbridge. A fountain gurgles peacefully in the center. Paths lead west toward the gathering grounds and east toward the production district." +map_symbol: "S" +exits: + east: 2 + west: 22 + up: 30 + down: 31 +objects: + - id: lumby_fountain + - id: charging_station + - id: bank_booth +mobs: + - "newbie_trainer" + - "general_store_clerk" +item_spawns: + - id: cape_of_agility + quantity: 1 + respawn_ticks: 60 + - id: graceful_hat + quantity: 1 + respawn_ticks: 60 + - id: graceful_torso + quantity: 1 + respawn_ticks: 60 + - id: graceful_legs + quantity: 1 + respawn_ticks: 60 + - id: graceful_gloves + quantity: 1 + respawn_ticks: 60 + - id: graceful_boots + quantity: 1 + respawn_ticks: 60 + - id: graceful_cape + quantity: 1 + respawn_ticks: 60 diff --git a/data/rooms/10.yaml b/data/rooms/town/10.yaml index edeac4d..edeac4d 100644 --- a/data/rooms/10.yaml +++ b/data/rooms/town/10.yaml diff --git a/data/rooms/town/11.yaml b/data/rooms/town/11.yaml new file mode 100644 index 0000000..9bc45a7 --- /dev/null +++ b/data/rooms/town/11.yaml @@ -0,0 +1,17 @@ +id: 11 +name: "Kitchen" +description: "A warm kitchen with a stone hearth and wooden counters. A large iron cooking range dominates one wall, and shelves are stocked with ingredients." +exits: + east: 12 + west: 10 +objects: + - id: cooking_range +mobs: + - id: zombie +item_spawns: + - id: bucket_of_water + quantity: 1 + respawn_ticks: 200 + - id: pot_of_flour + quantity: 1 + respawn_ticks: 200 diff --git a/data/rooms/town/12.yaml b/data/rooms/town/12.yaml new file mode 100644 index 0000000..e44ae3a --- /dev/null +++ b/data/rooms/town/12.yaml @@ -0,0 +1,28 @@ +id: 12 +name: "Forge" +description: "A blazing forge and anvil dominate this smoky workshop. The heat from the furnace is intense." +exits: + east: 13 + west: 11 +mobs: + - "weapons_smith" +objects: + - id: furnace + - id: anvil + - id: bank_booth +item_spawns: + - id: copper_ore + quantity: 3 + respawn_ticks: 30 + - id: tin_ore + quantity: 3 + respawn_ticks: 30 + - id: iron_ore + quantity: 3 + respawn_ticks: 30 + - id: coal + quantity: 5 + respawn_ticks: 30 + - id: hammer + quantity: 1 + respawn_ticks: 30 diff --git a/data/rooms/town/13.yaml b/data/rooms/town/13.yaml new file mode 100644 index 0000000..dc07dc1 --- /dev/null +++ b/data/rooms/town/13.yaml @@ -0,0 +1,46 @@ +id: 13 +name: "Crafting Workshop" +description: "A bustling workshop filled with crafting stations. A {130}spinning wheel{/} sits in one corner, a {173}pottery wheel{/} and {196}pottery oven{/} in another. Racks of tools and raw materials line the walls. The forge is just to the west." +exits: + east: 14 + west: 12 +objects: + - id: spinning_wheel + - id: pottery_wheel + - id: pottery_oven + - id: sheep + - id: clay_rock + - id: clay_rock +mobs: + - id: tanner + - id: cow + - id: cow + - id: cow +item_spawns: + - id: flax + quantity: 5 + respawn_ticks: 60 + - id: thread + quantity: 10 + respawn_ticks: 60 + - id: shears + quantity: 1 + respawn_ticks: 60 + - id: needle + quantity: 1 + respawn_ticks: 60 + - id: chisel + quantity: 1 + respawn_ticks: 60 + - id: ring_mould + quantity: 1 + respawn_ticks: 60 + - id: necklace_mould + quantity: 1 + respawn_ticks: 60 + - id: amulet_mould + quantity: 1 + respawn_ticks: 60 + - id: bracelet_mould + quantity: 1 + respawn_ticks: 60 diff --git a/data/rooms/town/14.yaml b/data/rooms/town/14.yaml new file mode 100644 index 0000000..ad515de --- /dev/null +++ b/data/rooms/town/14.yaml @@ -0,0 +1,18 @@ +id: 14 +name: "Fletching Bench" +description: "A workbench covered in wood shavings, feathers, and arrowheads. Racks of unfinished bows line the walls, and a pile of bowstrings sits in the corner." +exits: + east: 15 + west: 13 +mobs: + - id: moss_giant +item_spawns: + - id: bowstring + quantity: 5 + respawn_ticks: 50 + - id: knife + quantity: 1 + respawn_ticks: 50 + - id: chisel + quantity: 1 + respawn_ticks: 50 diff --git a/data/rooms/15.yaml b/data/rooms/town/15.yaml index a67624d..a67624d 100644 --- a/data/rooms/15.yaml +++ b/data/rooms/town/15.yaml diff --git a/data/rooms/16.yaml b/data/rooms/town/16.yaml index 3776f4f..3776f4f 100644 --- a/data/rooms/16.yaml +++ b/data/rooms/town/16.yaml diff --git a/data/rooms/17.yaml b/data/rooms/town/17.yaml index 512ec9e..512ec9e 100644 --- a/data/rooms/17.yaml +++ b/data/rooms/town/17.yaml diff --git a/data/rooms/18.yaml b/data/rooms/town/18.yaml index 9dfc446..9dfc446 100644 --- a/data/rooms/18.yaml +++ b/data/rooms/town/18.yaml diff --git a/data/rooms/19.yaml b/data/rooms/town/19.yaml index 35800a0..35800a0 100644 --- a/data/rooms/19.yaml +++ b/data/rooms/town/19.yaml diff --git a/data/rooms/town/2.yaml b/data/rooms/town/2.yaml new file mode 100644 index 0000000..686dc65 --- /dev/null +++ b/data/rooms/town/2.yaml @@ -0,0 +1,17 @@ +id: 2 +name: "Fishing Spot" +description: "A quiet spot along the riverbank. The water is clear and fish can be seen swimming beneath the surface. You can cast a line here with a fishing rod and bait." +map_symbol: "F" +exits: + east: 4 + north: 3 + west: 1 +objects: + - id: bait_fishing_spot +item_spawns: + - id: fishing_rod + quantity: 1 + respawn_ticks: 30 + - id: fishing_bait + quantity: 20 + respawn_ticks: 60 diff --git a/data/rooms/20.yaml b/data/rooms/town/20.yaml index 379322b..379322b 100644 --- a/data/rooms/20.yaml +++ b/data/rooms/town/20.yaml diff --git a/data/rooms/21.yaml b/data/rooms/town/21.yaml index 987f5ea..987f5ea 100644 --- a/data/rooms/21.yaml +++ b/data/rooms/town/21.yaml diff --git a/data/rooms/22.yaml b/data/rooms/town/22.yaml index 478995b..478995b 100644 --- a/data/rooms/22.yaml +++ b/data/rooms/town/22.yaml diff --git a/data/rooms/23.yaml b/data/rooms/town/23.yaml index f7301f6..f7301f6 100644 --- a/data/rooms/23.yaml +++ b/data/rooms/town/23.yaml diff --git a/data/rooms/24.yaml b/data/rooms/town/24.yaml index 60bf0d8..60bf0d8 100644 --- a/data/rooms/24.yaml +++ b/data/rooms/town/24.yaml diff --git a/data/rooms/25.yaml b/data/rooms/town/25.yaml index a3dd843..a3dd843 100644 --- a/data/rooms/25.yaml +++ b/data/rooms/town/25.yaml diff --git a/data/rooms/26.yaml b/data/rooms/town/26.yaml index a2899e7..a2899e7 100644 --- a/data/rooms/26.yaml +++ b/data/rooms/town/26.yaml diff --git a/data/rooms/27.yaml b/data/rooms/town/27.yaml index d435424..d435424 100644 --- a/data/rooms/27.yaml +++ b/data/rooms/town/27.yaml diff --git a/data/rooms/28.yaml b/data/rooms/town/28.yaml index 03913d5..03913d5 100644 --- a/data/rooms/28.yaml +++ b/data/rooms/town/28.yaml diff --git a/data/rooms/town/3.yaml b/data/rooms/town/3.yaml new file mode 100644 index 0000000..16ce1c8 --- /dev/null +++ b/data/rooms/town/3.yaml @@ -0,0 +1,15 @@ +id: 3 +name: "Fly Fishing Pool" +description: "A calm pool where insects hover over the water. Perfect for fly fishing." +map_symbol: "X" +exits: + south: 2 +objects: + - id: fly_fishing_spot +item_spawns: + - id: fly_fishing_rod + quantity: 1 + respawn_ticks: 30 + - id: feather + quantity: 15 + respawn_ticks: 60 diff --git a/data/rooms/30.yaml b/data/rooms/town/30.yaml index 8c167eb..8c167eb 100644 --- a/data/rooms/30.yaml +++ b/data/rooms/town/30.yaml diff --git a/data/rooms/31.yaml b/data/rooms/town/31.yaml index 3d010df..3d010df 100644 --- a/data/rooms/31.yaml +++ b/data/rooms/town/31.yaml diff --git a/data/rooms/town/4.yaml b/data/rooms/town/4.yaml new file mode 100644 index 0000000..2c9f27f --- /dev/null +++ b/data/rooms/town/4.yaml @@ -0,0 +1,29 @@ +id: 4 +name: "Woodcutting Glade" +description: "A sunny glade at the edge of the forest. A sturdy tree stands here, perfect for practicing woodcutting." +map_symbol: "W" +exits: + east: 6 + north: 5 + west: 2 +objects: + - id: tree + - id: tree + - id: tree + - id: tree +mobs: + - id: rat + - id: rat +item_spawns: + - id: bronze_axe + quantity: 1 + respawn_ticks: 60 + - id: matches + quantity: 100 + respawn_ticks: 120 + - id: firesteel + quantity: 1 + respawn_ticks: 120 + - id: lighter + quantity: 1 + respawn_ticks: 120 diff --git a/data/rooms/town/5.yaml b/data/rooms/town/5.yaml new file mode 100644 index 0000000..bd760b1 --- /dev/null +++ b/data/rooms/town/5.yaml @@ -0,0 +1,12 @@ +id: 5 +name: "Oak Grove" +description: "A stand of young oak trees. The wood here is tougher but more valuable." +map_symbol: "O" +exits: + south: 4 +objects: + - id: oak_tree +item_spawns: + - id: iron_axe + quantity: 1 + respawn_ticks: 60 diff --git a/data/rooms/town/6.yaml b/data/rooms/town/6.yaml new file mode 100644 index 0000000..0fb9c59 --- /dev/null +++ b/data/rooms/town/6.yaml @@ -0,0 +1,16 @@ +id: 6 +name: "Mining Pit" +description: "A small mining pit. The rocky walls glint with veins of copper ore." +map_symbol: "M" +exits: + east: 8 + north: 7 + west: 4 +objects: + - id: copper_rock + - id: copper_rock + - id: copper_rock +item_spawns: + - id: bronze_pickaxe + quantity: 1 + respawn_ticks: 30 diff --git a/data/rooms/7.yaml b/data/rooms/town/7.yaml index 37dfed9..37dfed9 100644 --- a/data/rooms/7.yaml +++ b/data/rooms/town/7.yaml diff --git a/data/rooms/8.yaml b/data/rooms/town/8.yaml index b82c1bb..b82c1bb 100644 --- a/data/rooms/8.yaml +++ b/data/rooms/town/8.yaml diff --git a/data/rooms/town/9.yaml b/data/rooms/town/9.yaml new file mode 100644 index 0000000..9a19943 --- /dev/null +++ b/data/rooms/town/9.yaml @@ -0,0 +1,14 @@ +id: 9 +name: "Scavenging Post" +description: "A cluttered yard full of {243}scrap metal{/} and discarded technology. Piles of salvageable debris are scattered across the ground. The air smells of ozone and rust." +exits: + east: 10 + west: 8 + north: 150 + south: 151 + northeast: 152 +objects: + - id: scrap_pile + - id: scrap_pile + - id: scrap_pile + - id: solar_altar diff --git a/data/rooms/50.yaml b/data/rooms/underground/50.yaml index 0c9ebf2..0c9ebf2 100644 --- a/data/rooms/50.yaml +++ b/data/rooms/underground/50.yaml diff --git a/data/rooms/51.yaml b/data/rooms/underground/51.yaml index 74a97ef..74a97ef 100644 --- a/data/rooms/51.yaml +++ b/data/rooms/underground/51.yaml diff --git a/data/rooms/52.yaml b/data/rooms/underground/52.yaml index 2f90abd..2f90abd 100644 --- a/data/rooms/52.yaml +++ b/data/rooms/underground/52.yaml diff --git a/data/rooms/53.yaml b/data/rooms/underground/53.yaml index 126719b..126719b 100644 --- a/data/rooms/53.yaml +++ b/data/rooms/underground/53.yaml diff --git a/data/rooms/54.yaml b/data/rooms/underground/54.yaml index e86e5b7..e86e5b7 100644 --- a/data/rooms/54.yaml +++ b/data/rooms/underground/54.yaml diff --git a/data/rooms/55.yaml b/data/rooms/underground/55.yaml index 8000170..8000170 100644 --- a/data/rooms/55.yaml +++ b/data/rooms/underground/55.yaml diff --git a/data/rooms/56.yaml b/data/rooms/underground/56.yaml index 375696d..375696d 100644 --- a/data/rooms/56.yaml +++ b/data/rooms/underground/56.yaml diff --git a/data/rooms/57.yaml b/data/rooms/underground/57.yaml index 714197d..714197d 100644 --- a/data/rooms/57.yaml +++ b/data/rooms/underground/57.yaml diff --git a/data/rooms/58.yaml b/data/rooms/underground/58.yaml index f4d1829..f4d1829 100644 --- a/data/rooms/58.yaml +++ b/data/rooms/underground/58.yaml diff --git a/data/rooms/59.yaml b/data/rooms/underground/59.yaml index a1cc594..a1cc594 100644 --- a/data/rooms/59.yaml +++ b/data/rooms/underground/59.yaml diff --git a/data/rooms/60.yaml b/data/rooms/underground/60.yaml index e9b7114..e9b7114 100644 --- a/data/rooms/60.yaml +++ b/data/rooms/underground/60.yaml diff --git a/data/rooms/61.yaml b/data/rooms/underground/61.yaml index a85c7ba..a85c7ba 100644 --- a/data/rooms/61.yaml +++ b/data/rooms/underground/61.yaml diff --git a/data/rooms/62.yaml b/data/rooms/underground/62.yaml index 9ed1fad..9ed1fad 100644 --- a/data/rooms/62.yaml +++ b/data/rooms/underground/62.yaml diff --git a/data/rooms/63.yaml b/data/rooms/underground/63.yaml index b6bf53e..b6bf53e 100644 --- a/data/rooms/63.yaml +++ b/data/rooms/underground/63.yaml diff --git a/data/rooms/64.yaml b/data/rooms/underground/64.yaml index b412992..b412992 100644 --- a/data/rooms/64.yaml +++ b/data/rooms/underground/64.yaml diff --git a/data/rooms/65.yaml b/data/rooms/underground/65.yaml index 47aed6b..47aed6b 100644 --- a/data/rooms/65.yaml +++ b/data/rooms/underground/65.yaml diff --git a/data/rooms/66.yaml b/data/rooms/underground/66.yaml index 755d5e2..755d5e2 100644 --- a/data/rooms/66.yaml +++ b/data/rooms/underground/66.yaml diff --git a/data/rooms/67.yaml b/data/rooms/underground/67.yaml index 6b8d663..6b8d663 100644 --- a/data/rooms/67.yaml +++ b/data/rooms/underground/67.yaml diff --git a/data/rooms/68.yaml b/data/rooms/underground/68.yaml index f631981..f631981 100644 --- a/data/rooms/68.yaml +++ b/data/rooms/underground/68.yaml diff --git a/data/rooms/wilderness/150.yaml b/data/rooms/wilderness/150.yaml new file mode 100644 index 0000000..36b86ea --- /dev/null +++ b/data/rooms/wilderness/150.yaml @@ -0,0 +1,32 @@ +id: 150 +name: "Hydroponics Bay" +description: "A large enclosed area with climate-controlled growing stations. {34}Lush green patches{/} of soil are laid out in neat rows under artificial UV lamps. A {94}tool shed{/} stands near the entrance. Exits lead to specialized growing areas." +map_symbol: "H" +exits: + north: 15 + east: 151 + south: 152 +objects: + - id: tool_shed +item_spawns: + - id: rake + quantity: 1 + respawn_ticks: 120 + - id: spade + quantity: 1 + respawn_ticks: 120 + - id: watering_can + quantity: 1 + respawn_ticks: 120 + - id: plant_cure + quantity: 3 + respawn_ticks: 200 + - id: guam_seed + quantity: 5 + respawn_ticks: 300 + - id: potato_seed + quantity: 10 + respawn_ticks: 300 + - id: onion_seed + quantity: 10 + respawn_ticks: 300 diff --git a/data/rooms/151.yaml b/data/rooms/wilderness/151.yaml index 1bb25bf..1bb25bf 100644 --- a/data/rooms/151.yaml +++ b/data/rooms/wilderness/151.yaml diff --git a/data/rooms/152.yaml b/data/rooms/wilderness/152.yaml index 5d2f62d..5d2f62d 100644 --- a/data/rooms/152.yaml +++ b/data/rooms/wilderness/152.yaml diff --git a/data/rooms/160.yaml b/data/rooms/wilderness/160.yaml index dea9d00..dea9d00 100644 --- a/data/rooms/160.yaml +++ b/data/rooms/wilderness/160.yaml diff --git a/data/rooms/161.yaml b/data/rooms/wilderness/161.yaml index c887347..c887347 100644 --- a/data/rooms/161.yaml +++ b/data/rooms/wilderness/161.yaml diff --git a/data/rooms/162.yaml b/data/rooms/wilderness/162.yaml index a8333d8..a8333d8 100644 --- a/data/rooms/162.yaml +++ b/data/rooms/wilderness/162.yaml diff --git a/data/rooms/170.yaml b/data/rooms/wilderness/170.yaml index 35d539f..35d539f 100644 --- a/data/rooms/170.yaml +++ b/data/rooms/wilderness/170.yaml diff --git a/data/rooms/171.yaml b/data/rooms/wilderness/171.yaml index 552ccd4..552ccd4 100644 --- a/data/rooms/171.yaml +++ b/data/rooms/wilderness/171.yaml diff --git a/internal/action/recipe.go b/internal/action/recipe.go index c1f30fb..5a69195 100644 --- a/internal/action/recipe.go +++ b/internal/action/recipe.go @@ -1,7 +1,6 @@ package action import ( - "os" "path/filepath" "gopkg.in/yaml.v3" @@ -9,7 +8,7 @@ import ( type ConsumeEntry struct { Items []string `yaml:"items"` - Qty int `yaml:"qty"` + Quantity int `yaml:"quantity"` Byproducts []string `yaml:"byproducts"` } @@ -80,25 +79,15 @@ func (s *RecipeStore) LoadByType(recipeType string) ([]RecipeDef, error) { func (s *RecipeStore) loadAllRaw() ([]RecipeDef, error) { dir := filepath.Join(s.dataDir, "recipes") - entries, err := os.ReadDir(dir) - if err != nil { - return nil, err - } var recipes []RecipeDef - for _, e := range entries { - if e.IsDir() || filepath.Ext(e.Name()) != ".yaml" { - continue - } - data, err := os.ReadFile(filepath.Join(dir, e.Name())) - if err != nil { - continue - } + WalkYAMLDir(dir, func(path, id string, data []byte) error { var r RecipeDef if err := yaml.Unmarshal(data, &r); err != nil { - continue + return nil } recipes = append(recipes, r) - } + return nil + }) return recipes, nil } @@ -190,23 +179,23 @@ func (r *RecipeDef) ConsumeAll(hasItem func(string) bool, removeItem func(string found := false for _, id := range e.Items { if hasItem(id) { - removeItem(id, e.Qty) - found = true - break - } - } - if !found { - return false + removeItem(id, e.Quantity) + found = true + break } } - return true + if !found { + return false + } +} +return true } func (r *RecipeDef) HasAllItemsQty(countItem func(string) int) bool { for _, e := range r.Consume { found := false for _, id := range e.Items { - qty := e.Qty + qty := e.Quantity if qty <= 0 { qty = 1 } diff --git a/internal/action/store.go b/internal/action/store.go index a8db9df..6cb2e39 100644 --- a/internal/action/store.go +++ b/internal/action/store.go @@ -5,10 +5,79 @@ import ( "math/rand" "os" "path/filepath" + "strings" + "sync" "gopkg.in/yaml.v3" ) +func BuildPathIndex(dir string) map[string]string { + index := make(map[string]string) + filepath.WalkDir(dir, func(path string, d os.DirEntry, err error) error { + if err != nil || d.IsDir() || !strings.HasSuffix(d.Name(), ".yaml") { + return nil + } + id := strings.TrimSuffix(d.Name(), ".yaml") + index[id] = path + return nil + }) + return index +} + +func BuildRoomIndex(dir string) map[int]string { + index := make(map[int]string) + filepath.WalkDir(dir, func(path string, d os.DirEntry, err error) error { + if err != nil || d.IsDir() || !strings.HasSuffix(d.Name(), ".yaml") { + return nil + } + id := strings.TrimSuffix(d.Name(), ".yaml") + var n int + if _, scanErr := fmt.Sscanf(id, "%d", &n); scanErr == nil { + index[n] = path + } + return nil + }) + return index +} + +func WalkYAMLDir(dir string, fn func(path, id string, data []byte) error) error { + return filepath.WalkDir(dir, func(path string, d os.DirEntry, err error) error { + if err != nil || d.IsDir() || !strings.HasSuffix(d.Name(), ".yaml") { + return nil + } + data, readErr := os.ReadFile(path) + if readErr != nil { + return nil + } + id := strings.TrimSuffix(d.Name(), ".yaml") + return fn(path, id, data) + }) +} + +type Duplicate struct { + ID string + Paths []string +} + +func CheckDuplicateIDs(dir string) []Duplicate { + seen := make(map[string][]string) + filepath.WalkDir(dir, func(path string, d os.DirEntry, err error) error { + if err != nil || d.IsDir() || !strings.HasSuffix(d.Name(), ".yaml") { + return nil + } + id := strings.TrimSuffix(d.Name(), ".yaml") + seen[id] = append(seen[id], path) + return nil + }) + var dups []Duplicate + for id, paths := range seen { + if len(paths) > 1 { + dups = append(dups, Duplicate{ID: id, Paths: paths}) + } + } + return dups +} + func SuccessChance(cfg SuccessFormula, level int, requiredLevel int) float64 { chance := cfg.Base + float64(level-requiredLevel)*cfg.PerLevel if chance > cfg.Cap { @@ -20,8 +89,26 @@ func SuccessChance(cfg SuccessFormula, level int, requiredLevel int) float64 { return chance } +var ( + dropIndex map[string]string + dropIndexMu sync.Mutex +) + +func loadDropIndex(dataDir string) map[string]string { + dropIndexMu.Lock() + defer dropIndexMu.Unlock() + if dropIndex == nil { + dropIndex = BuildPathIndex(filepath.Join(dataDir, "drops")) + } + return dropIndex +} + func LoadDropTable(dataDir, id string) (*DropTableDef, error) { - path := filepath.Join(dataDir, "drops", id+".yaml") + index := loadDropIndex(dataDir) + path, ok := index[id] + if !ok { + path = filepath.Join(dataDir, "drops", id+".yaml") + } data, err := os.ReadFile(path) if err != nil { return nil, fmt.Errorf("read drop table %s: %w", id, err) diff --git a/internal/config/config.go b/internal/config/config.go index 122c311..124d45d 100644 --- a/internal/config/config.go +++ b/internal/config/config.go @@ -60,7 +60,13 @@ func DefaultColors() ColorsConfig { } type GameConfig struct { - TickLength int `yaml:"tick_length"` + TickLength int `yaml:"tick_length"` + StartupValidation StartupValidationConfig `yaml:"startup_validation"` +} + +type StartupValidationConfig struct { + CheckSources []int `yaml:"check_sources"` + IgnoreUnreachable []int `yaml:"ignore_unreachable"` } type TelnetConfig struct { @@ -91,6 +97,10 @@ func Default() *Config { return &Config{ Game: GameConfig{ TickLength: 600, + StartupValidation: StartupValidationConfig{ + CheckSources: []int{1}, + IgnoreUnreachable: []int{}, + }, }, Colors: DefaultColors(), Telnet: TelnetConfig{ diff --git a/internal/game/action_burn.go b/internal/game/action_burn.go index 4d8b65e..c31d7d5 100644 --- a/internal/game/action_burn.go +++ b/internal/game/action_burn.go @@ -3,6 +3,7 @@ package game import ( "fmt" "math/rand" + "strings" "thehouseoficarus/internal/action" "thehouseoficarus/internal/engine" @@ -11,6 +12,18 @@ import ( "thehouseoficarus/internal/player" ) +func (g *Game) executeBurn(sess *net.Session, args []string, rawInput string) { + p := sess.Player + g.cancelAction(p) + g.doBurn(sess, p, strings.Join(args, " ")) +} + +func (g *Game) executeStoke(sess *net.Session, args []string, rawInput string) { + p := sess.Player + g.cancelAction(p) + g.doStoke(sess, p, strings.Join(args, " ")) +} + func (g *Game) doBurn(sess *net.Session, p *player.Player, input string) { if p.Action != nil { g.cancelAction(p) diff --git a/internal/game/action_steal.go b/internal/game/action_steal.go index ee5456c..3510ce7 100644 --- a/internal/game/action_steal.go +++ b/internal/game/action_steal.go @@ -16,6 +16,16 @@ import ( "thehouseoficarus/internal/world" ) +func (g *Game) executeSteal(sess *net.Session, args []string, rawInput string) { + p := sess.Player + g.cancelAction(p) + if len(args) == 0 { + g.doSteal(sess, "") + } else { + g.doSteal(sess, strings.Join(args, " ")) + } +} + var stallGuardTalk = &action.TalkConfig{ Nodes: map[string]action.TalkNode{ "start": { diff --git a/internal/game/aggro.go b/internal/game/aggro.go deleted file mode 100644 index 2a9fff4..0000000 --- a/internal/game/aggro.go +++ /dev/null @@ -1,53 +0,0 @@ -package game - -import ( - "fmt" - - "thehouseoficarus/internal/combat" - "thehouseoficarus/internal/engine" - "thehouseoficarus/internal/net" -) - -func (g *Game) checkAggro(sess *net.Session) { - p := sess.Player - - if combat.GetCombat(p.Name) != nil { - return - } - - playerLevel := p.CombatLevel() - mobs := g.MobStore.MobsInRoom(p.RoomID) - - for _, mob := range mobs { - if !mob.Aggressive || mob.HP <= 0 || mob.Protected { - continue - } - if combat.IsMobInCombat(mob.InstanceID) { - continue - } - mobLevel := mobCombatLevel(mob) - if playerLevel > mobLevel*2 { - continue - } - aggMob := mob - g.Ticks.Subscribe(engine.ToTicks(1), func() bool { - if combat.GetCombat(p.Name) != nil { - return false - } - if aggMob.HP <= 0 || aggMob.RoomID != p.RoomID { - return false - } - if combat.IsMobInCombat(aggMob.InstanceID) { - return false - } - attacker := aggMob.Name - if !aggMob.Unique { - attacker = "The " + aggMob.Name - } - sess.WriteLine(fmt.Sprintf("\n%s attacks you!", g.colorize(sess, "mob_name", attacker))) - g.startCombat(sess, p, aggMob) - return false - }) - break - } -} diff --git a/internal/game/cmd_alias.go b/internal/game/cmd_alias.go index e7e4e12..890b904 100644 --- a/internal/game/cmd_alias.go +++ b/internal/game/cmd_alias.go @@ -8,6 +8,14 @@ import ( "thehouseoficarus/internal/net" ) +func (g *Game) executeAlias(sess *net.Session, args []string, rawInput string) { + g.doAlias(sess, args) +} + +func (g *Game) executeUnalias(sess *net.Session, args []string, rawInput string) { + g.doUnalias(sess, args) +} + func (g *Game) doAlias(sess *net.Session, args []string) { if sess.Account == nil { sess.WriteLine("No account loaded.") diff --git a/internal/game/cmd_attack.go b/internal/game/cmd_attack.go index b0ce214..222e3c3 100644 --- a/internal/game/cmd_attack.go +++ b/internal/game/cmd_attack.go @@ -608,6 +608,20 @@ func (g *Game) stopCombat(playerName string) { } } +func (g *Game) executeAttack(sess *net.Session, args []string, rawInput string) { + if len(args) == 0 { + p := sess.Player + target := g.resolveDefaultMob(p.RoomID) + if target == "" { + sess.WriteLine("Attack what?") + return + } + g.doAttack(sess, target) + } else { + g.doAttack(sess, strings.Join(args, " ")) + } +} + func (g *Game) respawnMob(instanceID string) { inst := g.MobStore.GetInstance(instanceID) if inst == nil { diff --git a/internal/game/cmd_autotrigger.go b/internal/game/cmd_autotrigger.go index 3c41735..e2ecd1a 100644 --- a/internal/game/cmd_autotrigger.go +++ b/internal/game/cmd_autotrigger.go @@ -52,3 +52,7 @@ func (g *Game) doAutotrigger(sess *net.Session, input string) { p.AutotriggerMod = mod.ID sess.WriteLine(fmt.Sprintf("Autotrigger set to: %s", mod.Name)) } + +func (g *Game) executeAutotrigger(sess *net.Session, args []string, rawInput string) { + g.doAutotrigger(sess, strings.Join(args, " ")) +} diff --git a/internal/game/cmd_bank.go b/internal/game/cmd_bank.go index 0785b81..d91e115 100644 --- a/internal/game/cmd_bank.go +++ b/internal/game/cmd_bank.go @@ -10,6 +10,10 @@ import ( "thehouseoficarus/internal/player" ) +func (g *Game) executeBank(sess *net.Session, args []string, rawInput string) { + g.doBank(sess) +} + func (g *Game) handleBankInput(sess *net.Session, input string) { if sess.Player == nil { sess.State = net.StateGame diff --git a/internal/game/cmd_clean.go b/internal/game/cmd_clean.go index 1f00d75..47896bb 100644 --- a/internal/game/cmd_clean.go +++ b/internal/game/cmd_clean.go @@ -11,6 +11,10 @@ import ( "thehouseoficarus/internal/player" ) +func (g *Game) executeClean(sess *net.Session, args []string, rawInput string) { + g.doClean(sess, strings.Join(args, " ")) +} + func (g *Game) doClean(sess *net.Session, input string) { p := sess.Player diff --git a/internal/game/cmd_color.go b/internal/game/cmd_color.go index 3fb7716..257c965 100644 --- a/internal/game/cmd_color.go +++ b/internal/game/cmd_color.go @@ -128,6 +128,10 @@ func (g *Game) colorSource(sess *net.Session, category string) string { return "builtin" } +func (g *Game) executeColor(sess *net.Session, args []string, rawInput string) { + g.doColor(sess, strings.Join(args, " ")) +} + var colorCategoryOrder = []string{ "room_name", "room_number", diff --git a/internal/game/cmd_colortable.go b/internal/game/cmd_colortable.go index 5aa36d9..86299dc 100644 --- a/internal/game/cmd_colortable.go +++ b/internal/game/cmd_colortable.go @@ -37,6 +37,10 @@ func (g *Game) doColortable(sess *net.Session) { writeANSITable(sess, mode) } +func (g *Game) executeColortable(sess *net.Session, args []string, rawInput string) { + g.doColortable(sess) +} + func writeSectionHeader(sess *net.Session, title string, unicode bool) { if unicode { sess.WriteLine(fmt.Sprintf("── %s ──", title)) diff --git a/internal/game/cmd_consume.go b/internal/game/cmd_consume.go new file mode 100644 index 0000000..0a7d335 --- /dev/null +++ b/internal/game/cmd_consume.go @@ -0,0 +1,293 @@ +package game + +import ( + "fmt" + "strings" + "time" + + "thehouseoficarus/internal/engine" + "thehouseoficarus/internal/net" + "thehouseoficarus/internal/object" + "thehouseoficarus/internal/player" +) + +func (g *Game) executeEat(sess *net.Session, args []string, rawInput string) { + g.doEat(sess, strings.Join(args, " ")) +} + +func (g *Game) executeDrink(sess *net.Session, args []string, rawInput string) { + g.doDrink(sess, args) +} + +func (g *Game) doEat(sess *net.Session, input string) { + p := sess.Player + + if input == "" { + sess.WriteLine("Eat what?") + return + } + + qty, itemName := parseQty(input) + _ = qty + + matches := g.findInventoryMatches(itemName, p) + if len(matches) == 0 { + sess.WriteLine(fmt.Sprintf("You don't have any '%s'.", itemName)) + return + } + + unique := uniqueItemNames(matches) + if len(unique) > 1 { + g.showWhichOne(sess, matches) + return + } + + itemID := matches[0].ID + def, _ := g.ItemStore.Load(itemID) + + if def == nil || def.EatMessage == "" { + sess.WriteLine("You can't eat that.") + return + } + + if p.ConsumeCooldown > 0 { + sess.WriteLine("You're still digesting your last meal.") + return + } + + g.cancelRest(p.Name) + + if p.Action == nil && len(p.WalkSequence) == 0 { + g.doEatNow(sess, p, itemID, def) + return + } + + g.cancelAction(p) + + g.consumeQueue[p.Name] = &QueuedCommand{ + Session: sess, + Command: "eat", + Args: itemID, + Timestamp: time.Now(), + } + + if !p.OptionBool("queue_silently") { + sess.WriteLine(fmt.Sprintf("\nYou prepare to eat %s.", g.itemColorize(sess, def, def.Name))) + } +} + +func (g *Game) doEatNow(sess *net.Session, p *player.Player, itemID string, def *object.ItemDef) { + if def == nil { + var err error + def, err = g.ItemStore.Load(itemID) + if err != nil || def.EatMessage == "" { + return + } + } + + p.RemoveItem(itemID, 1) + + p.HP += def.HealValue + maxHP := p.MaxHP() + if p.HP > maxHP { + p.HP = maxHP + } + if p.HP < 0 { + p.HP = 0 + } + + if def.HealValue != 0 { + p.StartRegen() + } + + p.ConsumeCooldown = 3 + g.AccountStore.SaveCharacter(p) + + p.ActionState = &ActionState{Type: ActionEating, TargetName: def.Name} + + sess.WriteLine(g.colorize(sess, "eat_food", def.EatMessage)) + + if p.HP <= 0 { + g.endCombat(sess, p, nil) + } +} + +func (g *Game) processConsumeQueue(p *player.Player, sess *net.Session) bool { + qc, ok := g.consumeQueue[p.Name] + if !ok { + return false + } + delete(g.consumeQueue, p.Name) + + itemID := qc.Args + def, err := g.ItemStore.Load(itemID) + + if qc.Command == "drink" { + if err != nil || (def.PotionEffect == "" && def.HealValue <= 0) { + return false + } + if p.ConsumeCooldown > 0 { + return false + } + if !p.HasItem(itemID) { + sess.WriteLine("You no longer have that to drink.") + return false + } + g.applyPotion(sess, p, itemID, def) + return true + } + + if err != nil || def.EatMessage == "" { + return false + } + + if p.ConsumeCooldown > 0 { + return false + } + + if !p.HasItem(itemID) { + sess.WriteLine("You no longer have that to eat.") + return false + } + + g.doEatNow(sess, p, itemID, def) + return true +} + +func (g *Game) doDrink(sess *net.Session, args []string) { + p := sess.Player + + if len(args) == 0 { + sess.WriteLine("Drink what?") + return + } + + input := strings.Join(args, " ") + matches := g.findInventoryMatches(input, p) + if len(matches) == 0 { + sess.WriteLine(fmt.Sprintf("You don't have any '%s'.", input)) + return + } + + unique := uniqueItemNames(matches) + if len(unique) > 1 { + g.showWhichOne(sess, matches) + return + } + + itemID := matches[0].ID + def, _ := g.ItemStore.Load(itemID) + + if def == nil { + sess.WriteLine("Something went wrong.") + return + } + + if def.PotionEffect == "" && def.HealValue <= 0 { + sess.WriteLine(fmt.Sprintf("You can't drink the %s.", g.itemColorize(sess, def, def.Name))) + return + } + + if p.ConsumeCooldown > 0 { + sess.WriteLine("You're still recovering from your last drink.") + return + } + + g.cancelRest(p.Name) + + if p.Action == nil && len(p.WalkSequence) == 0 { + g.applyPotion(sess, p, itemID, def) + return + } + + g.cancelAction(p) + + g.consumeQueue[p.Name] = &QueuedCommand{ + Session: sess, + Command: "drink", + Args: itemID, + Timestamp: time.Now(), + } + + if !p.OptionBool("queue_silently") { + sess.WriteLine(fmt.Sprintf("\nYou prepare to drink the %s.", g.itemColorize(sess, def, def.Name))) + } +} + +func (g *Game) applyPotion(sess *net.Session, p *player.Player, itemID string, def *object.ItemDef) { + if def == nil { + var err error + def, err = g.ItemStore.Load(itemID) + if err != nil || (def.PotionEffect == "" && def.HealValue <= 0) { + return + } + } + + p.RemoveItem(itemID, 1) + + effect := strings.ToLower(def.PotionEffect) + + switch effect { + case "battery": + batteryRestore := def.PotionBonus + p.Battery += float64(batteryRestore) + if p.Battery > 100 { + p.Battery = 100 + } + sess.WriteLine(fmt.Sprintf("\nYou drink the %s. Your battery is restored by %d%%.", + g.itemColorize(sess, def, def.Name), batteryRestore)) + + case "heal", "": + healAmount := def.PotionBonus + if healAmount <= 0 { + healAmount = def.HealValue + } + if healAmount <= 0 { + healAmount = 50 + } + before := p.HP + maxHP := p.Level(player.Hitpoints) + if p.HP+healAmount > maxHP { + p.HP = maxHP + } else { + p.HP += healAmount + } + actualHeal := p.HP - before + sess.WriteLine(fmt.Sprintf("\nYou drink the %s. You restore %d hitpoints.", + g.itemColorize(sess, def, def.Name), actualHeal)) + + case "all_combat": + duration := engine.ToTicks(def.PotionDuration) + buffs := []string{"attack", "strength", "defense"} + for _, stat := range buffs { + p.ActiveBuffs = append(p.ActiveBuffs, player.PotionBuff{ + Stat: stat, + BonusPercent: def.PotionBonus, + TicksLeft: duration, + }) + } + sess.WriteLine(fmt.Sprintf("\nYou drink the %s. Your combat stats are boosted by %d%% for %d ticks.", + g.itemColorize(sess, def, def.Name), def.PotionBonus, duration)) + + default: + duration := engine.ToTicks(def.PotionDuration) + p.ActiveBuffs = append(p.ActiveBuffs, player.PotionBuff{ + Stat: effect, + BonusPercent: def.PotionBonus, + TicksLeft: duration, + }) + sess.WriteLine(fmt.Sprintf("\nYou drink the %s. Your %s is boosted by %d%% for %d ticks.", + g.itemColorize(sess, def, def.Name), effect, def.PotionBonus, duration)) + } + + p.ConsumeCooldown = 3 + p.ActionState = &ActionState{Type: ActionEating} + + if g.Hub != nil { + for _, other := range g.Hub.PlayersInRoom(p.RoomID) { + if other != sess && other.Player != nil { + other.WriteLine(g.colorize(other, "broadcast", fmt.Sprintf("\n%s drinks a %s.", p.Name, def.Name))) + } + } + } +} diff --git a/internal/game/cmd_cook.go b/internal/game/cmd_cook.go index 5b78745..288afb0 100644 --- a/internal/game/cmd_cook.go +++ b/internal/game/cmd_cook.go @@ -2,12 +2,17 @@ package game import ( "fmt" + "strings" "thehouseoficarus/internal/action" "thehouseoficarus/internal/net" "thehouseoficarus/internal/player" ) +func (g *Game) executeCook(sess *net.Session, args []string, rawInput string) { + g.doCook(sess, strings.Join(args, " ")) +} + func (g *Game) doCook(sess *net.Session, input string) { p := sess.Player g.cancelAction(p) diff --git a/internal/game/cmd_craft.go b/internal/game/cmd_craft.go index 7f8808b..447d980 100644 --- a/internal/game/cmd_craft.go +++ b/internal/game/cmd_craft.go @@ -8,6 +8,14 @@ import ( "thehouseoficarus/internal/player" ) +func (g *Game) executeCraft(sess *net.Session, args []string, rawInput string) { + g.doCraft(sess, strings.Join(args, " ")) +} + +func (g *Game) executeConstruct(sess *net.Session, args []string, rawInput string) { + g.doConstruct(sess, strings.Join(args, " ")) +} + func (g *Game) doCraft(sess *net.Session, input string) { g.doGenericStationSkill(sess, input, "crafting", player.Crafting, "last_craft", "Crafting", "craft", "Craft") } diff --git a/internal/game/cmd_description.go b/internal/game/cmd_description.go index ced5dcc..5d0c5c1 100644 --- a/internal/game/cmd_description.go +++ b/internal/game/cmd_description.go @@ -6,6 +6,10 @@ import ( "thehouseoficarus/internal/net" ) +func (g *Game) executeDescription(sess *net.Session, args []string, rawInput string) { + g.doDescription(sess) +} + func (g *Game) doDescription(sess *net.Session) { p := sess.Player sess.WriteLine("") diff --git a/internal/game/cmd_drink.go b/internal/game/cmd_drink.go deleted file mode 100644 index 44ef991..0000000 --- a/internal/game/cmd_drink.go +++ /dev/null @@ -1,150 +0,0 @@ -package game - -import ( - "fmt" - "strings" - "time" - - "thehouseoficarus/internal/engine" - "thehouseoficarus/internal/net" - "thehouseoficarus/internal/object" - "thehouseoficarus/internal/player" -) - -func (g *Game) doDrink(sess *net.Session, args []string) { - p := sess.Player - - if len(args) == 0 { - sess.WriteLine("Drink what?") - return - } - - input := strings.Join(args, " ") - matches := g.findInventoryMatches(input, p) - if len(matches) == 0 { - sess.WriteLine(fmt.Sprintf("You don't have any '%s'.", input)) - return - } - - unique := uniqueItemNames(matches) - if len(unique) > 1 { - g.showWhichOne(sess, matches) - return - } - - itemID := matches[0].ID - def, _ := g.ItemStore.Load(itemID) - - if def == nil { - sess.WriteLine("Something went wrong.") - return - } - - if def.PotionEffect == "" && def.HealValue <= 0 { - sess.WriteLine(fmt.Sprintf("You can't drink the %s.", g.itemColorize(sess, def, def.Name))) - return - } - - if p.ConsumeCooldown > 0 { - sess.WriteLine("You're still recovering from your last drink.") - return - } - - g.cancelRest(p.Name) - - if p.Action == nil && len(p.WalkSequence) == 0 { - g.applyPotion(sess, p, itemID, def) - return - } - - g.cancelAction(p) - - g.consumeQueue[p.Name] = &QueuedCommand{ - Session: sess, - Command: "drink", - Args: itemID, - Timestamp: time.Now(), - } - - if !p.OptionBool("queue_silently") { - sess.WriteLine(fmt.Sprintf("\nYou prepare to drink the %s.", g.itemColorize(sess, def, def.Name))) - } -} - -func (g *Game) applyPotion(sess *net.Session, p *player.Player, itemID string, def *object.ItemDef) { - if def == nil { - var err error - def, err = g.ItemStore.Load(itemID) - if err != nil || (def.PotionEffect == "" && def.HealValue <= 0) { - return - } - } - - p.RemoveItem(itemID, 1) - - effect := strings.ToLower(def.PotionEffect) - - switch effect { - case "battery": - batteryRestore := def.PotionBonus - p.Battery += float64(batteryRestore) - if p.Battery > 100 { - p.Battery = 100 - } - sess.WriteLine(fmt.Sprintf("\nYou drink the %s. Your battery is restored by %d%%.", - g.itemColorize(sess, def, def.Name), batteryRestore)) - - case "heal", "": - healAmount := def.PotionBonus - if healAmount <= 0 { - healAmount = def.HealValue - } - if healAmount <= 0 { - healAmount = 50 - } - before := p.HP - maxHP := p.Level(player.Hitpoints) - if p.HP+healAmount > maxHP { - p.HP = maxHP - } else { - p.HP += healAmount - } - actualHeal := p.HP - before - sess.WriteLine(fmt.Sprintf("\nYou drink the %s. You restore %d hitpoints.", - g.itemColorize(sess, def, def.Name), actualHeal)) - - case "all_combat": - duration := engine.ToTicks(def.PotionDuration) - buffs := []string{"attack", "strength", "defense"} - for _, stat := range buffs { - p.ActiveBuffs = append(p.ActiveBuffs, player.PotionBuff{ - Stat: stat, - BonusPercent: def.PotionBonus, - TicksLeft: duration, - }) - } - sess.WriteLine(fmt.Sprintf("\nYou drink the %s. Your combat stats are boosted by %d%% for %d ticks.", - g.itemColorize(sess, def, def.Name), def.PotionBonus, duration)) - - default: - duration := engine.ToTicks(def.PotionDuration) - p.ActiveBuffs = append(p.ActiveBuffs, player.PotionBuff{ - Stat: effect, - BonusPercent: def.PotionBonus, - TicksLeft: duration, - }) - sess.WriteLine(fmt.Sprintf("\nYou drink the %s. Your %s is boosted by %d%% for %d ticks.", - g.itemColorize(sess, def, def.Name), effect, def.PotionBonus, duration)) - } - - p.ConsumeCooldown = 3 - p.ActionState = &ActionState{Type: ActionEating} - - if g.Hub != nil { - for _, other := range g.Hub.PlayersInRoom(p.RoomID) { - if other != sess && other.Player != nil { - other.WriteLine(g.colorize(other, "broadcast", fmt.Sprintf("\n%s drinks a %s.", p.Name, def.Name))) - } - } - } -} diff --git a/internal/game/cmd_drop.go b/internal/game/cmd_drop.go index d3141e3..551b014 100644 --- a/internal/game/cmd_drop.go +++ b/internal/game/cmd_drop.go @@ -180,6 +180,20 @@ func (g *Game) doDrop(sess *net.Session, input string) { } } +func (g *Game) executeDrop(sess *net.Session, args []string, rawInput string) { + if len(args) == 0 { + sess.WriteLine("Drop what?") + } else if args[0] == "all" { + if len(args) == 1 { + g.doDropAll(sess) + } else { + g.doDropAllNamed(sess, strings.Join(args[1:], " ")) + } + } else { + g.doDrop(sess, strings.Join(args, " ")) + } +} + func (g *Game) handleDropAllConfirm(sess *net.Session, input string) { p := sess.Player if p == nil { diff --git a/internal/game/cmd_eat.go b/internal/game/cmd_eat.go deleted file mode 100644 index f94ade3..0000000 --- a/internal/game/cmd_eat.go +++ /dev/null @@ -1,145 +0,0 @@ -package game - -import ( - "fmt" - "time" - - "thehouseoficarus/internal/net" - "thehouseoficarus/internal/object" - "thehouseoficarus/internal/player" -) - -func (g *Game) doEat(sess *net.Session, input string) { - p := sess.Player - - if input == "" { - sess.WriteLine("Eat what?") - return - } - - qty, itemName := parseQty(input) - _ = qty - - matches := g.findInventoryMatches(itemName, p) - if len(matches) == 0 { - sess.WriteLine(fmt.Sprintf("You don't have any '%s'.", itemName)) - return - } - - unique := uniqueItemNames(matches) - if len(unique) > 1 { - g.showWhichOne(sess, matches) - return - } - - itemID := matches[0].ID - def, _ := g.ItemStore.Load(itemID) - - if def == nil || def.EatMessage == "" { - sess.WriteLine("You can't eat that.") - return - } - - if p.ConsumeCooldown > 0 { - sess.WriteLine("You're still digesting your last meal.") - return - } - - g.cancelRest(p.Name) - - if p.Action == nil && len(p.WalkSequence) == 0 { - g.doEatNow(sess, p, itemID, def) - return - } - - g.cancelAction(p) - - g.consumeQueue[p.Name] = &QueuedCommand{ - Session: sess, - Command: "eat", - Args: itemID, - Timestamp: time.Now(), - } - - if !p.OptionBool("queue_silently") { - sess.WriteLine(fmt.Sprintf("\nYou prepare to eat %s.", g.itemColorize(sess, def, def.Name))) - } -} - -func (g *Game) doEatNow(sess *net.Session, p *player.Player, itemID string, def *object.ItemDef) { - if def == nil { - var err error - def, err = g.ItemStore.Load(itemID) - if err != nil || def.EatMessage == "" { - return - } - } - - p.RemoveItem(itemID, 1) - - p.HP += def.HealValue - maxHP := p.MaxHP() - if p.HP > maxHP { - p.HP = maxHP - } - if p.HP < 0 { - p.HP = 0 - } - - if def.HealValue != 0 { - p.StartRegen() - } - - p.ConsumeCooldown = 3 - g.AccountStore.SaveCharacter(p) - - p.ActionState = &ActionState{Type: ActionEating, TargetName: def.Name} - - sess.WriteLine(g.colorize(sess, "eat_food", def.EatMessage)) - - if p.HP <= 0 { - g.endCombat(sess, p, nil) - } -} - -func (g *Game) processConsumeQueue(p *player.Player, sess *net.Session) bool { - qc, ok := g.consumeQueue[p.Name] - if !ok { - return false - } - delete(g.consumeQueue, p.Name) - - itemID := qc.Args - def, err := g.ItemStore.Load(itemID) - - if qc.Command == "drink" { - if err != nil || (def.PotionEffect == "" && def.HealValue <= 0) { - return false - } - if p.ConsumeCooldown > 0 { - return false - } - if !p.HasItem(itemID) { - sess.WriteLine("You no longer have that to drink.") - return false - } - g.applyPotion(sess, p, itemID, def) - return true - } - - if err != nil || def.EatMessage == "" { - return false - } - - if p.ConsumeCooldown > 0 { - return false - } - - if !p.HasItem(itemID) { - sess.WriteLine("You no longer have that to eat.") - return false - } - - g.doEatNow(sess, p, itemID, def) - return true -} diff --git a/internal/game/cmd_estate_directory.go b/internal/game/cmd_estate_directory.go index c79135f..dbc79f6 100644 --- a/internal/game/cmd_estate_directory.go +++ b/internal/game/cmd_estate_directory.go @@ -186,7 +186,7 @@ func (g *Game) getOwnedHouseRoom(p *player.Player, flagKey string) int { } houseMap := map[string]int{ - "local_neighborhood": 200, + "local_neighborhood": 300, } return houseMap[v] } diff --git a/internal/game/cmd_farm.go b/internal/game/cmd_farm.go index 5ef36d9..791cb6d 100644 --- a/internal/game/cmd_farm.go +++ b/internal/game/cmd_farm.go @@ -9,6 +9,64 @@ import ( "thehouseoficarus/internal/player" ) +func (g *Game) executePlant(sess *net.Session, args []string, rawInput string) { + p := sess.Player + g.cancelAction(p) + if len(args) == 0 { + sess.WriteLine("Plant what?") + } else { + g.doPlant(sess, strings.Join(args, " ")) + } +} + +func (g *Game) executeHarvest(sess *net.Session, args []string, rawInput string) { + p := sess.Player + g.cancelAction(p) + if len(args) == 0 { + g.doHarvest(sess, "") + } else { + g.doHarvest(sess, strings.Join(args, " ")) + } +} + +func (g *Game) executeRake(sess *net.Session, args []string, rawInput string) { + p := sess.Player + g.cancelAction(p) + if len(args) == 0 { + g.doRake(sess, "") + } else { + g.doRake(sess, strings.Join(args, " ")) + } +} + +func (g *Game) executeWater(sess *net.Session, args []string, rawInput string) { + p := sess.Player + g.cancelAction(p) + if len(args) == 0 { + g.doWater(sess, "") + } else { + g.doWater(sess, strings.Join(args, " ")) + } +} + +func (g *Game) executeCure(sess *net.Session, args []string, rawInput string) { + p := sess.Player + g.cancelAction(p) + if len(args) == 0 { + g.doCure(sess, "") + } else { + g.doCure(sess, strings.Join(args, " ")) + } +} + +func (g *Game) executeInspect(sess *net.Session, args []string, rawInput string) { + if len(args) == 0 { + g.doInspect(sess, "") + } else { + g.doInspect(sess, strings.Join(args, " ")) + } +} + func (g *Game) doPlant(sess *net.Session, input string) { p := sess.Player diff --git a/internal/game/cmd_fletch.go b/internal/game/cmd_fletch.go index 1f6a075..e218dca 100644 --- a/internal/game/cmd_fletch.go +++ b/internal/game/cmd_fletch.go @@ -9,6 +9,10 @@ import ( "thehouseoficarus/internal/player" ) +func (g *Game) executeFletch(sess *net.Session, args []string, rawInput string) { + g.doFletch(sess, strings.Join(args, " ")) +} + var fletchLogItems = map[string]bool{ "logs": true, "oak_logs": true, "willow_logs": true, "maple_logs": true, "yew_logs": true, "magic_logs": true, diff --git a/internal/game/cmd_get.go b/internal/game/cmd_get.go index bae721b..f3485fe 100644 --- a/internal/game/cmd_get.go +++ b/internal/game/cmd_get.go @@ -2,6 +2,7 @@ package game import ( "fmt" + "strings" "thehouseoficarus/internal/net" "thehouseoficarus/internal/player" @@ -419,3 +420,17 @@ func (g *Game) findInventoryMatches(input string, p *player.Player) []itemMatch } }) } + +func (g *Game) executeGet(sess *net.Session, args []string, rawInput string) { + if len(args) == 0 { + sess.WriteLine("Get what?") + } else if args[0] == "all" { + if len(args) == 1 { + g.doGetAll(sess) + } else { + g.doGetAllNamed(sess, strings.Join(args[1:], " ")) + } + } else { + g.doGet(sess, strings.Join(args, " ")) + } +} diff --git a/internal/game/cmd_handlers.go b/internal/game/cmd_handlers.go deleted file mode 100644 index b8db359..0000000 --- a/internal/game/cmd_handlers.go +++ /dev/null @@ -1,370 +0,0 @@ -package game - -import ( - "fmt" - "strings" - - "thehouseoficarus/internal/net" -) - -func (g *Game) executeGet(sess *net.Session, args []string, rawInput string) { - if len(args) == 0 { - sess.WriteLine("Get what?") - } else if args[0] == "all" { - if len(args) == 1 { - g.doGetAll(sess) - } else { - g.doGetAllNamed(sess, strings.Join(args[1:], " ")) - } - } else { - g.doGet(sess, strings.Join(args, " ")) - } -} - -func (g *Game) executeDrop(sess *net.Session, args []string, rawInput string) { - if len(args) == 0 { - sess.WriteLine("Drop what?") - } else if args[0] == "all" { - if len(args) == 1 { - g.doDropAll(sess) - } else { - g.doDropAllNamed(sess, strings.Join(args[1:], " ")) - } - } else { - g.doDrop(sess, strings.Join(args, " ")) - } -} - -func (g *Game) executeAttack(sess *net.Session, args []string, rawInput string) { - if len(args) == 0 { - p := sess.Player - target := g.resolveDefaultMob(p.RoomID) - if target == "" { - sess.WriteLine("Attack what?") - return - } - g.doAttack(sess, target) - } else { - g.doAttack(sess, strings.Join(args, " ")) - } -} - -func (g *Game) executeStyle(sess *net.Session, args []string, rawInput string) { - if len(args) == 0 { - g.doStyle(sess, "") - } else { - g.doStyle(sess, args[0]) - } -} - -func (g *Game) executeLook(sess *net.Session, args []string, rawInput string) { - if len(args) == 0 { - g.doLook(sess) - } else { - g.doLookTarget(sess, strings.Join(args, " ")) - } -} - -func (g *Game) executeMove(sess *net.Session, args []string, rawInput string) { - g.doMove(sess, strings.TrimSpace(rawInput), 1.0) -} - -func (g *Game) executeSay(sess *net.Session, args []string, rawInput string) { - if len(args) == 0 { - sess.WriteLine("Say what?") - } else { - msgStart := strings.Index(strings.ToLower(rawInput), "say ") + 4 - if msgStart >= 4 && msgStart < len(rawInput) { - g.doSay(sess, rawInput[msgStart:]) - } else { - g.doSay(sess, strings.Join(args, " ")) - } - } -} - -func (g *Game) executeScore(sess *net.Session, args []string, rawInput string) { - g.doScore(sess) -} - -func (g *Game) executeTask(sess *net.Session, args []string, rawInput string) { - g.doTask(sess) -} - -func (g *Game) executeStats(sess *net.Session, args []string, rawInput string) { - g.doStats(sess) -} - -func (g *Game) executeTech(sess *net.Session, args []string, rawInput string) { - g.doTech(sess, strings.Join(args, " ")) -} - -func (g *Game) executeInventory(sess *net.Session, args []string, rawInput string) { - g.doInventory(sess) -} - -func (g *Game) executeQuit(sess *net.Session, args []string, rawInput string) { - g.doQuit(sess) -} - -func (g *Game) executeDescription(sess *net.Session, args []string, rawInput string) { - g.doDescription(sess) -} - -func (g *Game) executeOption(sess *net.Session, args []string, rawInput string) { - g.doOption(sess, strings.Join(args, " ")) -} - -func (g *Game) executeColor(sess *net.Session, args []string, rawInput string) { - g.doColor(sess, strings.Join(args, " ")) -} - -func (g *Game) executeColortable(sess *net.Session, args []string, rawInput string) { - g.doColortable(sess) -} - -func (g *Game) executePrompt(sess *net.Session, args []string, rawInput string) { - if len(args) == 0 { - g.doPrompt(sess, "") - } else { - msgStart := strings.Index(strings.ToLower(rawInput), "prompt ") + 7 - if msgStart >= 7 && msgStart < len(rawInput) { - g.doPrompt(sess, rawInput[msgStart:]) - } else { - g.doPrompt(sess, strings.Join(args, " ")) - } - } -} - -func (g *Game) executeExits(sess *net.Session, args []string, rawInput string) { - g.doExits(sess) -} - -func (g *Game) executeMap(sess *net.Session, args []string, rawInput string) { - g.doMap(sess) -} - -func (g *Game) executeQueued(sess *net.Session, args []string, rawInput string) { - g.doQueued(sess) -} - -func (g *Game) executeHelp(sess *net.Session, args []string, rawInput string) { - if len(args) == 0 { - g.doHelp(sess, "") - } else { - g.doHelp(sess, strings.Join(args, " ")) - } -} - -func (g *Game) executeGather(sess *net.Session, args []string, rawInput string) { - verb := strings.TrimSpace(rawInput) - p := sess.Player - g.cancelAction(p) - if len(args) == 0 { - target := g.resolveDefaultTarget(p.RoomID, verb) - if target == "" { - sess.WriteLine(fmt.Sprintf("%s what?", verb)) - return - } - g.startAction(sess, verb, target) - } else { - g.startAction(sess, verb, strings.Join(args, " ")) - } -} - -func (g *Game) executeUse(sess *net.Session, args []string, rawInput string) { - if g.tryFinishingBlow(sess, strings.Join(args, " ")) { - return - } - g.doUse(sess, strings.Join(args, " ")) -} - -func (g *Game) executeCook(sess *net.Session, args []string, rawInput string) { - g.doCook(sess, strings.Join(args, " ")) -} - -func (g *Game) executeSmelt(sess *net.Session, args []string, rawInput string) { - g.doSmelt(sess, strings.Join(args, " ")) -} - -func (g *Game) executeSmith(sess *net.Session, args []string, rawInput string) { - g.doSmith(sess, strings.Join(args, " ")) -} - -func (g *Game) executeCraft(sess *net.Session, args []string, rawInput string) { - g.doCraft(sess, strings.Join(args, " ")) -} - -func (g *Game) executeEat(sess *net.Session, args []string, rawInput string) { - g.doEat(sess, strings.Join(args, " ")) -} - -func (g *Game) executeDrink(sess *net.Session, args []string, rawInput string) { - g.doDrink(sess, args) -} - -func (g *Game) executeFletch(sess *net.Session, args []string, rawInput string) { - g.doFletch(sess, strings.Join(args, " ")) -} - -func (g *Game) executeClean(sess *net.Session, args []string, rawInput string) { - g.doClean(sess, strings.Join(args, " ")) -} - -func (g *Game) executeMix(sess *net.Session, args []string, rawInput string) { - g.doMix(sess, strings.Join(args, " ")) -} - -func (g *Game) executeIdentify(sess *net.Session, args []string, rawInput string) { - g.doIdentify(sess, strings.Join(args, " ")) -} - -func (g *Game) executeAutotrigger(sess *net.Session, args []string, rawInput string) { - g.doAutotrigger(sess, strings.Join(args, " ")) -} - -func (g *Game) executeMods(sess *net.Session, args []string, rawInput string) { - showAll := len(args) > 0 && args[0] == "all" - g.doMods(sess, showAll) -} - -func (g *Game) executeSneak(sess *net.Session, args []string, rawInput string) { - g.doSneak(sess) -} - -func (g *Game) executeTrigger(sess *net.Session, args []string, rawInput string) { - g.doTrigger(sess, strings.Join(args, " ")) -} - -func (g *Game) executeTalk(sess *net.Session, args []string, rawInput string) { - p := sess.Player - g.cancelAction(p) - if len(args) == 0 { - sess.WriteLine("Talk to whom?") - } else { - g.startAction(sess, "talk", strings.Join(args, " ")) - } -} - -func (g *Game) executeBurn(sess *net.Session, args []string, rawInput string) { - p := sess.Player - g.cancelAction(p) - g.doBurn(sess, p, strings.Join(args, " ")) -} - -func (g *Game) executeStoke(sess *net.Session, args []string, rawInput string) { - p := sess.Player - g.cancelAction(p) - g.doStoke(sess, p, strings.Join(args, " ")) -} - -func (g *Game) executeAlias(sess *net.Session, args []string, rawInput string) { - g.doAlias(sess, args) -} - -func (g *Game) executeUnalias(sess *net.Session, args []string, rawInput string) { - g.doUnalias(sess, args) -} - -func (g *Game) executeSearch(sess *net.Session, args []string, rawInput string) { - p := sess.Player - g.cancelAction(p) - if len(args) == 0 { - sess.WriteLine("Search what?") - } else { - g.doSearch(sess, strings.Join(args, " ")) - } -} - -func (g *Game) executeSteal(sess *net.Session, args []string, rawInput string) { - p := sess.Player - g.cancelAction(p) - if len(args) == 0 { - g.doSteal(sess, "") - } else { - g.doSteal(sess, strings.Join(args, " ")) - } -} - -func (g *Game) executePlant(sess *net.Session, args []string, rawInput string) { - p := sess.Player - g.cancelAction(p) - if len(args) == 0 { - sess.WriteLine("Plant what?") - } else { - g.doPlant(sess, strings.Join(args, " ")) - } -} - -func (g *Game) executeHarvest(sess *net.Session, args []string, rawInput string) { - p := sess.Player - g.cancelAction(p) - if len(args) == 0 { - g.doHarvest(sess, "") - } else { - g.doHarvest(sess, strings.Join(args, " ")) - } -} - -func (g *Game) executeRake(sess *net.Session, args []string, rawInput string) { - p := sess.Player - g.cancelAction(p) - if len(args) == 0 { - g.doRake(sess, "") - } else { - g.doRake(sess, strings.Join(args, " ")) - } -} - -func (g *Game) executeWater(sess *net.Session, args []string, rawInput string) { - p := sess.Player - g.cancelAction(p) - if len(args) == 0 { - g.doWater(sess, "") - } else { - g.doWater(sess, strings.Join(args, " ")) - } -} - -func (g *Game) executeCure(sess *net.Session, args []string, rawInput string) { - p := sess.Player - g.cancelAction(p) - if len(args) == 0 { - g.doCure(sess, "") - } else { - g.doCure(sess, strings.Join(args, " ")) - } -} - -func (g *Game) executeInspect(sess *net.Session, args []string, rawInput string) { - if len(args) == 0 { - g.doInspect(sess, "") - } else { - g.doInspect(sess, strings.Join(args, " ")) - } -} - -func (g *Game) executeWalk(sess *net.Session, args []string, rawInput string) { - g.doWalk(sess, args) -} - -func (g *Game) executeBank(sess *net.Session, args []string, rawInput string) { - g.doBank(sess) -} - -func (g *Game) executeConstruct(sess *net.Session, args []string, rawInput string) { - g.doConstruct(sess, strings.Join(args, " ")) -} - -func (g *Game) executeJack(sess *net.Session, args []string, rawInput string) { - p := sess.Player - g.cancelAction(p) - g.doJack(sess, strings.Join(args, " ")) -} - -func (g *Game) executeWear(sess *net.Session, args []string, rawInput string) { - g.doWear(sess, strings.Join(args, " ")) -} - -func (g *Game) executeRemove(sess *net.Session, args []string, rawInput string) { - g.doRemove(sess, strings.Join(args, " ")) -} diff --git a/internal/game/cmd_id.go b/internal/game/cmd_id.go index f7158e9..cb886dc 100644 --- a/internal/game/cmd_id.go +++ b/internal/game/cmd_id.go @@ -2,6 +2,7 @@ package game import ( "fmt" + "strings" "thehouseoficarus/internal/action" "thehouseoficarus/internal/net" @@ -81,6 +82,10 @@ func junkMultiplier(junkID string, level int) int { return mult } +func (g *Game) executeIdentify(sess *net.Session, args []string, rawInput string) { + g.doIdentify(sess, strings.Join(args, " ")) +} + func (g *Game) doIdentify(sess *net.Session, input string) { p := sess.Player g.cancelAction(p) diff --git a/internal/game/cmd_inventory.go b/internal/game/cmd_inventory.go index ae7b328..5024642 100644 --- a/internal/game/cmd_inventory.go +++ b/internal/game/cmd_inventory.go @@ -6,6 +6,10 @@ import ( "thehouseoficarus/internal/net" ) +func (g *Game) executeInventory(sess *net.Session, args []string, rawInput string) { + g.doInventory(sess) +} + func (g *Game) doInventory(sess *net.Session) { p := sess.Player sess.WriteLine("") diff --git a/internal/game/cmd_jack.go b/internal/game/cmd_jack.go index 8cb5062..16f8b2a 100644 --- a/internal/game/cmd_jack.go +++ b/internal/game/cmd_jack.go @@ -10,6 +10,12 @@ import ( "thehouseoficarus/internal/player" ) +func (g *Game) executeJack(sess *net.Session, args []string, rawInput string) { + p := sess.Player + g.cancelAction(p) + g.doJack(sess, strings.Join(args, " ")) +} + func (g *Game) doJack(sess *net.Session, target string) { p := sess.Player diff --git a/internal/game/cmd_look.go b/internal/game/cmd_look.go index 5fa2cf4..6913333 100644 --- a/internal/game/cmd_look.go +++ b/internal/game/cmd_look.go @@ -768,6 +768,18 @@ func (g *Game) writeLookSideBySide(sess *net.Session, p *player.Player, descLine } } +func (g *Game) executeLook(sess *net.Session, args []string, rawInput string) { + if len(args) == 0 { + g.doLook(sess) + } else { + g.doLookTarget(sess, strings.Join(args, " ")) + } +} + +func (g *Game) executeExits(sess *net.Session, args []string, rawInput string) { + g.doExits(sess) +} + func (g *Game) showItemStats(sess *net.Session, def *object.ItemDef) { s := def.Stats hasAttack := s.StabAttack != 0 || s.SlashAttack != 0 || s.CrushAttack != 0 || diff --git a/internal/game/cmd_map.go b/internal/game/cmd_map.go index 7cad008..be35a66 100644 --- a/internal/game/cmd_map.go +++ b/internal/game/cmd_map.go @@ -4,6 +4,10 @@ import ( "thehouseoficarus/internal/net" ) +func (g *Game) executeMap(sess *net.Session, args []string, rawInput string) { + g.doMap(sess) +} + func (g *Game) doMap(sess *net.Session) { p := sess.Player mapWidth := p.OptionInt("mapwidth") diff --git a/internal/game/cmd_mix.go b/internal/game/cmd_mix.go index 8fc600b..7bf1f7b 100644 --- a/internal/game/cmd_mix.go +++ b/internal/game/cmd_mix.go @@ -1,11 +1,17 @@ package game import ( + "strings" + "thehouseoficarus/internal/action" "thehouseoficarus/internal/net" "thehouseoficarus/internal/player" ) +func (g *Game) executeMix(sess *net.Session, args []string, rawInput string) { + g.doMix(sess, strings.Join(args, " ")) +} + func (g *Game) doMix(sess *net.Session, input string) { p := sess.Player g.cancelAction(p) diff --git a/internal/game/cmd_mods.go b/internal/game/cmd_mods.go index 65d7ad7..438e11a 100644 --- a/internal/game/cmd_mods.go +++ b/internal/game/cmd_mods.go @@ -9,6 +9,11 @@ import ( "thehouseoficarus/internal/player" ) +func (g *Game) executeMods(sess *net.Session, args []string, rawInput string) { + showAll := len(args) > 0 && args[0] == "all" + g.doMods(sess, showAll) +} + func (g *Game) doMods(sess *net.Session, showAll bool) { p := sess.Player sciLevel := p.Level(player.Science) diff --git a/internal/game/cmd_move.go b/internal/game/cmd_move.go index 5d6ea66..e93b14b 100644 --- a/internal/game/cmd_move.go +++ b/internal/game/cmd_move.go @@ -2,6 +2,7 @@ package game import ( "fmt" + "strings" "thehouseoficarus/internal/combat" "thehouseoficarus/internal/engine" @@ -165,6 +166,10 @@ func (g *Game) seedRoomMobs(roomID int) { g.MobStore.SeedMobs(roomID, room.Mobs) } +func (g *Game) executeMove(sess *net.Session, args []string, rawInput string) { + g.doMove(sess, strings.TrimSpace(rawInput), 1.0) +} + func (g *Game) seedRoomObjects(roomID int) { room, err := g.World.LoadRoom(roomID) if err != nil { diff --git a/internal/game/cmd_option.go b/internal/game/cmd_option.go index fdf5371..19256ba 100644 --- a/internal/game/cmd_option.go +++ b/internal/game/cmd_option.go @@ -85,6 +85,10 @@ func (g *Game) doOption(sess *net.Session, input string) { sess.WriteLine(fmt.Sprintf("\n%s set to %s.", def.Name, formatOptionValue(p, def))) } +func (g *Game) executeOption(sess *net.Session, args []string, rawInput string) { + g.doOption(sess, strings.Join(args, " ")) +} + func formatOptionValue(p *player.Player, def *player.OptionDef) string { switch def.Type { case player.OptBool: diff --git a/internal/game/cmd_prompt.go b/internal/game/cmd_prompt.go index 8850ea1..d91556a 100644 --- a/internal/game/cmd_prompt.go +++ b/internal/game/cmd_prompt.go @@ -2,10 +2,24 @@ package game import ( "fmt" + "strings" "thehouseoficarus/internal/net" ) +func (g *Game) executePrompt(sess *net.Session, args []string, rawInput string) { + if len(args) == 0 { + g.doPrompt(sess, "") + } else { + msgStart := strings.Index(strings.ToLower(rawInput), "prompt ") + 7 + if msgStart >= 7 && msgStart < len(rawInput) { + g.doPrompt(sess, rawInput[msgStart:]) + } else { + g.doPrompt(sess, strings.Join(args, " ")) + } + } +} + func (g *Game) doPrompt(sess *net.Session, input string) { p := sess.Player diff --git a/internal/game/cmd_queued.go b/internal/game/cmd_queued.go index fdb1643..58ac74b 100644 --- a/internal/game/cmd_queued.go +++ b/internal/game/cmd_queued.go @@ -7,6 +7,10 @@ import ( "thehouseoficarus/internal/net" ) +func (g *Game) executeQueued(sess *net.Session, args []string, rawInput string) { + g.doQueued(sess) +} + func (g *Game) doQueued(sess *net.Session) { p := sess.Player diff --git a/internal/game/cmd_quit.go b/internal/game/cmd_quit.go index d52c9ae..46403f4 100644 --- a/internal/game/cmd_quit.go +++ b/internal/game/cmd_quit.go @@ -8,6 +8,10 @@ import ( "thehouseoficarus/internal/net" ) +func (g *Game) executeQuit(sess *net.Session, args []string, rawInput string) { + g.doQuit(sess) +} + func (g *Game) doQuit(sess *net.Session) { p := sess.Player diff --git a/internal/game/cmd_registry.go b/internal/game/cmd_registry.go index e5bf30e..0439cc2 100644 --- a/internal/game/cmd_registry.go +++ b/internal/game/cmd_registry.go @@ -168,3 +168,29 @@ func (g *Game) executeCommand(sess *net.Session, cmd string, args []string, rawI sess.WriteLine("Unknown command.") } + +func (g *Game) executeGather(sess *net.Session, args []string, rawInput string) { + verb := strings.TrimSpace(rawInput) + p := sess.Player + g.cancelAction(p) + if len(args) == 0 { + target := g.resolveDefaultTarget(p.RoomID, verb) + if target == "" { + sess.WriteLine(fmt.Sprintf("%s what?", verb)) + return + } + g.startAction(sess, verb, target) + } else { + g.startAction(sess, verb, strings.Join(args, " ")) + } +} + +func (g *Game) executeTalk(sess *net.Session, args []string, rawInput string) { + p := sess.Player + g.cancelAction(p) + if len(args) == 0 { + sess.WriteLine("Talk to whom?") + } else { + g.startAction(sess, "talk", strings.Join(args, " ")) + } +} diff --git a/internal/game/cmd_remove.go b/internal/game/cmd_remove.go index e168fd9..c046537 100644 --- a/internal/game/cmd_remove.go +++ b/internal/game/cmd_remove.go @@ -9,6 +9,10 @@ import ( "thehouseoficarus/internal/player" ) +func (g *Game) executeRemove(sess *net.Session, args []string, rawInput string) { + g.doRemove(sess, strings.Join(args, " ")) +} + func (g *Game) doRemove(sess *net.Session, input string) { p := sess.Player diff --git a/internal/game/cmd_say.go b/internal/game/cmd_say.go index 3d619a0..f21ed88 100644 --- a/internal/game/cmd_say.go +++ b/internal/game/cmd_say.go @@ -2,10 +2,24 @@ package game import ( "fmt" + "strings" "thehouseoficarus/internal/net" ) +func (g *Game) executeSay(sess *net.Session, args []string, rawInput string) { + if len(args) == 0 { + sess.WriteLine("Say what?") + } else { + msgStart := strings.Index(strings.ToLower(rawInput), "say ") + 4 + if msgStart >= 4 && msgStart < len(rawInput) { + g.doSay(sess, rawInput[msgStart:]) + } else { + g.doSay(sess, strings.Join(args, " ")) + } + } +} + func (g *Game) doSay(sess *net.Session, msg string) { p := sess.Player roomID := p.RoomID diff --git a/internal/game/cmd_score.go b/internal/game/cmd_score.go index 0b0caf2..b49fd7f 100644 --- a/internal/game/cmd_score.go +++ b/internal/game/cmd_score.go @@ -9,6 +9,10 @@ import ( "thehouseoficarus/internal/player" ) +func (g *Game) executeScore(sess *net.Session, args []string, rawInput string) { + g.doScore(sess) +} + func (g *Game) doScore(sess *net.Session) { p := sess.Player mode := g.colorMode(sess) diff --git a/internal/game/cmd_search.go b/internal/game/cmd_search.go index cc22d49..4122e0a 100644 --- a/internal/game/cmd_search.go +++ b/internal/game/cmd_search.go @@ -7,6 +7,16 @@ import ( "thehouseoficarus/internal/net" ) +func (g *Game) executeSearch(sess *net.Session, args []string, rawInput string) { + p := sess.Player + g.cancelAction(p) + if len(args) == 0 { + sess.WriteLine("Search what?") + } else { + g.doSearch(sess, strings.Join(args, " ")) + } +} + func (g *Game) doSearch(sess *net.Session, input string) { p := sess.Player g.cancelAction(p) diff --git a/internal/game/cmd_smelt.go b/internal/game/cmd_smelt.go index 53ff426..a72cf53 100644 --- a/internal/game/cmd_smelt.go +++ b/internal/game/cmd_smelt.go @@ -2,12 +2,17 @@ package game import ( "fmt" + "strings" "thehouseoficarus/internal/action" "thehouseoficarus/internal/net" "thehouseoficarus/internal/player" ) +func (g *Game) executeSmelt(sess *net.Session, args []string, rawInput string) { + g.doSmelt(sess, strings.Join(args, " ")) +} + func (g *Game) doSmelt(sess *net.Session, input string) { p := sess.Player g.cancelAction(p) diff --git a/internal/game/cmd_smith.go b/internal/game/cmd_smith.go index 067d251..a2eaad7 100644 --- a/internal/game/cmd_smith.go +++ b/internal/game/cmd_smith.go @@ -10,6 +10,10 @@ import ( "thehouseoficarus/internal/player" ) +func (g *Game) executeSmith(sess *net.Session, args []string, rawInput string) { + g.doSmith(sess, strings.Join(args, " ")) +} + func (g *Game) doSmith(sess *net.Session, input string) { p := sess.Player g.cancelAction(p) diff --git a/internal/game/cmd_sneak.go b/internal/game/cmd_sneak.go index b37862d..325a36b 100644 --- a/internal/game/cmd_sneak.go +++ b/internal/game/cmd_sneak.go @@ -6,6 +6,10 @@ import ( "thehouseoficarus/internal/net" ) +func (g *Game) executeSneak(sess *net.Session, args []string, rawInput string) { + g.doSneak(sess) +} + func (g *Game) doSneak(sess *net.Session) { p := sess.Player p.Sneaking = !p.Sneaking diff --git a/internal/game/cmd_stats.go b/internal/game/cmd_stats.go index 51bacf1..906abf2 100644 --- a/internal/game/cmd_stats.go +++ b/internal/game/cmd_stats.go @@ -9,6 +9,10 @@ import ( "thehouseoficarus/internal/player" ) +func (g *Game) executeStats(sess *net.Session, args []string, rawInput string) { + g.doStats(sess) +} + func (g *Game) doStats(sess *net.Session) { p := sess.Player totals := g.playerEquipBonuses(p) diff --git a/internal/game/cmd_style.go b/internal/game/cmd_style.go index 269fa3f..94dd234 100644 --- a/internal/game/cmd_style.go +++ b/internal/game/cmd_style.go @@ -43,3 +43,11 @@ func (g *Game) doStyle(sess *net.Session, input string) { } sess.WriteLine(fmt.Sprintf("\nUnknown style: %s. Choices: accurate, aggressive, defensive, balanced", input)) } + +func (g *Game) executeStyle(sess *net.Session, args []string, rawInput string) { + if len(args) == 0 { + g.doStyle(sess, "") + } else { + g.doStyle(sess, args[0]) + } +} diff --git a/internal/game/cmd_task.go b/internal/game/cmd_task.go index 5b67421..e54db15 100644 --- a/internal/game/cmd_task.go +++ b/internal/game/cmd_task.go @@ -6,6 +6,10 @@ import ( "thehouseoficarus/internal/net" ) +func (g *Game) executeTask(sess *net.Session, args []string, rawInput string) { + g.doTask(sess) +} + func (g *Game) doTask(sess *net.Session) { p := sess.Player diff --git a/internal/game/cmd_tech.go b/internal/game/cmd_tech.go index 89d5c2a..cb4c309 100644 --- a/internal/game/cmd_tech.go +++ b/internal/game/cmd_tech.go @@ -194,3 +194,7 @@ func (g *Game) doTechQuick(sess *net.Session, p *player.Player, input string) { g.AccountStore.SaveCharacter(p) sess.WriteLine(fmt.Sprintf("\nQuick tech set to %s.", matches[0].Name)) } + +func (g *Game) executeTech(sess *net.Session, args []string, rawInput string) { + g.doTech(sess, strings.Join(args, " ")) +} diff --git a/internal/game/cmd_trigger.go b/internal/game/cmd_trigger.go index 89ed397..7d637ca 100644 --- a/internal/game/cmd_trigger.go +++ b/internal/game/cmd_trigger.go @@ -7,9 +7,12 @@ import ( "thehouseoficarus/internal/combat" "thehouseoficarus/internal/net" "thehouseoficarus/internal/player" - "thehouseoficarus/internal/world" ) +func (g *Game) executeTrigger(sess *net.Session, args []string, rawInput string) { + g.doTrigger(sess, strings.Join(args, " ")) +} + func (g *Game) doTrigger(sess *net.Session, input string) { p := sess.Player input = strings.TrimSpace(input) @@ -106,635 +109,3 @@ func (g *Game) triggerCombatMod(sess *net.Session, p *player.Player, mod *ModDef p.AutotriggerMod = mod.ID g.startCombat(sess, p, mob) } - -func (g *Game) triggerTransport(sess *net.Session, p *player.Player, mod *ModDef) { - if combat.GetCombat(p.Name) != nil { - sess.WriteLine("You can't teleport during combat!") - return - } - - if p.Action != nil { - g.cancelAction(p) - } - - g.consumeJunkCost(p, mod) - - sciXP := mod.BaseXP - g.awardSkillXP(sess, p, player.Science, sciXP) - if p.OptionBool("xp_drops") { - sess.WriteLine(g.colorize(sess, "xp", fmt.Sprintf("+%dxp sci", sciXP))) - } - g.AccountStore.SaveCharacter(p) - - if g.Hub != nil { - for _, other := range g.Hub.PlayersInRoom(p.RoomID) { - if other != sess { - other.WriteLine(fmt.Sprintf("\n%s teleports away.", p.Name)) - } - } - } - - sess.WriteLine(fmt.Sprintf("\nYou activate %s...", mod.Name)) - - p.RoomID = mod.Destination - if g.Hub != nil { - g.Hub.LeaveRoom(sess) - g.Hub.EnterRoom(sess, p.RoomID) - } - - room, _ := g.World.LoadRoom(p.RoomID) - destName := fmt.Sprintf("room %d", p.RoomID) - if room != nil { - destName = room.Name - } - sess.WriteLine(fmt.Sprintf("You materialize at %s.", destName)) - g.AccountStore.SaveCharacter(p) - g.doLook(sess) -} - -func (g *Game) triggerProcessing(sess *net.Session, p *player.Player, mod *ModDef, targetArg string) { - if combat.GetCombat(p.Name) != nil { - sess.WriteLine("You can't do that during combat!") - return - } - - if targetArg == "" { - sess.WriteLine(fmt.Sprintf("Usage: trigger %s <item>", strings.ReplaceAll(mod.ID, "_", " "))) - return - } - - slot, inv := g.findInventoryItem(p, targetArg) - if slot < 0 { - sess.WriteLine("You don't have that item.") - return - } - - itemDef, err := g.ItemStore.Load(inv.ItemID) - if err != nil || itemDef.Value <= 0 { - sess.WriteLine("That item has no value.") - return - } - - if p.Action != nil { - g.cancelAction(p) - } - - g.consumeJunkCost(p, mod) - - creditValue := itemDef.Value - if mod.ID == "low_process" { - creditValue = itemDef.Value / 2 - if creditValue < 1 { - creditValue = 1 - } - } - - if inv.Quantity > 1 { - inv.Quantity-- - } else { - p.SetInvSlot(slot, nil) - } - - p.Credits += creditValue - - sciXP := mod.BaseXP - g.awardSkillXP(sess, p, player.Science, sciXP) - g.AccountStore.SaveCharacter(p) - - sess.WriteLine(fmt.Sprintf("You process the %s. You receive %s credits.", - itemDef.Name, g.colorize(sess, "credits_pickup", fmt.Sprint(creditValue)))) - - if p.OptionBool("xp_drops") { - sess.WriteLine(g.colorize(sess, "xp", fmt.Sprintf("+%dxp sci", sciXP))) - } -} - -func (g *Game) triggerUtility(sess *net.Session, p *player.Player, mod *ModDef, targetArg string) { - switch mod.ID { - case "low_process", "high_process": - g.triggerProcessing(sess, p, mod, targetArg) - case "bones_to_nutrients": - g.triggerBonesToNutrients(sess, p, mod) - case "em_grab": - g.triggerEmGrab(sess, p, mod, targetArg) - case "superheat": - g.triggerSuperheat(sess, p, mod, targetArg) - case "plank_make": - g.triggerPlankMake(sess, p, mod, targetArg) - } -} - -func (g *Game) triggerBonesToNutrients(sess *net.Session, p *player.Player, mod *ModDef) { - if combat.GetCombat(p.Name) != nil { - sess.WriteLine("You can't do that during combat!") - return - } - - boneCount := p.CountItem("bones") - if boneCount == 0 { - sess.WriteLine("You don't have any bones.") - return - } - - if p.Action != nil { - g.cancelAction(p) - } - - g.consumeJunkCost(p, mod) - - for i := 0; i < 28; i++ { - slot := p.InvSlot(i) - if slot != nil && slot.ItemID == "bones" { - slot.ItemID = "nutrient_bar" - } - } - - sciXP := mod.BaseXP * boneCount - g.awardSkillXP(sess, p, player.Science, sciXP) - g.AccountStore.SaveCharacter(p) - - sess.WriteLine(fmt.Sprintf("You convert %d bones into nutrient bars.", boneCount)) - if p.OptionBool("xp_drops") { - sess.WriteLine(g.colorize(sess, "xp", fmt.Sprintf("+%dxp sci", sciXP))) - } -} - -func (g *Game) triggerEmGrab(sess *net.Session, p *player.Player, mod *ModDef, targetArg string) { - if targetArg == "" { - sess.WriteLine("Grab what? Usage: trigger em grab <item>") - return - } - - if p.FirstFreeSlot() < 0 { - sess.WriteLine("Your inventory is full.") - return - } - - groundItems := g.World.GroundItems(p.RoomID) - var matchedID string - for itemID := range groundItems { - def, _ := g.ItemStore.Load(itemID) - if def != nil && def.MatchesName(targetArg) { - matchedID = itemID - break - } - if strings.HasPrefix(itemID, strings.ToLower(targetArg)) { - matchedID = itemID - break - } - } - - if matchedID == "" { - sess.WriteLine("You don't see that here.") - return - } - - if p.Action != nil { - g.cancelAction(p) - } - - g.consumeJunkCost(p, mod) - - qty := groundItems[matchedID] - g.World.RemoveGroundItem(p.RoomID, matchedID, qty) - - def, _ := g.ItemStore.Load(matchedID) - name := matchedID - if def != nil { - name = def.Name - } - - freeSlot := p.FirstFreeSlot() - p.SetInvSlot(freeSlot, &player.InventorySlot{ItemID: matchedID, Quantity: qty}) - - sciXP := mod.BaseXP - g.awardSkillXP(sess, p, player.Science, sciXP) - g.AccountStore.SaveCharacter(p) - - sess.WriteLine(fmt.Sprintf("You magnetically pull the %s toward you.", name)) - if p.OptionBool("xp_drops") { - sess.WriteLine(g.colorize(sess, "xp", fmt.Sprintf("+%dxp sci", sciXP))) - } -} - -func (g *Game) triggerSuperheat(sess *net.Session, p *player.Player, mod *ModDef, targetArg string) { - if combat.GetCombat(p.Name) != nil { - sess.WriteLine("You can't do that during combat!") - return - } - - if targetArg == "" { - sess.WriteLine("Superheat what? Usage: trigger superheat <ore>") - return - } - - slot, inv := g.findInventoryItem(p, targetArg) - if slot < 0 { - sess.WriteLine("You don't have that item.") - return - } - - recipe := g.RecipeStore.FindByInput("smelt", inv.ItemID) - if recipe == nil { - sess.WriteLine("You can't superheat that.") - return - } - - if recipe.Level > 0 && p.Level(player.SkillName(recipe.Skill)) < recipe.Level { - sess.WriteLine(fmt.Sprintf("You need level %d %s to smelt that.", recipe.Level, recipe.Skill)) - return - } - - for _, e := range recipe.Consume { - for _, itemID := range e.Items { - qty := e.Qty - if qty <= 0 { - qty = 1 - } - if p.CountItem(itemID) < qty { - def, _ := g.ItemStore.Load(itemID) - name := itemID - if def != nil { - name = def.Name - } - sess.WriteLine(fmt.Sprintf("You need %d %s.", qty, name)) - return - } - } - } - - if p.Action != nil { - g.cancelAction(p) - } - - g.consumeJunkCost(p, mod) - - for _, e := range recipe.Consume { - for _, itemID := range e.Items { - qty := e.Qty - if qty <= 0 { - qty = 1 - } - p.RemoveItem(itemID, qty) - } - } - - outputQty := recipe.OutputQty - if outputQty <= 0 { - outputQty = 1 - } - placed := false - for i := 0; i < 28; i++ { - slot := p.InvSlot(i) - if slot != nil && slot.ItemID == recipe.Output { - slot.Quantity += outputQty - placed = true - break - } - } - if !placed { - freeSlot := p.FirstFreeSlot() - p.SetInvSlot(freeSlot, &player.InventorySlot{ItemID: recipe.Output, Quantity: outputQty}) - } - - sciXP := mod.BaseXP - g.awardSkillXP(sess, p, player.Science, sciXP) - if recipe.XP > 0 { - g.awardSkillXP(sess, p, player.SkillName(recipe.Skill), recipe.XP) - } - g.AccountStore.SaveCharacter(p) - - outputDef, _ := g.ItemStore.Load(recipe.Output) - outputName := recipe.Output - if outputDef != nil { - outputName = outputDef.Name - } - inputDef, _ := g.ItemStore.Load(inv.ItemID) - inputName := inv.ItemID - if inputDef != nil { - inputName = inputDef.Name - } - - sess.WriteLine(fmt.Sprintf("You superheat the %s and produce a %s.", inputName, outputName)) - if p.OptionBool("xp_drops") { - parts := []string{fmt.Sprintf("+%dxp sci", sciXP)} - if recipe.XP > 0 { - parts = append(parts, fmt.Sprintf("+%dxp %s", recipe.XP, player.SkillAbbr[player.SkillName(recipe.Skill)])) - } - sess.WriteLine(g.colorize(sess, "xp", "("+strings.Join(parts, ", ")+")")) - } -} - -func (g *Game) triggerPlankMake(sess *net.Session, p *player.Player, mod *ModDef, targetArg string) { - if combat.GetCombat(p.Name) != nil { - sess.WriteLine("You can't do that during combat!") - return - } - - logTypes := map[string]struct { - plankID string - name string - cost int - }{ - "logs": {"planks", "planks", 3}, - "oak_logs": {"oak_planks", "oak planks", 7}, - "teak_logs": {"teak_planks", "teak planks", 14}, - "mahogany_logs": {"mahogany_planks", "mahogany planks", 28}, - } - - if targetArg != "" { - slot, inv := g.findInventoryItem(p, targetArg) - if slot < 0 { - sess.WriteLine("You don't have that item.") - return - } - info, ok := logTypes[inv.ItemID] - if !ok { - sess.WriteLine("You can't turn that into planks.") - return - } - - if p.Credits < info.cost { - sess.WriteLine(fmt.Sprintf("You need %d credits for Plank Make (70%% of sawmill cost).", info.cost)) - return - } - - if p.Action != nil { - g.cancelAction(p) - } - - g.consumeJunkCost(p, mod) - - p.RemoveItem(inv.ItemID, 1) - p.Credits -= info.cost - - freeSlot := p.FirstFreeSlot() - if freeSlot == -1 { - sess.WriteLine("Your inventory is full.") - return - } - p.SetInvSlot(freeSlot, &player.InventorySlot{ItemID: info.plankID, Quantity: 1}) - - sciXP := mod.BaseXP - g.awardSkillXP(sess, p, player.Science, sciXP) - g.awardSkillXP(sess, p, player.Construction, 10) - g.AccountStore.SaveCharacter(p) - - sess.WriteLine(fmt.Sprintf("You convert the log into %s.", info.name)) - if p.OptionBool("xp_drops") { - parts := []string{fmt.Sprintf("+%dxp sci", sciXP), "+10xp con"} - sess.WriteLine(g.colorize(sess, "xp", "("+strings.Join(parts, ", ")+")")) - } - return - } - - for logID, info := range logTypes { - qty := p.CountItem(logID) - if qty == 0 { - continue - } - - totalCost := info.cost * qty - if p.Credits < totalCost { - continue - } - - if p.Action != nil { - g.cancelAction(p) - } - - g.consumeJunkCost(p, mod) - - p.RemoveItem(logID, qty) - p.Credits -= totalCost - - processed := 0 - for i := 0; i < qty; i++ { - freeSlot := p.FirstFreeSlot() - if freeSlot == -1 { - g.World.AddGroundItem(p.RoomID, info.plankID, qty-i) - break - } - p.SetInvSlot(freeSlot, &player.InventorySlot{ItemID: info.plankID, Quantity: 1}) - processed++ - } - - sciXP := mod.BaseXP * qty - g.awardSkillXP(sess, p, player.Science, sciXP) - conXP := 10 * qty - g.awardSkillXP(sess, p, player.Construction, conXP) - g.AccountStore.SaveCharacter(p) - - sess.WriteLine(fmt.Sprintf("You convert %d logs into %s for %d credits.", processed, info.name, totalCost)) - if processed < qty { - sess.WriteLine(fmt.Sprintf("Your inventory is full. The remaining %d planks fall to the ground.", qty-processed)) - } - if p.OptionBool("xp_drops") { - parts := []string{fmt.Sprintf("+%dxp sci", sciXP), fmt.Sprintf("+%dxp con", conXP)} - sess.WriteLine(g.colorize(sess, "xp", "("+strings.Join(parts, ", ")+")")) - } - return - } - - sess.WriteLine("You don't have any logs to convert.") -} - -func (g *Game) triggerEnchant(sess *net.Session, p *player.Player, mod *ModDef, targetArg string) { - if chipInfo, ok := chipMap[mod.ID]; ok { - g.triggerChipBolts(sess, p, mod, chipInfo) - return - } - - enchants, ok := enchantMap[mod.ID] - if !ok { - sess.WriteLine("That enchantment has no known recipes.") - return - } - - if targetArg == "" { - sess.WriteLine(fmt.Sprintf("Enchant what? Use: trigger %s <jewelry item>", strings.ReplaceAll(mod.ID, "_", " "))) - return - } - - slot, inv := g.findInventoryItem(p, targetArg) - if slot < 0 { - sess.WriteLine("You don't have that item.") - return - } - - outputID, ok := enchants[inv.ItemID] - if !ok { - sess.WriteLine("You can't enchant that with this mod.") - return - } - - if p.Action != nil { - g.cancelAction(p) - } - - g.consumeJunkCost(p, mod) - - inv.ItemID = outputID - - sciXP := mod.BaseXP - g.awardSkillXP(sess, p, player.Science, sciXP) - g.AccountStore.SaveCharacter(p) - - outputDef, _ := g.ItemStore.Load(outputID) - outputName := outputID - if outputDef != nil { - outputName = outputDef.Name - } - inputDef, _ := g.ItemStore.Load(inv.ItemID) - inputName := inv.ItemID - if inputDef != nil { - inputName = inputDef.Name - } - - sess.WriteLine(fmt.Sprintf("You enchant the %s and it becomes a %s!", inputName, outputName)) - if p.OptionBool("xp_drops") { - sess.WriteLine(g.colorize(sess, "xp", fmt.Sprintf("+%dxp sci", sciXP))) - } -} - -func (g *Game) triggerChipBolts(sess *net.Session, p *player.Player, mod *ModDef, chip chipEntry) { - count := p.CountItem(chip.Input) - if count < chip.Qty { - inputDef, _ := g.ItemStore.Load(chip.Input) - name := chip.Input - if inputDef != nil { - name = inputDef.Name - } - sess.WriteLine(fmt.Sprintf("You need at least %d %s.", chip.Qty, name)) - return - } - - if p.Action != nil { - g.cancelAction(p) - } - - g.consumeJunkCost(p, mod) - - p.RemoveItem(chip.Input, chip.Qty) - placed := false - for i := 0; i < 28; i++ { - slot := p.InvSlot(i) - if slot != nil && slot.ItemID == chip.Output { - slot.Quantity += chip.Qty - placed = true - break - } - } - if !placed { - freeSlot := p.FirstFreeSlot() - p.SetInvSlot(freeSlot, &player.InventorySlot{ItemID: chip.Output, Quantity: chip.Qty}) - } - - sciXP := mod.BaseXP - g.awardSkillXP(sess, p, player.Science, sciXP) - g.AccountStore.SaveCharacter(p) - - inputDef, _ := g.ItemStore.Load(chip.Input) - name := chip.Input - if inputDef != nil { - name = inputDef.Name - } - - sess.WriteLine(fmt.Sprintf("You chip %d %s with arcane circuitry.", chip.Qty, name)) - if p.OptionBool("xp_drops") { - sess.WriteLine(g.colorize(sess, "xp", fmt.Sprintf("+%dxp sci", sciXP))) - } -} - -func (g *Game) scienceAttack(sess *net.Session, p *player.Player, mob *world.MobInstance, mod *ModDef) bool { - if p.Level(player.Science) < mod.Level { - sess.WriteLine(fmt.Sprintf("You need level %d science to trigger %s.", mod.Level, mod.Name)) - return false - } - if !g.hasJunkCost(p, mod) { - return false - } - - if g.processConsumeQueue(p, sess) { - p.ActionState = &ActionState{Type: ActionEating, TargetName: "food"} - return true - } - - g.consumeJunkCost(p, mod) - - equipSciBonus := g.totalEquipScienceAttack(p) - attRoll := (p.Level(player.Science) + g.buffLevelBonus(p, "science") + 8) * (equipSciBonus + 64) - - mobSciDef := mob.ScienceDefense - defRoll := (mob.Defense + 9) * (mobSciDef + 64) - - if mob.Weakness == mod.Element { - attRoll = attRoll * 13 / 10 - } - - if combat.HitCheck(attRoll, defRoll) { - dmg := combat.RollDamage(mod.MaxHit) - if dmg < 0 { - dmg = 0 - } - mob.HP -= dmg - if mob.HP < 0 { - mob.HP = 0 - } - if mob.HP < mob.MaxHP && mob.HP > 0 { - mob.StartRegen() - } - - sciXP := mod.BaseXP - hpXP := mod.BaseXP / 3 - if hpXP < 1 { - hpXP = 1 - } - var gains []xpGain - - g.awardSkillXP(sess, p, player.Science, sciXP) - gains = append(gains, xpGain{string(player.Science), sciXP}) - - g.awardSkillXP(sess, p, player.Hitpoints, hpXP) - gains = append(gains, xpGain{string(player.Hitpoints), hpXP}) - - g.AccountStore.SaveCharacter(p) - - mobName := mobDisplayName(mob, true) - prefix := fmt.Sprintf(" %s hits %s for %s damage.", - g.colorize(sess, "science_mod", mod.Name), - g.colorize(sess, "mob_name", mobName), - g.colorize(sess, "damage", fmt.Sprint(dmg))) - hpPart := fmt.Sprintf("[%s/%dhp]", g.colorize(sess, "enemy_hp", fmt.Sprint(mob.HP)), mob.MaxHP) - line := prefix + " " + hpPart - if p.OptionBool("xp_drops") && len(gains) > 0 { - var parts []string - for _, gain := range gains { - parts = append(parts, fmt.Sprintf("+%dxp %s", gain.XP, player.SkillAbbr[player.SkillName(gain.Skill)])) - } - line += g.colorize(sess, "xp", " ("+strings.Join(parts, ", ")+")") - } - sess.WriteLine(line) - } else { - sess.WriteLine(g.colorize(sess, "miss", fmt.Sprintf(" %s fails to connect.", mod.Name))) - } - return true -} - -func (g *Game) findInventoryItem(p *player.Player, input string) (int, *player.InventorySlot) { - lower := strings.ToLower(strings.TrimSpace(input)) - for i := 0; i < 28; i++ { - slot := p.InvSlot(i) - if slot == nil { - continue - } - def, err := g.ItemStore.Load(slot.ItemID) - if err != nil { - continue - } - if def.MatchesName(lower) { - return i, slot - } - } - return -1, nil -} diff --git a/internal/game/cmd_trigger_combat.go b/internal/game/cmd_trigger_combat.go new file mode 100644 index 0000000..545a117 --- /dev/null +++ b/internal/game/cmd_trigger_combat.go @@ -0,0 +1,104 @@ +package game + +import ( + "fmt" + "strings" + + "thehouseoficarus/internal/combat" + "thehouseoficarus/internal/net" + "thehouseoficarus/internal/player" + "thehouseoficarus/internal/world" +) + +func (g *Game) scienceAttack(sess *net.Session, p *player.Player, mob *world.MobInstance, mod *ModDef) bool { + if p.Level(player.Science) < mod.Level { + sess.WriteLine(fmt.Sprintf("You need level %d science to trigger %s.", mod.Level, mod.Name)) + return false + } + if !g.hasJunkCost(p, mod) { + return false + } + + if g.processConsumeQueue(p, sess) { + p.ActionState = &ActionState{Type: ActionEating, TargetName: "food"} + return true + } + + g.consumeJunkCost(p, mod) + + equipSciBonus := g.totalEquipScienceAttack(p) + attRoll := (p.Level(player.Science) + g.buffLevelBonus(p, "science") + 8) * (equipSciBonus + 64) + + mobSciDef := mob.ScienceDefense + defRoll := (mob.Defense + 9) * (mobSciDef + 64) + + if mob.Weakness == mod.Element { + attRoll = attRoll * 13 / 10 + } + + if combat.HitCheck(attRoll, defRoll) { + dmg := combat.RollDamage(mod.MaxHit) + if dmg < 0 { + dmg = 0 + } + mob.HP -= dmg + if mob.HP < 0 { + mob.HP = 0 + } + if mob.HP < mob.MaxHP && mob.HP > 0 { + mob.StartRegen() + } + + sciXP := mod.BaseXP + hpXP := mod.BaseXP / 3 + if hpXP < 1 { + hpXP = 1 + } + var gains []xpGain + + g.awardSkillXP(sess, p, player.Science, sciXP) + gains = append(gains, xpGain{string(player.Science), sciXP}) + + g.awardSkillXP(sess, p, player.Hitpoints, hpXP) + gains = append(gains, xpGain{string(player.Hitpoints), hpXP}) + + g.AccountStore.SaveCharacter(p) + + mobName := mobDisplayName(mob, true) + prefix := fmt.Sprintf(" %s hits %s for %s damage.", + g.colorize(sess, "science_mod", mod.Name), + g.colorize(sess, "mob_name", mobName), + g.colorize(sess, "damage", fmt.Sprint(dmg))) + hpPart := fmt.Sprintf("[%s/%dhp]", g.colorize(sess, "enemy_hp", fmt.Sprint(mob.HP)), mob.MaxHP) + line := prefix + " " + hpPart + if p.OptionBool("xp_drops") && len(gains) > 0 { + var parts []string + for _, gain := range gains { + parts = append(parts, fmt.Sprintf("+%dxp %s", gain.XP, player.SkillAbbr[player.SkillName(gain.Skill)])) + } + line += g.colorize(sess, "xp", " ("+strings.Join(parts, ", ")+")") + } + sess.WriteLine(line) + } else { + sess.WriteLine(g.colorize(sess, "miss", fmt.Sprintf(" %s fails to connect.", mod.Name))) + } + return true +} + +func (g *Game) findInventoryItem(p *player.Player, input string) (int, *player.InventorySlot) { + lower := strings.ToLower(strings.TrimSpace(input)) + for i := 0; i < 28; i++ { + slot := p.InvSlot(i) + if slot == nil { + continue + } + def, err := g.ItemStore.Load(slot.ItemID) + if err != nil { + continue + } + if def.MatchesName(lower) { + return i, slot + } + } + return -1, nil +} diff --git a/internal/game/cmd_trigger_enchant.go b/internal/game/cmd_trigger_enchant.go new file mode 100644 index 0000000..535616b --- /dev/null +++ b/internal/game/cmd_trigger_enchant.go @@ -0,0 +1,116 @@ +package game + +import ( + "fmt" + "strings" + + "thehouseoficarus/internal/net" + "thehouseoficarus/internal/player" +) + +func (g *Game) triggerEnchant(sess *net.Session, p *player.Player, mod *ModDef, targetArg string) { + if chipInfo, ok := chipMap[mod.ID]; ok { + g.triggerChipBolts(sess, p, mod, chipInfo) + return + } + + enchants, ok := enchantMap[mod.ID] + if !ok { + sess.WriteLine("That enchantment has no known recipes.") + return + } + + if targetArg == "" { + sess.WriteLine(fmt.Sprintf("Enchant what? Use: trigger %s <jewelry item>", strings.ReplaceAll(mod.ID, "_", " "))) + return + } + + slot, inv := g.findInventoryItem(p, targetArg) + if slot < 0 { + sess.WriteLine("You don't have that item.") + return + } + + outputID, ok := enchants[inv.ItemID] + if !ok { + sess.WriteLine("You can't enchant that with this mod.") + return + } + + if p.Action != nil { + g.cancelAction(p) + } + + g.consumeJunkCost(p, mod) + + inv.ItemID = outputID + + sciXP := mod.BaseXP + g.awardSkillXP(sess, p, player.Science, sciXP) + g.AccountStore.SaveCharacter(p) + + outputDef, _ := g.ItemStore.Load(outputID) + outputName := outputID + if outputDef != nil { + outputName = outputDef.Name + } + inputDef, _ := g.ItemStore.Load(inv.ItemID) + inputName := inv.ItemID + if inputDef != nil { + inputName = inputDef.Name + } + + sess.WriteLine(fmt.Sprintf("You enchant the %s and it becomes a %s!", inputName, outputName)) + if p.OptionBool("xp_drops") { + sess.WriteLine(g.colorize(sess, "xp", fmt.Sprintf("+%dxp sci", sciXP))) + } +} + +func (g *Game) triggerChipBolts(sess *net.Session, p *player.Player, mod *ModDef, chip chipEntry) { + count := p.CountItem(chip.Input) + if count < chip.Qty { + inputDef, _ := g.ItemStore.Load(chip.Input) + name := chip.Input + if inputDef != nil { + name = inputDef.Name + } + sess.WriteLine(fmt.Sprintf("You need at least %d %s.", chip.Qty, name)) + return + } + + if p.Action != nil { + g.cancelAction(p) + } + + g.consumeJunkCost(p, mod) + + p.RemoveItem(chip.Input, chip.Qty) + placed := false + for i := 0; i < 28; i++ { + slot := p.InvSlot(i) + if slot != nil && slot.ItemID == chip.Output { + slot.Quantity += chip.Qty + placed = true + break + } + } + if !placed { + freeSlot := p.FirstFreeSlot() + p.SetInvSlot(freeSlot, &player.InventorySlot{ItemID: chip.Output, Quantity: chip.Qty}) + } + + sciXP := mod.BaseXP + g.awardSkillXP(sess, p, player.Science, sciXP) + g.AccountStore.SaveCharacter(p) + + inputDef, _ := g.ItemStore.Load(chip.Input) + name := chip.Input + if inputDef != nil { + name = inputDef.Name + } + + sess.WriteLine(fmt.Sprintf("You chip %d %s with arcane circuitry.", chip.Qty, name)) + if p.OptionBool("xp_drops") { + sess.WriteLine(g.colorize(sess, "xp", fmt.Sprintf("+%dxp sci", sciXP))) + } +} diff --git a/internal/game/cmd_trigger_transport.go b/internal/game/cmd_trigger_transport.go new file mode 100644 index 0000000..2ca8db2 --- /dev/null +++ b/internal/game/cmd_trigger_transport.go @@ -0,0 +1,54 @@ +package game + +import ( + "fmt" + + "thehouseoficarus/internal/combat" + "thehouseoficarus/internal/net" + "thehouseoficarus/internal/player" +) + +func (g *Game) triggerTransport(sess *net.Session, p *player.Player, mod *ModDef) { + if combat.GetCombat(p.Name) != nil { + sess.WriteLine("You can't teleport during combat!") + return + } + + if p.Action != nil { + g.cancelAction(p) + } + + g.consumeJunkCost(p, mod) + + sciXP := mod.BaseXP + g.awardSkillXP(sess, p, player.Science, sciXP) + if p.OptionBool("xp_drops") { + sess.WriteLine(g.colorize(sess, "xp", fmt.Sprintf("+%dxp sci", sciXP))) + } + g.AccountStore.SaveCharacter(p) + + if g.Hub != nil { + for _, other := range g.Hub.PlayersInRoom(p.RoomID) { + if other != sess { + other.WriteLine(fmt.Sprintf("\n%s teleports away.", p.Name)) + } + } + } + + sess.WriteLine(fmt.Sprintf("\nYou activate %s...", mod.Name)) + + p.RoomID = mod.Destination + if g.Hub != nil { + g.Hub.LeaveRoom(sess) + g.Hub.EnterRoom(sess, p.RoomID) + } + + room, _ := g.World.LoadRoom(p.RoomID) + destName := fmt.Sprintf("room %d", p.RoomID) + if room != nil { + destName = room.Name + } + sess.WriteLine(fmt.Sprintf("You materialize at %s.", destName)) + g.AccountStore.SaveCharacter(p) + g.doLook(sess) +} diff --git a/internal/game/cmd_trigger_utility.go b/internal/game/cmd_trigger_utility.go new file mode 100644 index 0000000..efb23e7 --- /dev/null +++ b/internal/game/cmd_trigger_utility.go @@ -0,0 +1,397 @@ +package game + +import ( + "fmt" + "strings" + + "thehouseoficarus/internal/combat" + "thehouseoficarus/internal/net" + "thehouseoficarus/internal/player" +) + +func (g *Game) triggerUtility(sess *net.Session, p *player.Player, mod *ModDef, targetArg string) { + switch mod.ID { + case "low_process", "high_process": + g.triggerProcessing(sess, p, mod, targetArg) + case "bones_to_nutrients": + g.triggerBonesToNutrients(sess, p, mod) + case "em_grab": + g.triggerEmGrab(sess, p, mod, targetArg) + case "superheat": + g.triggerSuperheat(sess, p, mod, targetArg) + case "plank_make": + g.triggerPlankMake(sess, p, mod, targetArg) + } +} + +func (g *Game) triggerProcessing(sess *net.Session, p *player.Player, mod *ModDef, targetArg string) { + if combat.GetCombat(p.Name) != nil { + sess.WriteLine("You can't do that during combat!") + return + } + + if targetArg == "" { + sess.WriteLine(fmt.Sprintf("Usage: trigger %s <item>", strings.ReplaceAll(mod.ID, "_", " "))) + return + } + + slot, inv := g.findInventoryItem(p, targetArg) + if slot < 0 { + sess.WriteLine("You don't have that item.") + return + } + + itemDef, err := g.ItemStore.Load(inv.ItemID) + if err != nil || itemDef.Value <= 0 { + sess.WriteLine("That item has no value.") + return + } + + if p.Action != nil { + g.cancelAction(p) + } + + g.consumeJunkCost(p, mod) + + creditValue := itemDef.Value + if mod.ID == "low_process" { + creditValue = itemDef.Value / 2 + if creditValue < 1 { + creditValue = 1 + } + } + + if inv.Quantity > 1 { + inv.Quantity-- + } else { + p.SetInvSlot(slot, nil) + } + + p.Credits += creditValue + + sciXP := mod.BaseXP + g.awardSkillXP(sess, p, player.Science, sciXP) + g.AccountStore.SaveCharacter(p) + + sess.WriteLine(fmt.Sprintf("You process the %s. You receive %s credits.", + itemDef.Name, g.colorize(sess, "credits_pickup", fmt.Sprint(creditValue)))) + + if p.OptionBool("xp_drops") { + sess.WriteLine(g.colorize(sess, "xp", fmt.Sprintf("+%dxp sci", sciXP))) + } +} + +func (g *Game) triggerBonesToNutrients(sess *net.Session, p *player.Player, mod *ModDef) { + if combat.GetCombat(p.Name) != nil { + sess.WriteLine("You can't do that during combat!") + return + } + + boneCount := p.CountItem("bones") + if boneCount == 0 { + sess.WriteLine("You don't have any bones.") + return + } + + if p.Action != nil { + g.cancelAction(p) + } + + g.consumeJunkCost(p, mod) + + for i := 0; i < 28; i++ { + slot := p.InvSlot(i) + if slot != nil && slot.ItemID == "bones" { + slot.ItemID = "nutrient_bar" + } + } + + sciXP := mod.BaseXP * boneCount + g.awardSkillXP(sess, p, player.Science, sciXP) + g.AccountStore.SaveCharacter(p) + + sess.WriteLine(fmt.Sprintf("You convert %d bones into nutrient bars.", boneCount)) + if p.OptionBool("xp_drops") { + sess.WriteLine(g.colorize(sess, "xp", fmt.Sprintf("+%dxp sci", sciXP))) + } +} + +func (g *Game) triggerEmGrab(sess *net.Session, p *player.Player, mod *ModDef, targetArg string) { + if targetArg == "" { + sess.WriteLine("Grab what? Usage: trigger em grab <item>") + return + } + + if p.FirstFreeSlot() < 0 { + sess.WriteLine("Your inventory is full.") + return + } + + groundItems := g.World.GroundItems(p.RoomID) + var matchedID string + for itemID := range groundItems { + def, _ := g.ItemStore.Load(itemID) + if def != nil && def.MatchesName(targetArg) { + matchedID = itemID + break + } + if strings.HasPrefix(itemID, strings.ToLower(targetArg)) { + matchedID = itemID + break + } + } + + if matchedID == "" { + sess.WriteLine("You don't see that here.") + return + } + + if p.Action != nil { + g.cancelAction(p) + } + + g.consumeJunkCost(p, mod) + + qty := groundItems[matchedID] + g.World.RemoveGroundItem(p.RoomID, matchedID, qty) + + def, _ := g.ItemStore.Load(matchedID) + name := matchedID + if def != nil { + name = def.Name + } + + freeSlot := p.FirstFreeSlot() + p.SetInvSlot(freeSlot, &player.InventorySlot{ItemID: matchedID, Quantity: qty}) + + sciXP := mod.BaseXP + g.awardSkillXP(sess, p, player.Science, sciXP) + g.AccountStore.SaveCharacter(p) + + sess.WriteLine(fmt.Sprintf("You magnetically pull the %s toward you.", name)) + if p.OptionBool("xp_drops") { + sess.WriteLine(g.colorize(sess, "xp", fmt.Sprintf("+%dxp sci", sciXP))) + } +} + +func (g *Game) triggerSuperheat(sess *net.Session, p *player.Player, mod *ModDef, targetArg string) { + if combat.GetCombat(p.Name) != nil { + sess.WriteLine("You can't do that during combat!") + return + } + + if targetArg == "" { + sess.WriteLine("Superheat what? Usage: trigger superheat <ore>") + return + } + + slot, inv := g.findInventoryItem(p, targetArg) + if slot < 0 { + sess.WriteLine("You don't have that item.") + return + } + + recipe := g.RecipeStore.FindByInput("smelt", inv.ItemID) + if recipe == nil { + sess.WriteLine("You can't superheat that.") + return + } + + if recipe.Level > 0 && p.Level(player.SkillName(recipe.Skill)) < recipe.Level { + sess.WriteLine(fmt.Sprintf("You need level %d %s to smelt that.", recipe.Level, recipe.Skill)) + return + } + + for _, e := range recipe.Consume { + for _, itemID := range e.Items { + qty := e.Quantity + if qty <= 0 { + qty = 1 + } + if p.CountItem(itemID) < qty { + def, _ := g.ItemStore.Load(itemID) + name := itemID + if def != nil { + name = def.Name + } + sess.WriteLine(fmt.Sprintf("You need %d %s.", qty, name)) + return + } + } + } + + if p.Action != nil { + g.cancelAction(p) + } + + g.consumeJunkCost(p, mod) + + for _, e := range recipe.Consume { + for _, itemID := range e.Items { + qty := e.Quantity + if qty <= 0 { + qty = 1 + } + p.RemoveItem(itemID, qty) + } + } + + outputQty := recipe.OutputQty + if outputQty <= 0 { + outputQty = 1 + } + placed := false + for i := 0; i < 28; i++ { + slot := p.InvSlot(i) + if slot != nil && slot.ItemID == recipe.Output { + slot.Quantity += outputQty + placed = true + break + } + } + if !placed { + freeSlot := p.FirstFreeSlot() + p.SetInvSlot(freeSlot, &player.InventorySlot{ItemID: recipe.Output, Quantity: outputQty}) + } + + sciXP := mod.BaseXP + g.awardSkillXP(sess, p, player.Science, sciXP) + if recipe.XP > 0 { + g.awardSkillXP(sess, p, player.SkillName(recipe.Skill), recipe.XP) + } + g.AccountStore.SaveCharacter(p) + + outputDef, _ := g.ItemStore.Load(recipe.Output) + outputName := recipe.Output + if outputDef != nil { + outputName = outputDef.Name + } + inputDef, _ := g.ItemStore.Load(inv.ItemID) + inputName := inv.ItemID + if inputDef != nil { + inputName = inputDef.Name + } + + sess.WriteLine(fmt.Sprintf("You superheat the %s and produce a %s.", inputName, outputName)) + if p.OptionBool("xp_drops") { + parts := []string{fmt.Sprintf("+%dxp sci", sciXP)} + if recipe.XP > 0 { + parts = append(parts, fmt.Sprintf("+%dxp %s", recipe.XP, player.SkillAbbr[player.SkillName(recipe.Skill)])) + } + sess.WriteLine(g.colorize(sess, "xp", "("+strings.Join(parts, ", ")+")")) + } +} + +func (g *Game) triggerPlankMake(sess *net.Session, p *player.Player, mod *ModDef, targetArg string) { + if combat.GetCombat(p.Name) != nil { + sess.WriteLine("You can't do that during combat!") + return + } + + logTypes := map[string]struct { + plankID string + name string + cost int + }{ + "logs": {"planks", "planks", 3}, + "oak_logs": {"oak_planks", "oak planks", 7}, + "teak_logs": {"teak_planks", "teak planks", 14}, + "mahogany_logs": {"mahogany_planks", "mahogany planks", 28}, + } + + if targetArg != "" { + slot, inv := g.findInventoryItem(p, targetArg) + if slot < 0 { + sess.WriteLine("You don't have that item.") + return + } + info, ok := logTypes[inv.ItemID] + if !ok { + sess.WriteLine("You can't turn that into planks.") + return + } + + if p.Credits < info.cost { + sess.WriteLine(fmt.Sprintf("You need %d credits for Plank Make (70%% of sawmill cost).", info.cost)) + return + } + + if p.Action != nil { + g.cancelAction(p) + } + + g.consumeJunkCost(p, mod) + + p.RemoveItem(inv.ItemID, 1) + p.Credits -= info.cost + + freeSlot := p.FirstFreeSlot() + if freeSlot == -1 { + sess.WriteLine("Your inventory is full.") + return + } + p.SetInvSlot(freeSlot, &player.InventorySlot{ItemID: info.plankID, Quantity: 1}) + + sciXP := mod.BaseXP + g.awardSkillXP(sess, p, player.Science, sciXP) + g.awardSkillXP(sess, p, player.Construction, 10) + g.AccountStore.SaveCharacter(p) + + sess.WriteLine(fmt.Sprintf("You convert the log into %s.", info.name)) + if p.OptionBool("xp_drops") { + parts := []string{fmt.Sprintf("+%dxp sci", sciXP), "+10xp con"} + sess.WriteLine(g.colorize(sess, "xp", "("+strings.Join(parts, ", ")+")")) + } + return + } + + for logID, info := range logTypes { + qty := p.CountItem(logID) + if qty == 0 { + continue + } + + totalCost := info.cost * qty + if p.Credits < totalCost { + continue + } + + if p.Action != nil { + g.cancelAction(p) + } + + g.consumeJunkCost(p, mod) + + p.RemoveItem(logID, qty) + p.Credits -= totalCost + + processed := 0 + for i := 0; i < qty; i++ { + freeSlot := p.FirstFreeSlot() + if freeSlot == -1 { + g.World.AddGroundItem(p.RoomID, info.plankID, qty-i) + break + } + p.SetInvSlot(freeSlot, &player.InventorySlot{ItemID: info.plankID, Quantity: 1}) + processed++ + } + + sciXP := mod.BaseXP * qty + g.awardSkillXP(sess, p, player.Science, sciXP) + conXP := 10 * qty + g.awardSkillXP(sess, p, player.Construction, conXP) + g.AccountStore.SaveCharacter(p) + + sess.WriteLine(fmt.Sprintf("You convert %d logs into %s for %d credits.", processed, info.name, totalCost)) + if processed < qty { + sess.WriteLine(fmt.Sprintf("Your inventory is full. The remaining %d planks fall to the ground.", qty-processed)) + } + if p.OptionBool("xp_drops") { + parts := []string{fmt.Sprintf("+%dxp sci", sciXP), fmt.Sprintf("+%dxp con", conXP)} + sess.WriteLine(g.colorize(sess, "xp", "("+strings.Join(parts, ", ")+")")) + } + return + } + + sess.WriteLine("You don't have any logs to convert.") +} diff --git a/internal/game/cmd_use.go b/internal/game/cmd_use.go index fbe5945..4f830a8 100644 --- a/internal/game/cmd_use.go +++ b/internal/game/cmd_use.go @@ -10,6 +10,13 @@ import ( "thehouseoficarus/internal/player" ) +func (g *Game) executeUse(sess *net.Session, args []string, rawInput string) { + if g.tryFinishingBlow(sess, strings.Join(args, " ")) { + return + } + g.doUse(sess, strings.Join(args, " ")) +} + func (g *Game) doUse(sess *net.Session, input string) { if strings.TrimSpace(input) == "" { g.doHelp(sess, "use") diff --git a/internal/game/cmd_walk.go b/internal/game/cmd_walk.go index eca608f..9485af5 100644 --- a/internal/game/cmd_walk.go +++ b/internal/game/cmd_walk.go @@ -10,6 +10,10 @@ import ( "thehouseoficarus/internal/world" ) +func (g *Game) executeWalk(sess *net.Session, args []string, rawInput string) { + g.doWalk(sess, args) +} + func (g *Game) doWalk(sess *net.Session, args []string) { p := sess.Player if len(args) == 0 { diff --git a/internal/game/cmd_wear.go b/internal/game/cmd_wear.go index 36765e8..f2fd84c 100644 --- a/internal/game/cmd_wear.go +++ b/internal/game/cmd_wear.go @@ -9,6 +9,10 @@ import ( "thehouseoficarus/internal/player" ) +func (g *Game) executeWear(sess *net.Session, args []string, rawInput string) { + g.doWear(sess, strings.Join(args, " ")) +} + func (g *Game) checkRequirements(p *player.Player, def *object.ItemDef) string { if len(def.Requirements) == 0 { return "" diff --git a/internal/game/core_course.go b/internal/game/core_course.go new file mode 100644 index 0000000..908466d --- /dev/null +++ b/internal/game/core_course.go @@ -0,0 +1,135 @@ +package game + +import ( + "path/filepath" + "sync" + + "thehouseoficarus/internal/action" + "gopkg.in/yaml.v3" +) + +type ObstacleDef struct { + RoomID int `yaml:"room_id"` + Verb string `yaml:"verb"` + TicksPerPhase float64 `yaml:"ticks_per_phase"` + XP int `yaml:"xp"` + FailDamage [2]int `yaml:"fail_damage"` + Messages []string `yaml:"messages"` +} + +type CourseConfig struct { + ID string `yaml:"id"` + Name string `yaml:"name"` + RequiredLevel int `yaml:"required_level"` + StartRoom int `yaml:"start_room"` + CompletionXP int `yaml:"completion_xp"` + Obstacles []ObstacleDef `yaml:"obstacles"` +} + +type ObstacleInfo struct { + CourseID string + CourseName string + ObstacleIndex int + TotalObstacles int + Verb string + Messages []string + TicksPerPhase float64 + ObstacleXP int + CompletionXP int + FailDamage [2]int + NextRoom int + StartRoom int + RequiredLevel int +} + +var obstacleVerbs = map[string]bool{} + +var verbGerund = map[string]string{ + "scramble": "scrambling", + "jump": "jumping", + "swing": "swinging", + "balance": "balancing", + "climb": "climbing", + "crawl": "crawling", + "vault": "vaulting", + "leap": "leaping", + "slide": "sliding", +} + +type CourseStore struct { + dataDir string + mu sync.Mutex + courses map[string]*CourseConfig + roomToObstacle map[int]*ObstacleInfo + loaded bool +} + +func NewCourseStore(dataDir string) *CourseStore { + return &CourseStore{ + dataDir: dataDir, + courses: make(map[string]*CourseConfig), + } +} + +func (cs *CourseStore) LoadAll() { + cs.mu.Lock() + defer cs.mu.Unlock() + cs.loadAllLocked() +} + +func (cs *CourseStore) GetObstacle(roomID int) *ObstacleInfo { + cs.mu.Lock() + defer cs.mu.Unlock() + if !cs.loaded { + cs.loadAllLocked() + } + return cs.roomToObstacle[roomID] +} + +func (cs *CourseStore) loadAllLocked() { + cs.loaded = true + cs.roomToObstacle = make(map[int]*ObstacleInfo) + localVerbs := make(map[string]bool) + + action.WalkYAMLDir(filepath.Join(cs.dataDir, "courses"), func(path, id string, data []byte) error { + var cfg CourseConfig + if err := yaml.Unmarshal(data, &cfg); err != nil { + return nil + } + cs.courses[cfg.ID] = &cfg + + totalObstacles := len(cfg.Obstacles) + for i, obs := range cfg.Obstacles { + nextRoom := 0 + if i < totalObstacles-1 { + nextRoom = cfg.Obstacles[i+1].RoomID + } + + completionXP := 0 + if i == totalObstacles-1 { + completionXP = cfg.CompletionXP + } + + info := &ObstacleInfo{ + CourseID: cfg.ID, + CourseName: cfg.Name, + ObstacleIndex: i, + TotalObstacles: totalObstacles, + Verb: obs.Verb, + Messages: obs.Messages, + TicksPerPhase: obs.TicksPerPhase, + ObstacleXP: obs.XP, + CompletionXP: completionXP, + FailDamage: obs.FailDamage, + NextRoom: nextRoom, + StartRoom: cfg.StartRoom, + RequiredLevel: cfg.RequiredLevel, + } + cs.roomToObstacle[obs.RoomID] = info + localVerbs[obs.Verb] = true + } + return nil + }) + + obstacleVerbs = localVerbs +} diff --git a/internal/game/equip_stats.go b/internal/game/core_equip.go index 02b8348..02b8348 100644 --- a/internal/game/equip_stats.go +++ b/internal/game/core_equip.go diff --git a/internal/game/player_flags.go b/internal/game/core_flags.go index 6595cc4..6595cc4 100644 --- a/internal/game/player_flags.go +++ b/internal/game/core_flags.go diff --git a/internal/game/hacking.go b/internal/game/core_hacking.go index 3457728..3457728 100644 --- a/internal/game/hacking.go +++ b/internal/game/core_hacking.go diff --git a/internal/game/login_account.go b/internal/game/core_login_account.go index 87f8c62..87f8c62 100644 --- a/internal/game/login_account.go +++ b/internal/game/core_login_account.go diff --git a/internal/game/login_char.go b/internal/game/core_login_char.go index 84f146b..84f146b 100644 --- a/internal/game/login_char.go +++ b/internal/game/core_login_char.go diff --git a/internal/game/messages.go b/internal/game/core_messages.go index 1c9e85a..1c9e85a 100644 --- a/internal/game/messages.go +++ b/internal/game/core_messages.go diff --git a/internal/game/core_production.go b/internal/game/core_production.go new file mode 100644 index 0000000..227c4ad --- /dev/null +++ b/internal/game/core_production.go @@ -0,0 +1,803 @@ +package game + +import ( + "fmt" + "math/rand" + "sort" + "strconv" + "strings" + + "thehouseoficarus/internal/action" + "thehouseoficarus/internal/color" + "thehouseoficarus/internal/engine" + "thehouseoficarus/internal/net" + "thehouseoficarus/internal/object" + "thehouseoficarus/internal/player" + +) + +func (g *Game) startProduction(sess *net.Session, p *player.Player, recipe *action.RecipeDef, actionType, displayVerb, startMsg, endMsg string, count int) { + g.cancelAction(p) + g.cancelBackgroundAction(p) + + skill := recipe.EffectiveSkill() + if skill != "" { + skillLevel := p.Level(player.SkillName(skill)) + if skillLevel < recipe.Level { + sess.WriteLine(fmt.Sprintf("You need level %d %s to do that.", recipe.Level, skill)) + g.reprompt(sess) + return + } + } + + if !recipe.HasAllItemsQty(p.CountItem) { + sess.WriteLine("You don't have the required materials.") + g.reprompt(sess) + return + } + + outDef, _ := g.ItemStore.Load(recipe.Output) + + wait := recipe.Wait + if wait <= 0 { + wait = 4 + } + + outputName := recipe.Output + if outDef != nil { + outputName = outDef.Name + } + + p.Action = &action.Action{ + Type: actionType, + TargetID: recipe.ID, + TargetName: outputName, + Data: map[string]any{ + "recipe_id": recipe.ID, + "phase": 0, + "wait": wait, + "start_msg": startMsg, + "end_msg": endMsg, + "remaining": count, + }, + WaitLeft: engine.ToTicks(1), + } + + p.ActionState = &ActionState{Type: ActionProducing, TargetName: outputName, Verb: displayVerb} + + if g.Hub != nil { + for _, other := range g.Hub.PlayersInRoom(p.RoomID) { + if other != sess && other.Player != nil { + other.WriteLine(g.colorize(other, "broadcast", fmt.Sprintf("\n%s starts %s.", p.Name, displayVerb))) + } + } + } +} + +func (g *Game) startProductionFromRecipe(sess *net.Session, p *player.Player, recipe *action.RecipeDef, count int) { + _, stationName := g.findStation(p.RoomID, recipe.Station) + if stationName == "" { + stationName = "inventory" + } + + firstItem := recipe.FirstItemName(func(id string) (string, bool) { + def, err := g.ItemStore.Load(id) + if err != nil { + return id, false + } + return def.Name, true + }) + + info, ok := productionTypes[recipe.Type] + if !ok { + info = productionTypeInfo{recipe.Type, recipe.Type} + } + actionType := info.ActionType + displayVerb := info.DisplayVerb + + var startMsg, endMsg string + if stationName != "inventory" { + startMsg = fmt.Sprintf("You start %s %s on the %s.", displayVerb, firstItem, stationName) + } else { + startMsg = fmt.Sprintf("You start %s %s.", displayVerb, firstItem) + } + endMsg = fmt.Sprintf("You've finished %s.", displayVerb) + + g.startProduction(sess, p, recipe, actionType, displayVerb, startMsg, endMsg, count) +} + +func (g *Game) loadProductionRecipe(recipeID string) *action.RecipeDef { + all, err := g.RecipeStore.LoadAll() + if err == nil { + for _, r := range all { + if r.ID == recipeID { + return &r + } + } + } + if strings.HasPrefix(recipeID, "combine_") { + itemID := strings.TrimPrefix(recipeID, "combine_") + if itemDef, err := g.ItemStore.Load(itemID); err == nil && len(itemDef.MadeFrom) > 0 { + return g.buildCombineRecipe(itemDef) + } + } + return nil +} + +func (g *Game) advanceProduction(sess *net.Session, p *player.Player) bool { + recipeID := p.Action.Data["recipe_id"].(string) + phase := p.Action.Data["phase"].(int) + wait := p.Action.Data["wait"].(float64) + startMsg, _ := p.Action.Data["start_msg"].(string) + endMsg, _ := p.Action.Data["end_msg"].(string) + remaining, _ := p.Action.Data["remaining"].(int) + + recipe := g.loadProductionRecipe(recipeID) + if recipe == nil { + g.cancelAction(p) + return false + } + + if phase == 0 { + if startMsg != "" { + sess.WriteLine(fmt.Sprintf("\n%s", startMsg)) + } + p.Action.Data["phase"] = 1 + p.Action.WaitLeft = engine.ToTicks(wait) + return true + } + + skill := recipe.EffectiveSkill() + skillLevel := p.Level(player.SkillName(skill)) + chance := 1.0 + if recipe.Success != nil { + chance = action.SuccessChance(*recipe.Success, skillLevel, recipe.Level) + } + + if rand.Float64() < chance { + outputQty := recipe.OutputQty + if outputQty <= 0 { + outputQty = 1 + } + + byproducts := g.collectByproducts(p, recipe) + + placed := false + outDef, _ := g.ItemStore.Load(recipe.Output) + if outDef != nil && outDef.Stackable { + for i := 0; i < 28; i++ { + slot := p.InvSlot(i) + if slot != nil && slot.ItemID == recipe.Output { + recipe.ConsumeAll(p.HasItem, p.RemoveItem) + slot.Quantity += outputQty + placed = true + break + } + } + } + if !placed { + recipe.ConsumeAll(p.HasItem, p.RemoveItem) + freeSlot := p.FirstFreeSlot() + if freeSlot == -1 { + sess.WriteLine("Your inventory is too full!") + g.cancelAction(p) + return false + } + p.SetInvSlot(freeSlot, &player.InventorySlot{ItemID: recipe.Output, Quantity: outputQty}) + } + + for _, bp := range byproducts { + if slot := p.FirstFreeSlot(); slot >= 0 { + p.SetInvSlot(slot, &player.InventorySlot{ItemID: bp, Quantity: 1}) + } + } + + if recipe.XP > 0 { + if newLevel := p.AddSkillXP(player.SkillName(skill), recipe.XP); newLevel > 0 { + sess.WriteLine(g.colorize(sess, "level_up", fmt.Sprintf("*** You are now level %d %s! ***", newLevel, skill))) + } + } + g.AccountStore.SaveCharacter(p) + + msg := recipe.Message + if msg == "" { + outputName := recipe.Output + if outDef != nil { + outputName = outDef.Name + } + msg = fmt.Sprintf("You produce %s.", outputName) + } + if p.OptionBool("xp_drops") && recipe.XP > 0 { + abbr := player.SkillAbbr[player.SkillName(skill)] + msg += g.colorize(sess, "xp", fmt.Sprintf(" (+%dxp %s)", recipe.XP, abbr)) + } + sess.WriteLine(msg) + } else { + recipe.ConsumeAll(p.HasItem, p.RemoveItem) + + if recipe.Fail != "" { + freeSlot := p.FirstFreeSlot() + if freeSlot >= 0 { + p.SetInvSlot(freeSlot, &player.InventorySlot{ItemID: recipe.Fail, Quantity: 1}) + } + } + g.AccountStore.SaveCharacter(p) + + msg := recipe.FailMessage + if msg == "" { + msg = "You fail and the materials are lost." + } + sess.WriteLine(g.colorize(sess, "damage", msg)) + } + + if remaining > 0 { + remaining-- + p.Action.Data["remaining"] = remaining + if remaining <= 0 { + if endMsg != "" { + sess.WriteLine(fmt.Sprintf("\n%s", endMsg)) + } + g.cancelAction(p) + return false + } + } + + if g.canContinueProduction(p, recipe) { + p.Action.WaitLeft = engine.ToTicks(wait) + return true + } + + if endMsg != "" { + sess.WriteLine(fmt.Sprintf("\n%s", endMsg)) + } + g.cancelAction(p) + return false +} + +func (g *Game) collectByproducts(p *player.Player, recipe *action.RecipeDef) []string { + var byproducts []string + for _, e := range recipe.Consume { + if len(e.Byproducts) == 0 { + continue + } + for i, id := range e.Items { + if p.HasItem(id) && i < len(e.Byproducts) && e.Byproducts[i] != "" { + byproducts = append(byproducts, e.Byproducts[i]) + break + } + } + } + return byproducts +} + +func (g *Game) canContinueProduction(p *player.Player, recipe *action.RecipeDef) bool { + if !recipe.HasAllItemsQty(p.CountItem) { + return false + } + outputQty := recipe.OutputQty + if outputQty <= 0 { + outputQty = 1 + } + outDef, _ := g.ItemStore.Load(recipe.Output) + if outDef != nil && outDef.Stackable { + for i := 0; i < 28; i++ { + slot := p.InvSlot(i) + if slot != nil && slot.ItemID == recipe.Output { + return true + } + } + } + return p.FirstFreeSlot() >= 0 +} + +func (g *Game) handleRecipeChoice(sess *net.Session, input string) { + input = strings.TrimSpace(input) + + menuData := sess.PendingMenu + if len(menuData) == 0 { + sess.State = net.StateGame + g.reprompt(sess) + return + } + + if input == "" { + sess.PendingMenu = nil + sess.State = net.StateGame + sess.WriteLine("Never mind.") + g.reprompt(sess) + return + } + + if choice, err := strconv.Atoi(input); err == nil { + sess.PendingMenu = nil + sess.State = net.StateGame + if choice <= 0 || choice > len(menuData) { + sess.WriteLine("Never mind.") + g.reprompt(sess) + return + } + g.dispatchMenuEntry(sess, menuData[choice-1]) + return + } + + lower := strings.ToLower(input) + matchIdx := -1 + for i, entry := range menuData { + name := g.menuEntryName(entry) + if name == "" { + continue + } + if strings.ToLower(name) == lower || action.WordPrefixMatch(input, name) { + if matchIdx >= 0 { + sess.WriteLine("That's ambiguous.") + return + } + matchIdx = i + } + } + if matchIdx >= 0 { + sess.PendingMenu = nil + sess.State = net.StateGame + g.dispatchMenuEntry(sess, menuData[matchIdx]) + return + } + + sess.PendingMenu = nil + sess.State = net.StateGame + sess.WriteLine("Never mind.") + g.reprompt(sess) +} + +func (g *Game) menuEntryName(entry map[string]string) string { + if rid, ok := entry["recipe_id"]; ok { + all, _ := g.RecipeStore.LoadAll() + for _, r := range all { + if r.ID == rid { + if def, err := g.ItemStore.Load(r.Output); err == nil { + return def.Name + } + return r.Output + } + } + } + if rid, ok := entry["fletch_recipe_id"]; ok { + all, _ := g.RecipeStore.LoadAll() + for _, r := range all { + if r.ID == rid { + if def, err := g.ItemStore.Load(r.Output); err == nil { + return def.Name + } + return r.Output + } + } + } + if barID, ok := entry["bar_id"]; ok { + if def, _ := g.ItemStore.Load(barID); def != nil { + return def.Name + } + return barID + } + if cid, ok := entry["combine_item"]; ok { + if def, _ := g.ItemStore.Load(cid); def != nil { + return def.Name + } + return cid + } + return "" +} + +func (g *Game) dispatchMenuEntry(sess *net.Session, entry map[string]string) { + if cid, ok := entry["combine_item"]; ok { + g.promptHowMany(sess, "combine_"+cid) + return + } + if barID, ok := entry["bar_id"]; ok { + p := sess.Player + allRecipes, _ := g.RecipeStore.LoadAll() + g.showSmithTable(sess, p, barID, allRecipes) + return + } + if rid, ok := entry["fletch_recipe_id"]; ok { + p := sess.Player + allRecipes, _ := g.RecipeStore.LoadAll() + for _, r := range allRecipes { + if r.ID == rid { + g.startFletchAction(sess, p, &r, 0) + return + } + } + g.reprompt(sess) + return + } + if rid, ok := entry["recipe_id"]; ok { + g.promptHowMany(sess, rid) + return + } + g.reprompt(sess) +} + +func (g *Game) formatRecipeMaterials(r *action.RecipeDef) string { + var parts []string + for _, e := range r.Consume { + itemName := e.Items[0] + if def, err := g.ItemStore.Load(e.Items[0]); err == nil { + itemName = def.Name + } + if e.Quantity > 1 { + parts = append(parts, fmt.Sprintf("%s x%d", itemName, e.Quantity)) + } else { + parts = append(parts, itemName) + } + } + return strings.Join(parts, ", ") +} + +func (g *Game) showProductionTable(sess *net.Session, p *player.Player, recipes []action.RecipeDef, title, skill, lastFlagKey, promptVerb string, background bool) { + sort.Slice(recipes, func(i, j int) bool { + return recipes[i].Level < recipes[j].Level + }) + + mode := g.colorMode(sess) + skillLevel := p.Level(player.SkillName(skill)) + dimSpec := color.Parse("240") + + tbl := &Table{ + Title: title, + Columns: []string{"#", "Product", "Materials", "Level"}, + } + + for i, r := range recipes { + outDef, _ := g.ItemStore.Load(r.Output) + productName := r.Output + if outDef != nil { + productName = outDef.Name + } + + outputQty := r.OutputQty + if outputQty <= 0 { + outputQty = 1 + } + if outDef != nil && outDef.Stackable && outputQty > 1 { + productName = fmt.Sprintf("%s x%d", productName, outputQty) + } + + matStr := g.formatRecipeMaterials(&r) + levelStr := fmt.Sprint(r.Level) + numStr := fmt.Sprintf("%d", i+1) + + canMake := skillLevel >= r.Level && r.HasAllItemsQty(p.CountItem) + if canMake { + productName = g.itemColorize(sess, outDef, productName) + } else { + productName = color.Render(mode, dimSpec, productName) + matStr = color.Render(mode, dimSpec, matStr) + levelStr = color.Render(mode, dimSpec, levelStr) + numStr = color.Render(mode, dimSpec, numStr) + } + + tbl.Rows = append(tbl.Rows, []string{numStr, productName, matStr, levelStr}) + } + + unicode := p.OptionBool("unicode") + sess.WriteLine("") + for _, line := range tbl.Render(unicode) { + sess.WriteLine(line) + } + + lastRecipeID, _ := p.Flags[lastFlagKey].(string) + hint := "" + if lastRecipeID != "" { + for _, r := range recipes { + if r.ID == lastRecipeID { + if outDef, err := g.ItemStore.Load(r.Output); err == nil { + hint = outDef.Name + } + break + } + } + } + + if hint != "" { + sess.Write(fmt.Sprintf("%s what (enter for all %s): ", promptVerb, hint)) + } else { + sess.Write(fmt.Sprintf("%s what: ", promptVerb)) + } + + sess.PendingMenu = recipeMenuData(recipeDefIDs(recipes)) + sess.PendingSkill = skill + sess.PendingLastFlag = lastFlagKey + sess.PendingBackground = background + sess.State = net.StateProductChoice +} + +func (g *Game) handleProductChoice(sess *net.Session, input string) { + p := sess.Player + menuData := sess.PendingMenu + skill := sess.PendingSkill + lastFlagKey := sess.PendingLastFlag + background := sess.PendingBackground + sess.PendingMenu = nil + sess.PendingSkill = "" + sess.PendingLastFlag = "" + sess.PendingBackground = false + sess.State = net.StateGame + + input = strings.TrimSpace(input) + + allRecipes, err := g.RecipeStore.LoadAll() + if err != nil { + g.reprompt(sess) + return + } + + var recipes []action.RecipeDef + for _, entry := range menuData { + rid := entry["recipe_id"] + for _, r := range allRecipes { + if r.ID == rid { + recipes = append(recipes, r) + break + } + } + } + + if len(recipes) == 0 { + g.reprompt(sess) + return + } + + sort.Slice(recipes, func(i, j int) bool { + return recipes[i].Level < recipes[j].Level + }) + + lastRecipeID, _ := p.Flags[lastFlagKey].(string) + + sel, errMsg := g.resolveRecipeByInput(input, recipes, lastRecipeID) + switch errMsg { + case "ambiguous": + sess.WriteLine("That's ambiguous.") + g.reprompt(sess) + return + case "never_mind": + sess.WriteLine("Never mind.") + g.reprompt(sess) + return + } + + skillLevel := p.Level(player.SkillName(skill)) + if skillLevel < sel.Recipe.Level { + sess.WriteLine(fmt.Sprintf("You need level %d %s to make that.", sel.Recipe.Level, skill)) + g.reprompt(sess) + return + } + if !sel.Recipe.HasAllItemsQty(p.CountItem) { + sess.WriteLine("You don't have the materials for that.") + g.reprompt(sess) + return + } + + p.EnsureFlags() + p.Flags[lastFlagKey] = sel.Recipe.ID + g.AccountStore.SaveCharacter(p) + + if background { + g.startFletchAction(sess, p, sel.Recipe, sel.Count) + } else { + g.startProductionFromRecipe(sess, p, sel.Recipe, sel.Count) + } +} + +func (g *Game) hasToolType(p *player.Player, toolType string) bool { + if itemID, ok := p.Equipment[object.SlotMainHand]; ok { + if def, err := g.ItemStore.Load(itemID); err == nil && def.ToolType == toolType { + return true + } + } + for i := 0; i < 28; i++ { + slot := p.InvSlot(i) + if slot == nil { + continue + } + if def, err := g.ItemStore.Load(slot.ItemID); err == nil && def.ToolType == toolType { + return true + } + } + return false +} +type recipeEntry struct { + ItemName string + Recipe action.RecipeDef +} + +type productionTypeInfo struct { + ActionType string + DisplayVerb string +} + +var productionTypes = map[string]productionTypeInfo{ + "cooking": {"cook", "cooking"}, + "smelting": {"smelt", "smelting"}, + "smithing": {"smith", "smithing"}, + "crafting": {"craft", "crafting"}, + "combine": {"combine", "combining"}, + "fletching": {"fletch", "fletching"}, + "pharmacy": {"mix", "mixing"}, + "construction": {"construct", "constructing"}, +} + +var productionActionTypes map[string]bool + +func init() { + productionActionTypes = make(map[string]bool) + for _, pt := range productionTypes { + productionActionTypes[pt.ActionType] = true + } +} + +func recipeMenuData(recipeIDs []string) []map[string]string { + out := make([]map[string]string, len(recipeIDs)) + for i, id := range recipeIDs { + out[i] = map[string]string{"recipe_id": id} + } + return out +} + +func recipeDefIDs(defs []action.RecipeDef) []string { + ids := make([]string, len(defs)) + for i, d := range defs { + ids[i] = d.ID + } + return ids +} + +func entryMenuData(entries []recipeEntry) []map[string]string { + out := make([]map[string]string, len(entries)) + for i, e := range entries { + out[i] = map[string]string{"recipe_id": e.Recipe.ID} + } + return out +} + +func (g *Game) promptHowMany(sess *net.Session, recipeID string) { + sess.PendingRecipeID = recipeID + sess.State = net.StateHowMany + sess.Write("How many (return for all)?: ") +} + +type recipeSelection struct { + Recipe *action.RecipeDef + Count int +} + +func (g *Game) resolveRecipeByInput(input string, recipes []action.RecipeDef, lastRecipeID string) (sel recipeSelection, errMsg string) { + if input == "" { + if lastRecipeID == "" { + return sel, "never_mind" + } + for i := range recipes { + if recipes[i].ID == lastRecipeID { + sel.Recipe = &recipes[i] + return sel, "" + } + } + return sel, "never_mind" + } + + qty, productName := parseQty(input) + productName = strings.TrimSpace(productName) + + if idx, err := strconv.Atoi(productName); err == nil && idx > 0 && idx <= len(recipes) { + sel.Recipe = &recipes[idx-1] + sel.Count = qty + return sel, "" + } + + matchCount := 0 + for i := range recipes { + outDef, _ := g.ItemStore.Load(recipes[i].Output) + name := recipes[i].Output + if outDef != nil { + name = outDef.Name + } + if action.WordPrefixMatch(productName, name) { + if matchCount == 0 { + sel.Recipe = &recipes[i] + sel.Count = qty + } + matchCount++ + } + } + if matchCount > 1 { + return sel, "ambiguous" + } + if sel.Recipe == nil { + return sel, "never_mind" + } + return sel, "" +} + +func (g *Game) showMenuTable(sess *net.Session, title string, names []string) { + p := sess.Player + tbl := &Table{Title: title} + for i, name := range names { + tbl.Rows = append(tbl.Rows, []string{fmt.Sprintf("%d", i+1), name}) + } + unicode := p.OptionBool("unicode") + sess.WriteLine("") + for _, line := range tbl.Render(unicode) { + sess.WriteLine(line) + } +} + +func (g *Game) handleHowMany(sess *net.Session, input string) { + p := sess.Player + recipeID := sess.PendingRecipeID + sess.PendingRecipeID = "" + sess.State = net.StateGame + + input = strings.TrimSpace(input) + + var count int + if input == "" { + count = 0 + } else if n, err := strconv.Atoi(input); err == nil && n > 0 { + count = n + } else { + sess.WriteLine("Never mind.") + g.reprompt(sess) + return + } + + var recipe *action.RecipeDef + if strings.HasPrefix(recipeID, "combine_") { + itemID := strings.TrimPrefix(recipeID, "combine_") + itemDef, err := g.ItemStore.Load(itemID) + if err != nil || len(itemDef.MadeFrom) == 0 { + g.reprompt(sess) + return + } + recipe = g.buildCombineRecipe(itemDef) + } else { + all, err := g.RecipeStore.LoadAll() + if err != nil { + g.reprompt(sess) + return + } + for _, r := range all { + if r.ID == recipeID { + recipe = &r + break + } + } + } + + if recipe == nil { + g.reprompt(sess) + return + } + + g.startProductionFromRecipe(sess, p, recipe, count) +} + +func (g *Game) buildCombineRecipe(def *object.ItemDef) *action.RecipeDef { + var consume []action.ConsumeEntry + for _, mf := range def.MadeFrom { + consume = append(consume, action.ConsumeEntry{ + Items: mf.Items, + Quantity: mf.Quantity, + Byproducts: mf.Byproducts, + }) + } + wait := def.Ticks + if wait <= 0 { + wait = 2 + } + return &action.RecipeDef{ + ID: "combine_" + def.ID, + Type: "combine", + Wait: wait, + Consume: consume, + Output: def.ID, + Message: fmt.Sprintf("You create %s.", def.Name), + } +} diff --git a/internal/game/core_skill.go b/internal/game/core_skill.go new file mode 100644 index 0000000..c02cdf3 --- /dev/null +++ b/internal/game/core_skill.go @@ -0,0 +1,15 @@ +package game + +import ( + "fmt" + + "thehouseoficarus/internal/net" + "thehouseoficarus/internal/player" +) + +func (g *Game) awardSkillXP(sess *net.Session, p *player.Player, skill player.SkillName, xp int) { + newLevel := p.AddSkillXP(skill, xp) + if newLevel > 0 { + sess.WriteLine(g.colorize(sess, "level_up", fmt.Sprintf("*** You are now level %d %s! ***", newLevel, skill))) + } +} diff --git a/internal/game/core_startup.go b/internal/game/core_startup.go new file mode 100644 index 0000000..ab52762 --- /dev/null +++ b/internal/game/core_startup.go @@ -0,0 +1,770 @@ +package game + +import ( + "fmt" + "os" + "path/filepath" + "sort" + "strings" + + "thehouseoficarus/internal/action" +) + +type StartupIssue struct { + Level string + Type string + Message string +} + +func (g *Game) ValidateStartup() []StartupIssue { + var issues []StartupIssue + + issues = append(issues, validateDuplicateIDs(g.DataDir, "items", "item")...) + issues = append(issues, validateDuplicateIDs(g.DataDir, "rooms", "room")...) + issues = append(issues, validateDuplicateIDs(g.DataDir, "mobs", "mob")...) + issues = append(issues, validateDuplicateIDs(g.DataDir, "objects", "object")...) + issues = append(issues, validateDuplicateIDs(g.DataDir, "drops", "drop table")...) + issues = append(issues, validateDuplicateIDs(g.DataDir, "recipes", "recipe")...) + issues = append(issues, validateDuplicateIDs(g.DataDir, "courses", "course")...) + issues = append(issues, validateDuplicateIDs(g.DataDir, "modules", "module")...) + issues = append(issues, validateDuplicateIDs(g.DataDir, "help", "help topic")...) + + issues = append(issues, validateRoomReferences(g)...) + issues = append(issues, validateMobReferences(g)...) + issues = append(issues, validateObjectReferences(g)...) + issues = append(issues, validateItemReferences(g)...) + issues = append(issues, validateRecipeReferences(g)...) + issues = append(issues, validateDropTableReferences(g)...) + issues = append(issues, validateCourseReferences(g)...) + issues = append(issues, validateRoomWiring(g)...) + + return issues +} + +func validateDuplicateIDs(dataDir, subDir, label string) []StartupIssue { + dir := filepath.Join(dataDir, subDir) + dups := action.CheckDuplicateIDs(dir) + var issues []StartupIssue + for _, d := range dups { + short := make([]string, len(d.Paths)) + for i, p := range d.Paths { + short[i] = strings.TrimPrefix(p, dir+"/") + } + issues = append(issues, StartupIssue{ + Level: "ERROR", + Type: "duplicate", + Message: fmt.Sprintf("Duplicate %s ID %q found in: %s", + label, d.ID, strings.Join(short, ", ")), + }) + } + return issues +} + +func validateRoomReferences(g *Game) []StartupIssue { + var issues []StartupIssue + roomIndex := g.World.RoomIndex() + itemIDs := g.ItemStore.IDSet() + mobIDs := g.MobStore.AllDefIDs() + objIDs := g.ObjectStore.IDSet() + + for id := range roomIndex { + room, err := g.World.LoadRoom(id) + if err != nil { + issues = append(issues, StartupIssue{ + Level: "ERROR", + Type: "reference", + Message: fmt.Sprintf("Room %d: failed to load: %v", id, err), + }) + continue + } + if room.Name == "" { + issues = append(issues, StartupIssue{ + Level: "WARN", + Type: "reference", + Message: fmt.Sprintf("Room %d: has no name", id), + }) + } + + for dir, exit := range room.Exits { + if exit.Room <= 0 { + continue + } + if _, ok := roomIndex[exit.Room]; !ok { + issues = append(issues, StartupIssue{ + Level: "ERROR", + Type: "reference", + Message: fmt.Sprintf("Room %d: exit %q targets nonexistent room %d", + id, dir, exit.Room), + }) + } + } + + for _, rm := range room.Mobs { + if rm.ID == "" { + continue + } + if _, ok := mobIDs[rm.ID]; !ok { + issues = append(issues, StartupIssue{ + Level: "ERROR", + Type: "reference", + Message: fmt.Sprintf("Room %d: references nonexistent mob %q", + id, rm.ID), + }) + } + for _, wr := range rm.WanderRooms { + if _, ok := roomIndex[wr]; !ok { + issues = append(issues, StartupIssue{ + Level: "ERROR", + Type: "reference", + Message: fmt.Sprintf("Room %d: mob %q wander_rooms references nonexistent room %d", + id, rm.ID, wr), + }) + } + } + } + + for _, s := range room.ItemSpawns { + if s.ID != "" && !itemIDs[s.ID] { + issues = append(issues, StartupIssue{ + Level: "ERROR", + Type: "reference", + Message: fmt.Sprintf("Room %d: spawns nonexistent item %q", + id, s.ID), + }) + } + } + + for _, robj := range room.Objects { + if robj.ID != "" && !objIDs[robj.ID] { + issues = append(issues, StartupIssue{ + Level: "ERROR", + Type: "reference", + Message: fmt.Sprintf("Room %d: references nonexistent object %q", + id, robj.ID), + }) + } + for _, wr := range robj.WanderRooms { + if _, ok := roomIndex[wr]; !ok { + issues = append(issues, StartupIssue{ + Level: "ERROR", + Type: "reference", + Message: fmt.Sprintf("Room %d: object %q wander_rooms references nonexistent room %d", + id, robj.ID, wr), + }) + } + } + } + } + + return issues +} + +func validateMobReferences(g *Game) []StartupIssue { + var issues []StartupIssue + itemIDs := g.ItemStore.IDSet() + dropIDs := dropTableIDSet(g.DataDir) + mobIDs := g.MobStore.AllDefIDs() + + for id := range mobIDs { + def, err := g.MobStore.LoadDef(id) + if err != nil { + issues = append(issues, StartupIssue{ + Level: "ERROR", + Type: "reference", + Message: fmt.Sprintf("Mob %q: failed to load: %v", id, err), + }) + continue + } + if def.Name == "" { + issues = append(issues, StartupIssue{ + Level: "WARN", + Type: "reference", + Message: fmt.Sprintf("Mob %q: has no name", id), + }) + } + + if def.Drops.Remains != "" && !itemIDs[def.Drops.Remains] { + issues = append(issues, StartupIssue{ + Level: "ERROR", + Type: "reference", + Message: fmt.Sprintf("Mob %q: drops remains (item %q) does not exist", + id, def.Drops.Remains), + }) + } + + for _, d := range def.Drops.Loot { + if d.ItemID != "" && !itemIDs[d.ItemID] { + issues = append(issues, StartupIssue{ + Level: "ERROR", + Type: "reference", + Message: fmt.Sprintf("Mob %q: loot item %q does not exist", + id, d.ItemID), + }) + } + if d.Table != "" && !dropIDs[d.Table] { + issues = append(issues, StartupIssue{ + Level: "ERROR", + Type: "reference", + Message: fmt.Sprintf("Mob %q: loot table %q does not exist", + id, d.Table), + }) + } + } + + if def.StealTable != "" && !dropIDs[def.StealTable] { + issues = append(issues, StartupIssue{ + Level: "ERROR", + Type: "reference", + Message: fmt.Sprintf("Mob %q: steal_table %q does not exist", + id, def.StealTable), + }) + } + + if def.FinishingBlow != "" && !itemIDs[def.FinishingBlow] { + issues = append(issues, StartupIssue{ + Level: "ERROR", + Type: "reference", + Message: fmt.Sprintf("Mob %q: finishing_blow item %q does not exist", + id, def.FinishingBlow), + }) + } + } + + return issues +} + +func validateObjectReferences(g *Game) []StartupIssue { + var issues []StartupIssue + objIDs := g.ObjectStore.IDSet() + itemIDs := g.ItemStore.IDSet() + mobIDs := g.MobStore.AllDefIDs() + dropIDs := dropTableIDSet(g.DataDir) + roomIndex := g.World.RoomIndex() + + for id := range objIDs { + obj, err := g.ObjectStore.Load(id) + if err != nil { + issues = append(issues, StartupIssue{ + Level: "ERROR", + Type: "reference", + Message: fmt.Sprintf("Object %q: failed to load: %v", id, err), + }) + continue + } + if obj.Name == "" { + issues = append(issues, StartupIssue{ + Level: "WARN", + Type: "reference", + Message: fmt.Sprintf("Object %q: has no name", id), + }) + } + + if obj.RemovalItem != "" && !itemIDs[obj.RemovalItem] { + issues = append(issues, StartupIssue{ + Level: "ERROR", + Type: "reference", + Message: fmt.Sprintf("Object %q: removal_item %q does not exist", + id, obj.RemovalItem), + }) + } + + if obj.StealTable != "" && !dropIDs[obj.StealTable] { + issues = append(issues, StartupIssue{ + Level: "ERROR", + Type: "reference", + Message: fmt.Sprintf("Object %q: steal_table %q does not exist", + id, obj.StealTable), + }) + } + + if obj.GuardMob != "" && !mobIDs[obj.GuardMob] { + issues = append(issues, StartupIssue{ + Level: "ERROR", + Type: "reference", + Message: fmt.Sprintf("Object %q: guard_mob %q does not exist", + id, obj.GuardMob), + }) + } + + for _, ui := range obj.UseInteractions { + if ui.Item != "" && !itemIDs[ui.Item] { + issues = append(issues, StartupIssue{ + Level: "ERROR", + Type: "reference", + Message: fmt.Sprintf("Object %q: use_interaction item %q does not exist", + id, ui.Item), + }) + } + if ui.Action != nil { + issues = append(issues, validateNodeAction(fmt.Sprintf("Object %q: use_interaction", id), ui.Action, itemIDs, roomIndex)...) + } + } + + if obj.Gather != nil { + issues = append(issues, validateGatherConfig(fmt.Sprintf("Object %q: gather", id), obj.Gather, itemIDs, dropIDs)...) + } + + if obj.Talk != nil { + issues = append(issues, validateTalkConfig(fmt.Sprintf("Object %q: talk", id), obj.Talk, itemIDs, roomIndex)...) + } + + if obj.Use != nil { + issues = append(issues, validateUseConfig(fmt.Sprintf("Object %q: use", id), obj.Use, itemIDs)...) + } + } + + return issues +} + +func validateItemReferences(g *Game) []StartupIssue { + var issues []StartupIssue + itemIDs := g.ItemStore.IDSet() + dropIDs := dropTableIDSet(g.DataDir) + + for id := range itemIDs { + def, err := g.ItemStore.Load(id) + if err != nil { + issues = append(issues, StartupIssue{ + Level: "ERROR", + Type: "reference", + Message: fmt.Sprintf("Item %q: failed to load: %v", id, err), + }) + continue + } + if def.Name == "" { + issues = append(issues, StartupIssue{ + Level: "WARN", + Type: "reference", + Message: fmt.Sprintf("Item %q: has no name", id), + }) + } + + if def.SearchTable != "" && !dropIDs[def.SearchTable] { + issues = append(issues, StartupIssue{ + Level: "ERROR", + Type: "reference", + Message: fmt.Sprintf("Item %q: search_table %q does not exist", + id, def.SearchTable), + }) + } + + if def.SearchMiscTable != "" && !dropIDs[def.SearchMiscTable] { + issues = append(issues, StartupIssue{ + Level: "ERROR", + Type: "reference", + Message: fmt.Sprintf("Item %q: search_misc_table %q does not exist", + id, def.SearchMiscTable), + }) + } + + for _, mf := range def.MadeFrom { + for _, item := range mf.Items { + if item != "" && !itemIDs[item] { + issues = append(issues, StartupIssue{ + Level: "ERROR", + Type: "reference", + Message: fmt.Sprintf("Item %q: made_from item %q does not exist", + id, item), + }) + } + } + for _, bp := range mf.Byproducts { + if bp != "" && !itemIDs[bp] { + issues = append(issues, StartupIssue{ + Level: "ERROR", + Type: "reference", + Message: fmt.Sprintf("Item %q: made_from byproduct %q does not exist", + id, bp), + }) + } + } + } + + if def.FarmProduct != "" && !itemIDs[def.FarmProduct] { + issues = append(issues, StartupIssue{ + Level: "ERROR", + Type: "reference", + Message: fmt.Sprintf("Item %q (seed): farm_product %q does not exist", + id, def.FarmProduct), + }) + } + } + + return issues +} + +func validateRecipeReferences(g *Game) []StartupIssue { + var issues []StartupIssue + itemIDs := g.ItemStore.IDSet() + + allRecipes, err := g.RecipeStore.LoadAll() + if err != nil { + issues = append(issues, StartupIssue{ + Level: "ERROR", + Type: "reference", + Message: fmt.Sprintf("Failed to load recipes: %v", err), + }) + return issues + } + + recipeIDs := make(map[string]bool) + for _, r := range allRecipes { + if r.ID != "" { + if recipeIDs[r.ID] { + issues = append(issues, StartupIssue{ + Level: "ERROR", + Type: "duplicate", + Message: fmt.Sprintf("Recipe %q: duplicate ID field (two recipe files with same ID value)", + r.ID), + }) + } + recipeIDs[r.ID] = true + } + + for _, e := range r.Consume { + for _, item := range e.Items { + if item != "" && !itemIDs[item] { + issues = append(issues, StartupIssue{ + Level: "ERROR", + Type: "reference", + Message: fmt.Sprintf("Recipe %q (%s): consumes nonexistent item %q", + r.ID, r.Type, item), + }) + } + } + } + + if r.Output != "" && !itemIDs[r.Output] { + issues = append(issues, StartupIssue{ + Level: "ERROR", + Type: "reference", + Message: fmt.Sprintf("Recipe %q (%s): output item %q does not exist", + r.ID, r.Type, r.Output), + }) + } + + if r.Fail != "" && !itemIDs[r.Fail] { + issues = append(issues, StartupIssue{ + Level: "ERROR", + Type: "reference", + Message: fmt.Sprintf("Recipe %q (%s): fail product %q does not exist", + r.ID, r.Type, r.Fail), + }) + } + } + + return issues +} + +func validateDropTableReferences(g *Game) []StartupIssue { + var issues []StartupIssue + dropIDs := dropTableIDSet(g.DataDir) + itemIDs := g.ItemStore.IDSet() + + for id := range dropIDs { + dt, err := action.LoadDropTable(g.DataDir, id) + if err != nil { + issues = append(issues, StartupIssue{ + Level: "ERROR", + Type: "reference", + Message: fmt.Sprintf("Drop table %q: failed to load: %v", id, err), + }) + continue + } + for _, d := range dt.Drops { + if d.ItemID != "" && !itemIDs[d.ItemID] { + issues = append(issues, StartupIssue{ + Level: "ERROR", + Type: "reference", + Message: fmt.Sprintf("Drop table %q: drops nonexistent item %q", + id, d.ItemID), + }) + } + if d.Table != "" && !dropIDs[d.Table] && d.Table != id { + issues = append(issues, StartupIssue{ + Level: "ERROR", + Type: "reference", + Message: fmt.Sprintf("Drop table %q: references nonexistent sub-table %q", + id, d.Table), + }) + } + } + } + + return issues +} + +func validateCourseReferences(g *Game) []StartupIssue { + var issues []StartupIssue + roomIndex := g.World.RoomIndex() + + courses := g.CourseStore.AllCourses() + for id, cfg := range courses { + if cfg.StartRoom > 0 { + if _, ok := roomIndex[cfg.StartRoom]; !ok { + issues = append(issues, StartupIssue{ + Level: "ERROR", + Type: "reference", + Message: fmt.Sprintf("Course %q: start_room %d does not exist", + id, cfg.StartRoom), + }) + } + } + for _, obs := range cfg.Obstacles { + if _, ok := roomIndex[obs.RoomID]; !ok { + issues = append(issues, StartupIssue{ + Level: "ERROR", + Type: "reference", + Message: fmt.Sprintf("Course %q: obstacle room %d does not exist", + id, obs.RoomID), + }) + } + } + } + + return issues +} + +func validateRoomWiring(g *Game) []StartupIssue { + var issues []StartupIssue + roomIndex := g.World.RoomIndex() + cfg := g.ValidationConfig + + sourceSet := make(map[int]bool) + for _, s := range cfg.CheckSources { + sourceSet[s] = true + } + + ignoreTo := make(map[int]bool) + for _, r := range cfg.IgnoreUnreachable { + ignoreTo[r] = true + } + + hasExitTo := make(map[int]bool) + for id := range roomIndex { + room, err := g.World.LoadRoom(id) + if err != nil { + continue + } + for _, exit := range room.Exits { + if exit.Room > 0 { + hasExitTo[exit.Room] = true + } + } + } + + var orphans []int + for id := range roomIndex { + if ignoreTo[id] { + continue + } + if sourceSet[id] { + continue + } + if !hasExitTo[id] { + orphans = append(orphans, id) + } + } + if len(orphans) > 0 { + sort.Ints(orphans) + var strs []string + for _, id := range orphans { + strs = append(strs, fmt.Sprintf("%d", id)) + } + issues = append(issues, StartupIssue{ + Level: "WARN", + Type: "integrity", + Message: fmt.Sprintf("Orphan rooms (no exit leads to them): %s", + strings.Join(strs, ", ")), + }) + } + + return issues +} + +func validateGatherConfig(prefix string, cfg *action.GatherConfig, itemIDs map[string]bool, dropIDs map[string]bool) []StartupIssue { + var issues []StartupIssue + + if cfg.Bait != "" && !itemIDs[cfg.Bait] { + issues = append(issues, StartupIssue{ + Level: "ERROR", + Type: "reference", + Message: fmt.Sprintf("%s: bait item %q does not exist", + prefix, cfg.Bait), + }) + } + + for _, d := range cfg.Drops { + if d.ItemID != "" && !itemIDs[d.ItemID] { + issues = append(issues, StartupIssue{ + Level: "ERROR", + Type: "reference", + Message: fmt.Sprintf("%s: drop item %q does not exist", + prefix, d.ItemID), + }) + } + if d.Table != "" && !dropIDs[d.Table] { + issues = append(issues, StartupIssue{ + Level: "ERROR", + Type: "reference", + Message: fmt.Sprintf("%s: drop table %q does not exist", + prefix, d.Table), + }) + } + } + + return issues +} + +func validateTalkConfig(prefix string, cfg *action.TalkConfig, itemIDs map[string]bool, roomIndex map[int]bool) []StartupIssue { + var issues []StartupIssue + if cfg == nil { + return issues + } + for nodeID, node := range cfg.Nodes { + nodePrefix := fmt.Sprintf("%s: node %q", prefix, nodeID) + if node.Action != nil { + issues = append(issues, validateNodeAction(nodePrefix, node.Action, itemIDs, roomIndex)...) + } + } + return issues +} + +func validateUseConfig(prefix string, cfg *action.UseConfig, itemIDs map[string]bool) []StartupIssue { + var issues []StartupIssue + if cfg == nil { + return issues + } + + for itemID := range cfg.Consume { + if itemID != "" && !itemIDs[itemID] { + issues = append(issues, StartupIssue{ + Level: "ERROR", + Type: "reference", + Message: fmt.Sprintf("%s: consumes nonexistent item %q", + prefix, itemID), + }) + } + } + + if cfg.Reward.ItemID != "" && !itemIDs[cfg.Reward.ItemID] { + issues = append(issues, StartupIssue{ + Level: "ERROR", + Type: "reference", + Message: fmt.Sprintf("%s: reward item %q does not exist", + prefix, cfg.Reward.ItemID), + }) + } + + return issues +} + +func validateNodeAction(prefix string, na *action.NodeAction, itemIDs map[string]bool, roomIndex map[int]bool) []StartupIssue { + var issues []StartupIssue + if na == nil { + return issues + } + + if na.GiveItem != "" && !itemIDs[na.GiveItem] { + issues = append(issues, StartupIssue{ + Level: "ERROR", + Type: "reference", + Message: fmt.Sprintf("%s: give_item %q does not exist", + prefix, na.GiveItem), + }) + } + + if na.TakeItem != "" && !itemIDs[na.TakeItem] { + issues = append(issues, StartupIssue{ + Level: "ERROR", + Type: "reference", + Message: fmt.Sprintf("%s: take_item %q does not exist", + prefix, na.TakeItem), + }) + } + + if na.Teleport > 0 { + if _, ok := roomIndex[na.Teleport]; !ok { + issues = append(issues, StartupIssue{ + Level: "ERROR", + Type: "reference", + Message: fmt.Sprintf("%s: teleport to nonexistent room %d", + prefix, na.Teleport), + }) + } + } + + if na.Shop != nil { + for _, si := range na.Shop.Items { + if si.ItemID != "" && !itemIDs[si.ItemID] { + issues = append(issues, StartupIssue{ + Level: "ERROR", + Type: "reference", + Message: fmt.Sprintf("%s: shop item %q does not exist", + prefix, si.ItemID), + }) + } + } + } + + return issues +} + +func dropTableIDSet(dataDir string) map[string]bool { + dir := filepath.Join(dataDir, "drops") + ids := make(map[string]bool) + action.WalkYAMLDir(dir, func(path, id string, data []byte) error { + ids[id] = true + return nil + }) + return ids +} + +func (cs *CourseStore) AllCourses() map[string]*CourseConfig { + cs.mu.Lock() + defer cs.mu.Unlock() + if !cs.loaded { + cs.loadAllLocked() + } + return cs.courses +} + +func (g *Game) ValidateAndLog() { + LogStartupIssues(g.ValidateStartup()) +} + +func LogStartupIssues(issues []StartupIssue) { + if len(issues) == 0 { + fmt.Fprintf(os.Stderr, "Startup validation: OK\n") + return + } + + errors := 0 + warns := 0 + for _, issue := range issues { + if issue.Level == "ERROR" { + errors++ + } else { + warns++ + } + } + + fmt.Fprintf(os.Stderr, "\n=== Startup Validation: %d error(s), %d warning(s) ===\n\n", errors, warns) + + sort.Slice(issues, func(i, j int) bool { + if issues[i].Level != issues[j].Level { + return issues[i].Level == "ERROR" + } + return issues[i].Message < issues[j].Message + }) + + for _, issue := range issues { + tag := fmt.Sprintf("[%s]", issue.Level) + fmt.Fprintf(os.Stderr, " %-7s %s\n", tag, issue.Message) + } + fmt.Fprintln(os.Stderr) + + if errors > 0 { + fmt.Fprintf(os.Stderr, "*** %d startup errors detected. The server may behave unexpectedly. ***\n", errors) + } +}
\ No newline at end of file diff --git a/internal/game/stations.go b/internal/game/core_stations.go index d30a35c..d30a35c 100644 --- a/internal/game/stations.go +++ b/internal/game/core_stations.go diff --git a/internal/game/types.go b/internal/game/core_types.go index d41b18a..d41b18a 100644 --- a/internal/game/types.go +++ b/internal/game/core_types.go diff --git a/internal/game/core_utils.go b/internal/game/core_utils.go new file mode 100644 index 0000000..409422e --- /dev/null +++ b/internal/game/core_utils.go @@ -0,0 +1,116 @@ +package game + +import ( + "fmt" + "math/rand" + "strconv" + "strings" + + "thehouseoficarus/internal/net" + "thehouseoficarus/internal/player" + "thehouseoficarus/internal/world" +) + +func plural(n int) string { + if n == 1 { + return "" + } + return "s" +} + +func parseQty(input string) (int, string) { + parts := strings.Fields(input) + if len(parts) > 1 { + if n, err := strconv.Atoi(parts[0]); err == nil && n > 0 { + return n, strings.Join(parts[1:], " ") + } + } + return 0, input +} + +func parseChoiceIndex(s string) (int, error) { + var idx int + _, err := fmt.Sscanf(s, "%d", &idx) + return idx, err +} + +func mobDisplayName(m *world.MobInstance, definite bool) string { + if m.Unique { + return m.Name + } + if definite { + return "the " + m.Name + } + return "a " + m.Name +} + +func mobCombatLevel(m *world.MobInstance) int { + base := float64(m.Defense+m.MaxHP) / 4.0 + melee := float64(m.Attack+m.Strength) / 4.0 + ranged := float64(m.Ranged) * 3.0 / 8.0 + science := float64(m.Science) * 3.0 / 8.0 + best := melee + if ranged > best { + best = ranged + } + if science > best { + best = science + } + return int(base + best + 0.5) +} + +func uniqueItemNames(matches []itemMatch) []string { + seen := make(map[string]bool) + var out []string + for _, m := range matches { + if !seen[m.Name] { + seen[m.Name] = true + out = append(out, m.Name) + } + } + return out +} + +func (g *Game) showWhichOne(sess *net.Session, matches []itemMatch) { + sess.WriteLine("Which one?") + seen := make(map[string]bool) + for _, m := range matches { + if seen[m.Name] { + continue + } + seen[m.Name] = true + def, _ := g.ItemStore.Load(m.ID) + coloredName := g.itemColorize(sess, def, m.Name) + sess.WriteLine(fmt.Sprintf(" - %s", coloredName)) + } +} + +func randInt(max int) int { + if max <= 0 { + return 0 + } + return rand.Intn(max) +} + +func formatPickupList(sess *net.Session, picked []string) { + for i, name := range picked { + if i == len(picked)-1 { + sess.WriteLine(name) + } else if i == len(picked)-2 { + sess.Write(name + " and ") + } else { + sess.Write(name + ", ") + } + } +} + +func (g *Game) newInventorySlot(itemID string, qty int) *player.InventorySlot { + slot := &player.InventorySlot{ItemID: itemID, Quantity: qty} + if def, err := g.ItemStore.Load(itemID); err == nil && def.MaxQuality > 0 { + slot.Quality = def.Quality + slot.MaxQuality = def.MaxQuality + } + return slot +} + + diff --git a/internal/game/course.go b/internal/game/course.go deleted file mode 100644 index 335c97f..0000000 --- a/internal/game/course.go +++ /dev/null @@ -1,141 +0,0 @@ -package game - -import ( - "os" - "path/filepath" - "sync" - - "gopkg.in/yaml.v3" -) - -type ObstacleDef struct { - RoomID int `yaml:"room_id"` - Verb string `yaml:"verb"` - TicksPerPhase float64 `yaml:"ticks_per_phase"` - XP int `yaml:"xp"` - FailDamage [2]int `yaml:"fail_damage"` - Messages []string `yaml:"messages"` -} - -type CourseConfig struct { - ID string `yaml:"id"` - Name string `yaml:"name"` - RequiredLevel int `yaml:"required_level"` - StartRoom int `yaml:"start_room"` - CompletionXP int `yaml:"completion_xp"` - Obstacles []ObstacleDef `yaml:"obstacles"` -} - -type ObstacleInfo struct { - CourseID string - CourseName string - ObstacleIndex int - TotalObstacles int - Verb string - Messages []string - TicksPerPhase float64 - ObstacleXP int - CompletionXP int - FailDamage [2]int - NextRoom int - StartRoom int - RequiredLevel int -} - -var obstacleVerbs = map[string]bool{} - -var verbGerund = map[string]string{ - "scramble": "scrambling", - "jump": "jumping", - "swing": "swinging", - "balance": "balancing", - "climb": "climbing", - "crawl": "crawling", - "vault": "vaulting", - "leap": "leaping", - "slide": "sliding", -} - -type CourseStore struct { - dataDir string - mu sync.Mutex - courses map[string]*CourseConfig - roomToObstacle map[int]*ObstacleInfo - loaded bool -} - -func NewCourseStore(dataDir string) *CourseStore { - return &CourseStore{ - dataDir: dataDir, - courses: make(map[string]*CourseConfig), - } -} - -func (cs *CourseStore) LoadAll() { - cs.mu.Lock() - defer cs.mu.Unlock() - cs.loadAllLocked() -} - -func (cs *CourseStore) GetObstacle(roomID int) *ObstacleInfo { - cs.mu.Lock() - defer cs.mu.Unlock() - if !cs.loaded { - cs.loadAllLocked() - } - return cs.roomToObstacle[roomID] -} - -func (cs *CourseStore) loadAllLocked() { - cs.loaded = true - cs.roomToObstacle = make(map[int]*ObstacleInfo) - localVerbs := make(map[string]bool) - - pattern := filepath.Join(cs.dataDir, "courses", "*.yaml") - files, _ := filepath.Glob(pattern) - - for _, f := range files { - data, err := os.ReadFile(f) - if err != nil { - continue - } - var cfg CourseConfig - if err := yaml.Unmarshal(data, &cfg); err != nil { - continue - } - cs.courses[cfg.ID] = &cfg - - totalObstacles := len(cfg.Obstacles) - for i, obs := range cfg.Obstacles { - nextRoom := 0 - if i < totalObstacles-1 { - nextRoom = cfg.Obstacles[i+1].RoomID - } - - completionXP := 0 - if i == totalObstacles-1 { - completionXP = cfg.CompletionXP - } - - info := &ObstacleInfo{ - CourseID: cfg.ID, - CourseName: cfg.Name, - ObstacleIndex: i, - TotalObstacles: totalObstacles, - Verb: obs.Verb, - Messages: obs.Messages, - TicksPerPhase: obs.TicksPerPhase, - ObstacleXP: obs.XP, - CompletionXP: completionXP, - FailDamage: obs.FailDamage, - NextRoom: nextRoom, - StartRoom: cfg.StartRoom, - RequiredLevel: cfg.RequiredLevel, - } - cs.roomToObstacle[obs.RoomID] = info - localVerbs[obs.Verb] = true - } - } - - obstacleVerbs = localVerbs -} diff --git a/internal/game/death.go b/internal/game/death.go deleted file mode 100644 index d2c1b73..0000000 --- a/internal/game/death.go +++ /dev/null @@ -1,66 +0,0 @@ -package game - -import ( - "sort" - - "thehouseoficarus/internal/player" -) - -func (g *Game) dropItemsOnDeath(p *player.Player) { - roomID := p.RoomID - - if p.Credits > 0 { - g.World.AddGroundItem(roomID, "credits", p.Credits) - p.Credits = 0 - } - - var items []deathDrop - - for slot, inv := range p.Inventory { - if inv == nil || inv.Quantity <= 0 { - continue - } - val := 0 - if def, err := g.ItemStore.Load(inv.ItemID); err == nil { - val = def.Value * inv.Quantity - } - items = append(items, deathDrop{ - itemID: inv.ItemID, - quantity: inv.Quantity, - totalVal: val, - invSlot: slot, - }) - } - - for eqSlot, itemID := range p.Equipment { - val := 0 - if def, err := g.ItemStore.Load(itemID); err == nil { - val = def.Value - } - items = append(items, deathDrop{ - itemID: itemID, - quantity: 1, - totalVal: val, - isEquip: true, - equipSlot: eqSlot, - }) - } - - if len(items) <= 3 { - return - } - - sort.Slice(items, func(i, j int) bool { - return items[i].totalVal > items[j].totalVal - }) - - for i := 3; i < len(items); i++ { - it := items[i] - if it.isEquip { - delete(p.Equipment, it.equipSlot) - } else { - p.SetInvSlot(it.invSlot, nil) - } - g.World.AddGroundItem(roomID, it.itemID, it.quantity) - } -} diff --git a/internal/game/game.go b/internal/game/game.go index b8eadce..5d6e21e 100644 --- a/internal/game/game.go +++ b/internal/game/game.go @@ -35,18 +35,19 @@ type QueuedCommand struct { } type Game struct { - World *world.World - ObjectStore *object.ObjectStore - ItemStore *object.ItemStore - AccountStore *player.AccountStore - MobStore *world.MobStore - RecipeStore *action.RecipeStore - CourseStore *CourseStore - Hub *net.Hub - Ticks *engine.Engine - WorldFlags map[string]any - ColorConfig *config.ColorsConfig - DataDir string + World *world.World + ObjectStore *object.ObjectStore + ItemStore *object.ItemStore + AccountStore *player.AccountStore + MobStore *world.MobStore + RecipeStore *action.RecipeStore + CourseStore *CourseStore + Hub *net.Hub + Ticks *engine.Engine + WorldFlags map[string]any + ColorConfig *config.ColorsConfig + DataDir string + ValidationConfig config.StartupValidationConfig restTimers map[string]uint64 charsMu sync.Mutex loggedInChars map[string]*net.Session @@ -59,7 +60,7 @@ type Game struct { hackingStates map[string]*hacking.Session } -func New(dataDir string, colorConfig *config.ColorsConfig) *Game { +func New(dataDir string, colorConfig *config.ColorsConfig, valConfig config.StartupValidationConfig) *Game { g := &Game{ World: world.New(dataDir), ObjectStore: object.NewObjectStore(dataDir), @@ -72,6 +73,7 @@ func New(dataDir string, colorConfig *config.ColorsConfig) *Game { WorldFlags: make(map[string]any), ColorConfig: colorConfig, DataDir: dataDir, + ValidationConfig: valConfig, restTimers: make(map[string]uint64), loggedInChars: make(map[string]*net.Session), freeQueue: make(map[string][]QueuedCommand), @@ -83,6 +85,7 @@ func New(dataDir string, colorConfig *config.ColorsConfig) *Game { } g.CourseStore.LoadAll() g.LoadMods() + g.ValidateAndLog() return g } diff --git a/internal/game/help.go b/internal/game/help.go deleted file mode 100644 index 03e2b8c..0000000 --- a/internal/game/help.go +++ /dev/null @@ -1,155 +0,0 @@ -package game - -import ( - "fmt" - "os" - "path/filepath" - "strings" - - "thehouseoficarus/internal/net" - "gopkg.in/yaml.v3" -) - -type HelpDef struct { - Name string `yaml:"name"` - Category string `yaml:"category"` - Content string `yaml:"description"` -} - -type cmdEntry struct { - Name string - Type string - Desc string -} - -var commandList = []cmdEntry{ - {"alias", "Instant", "Create command shortcuts"}, - {"attack / kill", "Active", "Attack a mob"}, - {"autotrigger / auto", "Instant", "Set a module to auto-trigger"}, - {"bank", "Active", "Open bank interface"}, - {"burn", "Active", "Start a fire"}, - {"chop / cut", "Active", "Chop trees (Woodcutting)"}, - {"clean", "Free", "Clean grimy herbs (Pharmacy)"}, - {"color / colors", "Instant", "Customize display colors"}, - {"colortable", "Instant", "Display color reference chart"}, - {"construct / make", "Active", "Build furniture (Construction)"}, - {"cook", "Active", "Cook raw food on a fire or range"}, - {"craft", "Active", "Craft jewelry (Crafting)"}, - {"description / desc", "Instant", "Set your character description"}, - {"drink", "Free", "Drink a potion"}, - {"drop", "Active", "Drop items to the ground"}, - {"eat", "Free", "Eat food to restore hitpoints"}, - {"equipment / eq", "Instant", "Show equipped items"}, - {"exits", "Instant", "List available exits"}, - {"farm", "Active", "Farm crops (Farming)"}, - {"fish", "Active", "Fish at fishing spots (Fishing)"}, - {"fletch", "Free", "Fletch logs into bows (Fletching)"}, - {"get / take / pick", "Active", "Pick up items from the ground"}, - {"help", "Instant", "Show help topics"}, - {"id / identify", "Active", "Identify herbs (Pharmacy)"}, - {"inventory / i / inv", "Instant", "Show your inventory"}, - {"jack / jackin", "Active", "Jack into a terminal (Hacking)"}, - {"look / l", "Instant", "Look around or examine things"}, - {"map", "Instant", "Display an ASCII map of the area"}, - {"mine", "Active", "Mine rocks (Mining)"}, - {"mix", "Active", "Mix potions (Pharmacy)"}, - {"mods / modlist", "Instant", "List available science modules"}, - {"north / south / east / west / up / down", "Active", "Move in a direction"}, - {"option / options", "Instant", "View or change settings"}, - {"prompt", "Instant", "Set custom command prompt"}, - {"pull / push", "Active", "Interact with objects"}, - {"queued", "Instant", "Show pending tick actions"}, - {"quit", "Active", "Rest and disconnect"}, - {"remove / unwear / unwield", "Free", "Unequip items"}, - {"say", "Instant", "Chat with players in your room"}, - {"score / sc", "Instant", "View your stats and skills"}, - {"search", "Active", "Search items for loot"}, - {"smelt", "Active", "Smelt ore into bars (Smithing)"}, - {"smith", "Active", "Smith bars into items (Smithing)"}, - {"sneak", "Instant", "Toggle sneak mode"}, - {"steal", "Active", "Steal from mobs (Thieving)"}, - {"stoke", "Active", "Add logs to a fire"}, - {"style", "Instant", "Change combat style"}, - {"talk / speak / ask", "Active", "Talk to NPCs"}, - {"tech", "Instant", "Toggle technology abilities"}, - {"trigger", "Active", "Trigger a science module"}, - {"unalias", "Instant", "Remove command shortcuts"}, - {"use", "Active", "Use an object (crafting)"}, - {"walk", "Active", "Pathfind to a room or multi-step walk"}, - {"wear / wield", "Free", "Equip items"}, -} - -func LoadHelp(dataDir string) ([]HelpDef, error) { - dir := filepath.Join(dataDir, "help") - entries, err := os.ReadDir(dir) - if err != nil { - return nil, err - } - - var helps []HelpDef - for _, entry := range entries { - if entry.IsDir() || filepath.Ext(entry.Name()) != ".yaml" { - continue - } - data, err := os.ReadFile(filepath.Join(dir, entry.Name())) - if err != nil { - continue - } - var h HelpDef - if err := yaml.Unmarshal(data, &h); err != nil { - continue - } - helps = append(helps, h) - } - return helps, nil -} - -func (g *Game) doHelp(sess *net.Session, topic string) { - if topic == "" { - unicode := true - if p := sess.Player; p != nil { - unicode = p.OptionBool("unicode") - } - - sess.WriteLine("") - t := &Table{ - Title: "Commands", - Columns: []string{"Command", "Type", "Description"}, - } - for _, c := range commandList { - t.Rows = append(t.Rows, []string{c.Name, c.Type, c.Desc}) - } - for _, line := range t.Render(unicode) { - sess.WriteLine(line) - } - sess.WriteLine("") - sess.WriteLine("Command types: Instant (runs immediately), Free (queued before active),") - sess.WriteLine("Active (replaces current action, queued per tick).") - sess.WriteLine("") - sess.WriteLine("Use 'help <command>' for detailed usage of a specific command.") - sess.WriteLine("Use 'option' to view and change settings, 'color' to customize colors.") - return - } - - helps, err := LoadHelp(g.DataDir) - if err != nil || len(helps) == 0 { - sess.WriteLine("No help available.") - return - } - - topic = strings.ToLower(topic) - for _, h := range helps { - if strings.ToLower(h.Name) == topic { - sess.WriteLine(fmt.Sprintf("\n %s", h.Content)) - return - } - } - sess.WriteLine(fmt.Sprintf("No help found for '%s'.", topic)) -} - -func firstLine(s string) string { - if idx := strings.Index(s, "\n"); idx >= 0 { - return s[:idx] - } - return s -} diff --git a/internal/game/production_core.go b/internal/game/production_core.go deleted file mode 100644 index 42f64e1..0000000 --- a/internal/game/production_core.go +++ /dev/null @@ -1,606 +0,0 @@ -package game - -import ( - "fmt" - "math/rand" - "sort" - "strconv" - "strings" - - "thehouseoficarus/internal/action" - "thehouseoficarus/internal/color" - "thehouseoficarus/internal/engine" - "thehouseoficarus/internal/net" - "thehouseoficarus/internal/object" - "thehouseoficarus/internal/player" - -) - -func (g *Game) startProduction(sess *net.Session, p *player.Player, recipe *action.RecipeDef, actionType, displayVerb, startMsg, endMsg string, count int) { - g.cancelAction(p) - g.cancelBackgroundAction(p) - - skill := recipe.EffectiveSkill() - if skill != "" { - skillLevel := p.Level(player.SkillName(skill)) - if skillLevel < recipe.Level { - sess.WriteLine(fmt.Sprintf("You need level %d %s to do that.", recipe.Level, skill)) - g.reprompt(sess) - return - } - } - - if !recipe.HasAllItemsQty(p.CountItem) { - sess.WriteLine("You don't have the required materials.") - g.reprompt(sess) - return - } - - outDef, _ := g.ItemStore.Load(recipe.Output) - - wait := recipe.Wait - if wait <= 0 { - wait = 4 - } - - outputName := recipe.Output - if outDef != nil { - outputName = outDef.Name - } - - p.Action = &action.Action{ - Type: actionType, - TargetID: recipe.ID, - TargetName: outputName, - Data: map[string]any{ - "recipe_id": recipe.ID, - "phase": 0, - "wait": wait, - "start_msg": startMsg, - "end_msg": endMsg, - "remaining": count, - }, - WaitLeft: engine.ToTicks(1), - } - - p.ActionState = &ActionState{Type: ActionProducing, TargetName: outputName, Verb: displayVerb} - - if g.Hub != nil { - for _, other := range g.Hub.PlayersInRoom(p.RoomID) { - if other != sess && other.Player != nil { - other.WriteLine(g.colorize(other, "broadcast", fmt.Sprintf("\n%s starts %s.", p.Name, displayVerb))) - } - } - } -} - -func (g *Game) startProductionFromRecipe(sess *net.Session, p *player.Player, recipe *action.RecipeDef, count int) { - _, stationName := g.findStation(p.RoomID, recipe.Station) - if stationName == "" { - stationName = "inventory" - } - - firstItem := recipe.FirstItemName(func(id string) (string, bool) { - def, err := g.ItemStore.Load(id) - if err != nil { - return id, false - } - return def.Name, true - }) - - info, ok := productionTypes[recipe.Type] - if !ok { - info = productionTypeInfo{recipe.Type, recipe.Type} - } - actionType := info.ActionType - displayVerb := info.DisplayVerb - - var startMsg, endMsg string - if stationName != "inventory" { - startMsg = fmt.Sprintf("You start %s %s on the %s.", displayVerb, firstItem, stationName) - } else { - startMsg = fmt.Sprintf("You start %s %s.", displayVerb, firstItem) - } - endMsg = fmt.Sprintf("You've finished %s.", displayVerb) - - g.startProduction(sess, p, recipe, actionType, displayVerb, startMsg, endMsg, count) -} - -func (g *Game) loadProductionRecipe(recipeID string) *action.RecipeDef { - all, err := g.RecipeStore.LoadAll() - if err == nil { - for _, r := range all { - if r.ID == recipeID { - return &r - } - } - } - if strings.HasPrefix(recipeID, "combine_") { - itemID := strings.TrimPrefix(recipeID, "combine_") - if itemDef, err := g.ItemStore.Load(itemID); err == nil && len(itemDef.MadeFrom) > 0 { - return g.buildCombineRecipe(itemDef) - } - } - return nil -} - -func (g *Game) advanceProduction(sess *net.Session, p *player.Player) bool { - recipeID := p.Action.Data["recipe_id"].(string) - phase := p.Action.Data["phase"].(int) - wait := p.Action.Data["wait"].(float64) - startMsg, _ := p.Action.Data["start_msg"].(string) - endMsg, _ := p.Action.Data["end_msg"].(string) - remaining, _ := p.Action.Data["remaining"].(int) - - recipe := g.loadProductionRecipe(recipeID) - if recipe == nil { - g.cancelAction(p) - return false - } - - if phase == 0 { - if startMsg != "" { - sess.WriteLine(fmt.Sprintf("\n%s", startMsg)) - } - p.Action.Data["phase"] = 1 - p.Action.WaitLeft = engine.ToTicks(wait) - return true - } - - skill := recipe.EffectiveSkill() - skillLevel := p.Level(player.SkillName(skill)) - chance := 1.0 - if recipe.Success != nil { - chance = action.SuccessChance(*recipe.Success, skillLevel, recipe.Level) - } - - if rand.Float64() < chance { - outputQty := recipe.OutputQty - if outputQty <= 0 { - outputQty = 1 - } - - byproducts := g.collectByproducts(p, recipe) - - placed := false - outDef, _ := g.ItemStore.Load(recipe.Output) - if outDef != nil && outDef.Stackable { - for i := 0; i < 28; i++ { - slot := p.InvSlot(i) - if slot != nil && slot.ItemID == recipe.Output { - recipe.ConsumeAll(p.HasItem, p.RemoveItem) - slot.Quantity += outputQty - placed = true - break - } - } - } - if !placed { - recipe.ConsumeAll(p.HasItem, p.RemoveItem) - freeSlot := p.FirstFreeSlot() - if freeSlot == -1 { - sess.WriteLine("Your inventory is too full!") - g.cancelAction(p) - return false - } - p.SetInvSlot(freeSlot, &player.InventorySlot{ItemID: recipe.Output, Quantity: outputQty}) - } - - for _, bp := range byproducts { - if slot := p.FirstFreeSlot(); slot >= 0 { - p.SetInvSlot(slot, &player.InventorySlot{ItemID: bp, Quantity: 1}) - } - } - - if recipe.XP > 0 { - if newLevel := p.AddSkillXP(player.SkillName(skill), recipe.XP); newLevel > 0 { - sess.WriteLine(g.colorize(sess, "level_up", fmt.Sprintf("*** You are now level %d %s! ***", newLevel, skill))) - } - } - g.AccountStore.SaveCharacter(p) - - msg := recipe.Message - if msg == "" { - outputName := recipe.Output - if outDef != nil { - outputName = outDef.Name - } - msg = fmt.Sprintf("You produce %s.", outputName) - } - if p.OptionBool("xp_drops") && recipe.XP > 0 { - abbr := player.SkillAbbr[player.SkillName(skill)] - msg += g.colorize(sess, "xp", fmt.Sprintf(" (+%dxp %s)", recipe.XP, abbr)) - } - sess.WriteLine(msg) - } else { - recipe.ConsumeAll(p.HasItem, p.RemoveItem) - - if recipe.Fail != "" { - freeSlot := p.FirstFreeSlot() - if freeSlot >= 0 { - p.SetInvSlot(freeSlot, &player.InventorySlot{ItemID: recipe.Fail, Quantity: 1}) - } - } - g.AccountStore.SaveCharacter(p) - - msg := recipe.FailMessage - if msg == "" { - msg = "You fail and the materials are lost." - } - sess.WriteLine(g.colorize(sess, "damage", msg)) - } - - if remaining > 0 { - remaining-- - p.Action.Data["remaining"] = remaining - if remaining <= 0 { - if endMsg != "" { - sess.WriteLine(fmt.Sprintf("\n%s", endMsg)) - } - g.cancelAction(p) - return false - } - } - - if g.canContinueProduction(p, recipe) { - p.Action.WaitLeft = engine.ToTicks(wait) - return true - } - - if endMsg != "" { - sess.WriteLine(fmt.Sprintf("\n%s", endMsg)) - } - g.cancelAction(p) - return false -} - -func (g *Game) collectByproducts(p *player.Player, recipe *action.RecipeDef) []string { - var byproducts []string - for _, e := range recipe.Consume { - if len(e.Byproducts) == 0 { - continue - } - for i, id := range e.Items { - if p.HasItem(id) && i < len(e.Byproducts) && e.Byproducts[i] != "" { - byproducts = append(byproducts, e.Byproducts[i]) - break - } - } - } - return byproducts -} - -func (g *Game) canContinueProduction(p *player.Player, recipe *action.RecipeDef) bool { - if !recipe.HasAllItemsQty(p.CountItem) { - return false - } - outputQty := recipe.OutputQty - if outputQty <= 0 { - outputQty = 1 - } - outDef, _ := g.ItemStore.Load(recipe.Output) - if outDef != nil && outDef.Stackable { - for i := 0; i < 28; i++ { - slot := p.InvSlot(i) - if slot != nil && slot.ItemID == recipe.Output { - return true - } - } - } - return p.FirstFreeSlot() >= 0 -} - -func (g *Game) handleRecipeChoice(sess *net.Session, input string) { - input = strings.TrimSpace(input) - - menuData := sess.PendingMenu - if len(menuData) == 0 { - sess.State = net.StateGame - g.reprompt(sess) - return - } - - if input == "" { - sess.PendingMenu = nil - sess.State = net.StateGame - sess.WriteLine("Never mind.") - g.reprompt(sess) - return - } - - if choice, err := strconv.Atoi(input); err == nil { - sess.PendingMenu = nil - sess.State = net.StateGame - if choice <= 0 || choice > len(menuData) { - sess.WriteLine("Never mind.") - g.reprompt(sess) - return - } - g.dispatchMenuEntry(sess, menuData[choice-1]) - return - } - - lower := strings.ToLower(input) - matchIdx := -1 - for i, entry := range menuData { - name := g.menuEntryName(entry) - if name == "" { - continue - } - if strings.ToLower(name) == lower || action.WordPrefixMatch(input, name) { - if matchIdx >= 0 { - sess.WriteLine("That's ambiguous.") - return - } - matchIdx = i - } - } - if matchIdx >= 0 { - sess.PendingMenu = nil - sess.State = net.StateGame - g.dispatchMenuEntry(sess, menuData[matchIdx]) - return - } - - sess.PendingMenu = nil - sess.State = net.StateGame - sess.WriteLine("Never mind.") - g.reprompt(sess) -} - -func (g *Game) menuEntryName(entry map[string]string) string { - if rid, ok := entry["recipe_id"]; ok { - all, _ := g.RecipeStore.LoadAll() - for _, r := range all { - if r.ID == rid { - if def, err := g.ItemStore.Load(r.Output); err == nil { - return def.Name - } - return r.Output - } - } - } - if rid, ok := entry["fletch_recipe_id"]; ok { - all, _ := g.RecipeStore.LoadAll() - for _, r := range all { - if r.ID == rid { - if def, err := g.ItemStore.Load(r.Output); err == nil { - return def.Name - } - return r.Output - } - } - } - if barID, ok := entry["bar_id"]; ok { - if def, _ := g.ItemStore.Load(barID); def != nil { - return def.Name - } - return barID - } - if cid, ok := entry["combine_item"]; ok { - if def, _ := g.ItemStore.Load(cid); def != nil { - return def.Name - } - return cid - } - return "" -} - -func (g *Game) dispatchMenuEntry(sess *net.Session, entry map[string]string) { - if cid, ok := entry["combine_item"]; ok { - g.promptHowMany(sess, "combine_"+cid) - return - } - if barID, ok := entry["bar_id"]; ok { - p := sess.Player - allRecipes, _ := g.RecipeStore.LoadAll() - g.showSmithTable(sess, p, barID, allRecipes) - return - } - if rid, ok := entry["fletch_recipe_id"]; ok { - p := sess.Player - allRecipes, _ := g.RecipeStore.LoadAll() - for _, r := range allRecipes { - if r.ID == rid { - g.startFletchAction(sess, p, &r, 0) - return - } - } - g.reprompt(sess) - return - } - if rid, ok := entry["recipe_id"]; ok { - g.promptHowMany(sess, rid) - return - } - g.reprompt(sess) -} - -func (g *Game) formatRecipeMaterials(r *action.RecipeDef) string { - var parts []string - for _, e := range r.Consume { - itemName := e.Items[0] - if def, err := g.ItemStore.Load(e.Items[0]); err == nil { - itemName = def.Name - } - if e.Qty > 1 { - parts = append(parts, fmt.Sprintf("%s x%d", itemName, e.Qty)) - } else { - parts = append(parts, itemName) - } - } - return strings.Join(parts, ", ") -} - -func (g *Game) showProductionTable(sess *net.Session, p *player.Player, recipes []action.RecipeDef, title, skill, lastFlagKey, promptVerb string, background bool) { - sort.Slice(recipes, func(i, j int) bool { - return recipes[i].Level < recipes[j].Level - }) - - mode := g.colorMode(sess) - skillLevel := p.Level(player.SkillName(skill)) - dimSpec := color.Parse("240") - - tbl := &Table{ - Title: title, - Columns: []string{"#", "Product", "Materials", "Level"}, - } - - for i, r := range recipes { - outDef, _ := g.ItemStore.Load(r.Output) - productName := r.Output - if outDef != nil { - productName = outDef.Name - } - - outputQty := r.OutputQty - if outputQty <= 0 { - outputQty = 1 - } - if outDef != nil && outDef.Stackable && outputQty > 1 { - productName = fmt.Sprintf("%s x%d", productName, outputQty) - } - - matStr := g.formatRecipeMaterials(&r) - levelStr := fmt.Sprint(r.Level) - numStr := fmt.Sprintf("%d", i+1) - - canMake := skillLevel >= r.Level && r.HasAllItemsQty(p.CountItem) - if canMake { - productName = g.itemColorize(sess, outDef, productName) - } else { - productName = color.Render(mode, dimSpec, productName) - matStr = color.Render(mode, dimSpec, matStr) - levelStr = color.Render(mode, dimSpec, levelStr) - numStr = color.Render(mode, dimSpec, numStr) - } - - tbl.Rows = append(tbl.Rows, []string{numStr, productName, matStr, levelStr}) - } - - unicode := p.OptionBool("unicode") - sess.WriteLine("") - for _, line := range tbl.Render(unicode) { - sess.WriteLine(line) - } - - lastRecipeID, _ := p.Flags[lastFlagKey].(string) - hint := "" - if lastRecipeID != "" { - for _, r := range recipes { - if r.ID == lastRecipeID { - if outDef, err := g.ItemStore.Load(r.Output); err == nil { - hint = outDef.Name - } - break - } - } - } - - if hint != "" { - sess.Write(fmt.Sprintf("%s what (enter for all %s): ", promptVerb, hint)) - } else { - sess.Write(fmt.Sprintf("%s what: ", promptVerb)) - } - - sess.PendingMenu = recipeMenuData(recipeDefIDs(recipes)) - sess.PendingSkill = skill - sess.PendingLastFlag = lastFlagKey - sess.PendingBackground = background - sess.State = net.StateProductChoice -} - -func (g *Game) handleProductChoice(sess *net.Session, input string) { - p := sess.Player - menuData := sess.PendingMenu - skill := sess.PendingSkill - lastFlagKey := sess.PendingLastFlag - background := sess.PendingBackground - sess.PendingMenu = nil - sess.PendingSkill = "" - sess.PendingLastFlag = "" - sess.PendingBackground = false - sess.State = net.StateGame - - input = strings.TrimSpace(input) - - allRecipes, err := g.RecipeStore.LoadAll() - if err != nil { - g.reprompt(sess) - return - } - - var recipes []action.RecipeDef - for _, entry := range menuData { - rid := entry["recipe_id"] - for _, r := range allRecipes { - if r.ID == rid { - recipes = append(recipes, r) - break - } - } - } - - if len(recipes) == 0 { - g.reprompt(sess) - return - } - - sort.Slice(recipes, func(i, j int) bool { - return recipes[i].Level < recipes[j].Level - }) - - lastRecipeID, _ := p.Flags[lastFlagKey].(string) - - sel, errMsg := g.resolveRecipeByInput(input, recipes, lastRecipeID) - switch errMsg { - case "ambiguous": - sess.WriteLine("That's ambiguous.") - g.reprompt(sess) - return - case "never_mind": - sess.WriteLine("Never mind.") - g.reprompt(sess) - return - } - - skillLevel := p.Level(player.SkillName(skill)) - if skillLevel < sel.Recipe.Level { - sess.WriteLine(fmt.Sprintf("You need level %d %s to make that.", sel.Recipe.Level, skill)) - g.reprompt(sess) - return - } - if !sel.Recipe.HasAllItemsQty(p.CountItem) { - sess.WriteLine("You don't have the materials for that.") - g.reprompt(sess) - return - } - - p.EnsureFlags() - p.Flags[lastFlagKey] = sel.Recipe.ID - g.AccountStore.SaveCharacter(p) - - if background { - g.startFletchAction(sess, p, sel.Recipe, sel.Count) - } else { - g.startProductionFromRecipe(sess, p, sel.Recipe, sel.Count) - } -} - -func (g *Game) hasToolType(p *player.Player, toolType string) bool { - if itemID, ok := p.Equipment[object.SlotMainHand]; ok { - if def, err := g.ItemStore.Load(itemID); err == nil && def.ToolType == toolType { - return true - } - } - for i := 0; i < 28; i++ { - slot := p.InvSlot(i) - if slot == nil { - continue - } - if def, err := g.ItemStore.Load(slot.ItemID); err == nil && def.ToolType == toolType { - return true - } - } - return false -} diff --git a/internal/game/production_menu.go b/internal/game/production_menu.go deleted file mode 100644 index 329110b..0000000 --- a/internal/game/production_menu.go +++ /dev/null @@ -1,209 +0,0 @@ -package game - -import ( - "fmt" - "strconv" - "strings" - - "thehouseoficarus/internal/action" - "thehouseoficarus/internal/net" - "thehouseoficarus/internal/object" -) - -type recipeEntry struct { - ItemName string - Recipe action.RecipeDef -} - -type productionTypeInfo struct { - ActionType string - DisplayVerb string -} - -var productionTypes = map[string]productionTypeInfo{ - "cooking": {"cook", "cooking"}, - "smelting": {"smelt", "smelting"}, - "smithing": {"smith", "smithing"}, - "crafting": {"craft", "crafting"}, - "combine": {"combine", "combining"}, - "fletching": {"fletch", "fletching"}, - "pharmacy": {"mix", "mixing"}, - "construction": {"construct", "constructing"}, -} - -var productionActionTypes map[string]bool - -func init() { - productionActionTypes = make(map[string]bool) - for _, pt := range productionTypes { - productionActionTypes[pt.ActionType] = true - } -} - -func recipeMenuData(recipeIDs []string) []map[string]string { - out := make([]map[string]string, len(recipeIDs)) - for i, id := range recipeIDs { - out[i] = map[string]string{"recipe_id": id} - } - return out -} - -func recipeDefIDs(defs []action.RecipeDef) []string { - ids := make([]string, len(defs)) - for i, d := range defs { - ids[i] = d.ID - } - return ids -} - -func entryMenuData(entries []recipeEntry) []map[string]string { - out := make([]map[string]string, len(entries)) - for i, e := range entries { - out[i] = map[string]string{"recipe_id": e.Recipe.ID} - } - return out -} - -func (g *Game) promptHowMany(sess *net.Session, recipeID string) { - sess.PendingRecipeID = recipeID - sess.State = net.StateHowMany - sess.Write("How many (return for all)?: ") -} - -type recipeSelection struct { - Recipe *action.RecipeDef - Count int -} - -func (g *Game) resolveRecipeByInput(input string, recipes []action.RecipeDef, lastRecipeID string) (sel recipeSelection, errMsg string) { - if input == "" { - if lastRecipeID == "" { - return sel, "never_mind" - } - for i := range recipes { - if recipes[i].ID == lastRecipeID { - sel.Recipe = &recipes[i] - return sel, "" - } - } - return sel, "never_mind" - } - - qty, productName := parseQty(input) - productName = strings.TrimSpace(productName) - - if idx, err := strconv.Atoi(productName); err == nil && idx > 0 && idx <= len(recipes) { - sel.Recipe = &recipes[idx-1] - sel.Count = qty - return sel, "" - } - - matchCount := 0 - for i := range recipes { - outDef, _ := g.ItemStore.Load(recipes[i].Output) - name := recipes[i].Output - if outDef != nil { - name = outDef.Name - } - if action.WordPrefixMatch(productName, name) { - if matchCount == 0 { - sel.Recipe = &recipes[i] - sel.Count = qty - } - matchCount++ - } - } - if matchCount > 1 { - return sel, "ambiguous" - } - if sel.Recipe == nil { - return sel, "never_mind" - } - return sel, "" -} - -func (g *Game) showMenuTable(sess *net.Session, title string, names []string) { - p := sess.Player - tbl := &Table{Title: title} - for i, name := range names { - tbl.Rows = append(tbl.Rows, []string{fmt.Sprintf("%d", i+1), name}) - } - unicode := p.OptionBool("unicode") - sess.WriteLine("") - for _, line := range tbl.Render(unicode) { - sess.WriteLine(line) - } -} - -func (g *Game) handleHowMany(sess *net.Session, input string) { - p := sess.Player - recipeID := sess.PendingRecipeID - sess.PendingRecipeID = "" - sess.State = net.StateGame - - input = strings.TrimSpace(input) - - var count int - if input == "" { - count = 0 - } else if n, err := strconv.Atoi(input); err == nil && n > 0 { - count = n - } else { - sess.WriteLine("Never mind.") - g.reprompt(sess) - return - } - - var recipe *action.RecipeDef - if strings.HasPrefix(recipeID, "combine_") { - itemID := strings.TrimPrefix(recipeID, "combine_") - itemDef, err := g.ItemStore.Load(itemID) - if err != nil || len(itemDef.MadeFrom) == 0 { - g.reprompt(sess) - return - } - recipe = g.buildCombineRecipe(itemDef) - } else { - all, err := g.RecipeStore.LoadAll() - if err != nil { - g.reprompt(sess) - return - } - for _, r := range all { - if r.ID == recipeID { - recipe = &r - break - } - } - } - - if recipe == nil { - g.reprompt(sess) - return - } - - g.startProductionFromRecipe(sess, p, recipe, count) -} - -func (g *Game) buildCombineRecipe(def *object.ItemDef) *action.RecipeDef { - var consume []action.ConsumeEntry - for _, mf := range def.MadeFrom { - consume = append(consume, action.ConsumeEntry{ - Items: mf.Items, - Qty: mf.Qty, - Byproducts: mf.Byproducts, - }) - } - wait := def.Ticks - if wait <= 0 { - wait = 2 - } - return &action.RecipeDef{ - ID: "combine_" + def.ID, - Type: "combine", - Wait: wait, - Consume: consume, - Output: def.ID, - Message: fmt.Sprintf("You create %s.", def.Name), - } -} diff --git a/internal/game/science.go b/internal/game/science.go deleted file mode 100644 index 8c7f0af..0000000 --- a/internal/game/science.go +++ /dev/null @@ -1,231 +0,0 @@ -package game - -import ( - "fmt" - "os" - "path/filepath" - "sort" - "strings" - - "gopkg.in/yaml.v3" - - "thehouseoficarus/internal/object" - "thehouseoficarus/internal/player" -) - -type ModCategory string - -const ( - ModCombat ModCategory = "combat" - ModUtility ModCategory = "utility" - ModEnchant ModCategory = "enchant" - ModProcessing ModCategory = "processing" - ModTransport ModCategory = "transport" -) - -type ModDef struct { - ID string `yaml:"id"` - Name string `yaml:"name"` - Level int `yaml:"level"` - MaxHit int `yaml:"max_hit"` - BaseXP int `yaml:"base_xp"` - JunkCost map[string]int `yaml:"junk_cost"` - Category ModCategory `yaml:"category"` - Element string `yaml:"element"` - Destination int `yaml:"destination"` -} - -var AllMods []*ModDef - -var modByID map[string]*ModDef - -func (g *Game) LoadMods() error { - dir := filepath.Join(g.DataDir, "modules") - entries, err := os.ReadDir(dir) - if err != nil { - return err - } - AllMods = nil - modByID = make(map[string]*ModDef) - for _, e := range entries { - if e.IsDir() || filepath.Ext(e.Name()) != ".yaml" { - continue - } - data, err := os.ReadFile(filepath.Join(dir, e.Name())) - if err != nil { - continue - } - var m ModDef - if err := yaml.Unmarshal(data, &m); err != nil { - continue - } - AllMods = append(AllMods, &m) - modByID[m.ID] = AllMods[len(AllMods)-1] - } - modByID = make(map[string]*ModDef, len(AllMods)) - for _, m := range AllMods { - modByID[m.ID] = m - } - return nil -} - -func GetMod(id string) *ModDef { - return modByID[id] -} - -func FindMod(input string) *ModDef { - if m, ok := modByID[input]; ok { - return m - } - lower := strings.ToLower(strings.ReplaceAll(input, " ", "_")) - for _, m := range AllMods { - if strings.HasPrefix(m.ID, lower) { - return m - } - } - lowerSpace := strings.ToLower(input) - for _, m := range AllMods { - if strings.HasPrefix(strings.ToLower(m.Name), lowerSpace) { - return m - } - } - return nil -} - -type chipEntry struct { - Input string - Output string - Qty int -} - -var enchantMap = map[string]map[string]string{ - "enchant_1": { - "sapphire_ring": "ring_of_recoil", - "sapphire_necklace": "necklace_of_passage", - "sapphire_bracelet": "bracelet_of_clay", - }, - "enchant_2": { - "emerald_ring": "ring_of_dueling", - "emerald_necklace": "binding_necklace", - "emerald_bracelet": "bracelet_of_slaughter", - }, - "enchant_3": { - "ruby_ring": "ring_of_forging", - "ruby_necklace": "digsite_pendant", - "ruby_bracelet": "inoculation_bracelet", - }, - "enchant_4": { - "diamond_ring": "ring_of_life", - "diamond_necklace": "phoenix_necklace", - "diamond_bracelet": "abyssal_bracelet", - }, -} - -var chipMap = map[string]chipEntry{ - "chip_sapphire": {"sapphire_bolts", "sapphire_bolts_e", 10}, - "chip_emerald": {"emerald_bolts", "emerald_bolts_e", 10}, - "chip_ruby": {"ruby_bolts", "ruby_bolts_e", 10}, - "chip_diamond": {"diamond_bolts", "diamond_bolts_e", 10}, -} - -func (g *Game) hasDeckEquipped(p *player.Player) bool { - itemID, ok := p.Equipment[object.SlotMainHand] - if !ok { - return false - } - def, err := g.ItemStore.Load(itemID) - if err != nil { - return false - } - return def.WeaponType == object.WeaponScience -} - -func (g *Game) equippedProvidesJunk(p *player.Player) string { - itemID, ok := p.Equipment[object.SlotMainHand] - if !ok { - return "" - } - def, err := g.ItemStore.Load(itemID) - if err != nil { - return "" - } - return def.ProvidesJunk -} - -func (g *Game) effectiveJunkCost(p *player.Player, mod *ModDef) map[string]int { - cost := make(map[string]int) - for k, v := range mod.JunkCost { - cost[k] = v - } - - hasDeck := g.hasDeckEquipped(p) - - if hasDeck { - delete(cost, "scrap_metal") - } - - providesJunk := g.equippedProvidesJunk(p) - if providesJunk != "" { - delete(cost, providesJunk) - } - - return cost -} - -func (g *Game) hasJunkCost(p *player.Player, mod *ModDef) bool { - cost := g.effectiveJunkCost(p, mod) - for itemID, qty := range cost { - if p.CountItem(itemID) < qty { - return false - } - } - return true -} - -func (g *Game) consumeJunkCost(p *player.Player, mod *ModDef) bool { - cost := g.effectiveJunkCost(p, mod) - for itemID, qty := range cost { - if !p.RemoveItem(itemID, qty) { - return false - } - } - g.AccountStore.SaveCharacter(p) - return true -} - -func (g *Game) junkCostString(p *player.Player, mod *ModDef) string { - cost := g.effectiveJunkCost(p, mod) - delete(cost, "scrap_metal") - if len(cost) == 0 { - return "free" - } - var parts []string - for itemID, qty := range cost { - def, _ := g.ItemStore.Load(itemID) - name := itemID - if def != nil { - name = def.Name - } - name = strings.TrimSuffix(name, "junk") - if qty > 1 { - parts = append(parts, fmt.Sprintf("%d %s", qty, name)) - } else { - parts = append(parts, name) - } - } - sort.Strings(parts) - return strings.Join(parts, ", ") -} - -func (g *Game) totalEquipScienceAttack(p *player.Player) int { - total := 0 - for _, itemID := range p.Equipment { - def, err := g.ItemStore.Load(itemID) - if err == nil { - total += def.Stats.ScienceAttack - } - } - return total -} - - diff --git a/internal/game/assassin.go b/internal/game/sys_assassin.go index 1927399..1927399 100644 --- a/internal/game/assassin.go +++ b/internal/game/sys_assassin.go diff --git a/internal/game/buff.go b/internal/game/sys_buff.go index 9449731..9449731 100644 --- a/internal/game/buff.go +++ b/internal/game/sys_buff.go diff --git a/internal/game/sys_combat.go b/internal/game/sys_combat.go new file mode 100644 index 0000000..030bed1 --- /dev/null +++ b/internal/game/sys_combat.go @@ -0,0 +1,114 @@ +package game + +import ( + "fmt" + "sort" + + "thehouseoficarus/internal/combat" + "thehouseoficarus/internal/engine" + "thehouseoficarus/internal/net" + "thehouseoficarus/internal/player" +) + +func (g *Game) dropItemsOnDeath(p *player.Player) { + roomID := p.RoomID + + if p.Credits > 0 { + g.World.AddGroundItem(roomID, "credits", p.Credits) + p.Credits = 0 + } + + var items []deathDrop + + for slot, inv := range p.Inventory { + if inv == nil || inv.Quantity <= 0 { + continue + } + val := 0 + if def, err := g.ItemStore.Load(inv.ItemID); err == nil { + val = def.Value * inv.Quantity + } + items = append(items, deathDrop{ + itemID: inv.ItemID, + quantity: inv.Quantity, + totalVal: val, + invSlot: slot, + }) + } + + for eqSlot, itemID := range p.Equipment { + val := 0 + if def, err := g.ItemStore.Load(itemID); err == nil { + val = def.Value + } + items = append(items, deathDrop{ + itemID: itemID, + quantity: 1, + totalVal: val, + isEquip: true, + equipSlot: eqSlot, + }) + } + + if len(items) <= 3 { + return + } + + sort.Slice(items, func(i, j int) bool { + return items[i].totalVal > items[j].totalVal + }) + + for i := 3; i < len(items); i++ { + it := items[i] + if it.isEquip { + delete(p.Equipment, it.equipSlot) + } else { + p.SetInvSlot(it.invSlot, nil) + } + g.World.AddGroundItem(roomID, it.itemID, it.quantity) + } +} + +func (g *Game) checkAggro(sess *net.Session) { + p := sess.Player + + if combat.GetCombat(p.Name) != nil { + return + } + + playerLevel := p.CombatLevel() + mobs := g.MobStore.MobsInRoom(p.RoomID) + + for _, mob := range mobs { + if !mob.Aggressive || mob.HP <= 0 || mob.Protected { + continue + } + if combat.IsMobInCombat(mob.InstanceID) { + continue + } + mobLevel := mobCombatLevel(mob) + if playerLevel > mobLevel*2 { + continue + } + aggMob := mob + g.Ticks.Subscribe(engine.ToTicks(1), func() bool { + if combat.GetCombat(p.Name) != nil { + return false + } + if aggMob.HP <= 0 || aggMob.RoomID != p.RoomID { + return false + } + if combat.IsMobInCombat(aggMob.InstanceID) { + return false + } + attacker := aggMob.Name + if !aggMob.Unique { + attacker = "The " + aggMob.Name + } + sess.WriteLine(fmt.Sprintf("\n%s attacks you!", g.colorize(sess, "mob_name", attacker))) + g.startCombat(sess, p, aggMob) + return false + }) + break + } +} diff --git a/internal/game/construction.go b/internal/game/sys_construction.go index 06713cd..06713cd 100644 --- a/internal/game/construction.go +++ b/internal/game/sys_construction.go diff --git a/internal/game/sys_science.go b/internal/game/sys_science.go new file mode 100644 index 0000000..23aeef4 --- /dev/null +++ b/internal/game/sys_science.go @@ -0,0 +1,220 @@ +package game + +import ( + "fmt" + "path/filepath" + "sort" + "strings" + + "gopkg.in/yaml.v3" + + "thehouseoficarus/internal/action" + "thehouseoficarus/internal/object" + "thehouseoficarus/internal/player" +) + +type ModCategory string + +const ( + ModCombat ModCategory = "combat" + ModUtility ModCategory = "utility" + ModEnchant ModCategory = "enchant" + ModProcessing ModCategory = "processing" + ModTransport ModCategory = "transport" +) + +type ModDef struct { + ID string `yaml:"id"` + Name string `yaml:"name"` + Level int `yaml:"level"` + MaxHit int `yaml:"max_hit"` + BaseXP int `yaml:"base_xp"` + JunkCost map[string]int `yaml:"junk_cost"` + Category ModCategory `yaml:"category"` + Element string `yaml:"element"` + Destination int `yaml:"destination"` +} + +var AllMods []*ModDef + +var modByID map[string]*ModDef + +func (g *Game) LoadMods() error { + dir := filepath.Join(g.DataDir, "modules") + AllMods = nil + modByID = make(map[string]*ModDef) + action.WalkYAMLDir(dir, func(path, id string, data []byte) error { + var m ModDef + if err := yaml.Unmarshal(data, &m); err != nil { + return nil + } + AllMods = append(AllMods, &m) + return nil + }) + modByID = make(map[string]*ModDef, len(AllMods)) + for _, m := range AllMods { + modByID[m.ID] = m + } + return nil +} + +func GetMod(id string) *ModDef { + return modByID[id] +} + +func FindMod(input string) *ModDef { + if m, ok := modByID[input]; ok { + return m + } + lower := strings.ToLower(strings.ReplaceAll(input, " ", "_")) + for _, m := range AllMods { + if strings.HasPrefix(m.ID, lower) { + return m + } + } + lowerSpace := strings.ToLower(input) + for _, m := range AllMods { + if strings.HasPrefix(strings.ToLower(m.Name), lowerSpace) { + return m + } + } + return nil +} + +type chipEntry struct { + Input string + Output string + Qty int +} + +var enchantMap = map[string]map[string]string{ + "enchant_1": { + "sapphire_ring": "ring_of_recoil", + "sapphire_necklace": "necklace_of_passage", + "sapphire_bracelet": "bracelet_of_clay", + }, + "enchant_2": { + "emerald_ring": "ring_of_dueling", + "emerald_necklace": "binding_necklace", + "emerald_bracelet": "bracelet_of_slaughter", + }, + "enchant_3": { + "ruby_ring": "ring_of_forging", + "ruby_necklace": "digsite_pendant", + "ruby_bracelet": "inoculation_bracelet", + }, + "enchant_4": { + "diamond_ring": "ring_of_life", + "diamond_necklace": "phoenix_necklace", + "diamond_bracelet": "abyssal_bracelet", + }, +} + +var chipMap = map[string]chipEntry{ + "chip_sapphire": {"sapphire_bolts", "sapphire_bolts_e", 10}, + "chip_emerald": {"emerald_bolts", "emerald_bolts_e", 10}, + "chip_ruby": {"ruby_bolts", "ruby_bolts_e", 10}, + "chip_diamond": {"diamond_bolts", "diamond_bolts_e", 10}, +} + +func (g *Game) hasDeckEquipped(p *player.Player) bool { + itemID, ok := p.Equipment[object.SlotMainHand] + if !ok { + return false + } + def, err := g.ItemStore.Load(itemID) + if err != nil { + return false + } + return def.WeaponType == object.WeaponScience +} + +func (g *Game) equippedProvidesJunk(p *player.Player) string { + itemID, ok := p.Equipment[object.SlotMainHand] + if !ok { + return "" + } + def, err := g.ItemStore.Load(itemID) + if err != nil { + return "" + } + return def.ProvidesJunk +} + +func (g *Game) effectiveJunkCost(p *player.Player, mod *ModDef) map[string]int { + cost := make(map[string]int) + for k, v := range mod.JunkCost { + cost[k] = v + } + + hasDeck := g.hasDeckEquipped(p) + + if hasDeck { + delete(cost, "scrap_metal") + } + + providesJunk := g.equippedProvidesJunk(p) + if providesJunk != "" { + delete(cost, providesJunk) + } + + return cost +} + +func (g *Game) hasJunkCost(p *player.Player, mod *ModDef) bool { + cost := g.effectiveJunkCost(p, mod) + for itemID, qty := range cost { + if p.CountItem(itemID) < qty { + return false + } + } + return true +} + +func (g *Game) consumeJunkCost(p *player.Player, mod *ModDef) bool { + cost := g.effectiveJunkCost(p, mod) + for itemID, qty := range cost { + if !p.RemoveItem(itemID, qty) { + return false + } + } + g.AccountStore.SaveCharacter(p) + return true +} + +func (g *Game) junkCostString(p *player.Player, mod *ModDef) string { + cost := g.effectiveJunkCost(p, mod) + delete(cost, "scrap_metal") + if len(cost) == 0 { + return "free" + } + var parts []string + for itemID, qty := range cost { + def, _ := g.ItemStore.Load(itemID) + name := itemID + if def != nil { + name = def.Name + } + name = strings.TrimSuffix(name, "junk") + if qty > 1 { + parts = append(parts, fmt.Sprintf("%d %s", qty, name)) + } else { + parts = append(parts, name) + } + } + sort.Strings(parts) + return strings.Join(parts, ", ") +} + +func (g *Game) totalEquipScienceAttack(p *player.Player) int { + total := 0 + for _, itemID := range p.Equipment { + def, err := g.ItemStore.Load(itemID) + if err == nil { + total += def.Stats.ScienceAttack + } + } + return total +} + + diff --git a/internal/game/tech.go b/internal/game/sys_technology.go index a24c66d..a24c66d 100644 --- a/internal/game/tech.go +++ b/internal/game/sys_technology.go diff --git a/internal/game/color.go b/internal/game/ui_color.go index 962728a..962728a 100644 --- a/internal/game/color.go +++ b/internal/game/ui_color.go diff --git a/internal/game/ui_help.go b/internal/game/ui_help.go new file mode 100644 index 0000000..151d1ba --- /dev/null +++ b/internal/game/ui_help.go @@ -0,0 +1,152 @@ +package game + +import ( + "fmt" + "path/filepath" + "strings" + + "thehouseoficarus/internal/action" + "thehouseoficarus/internal/net" + "gopkg.in/yaml.v3" +) + +type HelpDef struct { + Name string `yaml:"name"` + Category string `yaml:"category"` + Content string `yaml:"description"` +} + +type cmdEntry struct { + Name string + Type string + Desc string +} + +var commandList = []cmdEntry{ + {"alias", "Instant", "Create command shortcuts"}, + {"attack / kill", "Active", "Attack a mob"}, + {"autotrigger / auto", "Instant", "Set a module to auto-trigger"}, + {"bank", "Active", "Open bank interface"}, + {"burn", "Active", "Start a fire"}, + {"chop / cut", "Active", "Chop trees (Woodcutting)"}, + {"clean", "Free", "Clean grimy herbs (Pharmacy)"}, + {"color / colors", "Instant", "Customize display colors"}, + {"colortable", "Instant", "Display color reference chart"}, + {"construct / make", "Active", "Build furniture (Construction)"}, + {"cook", "Active", "Cook raw food on a fire or range"}, + {"craft", "Active", "Craft jewelry (Crafting)"}, + {"description / desc", "Instant", "Set your character description"}, + {"drink", "Free", "Drink a potion"}, + {"drop", "Active", "Drop items to the ground"}, + {"eat", "Free", "Eat food to restore hitpoints"}, + {"equipment / eq", "Instant", "Show equipped items"}, + {"exits", "Instant", "List available exits"}, + {"farm", "Active", "Farm crops (Farming)"}, + {"fish", "Active", "Fish at fishing spots (Fishing)"}, + {"fletch", "Free", "Fletch logs into bows (Fletching)"}, + {"get / take / pick", "Active", "Pick up items from the ground"}, + {"help", "Instant", "Show help topics"}, + {"id / identify", "Active", "Identify herbs (Pharmacy)"}, + {"inventory / i / inv", "Instant", "Show your inventory"}, + {"jack / jackin", "Active", "Jack into a terminal (Hacking)"}, + {"look / l", "Instant", "Look around or examine things"}, + {"map", "Instant", "Display an ASCII map of the area"}, + {"mine", "Active", "Mine rocks (Mining)"}, + {"mix", "Active", "Mix potions (Pharmacy)"}, + {"mods / modlist", "Instant", "List available science modules"}, + {"north / south / east / west / up / down", "Active", "Move in a direction"}, + {"option / options", "Instant", "View or change settings"}, + {"prompt", "Instant", "Set custom command prompt"}, + {"pull / push", "Active", "Interact with objects"}, + {"queued", "Instant", "Show pending tick actions"}, + {"quit", "Active", "Rest and disconnect"}, + {"remove / unwear / unwield", "Free", "Unequip items"}, + {"say", "Instant", "Chat with players in your room"}, + {"score / sc", "Instant", "View your stats and skills"}, + {"search", "Active", "Search items for loot"}, + {"smelt", "Active", "Smelt ore into bars (Smithing)"}, + {"smith", "Active", "Smith bars into items (Smithing)"}, + {"sneak", "Instant", "Toggle sneak mode"}, + {"steal", "Active", "Steal from mobs (Thieving)"}, + {"stoke", "Active", "Add logs to a fire"}, + {"style", "Instant", "Change combat style"}, + {"talk / speak / ask", "Active", "Talk to NPCs"}, + {"tech", "Instant", "Toggle technology abilities"}, + {"trigger", "Active", "Trigger a science module"}, + {"unalias", "Instant", "Remove command shortcuts"}, + {"use", "Active", "Use an object (crafting)"}, + {"walk", "Active", "Pathfind to a room or multi-step walk"}, + {"wear / wield", "Free", "Equip items"}, +} + +func LoadHelp(dataDir string) ([]HelpDef, error) { + dir := filepath.Join(dataDir, "help") + var helps []HelpDef + action.WalkYAMLDir(dir, func(path, id string, data []byte) error { + var h HelpDef + if err := yaml.Unmarshal(data, &h); err != nil { + return nil + } + helps = append(helps, h) + return nil + }) + return helps, nil +} + +func (g *Game) doHelp(sess *net.Session, topic string) { + if topic == "" { + unicode := true + if p := sess.Player; p != nil { + unicode = p.OptionBool("unicode") + } + + sess.WriteLine("") + t := &Table{ + Title: "Commands", + Columns: []string{"Command", "Type", "Description"}, + } + for _, c := range commandList { + t.Rows = append(t.Rows, []string{c.Name, c.Type, c.Desc}) + } + for _, line := range t.Render(unicode) { + sess.WriteLine(line) + } + sess.WriteLine("") + sess.WriteLine("Command types: Instant (runs immediately), Free (queued before active),") + sess.WriteLine("Active (replaces current action, queued per tick).") + sess.WriteLine("") + sess.WriteLine("Use 'help <command>' for detailed usage of a specific command.") + sess.WriteLine("Use 'option' to view and change settings, 'color' to customize colors.") + return + } + + helps, err := LoadHelp(g.DataDir) + if err != nil || len(helps) == 0 { + sess.WriteLine("No help available.") + return + } + + topic = strings.ToLower(topic) + for _, h := range helps { + if strings.ToLower(h.Name) == topic { + sess.WriteLine(fmt.Sprintf("\n %s", h.Content)) + return + } + } + sess.WriteLine(fmt.Sprintf("No help found for '%s'.", topic)) +} + +func firstLine(s string) string { + if idx := strings.Index(s, "\n"); idx >= 0 { + return s[:idx] + } + return s +} + +func (g *Game) executeHelp(sess *net.Session, args []string, rawInput string) { + if len(args) == 0 { + g.doHelp(sess, "") + } else { + g.doHelp(sess, strings.Join(args, " ")) + } +} diff --git a/internal/game/map.go b/internal/game/ui_map.go index 32d3d7c..32d3d7c 100644 --- a/internal/game/map.go +++ b/internal/game/ui_map.go diff --git a/internal/game/prompt.go b/internal/game/ui_prompt.go index 2ecf367..2ecf367 100644 --- a/internal/game/prompt.go +++ b/internal/game/ui_prompt.go diff --git a/internal/game/table.go b/internal/game/ui_table.go index b96dca1..b96dca1 100644 --- a/internal/game/table.go +++ b/internal/game/ui_table.go diff --git a/internal/game/utils.go b/internal/game/utils.go deleted file mode 100644 index 9148ea3..0000000 --- a/internal/game/utils.go +++ /dev/null @@ -1,121 +0,0 @@ -package game - -import ( - "fmt" - "math/rand" - "strconv" - "strings" - - "thehouseoficarus/internal/net" - "thehouseoficarus/internal/player" - "thehouseoficarus/internal/world" -) - -func plural(n int) string { - if n == 1 { - return "" - } - return "s" -} - -func parseQty(input string) (int, string) { - parts := strings.Fields(input) - if len(parts) > 1 { - if n, err := strconv.Atoi(parts[0]); err == nil && n > 0 { - return n, strings.Join(parts[1:], " ") - } - } - return 0, input -} - -func parseChoiceIndex(s string) (int, error) { - var idx int - _, err := fmt.Sscanf(s, "%d", &idx) - return idx, err -} - -func mobDisplayName(m *world.MobInstance, definite bool) string { - if m.Unique { - return m.Name - } - if definite { - return "the " + m.Name - } - return "a " + m.Name -} - -func mobCombatLevel(m *world.MobInstance) int { - base := float64(m.Defense+m.MaxHP) / 4.0 - melee := float64(m.Attack+m.Strength) / 4.0 - ranged := float64(m.Ranged) * 3.0 / 8.0 - science := float64(m.Science) * 3.0 / 8.0 - best := melee - if ranged > best { - best = ranged - } - if science > best { - best = science - } - return int(base + best + 0.5) -} - -func uniqueItemNames(matches []itemMatch) []string { - seen := make(map[string]bool) - var out []string - for _, m := range matches { - if !seen[m.Name] { - seen[m.Name] = true - out = append(out, m.Name) - } - } - return out -} - -func (g *Game) showWhichOne(sess *net.Session, matches []itemMatch) { - sess.WriteLine("Which one?") - seen := make(map[string]bool) - for _, m := range matches { - if seen[m.Name] { - continue - } - seen[m.Name] = true - def, _ := g.ItemStore.Load(m.ID) - coloredName := g.itemColorize(sess, def, m.Name) - sess.WriteLine(fmt.Sprintf(" - %s", coloredName)) - } -} - -func randInt(max int) int { - if max <= 0 { - return 0 - } - return rand.Intn(max) -} - -func formatPickupList(sess *net.Session, picked []string) { - for i, name := range picked { - if i == len(picked)-1 { - sess.WriteLine(name) - } else if i == len(picked)-2 { - sess.Write(name + " and ") - } else { - sess.Write(name + ", ") - } - } -} - -func (g *Game) newInventorySlot(itemID string, qty int) *player.InventorySlot { - slot := &player.InventorySlot{ItemID: itemID, Quantity: qty} - if def, err := g.ItemStore.Load(itemID); err == nil && def.MaxQuality > 0 { - slot.Quality = def.Quality - slot.MaxQuality = def.MaxQuality - } - return slot -} - -func (g *Game) awardSkillXP(sess *net.Session, p *player.Player, skill player.SkillName, xp int) { - newLevel := p.AddSkillXP(skill, xp) - if newLevel > 0 { - sess.WriteLine(g.colorize(sess, "level_up", fmt.Sprintf("*** You are now level %d %s! ***", newLevel, skill))) - } -} diff --git a/internal/object/item.go b/internal/object/item.go index 7c682a4..8ec1565 100644 --- a/internal/object/item.go +++ b/internal/object/item.go @@ -74,7 +74,7 @@ type ItemDef struct { type MadeFromEntry struct { Items []string `yaml:"items"` - Qty int `yaml:"qty"` + Quantity int `yaml:"quantity"` Byproducts []string `yaml:"byproducts"` } diff --git a/internal/object/item_store.go b/internal/object/item_store.go index 9e932ba..d75179f 100644 --- a/internal/object/item_store.go +++ b/internal/object/item_store.go @@ -4,28 +4,34 @@ import ( "fmt" "os" "path/filepath" - "strings" + "thehouseoficarus/internal/action" "gopkg.in/yaml.v3" ) type ItemStore struct { - dataDir string - cache map[string]*ItemDef + dataDir string + pathIndex map[string]string + cache map[string]*ItemDef } func NewItemStore(dataDir string) *ItemStore { - return &ItemStore{ - dataDir: dataDir, - cache: make(map[string]*ItemDef), + s := &ItemStore{ + dataDir: dataDir, + pathIndex: action.BuildPathIndex(filepath.Join(dataDir, "items")), + cache: make(map[string]*ItemDef), } + return s } func (s *ItemStore) Load(id string) (*ItemDef, error) { if def, ok := s.cache[id]; ok { return def, nil } - path := filepath.Join(s.dataDir, "items", id+".yaml") + path, ok := s.pathIndex[id] + if !ok { + return nil, fmt.Errorf("read item %s: no such item", id) + } data, err := os.ReadFile(path) if err != nil { return nil, fmt.Errorf("read item %s: %w", id, err) @@ -40,21 +46,31 @@ func (s *ItemStore) Load(id string) (*ItemDef, error) { func (s *ItemStore) LoadAll() ([]*ItemDef, error) { dir := filepath.Join(s.dataDir, "items") - entries, err := os.ReadDir(dir) - if err != nil { - return nil, err - } var defs []*ItemDef - for _, e := range entries { - if e.IsDir() || filepath.Ext(e.Name()) != ".yaml" { - continue + err := action.WalkYAMLDir(dir, func(path, id string, data []byte) error { + if def, ok := s.cache[id]; ok { + defs = append(defs, def) + return nil } - id := strings.TrimSuffix(e.Name(), ".yaml") - def, err := s.Load(id) - if err != nil { - continue + var def ItemDef + if err := yaml.Unmarshal(data, &def); err != nil { + return nil } - defs = append(defs, def) + s.cache[id] = &def + defs = append(defs, &def) + return nil + }) + return defs, err +} + +func (s *ItemStore) PathIndex() map[string]string { + return s.pathIndex +} + +func (s *ItemStore) IDSet() map[string]bool { + ids := make(map[string]bool) + for id := range s.pathIndex { + ids[id] = true } - return defs, nil + return ids } diff --git a/internal/object/object.go b/internal/object/object.go index 4d8db69..826a315 100644 --- a/internal/object/object.go +++ b/internal/object/object.go @@ -3,7 +3,7 @@ package object import "thehouseoficarus/internal/action" type UseInteraction struct { - Item string `yaml:"item"` + Item string `yaml:"item_id"` Condition *action.Condition `yaml:"condition"` Message string `yaml:"message"` Action *action.NodeAction `yaml:"action"` diff --git a/internal/object/store.go b/internal/object/store.go index a884601..a11ff7a 100644 --- a/internal/object/store.go +++ b/internal/object/store.go @@ -5,18 +5,21 @@ import ( "os" "path/filepath" + "thehouseoficarus/internal/action" "gopkg.in/yaml.v3" ) type ObjectStore struct { - dataDir string - cache map[string]*ObjectDef + dataDir string + pathIndex map[string]string + cache map[string]*ObjectDef } func NewObjectStore(dataDir string) *ObjectStore { return &ObjectStore{ - dataDir: dataDir, - cache: make(map[string]*ObjectDef), + dataDir: dataDir, + pathIndex: action.BuildPathIndex(filepath.Join(dataDir, "objects")), + cache: make(map[string]*ObjectDef), } } @@ -24,7 +27,10 @@ func (s *ObjectStore) Load(id string) (*ObjectDef, error) { if def, ok := s.cache[id]; ok { return def, nil } - path := filepath.Join(s.dataDir, "objects", fmt.Sprintf("%s.yaml", id)) + path, ok := s.pathIndex[id] + if !ok { + return nil, fmt.Errorf("read object %s: no such object", id) + } data, err := os.ReadFile(path) if err != nil { return nil, fmt.Errorf("read object %s: %w", id, err) @@ -36,3 +42,15 @@ func (s *ObjectStore) Load(id string) (*ObjectDef, error) { s.cache[id] = &def return &def, nil } + +func (s *ObjectStore) PathIndex() map[string]string { + return s.pathIndex +} + +func (s *ObjectStore) IDSet() map[string]bool { + ids := make(map[string]bool) + for id := range s.pathIndex { + ids[id] = true + } + return ids +} diff --git a/internal/world/mob.go b/internal/world/mob.go index f7988ce..9d07532 100644 --- a/internal/world/mob.go +++ b/internal/world/mob.go @@ -144,6 +144,7 @@ func (m *MobInstance) StartRegen() { type MobStore struct { dataDir string mu sync.Mutex + pathIndex map[string]string defs map[string]*MobDef instances map[string]*MobInstance } @@ -151,6 +152,7 @@ type MobStore struct { func NewMobStore(dataDir string) *MobStore { return &MobStore{ dataDir: dataDir, + pathIndex: action.BuildPathIndex(filepath.Join(dataDir, "mobs")), defs: make(map[string]*MobDef), instances: make(map[string]*MobInstance), } @@ -164,7 +166,10 @@ func (s *MobStore) LoadDef(id string) (*MobDef, error) { } s.mu.Unlock() - path := filepath.Join(s.dataDir, "mobs", id+".yaml") + path, ok := s.pathIndex[id] + if !ok { + return nil, fmt.Errorf("read mob %s: no such mob", id) + } data, err := os.ReadFile(path) if err != nil { return nil, fmt.Errorf("read mob %s: %w", id, err) @@ -180,6 +185,14 @@ func (s *MobStore) LoadDef(id string) (*MobDef, error) { return &def, nil } +func (s *MobStore) AllDefIDs() map[string]bool { + ids := make(map[string]bool) + for id := range s.pathIndex { + ids[id] = true + } + return ids +} + func (s *MobStore) GetInstance(id string) *MobInstance { s.mu.Lock() defer s.mu.Unlock() diff --git a/internal/world/room.go b/internal/world/room.go index c0f531e..f006acc 100644 --- a/internal/world/room.go +++ b/internal/world/room.go @@ -41,8 +41,8 @@ var ExitOrder = []ExitDir{ } type SpawnDef struct { - ItemID string `yaml:"item_id"` - Quantity int `yaml:"quantity"` + ID string `yaml:"id"` + Quantity int `yaml:"quantity"` RespawnTicks float64 `yaml:"respawn_ticks"` } @@ -72,7 +72,7 @@ type Room struct { MapSymbol string `yaml:"map_symbol"` Exits map[ExitDir]ExitDef `yaml:"exits"` Objects []RoomObject `yaml:"objects"` - Spawns []SpawnDef `yaml:"spawns"` + ItemSpawns []SpawnDef `yaml:"item_spawns"` Mobs []RoomMob `yaml:"mobs"` OnEnter []EnterStep `yaml:"on_enter"` } diff --git a/internal/world/world.go b/internal/world/world.go index 3094c54..0b40918 100644 --- a/internal/world/world.go +++ b/internal/world/world.go @@ -7,36 +7,38 @@ import ( "strings" "sync" + "thehouseoficarus/internal/action" "gopkg.in/yaml.v3" ) type World struct { - dataDir string - mu sync.Mutex - groundItems map[int][]*groundEntry - seeded map[int]bool - objStates map[string]*ObjState - objMoves []ObjMove + dataDir string + mu sync.Mutex + roomPathIndex map[int]string + groundItems map[int][]*groundEntry + seeded map[int]bool + objStates map[string]*ObjState + objMoves []ObjMove } func New(dataDir string) *World { return &World{ - dataDir: dataDir, - groundItems: make(map[int][]*groundEntry), - seeded: make(map[int]bool), - objStates: make(map[string]*ObjState), + dataDir: dataDir, + roomPathIndex: action.BuildRoomIndex(filepath.Join(dataDir, "rooms")), + groundItems: make(map[int][]*groundEntry), + seeded: make(map[int]bool), + objStates: make(map[string]*ObjState), } } func (w *World) LoadRoom(id int) (*Room, error) { - path := filepath.Join(w.dataDir, "rooms", fmt.Sprintf("%d.yaml", id)) + path, ok := w.roomPathIndex[id] + if !ok { + return nil, fmt.Errorf("read room %d: no such room", id) + } data, err := os.ReadFile(path) if err != nil { - path = filepath.Join(w.dataDir, "rooms", "player_housing", fmt.Sprintf("%d.yaml", id)) - data, err = os.ReadFile(path) - if err != nil { - return nil, fmt.Errorf("read room %d: %w", id, err) - } + return nil, fmt.Errorf("read room %d: %w", id, err) } var room Room if err := yaml.Unmarshal(data, &room); err != nil { @@ -46,8 +48,8 @@ func (w *World) LoadRoom(id int) (*Room, error) { if room.Exits == nil { room.Exits = make(map[ExitDir]ExitDef) } - if room.Spawns == nil { - room.Spawns = make([]SpawnDef, 0) + if room.ItemSpawns == nil { + room.ItemSpawns = make([]SpawnDef, 0) } if room.Mobs == nil { room.Mobs = make([]RoomMob, 0) @@ -84,10 +86,10 @@ func (w *World) SeedGroundItems(roomID int) { w.mu.Lock() defer w.mu.Unlock() - for _, s := range room.Spawns { + for _, s := range room.ItemSpawns { merged := false for _, e := range w.groundItems[roomID] { - if e.quantity > 0 && strings.EqualFold(e.itemID, s.ItemID) && + if e.quantity > 0 && strings.EqualFold(e.itemID, s.ID) && (e.reserveTimer <= 0 || e.reservedFor == "") && e.despawnTimer <= 0 { e.quantity += s.Quantity @@ -100,7 +102,7 @@ func (w *World) SeedGroundItems(roomID int) { } if !merged { e := &groundEntry{ - itemID: s.ItemID, + itemID: s.ID, quantity: s.Quantity, isSpawn: true, respawnDelay: int(s.RespawnTicks), @@ -111,6 +113,14 @@ func (w *World) SeedGroundItems(roomID int) { } } +func (w *World) RoomIndex() map[int]bool { + ids := make(map[int]bool) + for id := range w.roomPathIndex { + ids[id] = true + } + return ids +} + func (w *World) Tick() { w.mu.Lock() defer w.mu.Unlock() diff --git a/worldbuilding_guide/construction.md b/worldbuilding_guide/construction.md index d4ba840..5775fbf 100644 --- a/worldbuilding_guide/construction.md +++ b/worldbuilding_guide/construction.md @@ -96,7 +96,7 @@ station: [workbench] tool: saw consume: - items: [oak_logs] - qty: 1 + quantity: 1 output: oak_planks message: "You saw the oak logs into sturdy oak planks." ``` @@ -111,7 +111,7 @@ wait: 6 station: [workbench] consume: - items: [planks] - qty: 3 + quantity: 3 output: wooden_table message: "You build a sturdy wooden table." ``` diff --git a/worldbuilding_guide/items.md b/worldbuilding_guide/items.md index a1ca8c1..2e36349 100644 --- a/worldbuilding_guide/items.md +++ b/worldbuilding_guide/items.md @@ -149,10 +149,10 @@ color: "222" ticks: 2 made_from: - items: [pot_of_flour] - qty: 1 + quantity: 1 byproducts: [empty_pot] - items: [bucket_of_water, pitcher_of_water] - qty: 1 + quantity: 1 byproducts: [empty_bucket, empty_pitcher] ``` @@ -169,10 +169,10 @@ Use `""` for items that produce no byproduct: ```yaml made_from: - items: [pot_of_flour, loose_flour] - qty: 1 + quantity: 1 byproducts: [empty_pot, ""] # pot returns empty_pot, loose flour returns nothing - items: [bucket_of_water] - qty: 1 + quantity: 1 byproducts: [empty_bucket] ``` @@ -181,10 +181,10 @@ Omit `byproducts` entirely if no items in that slot produce a byproduct: ```yaml made_from: - items: [pot_of_flour] - qty: 1 + quantity: 1 byproducts: [empty_pot] # returns empty_pot - items: [salt] - qty: 1 # no byproducts field — salt is consumed entirely + quantity: 1 # no byproducts field — salt is consumed entirely ``` See also `recipes.md` for station-based recipes. diff --git a/worldbuilding_guide/objects.md b/worldbuilding_guide/objects.md index a7da5e6..38eaeeb 100644 --- a/worldbuilding_guide/objects.md +++ b/worldbuilding_guide/objects.md @@ -124,9 +124,9 @@ Simple message (no action): id: anvil name: anvil use_interactions: - - item: silver_bar + - item_id: silver_bar message: "You should use this with a mold at a furnace." - - item: gold_bar + - item_id: gold_bar message: "You should use this with a mold at a furnace." ``` @@ -135,11 +135,11 @@ Puzzle interaction (take item, set flag): id: crystal_slot name: crystal slot use_interactions: - - item: crystal_key + - item_id: crystal_key condition: flag: crystal_inserted message: "The crystal key is already in the slot." - - item: crystal_key + - item_id: crystal_key message: "You insert the crystal key into the slot. It clicks into place." action: take_item: crystal_key @@ -150,7 +150,7 @@ use_interactions: Quest item exchange: ```yaml use_interactions: - - item: ancient_scroll + - item_id: ancient_scroll condition: player_flag: quest_started message: "You place the scroll on the pedestal. The door rumbles open!" @@ -166,7 +166,7 @@ use_interactions: | Field | Type | Description | | ----------- | ---------- | ------------------------------------------------ | -| `item` | string | Item ID that triggers this interaction | +| `item_id` | string | Item ID that triggers this interaction | | `condition` | Condition | Optional condition (same as exits/talk/use_interactions) | | `message` | string | Message shown to the player | | `action` | NodeAction | Optional actions (same as talk node actions) | diff --git a/worldbuilding_guide/recipes.md b/worldbuilding_guide/recipes.md index 81a1240..29b513a 100644 --- a/worldbuilding_guide/recipes.md +++ b/worldbuilding_guide/recipes.md @@ -4,7 +4,7 @@ Recipes define how items are processed on stations to produce new items. They are the foundation for cooking, smithing, crafting, and fletching. -Recipe files live in `data/recipes/<id>.yaml`. +Recipe files live in `data/recipes/<type>/<id>.yaml` (e.g., `data/recipes/smithing/smith_bronze_dagger.yaml`). ### Recipe vs MadeFrom @@ -39,7 +39,7 @@ Each consume entry defines an ingredient slot with multiple valid items. The fir ```yaml consume: - items: [item_id, alternative_id, ...] - qty: 1 + quantity: 1 byproducts: [byproduct_for_item, byproduct_for_alt, ...] ``` @@ -48,10 +48,10 @@ consume: ```yaml consume: - items: [bucket_of_water, vial_of_water] - qty: 1 + quantity: 1 byproducts: [empty_bucket, ""] # bucket returns empty, vial is consumed entirely - items: [herb] - qty: 1 # no byproducts — herb is consumed entirely + quantity: 1 # no byproducts — herb is consumed entirely ``` ### Station-based recipe (cooking on a fire) @@ -66,7 +66,7 @@ wait: 6 station: [fire, cooking_range] consume: - items: [raw_trout] - qty: 1 + quantity: 1 output: trout fail: burnt_fish message: "Cooked to perfection. It looks great!" @@ -85,7 +85,7 @@ wait: 6 station: [cooking_range] consume: - items: [bread_dough] - qty: 1 + quantity: 1 output: bread fail: burnt_meat message: "You bake the dough into a fresh loaf of bread." @@ -106,9 +106,9 @@ wait: 4 station: [furnace] consume: - items: [iron_ore] - qty: 1 + quantity: 1 - items: [coal] - qty: 2 + quantity: 2 output: steel_bar message: "You remove a white hot steel bar!" fail_message: "You fail to smelt a usable bar." @@ -137,7 +137,7 @@ wait: 4 station: [anvil] consume: - items: [steel_bar] - qty: 5 + quantity: 5 output: steel_platebody message: "You hammer out a steel platebody." ``` @@ -154,7 +154,7 @@ wait: 4 station: [anvil] consume: - items: [iron_bar] - qty: 1 + quantity: 1 output: iron_nails output_qty: 15 message: "You hammer out some iron nails." @@ -171,9 +171,9 @@ name: bread dough color: "222" made_from: - items: [pot_of_flour] - qty: 1 + quantity: 1 - items: [bucket_of_water, pitcher_of_water, vial_of_water] - qty: 1 + quantity: 1 ``` The player uses `use flour on water` to combine them. The system finds that `bread_dough` can be made from these ingredients and produces it. diff --git a/worldbuilding_guide/rooms.md b/worldbuilding_guide/rooms.md index f6e74ea..3d6db7d 100644 --- a/worldbuilding_guide/rooms.md +++ b/worldbuilding_guide/rooms.md @@ -67,14 +67,14 @@ exits: blocked_message: "The bridge is out, and the toll collector blocks the path." ``` -### Spawns — ground items that respawn +### Item Spawns — ground items that respawn ```yaml -spawns: - - item_id: bronze_pickaxe +item_spawns: + - id: bronze_pickaxe quantity: 1 respawn_ticks: 30 # reappears 30 ticks (18 seconds) after being picked up - - item_id: copper_ore + - id: copper_ore quantity: 3 respawn_ticks: 50 ``` |
