From 874512e3b27664a1761465a859878c6720b49c44 Mon Sep 17 00:00:00 2001 From: Storm Dragon Date: Fri, 27 Feb 2026 23:58:21 -0500 Subject: [PATCH] A bit of repository cleanup. --- AGENTS.md | 229 ----------------------------------------------------- package.sh | 223 --------------------------------------------------- 2 files changed, 452 deletions(-) delete mode 100644 AGENTS.md delete mode 100755 package.sh diff --git a/AGENTS.md b/AGENTS.md deleted file mode 100644 index e089cba..0000000 --- a/AGENTS.md +++ /dev/null @@ -1,229 +0,0 @@ -# Draugnorak Project Guidelines - -## NVGT Workflow - -- Use the `nvgt-engine-dev` skill for NVGT API behavior, include/module decisions, and engine-source verification. -- If API behavior is uncertain, verify against primary sources in `nvgt/` (engine source) and `docs/nvgt/` before coding. -- Reuse shared helpers in `libstorm-nvgt/` before creating project-local replacements. - -## libstorm-nvgt Workflow - -- Treat `~/git/libstorm-nvgt` as 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-nvgt` submodule commit. - - Verify Draugnorak still compiles with `./nvgt -c draugnorak.nvgt` after updating the pointer. - -## AGENTS.md Maintenance - -- Keep this file aligned with the real repository layout and active workflows. -- Update `AGENTS.md` in the same PR/commit when any of the following change: - - Core directories/modules (for example new systems under `src/`, `scripts/`, or `docs/`). - - Required build/test/validation commands. - - Localization workflow expectations. - - Canonical engine/library source locations or skill usage expectations. -- 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 as `es.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.nvgt` after 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.py` - - `python3 scripts/validate_i18n_catalog.py` - - `python3 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.ini` and `lang/en.template.ini` in sync with code changes. -- Validate all translation catalogs with `python3 scripts/validate_i18n_catalog.py` and fix missing keys/placeholders before merging. -- Run `python3 scripts/audit_untranslated_strings.py` after text-heavy changes; keep `scripts/i18n_audit_allowlist.txt` small and commented. -- Preserve placeholders exactly as written (for example `{arg1}`, `{language}`) and keep escapes such as `\n` and `\t` intact. -- For new translations, copy `lang/en.template.ini` to `lang/.ini`, then update `[meta]` (`code`, `name`, `native_name`) to match the file. -- Translator-facing instructions live in `translate.md`; developer-level localization details live in `docs/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.md` for module and creature patterns -- See `docs/rune_system.md` for rune data/effects/save requirements diff --git a/package.sh b/package.sh deleted file mode 100755 index 48da1ee..0000000 --- a/package.sh +++ /dev/null @@ -1,223 +0,0 @@ -#!/usr/bin/env bash - -set -euo pipefail - -# create Draugnorak package for all platforms. - -tmpAndroidToolsDir="" -tmpAndroidConfigBackup="" -createdAndroidConfig="0" -tmpAndroidWrapperSource="" -tmpAndroidPackFile="" -tmpAndroidPackBuilder="" - -trap 'rm -fv README.html; if [[ -n "${tmpAndroidToolsDir}" && -d "${tmpAndroidToolsDir}" ]]; then rm -rf "${tmpAndroidToolsDir}"; fi; if [[ -n "${tmpAndroidConfigBackup}" && -f "${tmpAndroidConfigBackup}" ]]; then mv -f "${tmpAndroidConfigBackup}" draugnorak.properties; elif [[ "${createdAndroidConfig}" == "1" ]]; then rm -f draugnorak.properties; fi; if [[ -n "${tmpAndroidWrapperSource}" && -f "${tmpAndroidWrapperSource}" ]]; then rm -f "${tmpAndroidWrapperSource}"; fi; if [[ -n "${tmpAndroidPackBuilder}" && -f "${tmpAndroidPackBuilder}" ]]; then rm -f "${tmpAndroidPackBuilder}"; fi; if [[ -n "${tmpAndroidPackFile}" && -f "${tmpAndroidPackFile}" ]]; then rm -f "${tmpAndroidPackFile}"; fi' EXIT - -escape_nvgt_string() { - local inputValue="$1" - inputValue="${inputValue//\\/\\\\}" - inputValue="${inputValue//\"/\\\"}" - printf '%s\n' "${inputValue}" -} - -find_android_sdk_root() { - local sdkRoot - for sdkRoot in "${ANDROID_HOME:-}" "${ANDROID_SDK_HOME:-}" "/opt/android-sdk" "${HOME}/Android/Sdk" "${HOME}/Android/sdk"; do - if [[ -n "${sdkRoot}" && -d "${sdkRoot}" ]]; then - printf '%s\n' "${sdkRoot}" - return 0 - fi - done - return 1 -} - -find_latest_build_tools_dir() { - local sdkRoot="$1" - local buildToolsDir="" - if [[ ! -d "${sdkRoot}/build-tools" ]]; then - return 1 - fi - buildToolsDir="$(find "${sdkRoot}/build-tools" -mindepth 1 -maxdepth 1 -type d | sort -V | tail -n 1)" - if [[ -z "${buildToolsDir}" ]]; then - return 1 - fi - printf '%s\n' "${buildToolsDir}" -} - -find_latest_android_jar() { - local sdkRoot="$1" - local androidJar="" - if [[ ! -d "${sdkRoot}/platforms" ]]; then - return 1 - fi - androidJar="$(find "${sdkRoot}/platforms" -mindepth 2 -maxdepth 2 -type f -name android.jar | sort -V | tail -n 1)" - if [[ -z "${androidJar}" ]]; then - return 1 - fi - printf '%s\n' "${androidJar}" -} - -setup_android_tools_workaround() { - local sdkRoot="$1" - local buildToolsDir="$2" - local androidJar="$3" - local javaBin="" - local keytoolBin="" - local adbBin="" - - tmpAndroidToolsDir="$(mktemp -d)" - - ln -sf "${buildToolsDir}/zipalign" "${tmpAndroidToolsDir}/zipalign" - ln -sf "${buildToolsDir}/lib/apksigner.jar" "${tmpAndroidToolsDir}/apksigner.jar" - ln -sf "${androidJar}" "${tmpAndroidToolsDir}/android.jar" - - if command -v java >/dev/null 2>&1; then - javaBin="$(command -v java)" - ln -sf "${javaBin}" "${tmpAndroidToolsDir}/java" - fi - - if command -v keytool >/dev/null 2>&1; then - keytoolBin="$(command -v keytool)" - ln -sf "${keytoolBin}" "${tmpAndroidToolsDir}/keytool" - fi - - if command -v adb >/dev/null 2>&1; then - adbBin="$(command -v adb)" - ln -sf "${adbBin}" "${tmpAndroidToolsDir}/adb" - fi - - cat > "${tmpAndroidToolsDir}/aapt2" < "${builderScriptPath}" <> "${builderScriptPath}" - done < <(find sounds -type f | sort) - - cat >> "${builderScriptPath}" <<'EOF' - soundPack.close(); -} -EOF - - ./nvgt "${builderScriptPath}" - if [[ ! -f "${outputPackPath}" ]]; then - echo "Failed to build Android sound pack: ${outputPackPath}" - exit 1 - fi -} - -# Generate documentation -pandoc -s files/instructions.md -o README.html - -# Create packages -for platformName in linux mac windows android; do - echo "Packaging Draugnorak for ${platformName^}..." - if [[ "${platformName}" == "android" ]]; then - androidKeystorePath="${DRAUGNORAK_ANDROID_KEYSTORE:-${PWD}/.nvgt_android.keystore}" - sdkRoot="$(find_android_sdk_root || true)" - if [[ -z "${sdkRoot}" ]]; then - echo "Android SDK not found. Set ANDROID_HOME or ANDROID_SDK_HOME." - exit 1 - fi - buildToolsDir="$(find_latest_build_tools_dir "${sdkRoot}" || true)" - if [[ -z "${buildToolsDir}" || ! -x "${buildToolsDir}/aapt2" || ! -x "${buildToolsDir}/zipalign" || ! -f "${buildToolsDir}/lib/apksigner.jar" ]]; then - echo "Missing required Android build tools in ${sdkRoot}." - exit 1 - fi - androidJar="$(find_latest_android_jar "${sdkRoot}" || true)" - if [[ -z "${androidJar}" ]]; then - echo "No android.jar found in ${sdkRoot}/platforms." - exit 1 - fi - setup_android_tools_workaround "${sdkRoot}" "${buildToolsDir}" "${androidJar}" - - if [[ -f draugnorak.properties ]]; then - tmpAndroidConfigBackup="$(mktemp)" - cp draugnorak.properties "${tmpAndroidConfigBackup}" - cat "${tmpAndroidConfigBackup}" > draugnorak.properties - else - createdAndroidConfig="1" - fi - { - printf '%s\n' "build.android_install = 0" - printf '%s\n' "build.android_signature_cert = ${androidKeystorePath}" - printf '%s\n' "build.output_basename = draugnorak" - } >> draugnorak.properties - - tmpAndroidPackFile=".draugnorak_android_sounds.dat" - tmpAndroidPackBuilder=".draugnorak_make_android_pack.nvgt" - build_android_sound_pack "${tmpAndroidPackFile}" "${tmpAndroidPackBuilder}" - - tmpAndroidWrapperSource=".draugnorak_android_bundle_pragmas.nvgt" - cat > "${tmpAndroidWrapperSource}" <<'EOF' -#pragma embed ".draugnorak_android_sounds.dat" -#pragma asset files -#pragma document "README.html" - -pack@ androidSoundPack; -bool preglobals() { - @androidSoundPack = pack(); - if (androidSoundPack.open("*.draugnorak_android_sounds.dat", PACK_OPEN_MODE_READ)) { - @sound_default_pack = @androidSoundPack; - } - return true; -} -EOF - - PATH="${tmpAndroidToolsDir}:${PATH}" ./nvgt -c --platform "${platformName}" --include "${tmpAndroidWrapperSource}" draugnorak.nvgt - else - ./nvgt -c --platform "${platformName}" draugnorak.nvgt - fi - case "${platformName}" in - "linux"|"windows") - zip -r draugnorak.zip files/ sounds/ README.html - mv draugnorak.zip "draugnorak-${platformName}.zip" - ;; - "mac") - mkdir -p draugnorak.app/Contents/Resources - cp -r files draugnorak.app/Contents/Resources - cp -r sounds draugnorak.app/Contents/Resources - cp README.html draugnorak.app/Contents/Resources - zip -r draugnorak.app.zip draugnorak.app fix_mac.sh - rm -rfv draugnorak.app/ - ;; - "android") - zip -r draugnorak-android.zip draugnorak.apk files/ sounds/ README.html - ;; - esac -done - -echo "Packaging complete!" - -exit 0