11 KiB
11 KiB
Draugnorak Project Guidelines
NVGT Workflow
- Use the
nvgt-engine-devskill for NVGT API behavior, include/module decisions, and engine-source verification. - If API behavior is uncertain, verify against primary sources in
nvgt/(engine source) anddocs/nvgt/before coding. - Reuse shared helpers in
libstorm-nvgt/before creating project-local replacements.
libstorm-nvgt Workflow
- Treat
~/git/libstorm-nvgtas the canonical repository for shared library changes. - Do not make canonical library changes directly inside this repo's
libstorm-nvgt/copy first. - Hard stop: do not implement shared-library edits in this repo's
libstorm-nvgt/submodule copy. Make the change in~/git/libstorm-nvgt, commit it there, then update the submodule pointer here. - When shared helper behavior must change:
- Implement and commit the change in
~/git/libstorm-nvgt. - Update this repo to the new
libstorm-nvgtsubmodule commit. - Verify Draugnorak still compiles with
./nvgt -c draugnorak.nvgtafter updating the pointer.
- Implement and commit the change in
AGENTS.md Maintenance
- Keep this file aligned with the real repository layout and active workflows.
- Update
AGENTS.mdin the same PR/commit when any of the following change:- Core directories/modules (for example new systems under
src/,scripts/, ordocs/). - Required build/test/validation commands.
- Localization workflow expectations.
- Canonical engine/library source locations or skill usage expectations.
- Core directories/modules (for example new systems under
- If a section is uncertain or outdated, replace it with a short verified statement instead of leaving stale instructions.
Project Structure
Key paths (focused, not exhaustive):
draugnorak.nvgt- Main game entry point.src/- Core gameplay systems.constants.nvgt,player.nvgt,time_system.nvgt- Global state and timing.world_state.nvgt,src/world/- World object orchestration and world systems.src/enemies/,combat.nvgt,creature_*- Enemy and combat behavior.inventory.nvgt,inventory_items.nvgt,inventory_menus.nvgt,item_registry.nvgt- Inventory/equipment/items.crafting.nvgt,src/crafting/- Crafting orchestration and recipe categories.quest_system.nvgt,src/quests/,src/bosses/- Quests, adventures, and boss content.base_system.nvgt,environment.nvgt,weather.nvgt,fishing.nvgt,pet_system.nvgt,fylgja_system.nvgt- Survival systems.i18n.nvgt- Translation loading and lookup wrappers.save_system.nvgt- Save/load behavior.
lang/- Localization catalogs (en.ini,en.template.ini, and per-language files such ases.ini).scripts/- Build and i18n tooling (generate_i18n_catalog.py,validate_i18n_catalog.py,audit_untranslated_strings.py).docs/- Implementation references (patterns.md,rune_system.md,localization.md).libstorm-nvgt/- Shared NVGT helpers reused by this project.sounds/- Game audio assets.
Game Mechanics
Inventory Limits
- Personal inventory stacks are capped at 9
- Skin pouches add +2 stack capacity, backpacks add +9
Map Layout
- Base area: x 0-4 (wood terrain)
- Grass area: x 5-19 (grass terrain, contains trees)
- Gravel area: x 20-34 (gravel terrain, contains stones)
Healing System
- Base area provides passive healing when player health < max
- Without herb garden: 1 HP every 2.5 minutes (150000ms)
- With herb garden: 1 HP every 30 seconds (30000ms)
- Herb garden can only be built in base area (x <= 4)
- Only one herb garden allowed per base
Fire System
- Fires require a firepit to build
- New fires start with 12 minutes (720000ms) of fuel
- Warning at 30 seconds remaining
- Fire goes out when fuel depletes
- Fire sound plays within 3 tiles distance
- Jumping over fire prevents damage
- Feeding fire is done from the Action menu (A)
Snare System
- Snares become active when player moves away
- Check every hour for catching/escaping small game
- Catch chance starts at 5%, increases by 5% per hour (max 75%)
- Escape chance: 0% for first hour after catch, then increases by 2% per hour (max 95%)
- Snare sound plays within 2 tiles distance
- Residents can retrieve game from snares (daytime only, requires meat in storage)
Tree System
- Trees regenerate fully after ~5 minutes (minute-by-minute refill logic)
- Tree ambient sound plays within 4 tiles distance
- Trees only play sound when not chopped
- Climb down only when in a tree (Down arrow does nothing during jumps or when not in a tree)
- Trees have height; falling damage is applied when falling from height
Notification System
- Important events use
notify()function (plays sounds/notify.ogg + speaks message) - Last 10 notifications stored in history
- Navigation keys:
\- Repeat most recent notification]- Next (newer) notification[(Shift+Comma) - Previous (older) notification
- Navigating history speaks message without notification sound
- Speech history (screen_reader_speak wrapper) uses
,and.for previous/next message
Search System
- Hold Shift for 1 second to search
- Search completes after 1-second delay
Undead System
- At night, zombies spawn (5 max) and wander outside the base
- Zombies cannot enter the base while barricade health > 0
- Zombies attack the barricade for 4-6 damage when they reach it; play
sounds/enemies/zombie_hit.ogg - Zombies vanish at daybreak
- Player can hit zombies with spear (1-tile range) or sling (8-tile range)
Barricade System
- Base starts with 100 barricade health, capped at 500
- In base, press B to report barricade health
- Crafting menu includes Barricade category for reinforcement
- Reinforcement costs and health: 3 sticks (+10), 5 vines (+15), 1 log (+30), 5 stones (+20)
- Barricade health does not reset during gameplay
Mountains, Rope Climbing, Falling
- Mountain ranges can appear during area expansion with elevation-based terrain
- Steep slopes require a rope; the player is prompted to press Up/Down to climb
- Moving left/right during rope climb cancels and causes a fall
- Falling damage is applied beyond a safe height (10 feet)
World Expansion & Invasions
- After day 2, bandit invasions can trigger and expand the map to the east
- Expansion is either a 30-tile biome strip or a 60-tile mountain range
- Invasions last 1 hour and spawn bandits in the expanded area during daytime
Weather & Ambience
- Weather transitions between clear, windy, rainy, stormy with wind/rain/thunder audio
- Day/night ambience crossfades on hour changes
Inventory + Equipment
- Item definitions live in
src/item_registry.nvgt(personal + storage inventories) - Equipment includes spear, axe, sling, bow, clothing, pouches, backpacks
- Combat logic currently supports spear/axe/sling; bow attacks are not implemented yet
- Quivers gate arrow capacity (12 arrows per quiver)
- Quick slots (keys 1-0) bind equipment from the Equipment menu
Buildings
- Firepit, Fire, Herb Garden, Storage, Pasture, Stable, Altar
- Storage enables base inventory menus and increases resident recruitment chance
Residents and Base Automation
- Residents consume meat daily, can repair the barricade, defend with stored weapons, and collect resources
- Residents use spears or slings (requires stones) for defense
- Daily weapon breakage occurs based on resident count
Favor, Altars, Incense, Blessings
- Altar sacrifices (S key, base only) convert items to Favor
- Burning incense (A key action) grants Favor per hour while active
- Blessings can trigger (heal, speed boost, barricade repair) and consume Favor
Quests (Mini-Games)
- Quest menu (Q, base only) appears after altar/favor requirements
- Max 4 active quests; rewards grant Favor and resources
Adventures & Bosses
- Adventure menu (Tab) available outside base; limited to once per day
- Mountain adventure: Unicorn boss; victory grants Favor and unlocks Rune of Swiftness
Runes
- Rune system in
src/runes/(data + effects) - Runes are crafted in Crafting > Runes after unlock (requires knife + clay + favor)
- Rune of Swiftness grants move speed and gathering bonuses; runed items are tracked separately
Menu Structure
Crafting Menu (C key, base only)
Organized into categories:
- Weapons: Spear, Sling
- Tools: Knife, Snare, Stone Axe, Fishing Pole, Rope, Reed Basket, Clay Pot
- Materials: Butcher Game, Incense
- Clothing: Skin gear, Moccasins, Pouch, Backpack
- Buildings: Firepit, Fire, Herb Garden, Storage, Pasture, Stable, Altar
- Barricade: Reinforcement options
- Runes: Available after rune unlocks
Equipment Menu (E key)
- Only shows items player actually has
- Shows equipped status
- Says "Nothing to equip" if inventory is empty
Inventory Menu (I key)
- Base + storage built: root menu for personal vs storage
- No storage: personal inventory only
Action Menu (A key)
- Place snares, feed fires, burn incense (context-sensitive)
- Tab in menu performs “max” action for the selected option
Base Info (B key)
- Barricade health, residents, storage totals, base buildings
Quest Menu (Q key)
- Base-only quest selection for mini-games
Adventure Menu (Tab key)
- Terrain-based adventures outside the base (once per day)
Testing
- Always run
./nvgt -c draugnorak.nvgtafter code changes - This compiles without opening the game window and prevents it from taking over the terminal
- If user-facing text changed, also run:
python3 scripts/generate_i18n_catalog.pypython3 scripts/validate_i18n_catalog.pypython3 scripts/audit_untranslated_strings.py
Localization Workflow
- Any new or changed user-facing string must be localizable; avoid hardcoded UI/gameplay text in NVGT files.
- Update the English catalogs in the same change as text changes by running
python3 scripts/generate_i18n_catalog.py. - Keep
lang/en.iniandlang/en.template.iniin sync with code changes. - Validate all translation catalogs with
python3 scripts/validate_i18n_catalog.pyand fix missing keys/placeholders before merging. - Run
python3 scripts/audit_untranslated_strings.pyafter text-heavy changes; keepscripts/i18n_audit_allowlist.txtsmall and commented. - Preserve placeholders exactly as written (for example
{arg1},{language}) and keep escapes such as\nand\tintact. - For new translations, copy
lang/en.template.initolang/<code>.ini, then update[meta](code,name,native_name) to match the file. - Translator-facing instructions live in
translate.md; developer-level localization details live indocs/localization.md.
Code Standards
- Use
notify()for important game events that should be reviewable - Use
screen_reader_speak()for immediate feedback that doesn't need to be stored - All menus must call
menu_background_tick()each loop to keep game state updating - Time references: When discussing time (hours, minutes, days), assume game time unless explicitly stated as "real time". Game time runs at 60x speed: 1 real minute = 1 game hour, 24 real minutes = 1 game day.
- See
docs/patterns.mdfor module and creature patterns - See
docs/rune_system.mdfor rune data/effects/save requirements