From 9a6f991fda20929d17b539a530df0e16e3a2e4c6 Mon Sep 17 00:00:00 2001 From: Valtteri Valo Date: Sun, 16 Aug 2026 11:11:53 +0300 Subject: [PATCH 01/15] Fix OSRS asset preload args --- ocean/osrs/scripts/osrs_asset_manifest.py | 16 ++++- tests/test_osrs_asset_manifest_preload.py | 80 +++++++++++++++++++++++ 2 files changed, 94 insertions(+), 2 deletions(-) create mode 100644 tests/test_osrs_asset_manifest_preload.py diff --git a/ocean/osrs/scripts/osrs_asset_manifest.py b/ocean/osrs/scripts/osrs_asset_manifest.py index 86db01e6bb..a4ce467b64 100755 --- a/ocean/osrs/scripts/osrs_asset_manifest.py +++ b/ocean/osrs/scripts/osrs_asset_manifest.py @@ -294,17 +294,29 @@ def print_group_files(manifest: AssetManifest, group_names: list[str]) -> None: print(f"{group.name}\t{asset_path}") -def print_emcc_preload_args(manifest: AssetManifest, group_names: list[str]) -> None: +def emcc_preload_args(manifest: AssetManifest, group_names: list[str]) -> list[str]: requested = set(group_names) manifest_names = {group.name for group in manifest.required_groups} unknown = requested - manifest_names if unknown: raise SystemExit(f"osrs-assets: unknown groups: {', '.join(sorted(unknown))}") + seen: set[str] = set() + lines: list[str] = [] for group in manifest.required_groups: if requested and group.name not in requested: continue for asset_path in group.files: - print(f"--preload-file ocean/osrs/data/{asset_path}@{asset_path}") + if asset_path in seen: + continue + seen.add(asset_path) + runtime_path = f"ocean/osrs/data/{asset_path}" + lines.append(f"--preload-file {runtime_path}@{runtime_path}") + return lines + + +def print_emcc_preload_args(manifest: AssetManifest, group_names: list[str]) -> None: + for line in emcc_preload_args(manifest, group_names): + print(line) def main(argv: list[str]) -> int: diff --git a/tests/test_osrs_asset_manifest_preload.py b/tests/test_osrs_asset_manifest_preload.py new file mode 100644 index 0000000000..483533d115 --- /dev/null +++ b/tests/test_osrs_asset_manifest_preload.py @@ -0,0 +1,80 @@ +from pathlib import Path + +from ocean.osrs.scripts import osrs_asset_manifest + + +def synthetic_manifest(*groups: tuple[str, tuple[str, ...]]) -> osrs_asset_manifest.AssetManifest: + return osrs_asset_manifest.AssetManifest( + format=osrs_asset_manifest.EXPECTED_FORMAT, + asset_version="test", + archive=osrs_asset_manifest.AssetArchive( + name="test.tar.gz", + url="https://example.com/test.tar.gz", + sha256="0" * 64, + strip_components=0, + ), + required_groups=tuple( + osrs_asset_manifest.RequiredGroup(name=name, files=files) + for name, files in groups + ), + ) + + +def test_selected_groups_emit_ordered_unique_full_vfs_paths() -> None: + manifest = synthetic_manifest( + ("core", ("shared.bin", "core.bin")), + ("inferno", ("shared.bin", "inferno.bin")), + ) + + assert osrs_asset_manifest.emcc_preload_args(manifest, ["core", "inferno"]) == [ + "--preload-file ocean/osrs/data/shared.bin@ocean/osrs/data/shared.bin", + "--preload-file ocean/osrs/data/core.bin@ocean/osrs/data/core.bin", + "--preload-file ocean/osrs/data/inferno.bin@ocean/osrs/data/inferno.bin", + ] + + +def test_group_argument_order_does_not_change_manifest_order() -> None: + manifest = synthetic_manifest( + ("core", ("core.bin",)), + ("inferno", ("inferno.bin",)), + ) + + forward = osrs_asset_manifest.emcc_preload_args(manifest, ["core", "inferno"]) + reverse = osrs_asset_manifest.emcc_preload_args(manifest, ["inferno", "core"]) + + assert reverse == forward + assert forward == [ + "--preload-file ocean/osrs/data/core.bin@ocean/osrs/data/core.bin", + "--preload-file ocean/osrs/data/inferno.bin@ocean/osrs/data/inferno.bin", + ] + + +def test_empty_group_selection_emits_every_asset_once() -> None: + manifest = synthetic_manifest( + ("core", ("shared.bin", "core.bin")), + ("inferno", ("shared.bin", "inferno.bin")), + ("gui", ("gui.bin",)), + ) + + assert osrs_asset_manifest.emcc_preload_args(manifest, []) == [ + "--preload-file ocean/osrs/data/shared.bin@ocean/osrs/data/shared.bin", + "--preload-file ocean/osrs/data/core.bin@ocean/osrs/data/core.bin", + "--preload-file ocean/osrs/data/inferno.bin@ocean/osrs/data/inferno.bin", + "--preload-file ocean/osrs/data/gui.bin@ocean/osrs/data/gui.bin", + ] + + +def test_inferno_web_groups_emit_43_unique_matching_vfs_paths() -> None: + root = Path(__file__).resolve().parents[1] + manifest = osrs_asset_manifest.load_manifest(root / "ocean/osrs/asset_manifest.json") + lines = osrs_asset_manifest.emcc_preload_args( + manifest, + ["core", "inferno", "combat_visuals", "gui", "items"], + ) + + assert len(lines) == 43 + assert len(set(lines)) == 43 + for line in lines: + source, destination = line.removeprefix("--preload-file ").split("@", 1) + assert source == destination + assert source.startswith("ocean/osrs/data/") From 2bf7d99c5487968d3af42d274b27d199f7c62f38 Mon Sep 17 00:00:00 2001 From: Valtteri Valo Date: Sun, 16 Aug 2026 11:24:34 +0300 Subject: [PATCH 02/15] Add Inferno web build --- build.sh | 37 +++++ tools/web/osrs_inferno_shell.html | 222 ++++++++++++++++++++++++++++++ 2 files changed, 259 insertions(+) create mode 100644 tools/web/osrs_inferno_shell.html diff --git a/build.sh b/build.sh index 052bbcc4d5..32c89fb3ad 100755 --- a/build.sh +++ b/build.sh @@ -287,6 +287,43 @@ if [ "$MODE" = "cpu" ]; then echo "Built: ./$OUTPUT_NAME" exit 0 elif [ "$MODE" = "web" ]; then + if [ "$ENV" = "osrs_inferno" ]; then + mkdir -p "build/web/$ENV" + OSRS_PRELOAD_LINES=$(python3 ocean/osrs/scripts/osrs_asset_manifest.py \ + emcc-preload-args ocean/osrs/asset_manifest.json \ + --group core \ + --group inferno \ + --group combat_visuals \ + --group gui \ + --group items) + OSRS_PRELOAD=() + while IFS= read -r line; do + [ -z "$line" ] && continue + if [[ "$line" != "--preload-file "* ]]; then + echo "Error: invalid OSRS preload argument: $line" + exit 1 + fi + OSRS_PRELOAD+=(--preload-file "${line#--preload-file }") + done <<< "$OSRS_PRELOAD_LINES" + echo "Compiling $ENV for web..." + emcc \ + -o "build/web/$ENV/game.html" \ + ocean/osrs_inferno/osrs_inferno.c \ + -O3 -Wall -Wno-narrowing \ + "${LINK_ARCHIVES[@]}" \ + -I. -Isrc -I$SRC_DIR -Ivendor "${INCLUDES[@]}" \ + -L. -L./$RAYLIB_NAME/lib \ + -sASSERTIONS=2 -gsource-map \ + -sUSE_GLFW=3 -sUSE_WEBGL2=1 -sASYNCIFY -sFILESYSTEM -sFORCE_FILESYSTEM=1 \ + -sLZ4=1 \ + --shell-file tools/web/osrs_inferno_shell.html \ + -sINITIAL_MEMORY=512MB -sALLOW_MEMORY_GROWTH -sSTACK_SIZE=512KB \ + -DPLATFORM_WEB -DGRAPHICS_API_OPENGL_ES3 \ + "${OSRS_PRELOAD[@]}" \ + "${EXTRA_CFLAGS[@]}" + echo "Built: build/web/$ENV/game.html" + exit 0 + fi ENV_HEADER="$SRC_DIR/$ENV.h" if ! grep -q 'typedef[[:space:]].*obs_t' "$ENV_HEADER" 2>/dev/null; then echo "Error: $ENV_HEADER must typedef obs_t for web eval" diff --git a/tools/web/osrs_inferno_shell.html b/tools/web/osrs_inferno_shell.html new file mode 100644 index 0000000000..afbdc7f690 --- /dev/null +++ b/tools/web/osrs_inferno_shell.html @@ -0,0 +1,222 @@ + + + + + + OSRS Inferno Simulator + + + +
+

OSRS Inferno

+
Loading simulator
+
+ + +
+
+
+ +
+ + {{{ SCRIPT }}} + + From 3962fef2e8e6ef5657de028caf5c583cf9446a9c Mon Sep 17 00:00:00 2001 From: Valtteri Valo Date: Sun, 16 Aug 2026 11:37:41 +0300 Subject: [PATCH 03/15] Package Inferno web bundle --- tests/test_package_osrs_inferno.py | 284 +++++++++++++++++++++++++++++ tools/web/package_osrs_inferno.py | 210 +++++++++++++++++++++ 2 files changed, 494 insertions(+) create mode 100644 tests/test_package_osrs_inferno.py create mode 100644 tools/web/package_osrs_inferno.py diff --git a/tests/test_package_osrs_inferno.py b/tests/test_package_osrs_inferno.py new file mode 100644 index 0000000000..a9d9b33393 --- /dev/null +++ b/tests/test_package_osrs_inferno.py @@ -0,0 +1,284 @@ +import hashlib +import json +import re +import subprocess +import sys +from pathlib import Path + +import pytest + + +REPOSITORY_ROOT = Path(__file__).resolve().parents[1] +PACKAGE_SCRIPT = REPOSITORY_ROOT / "tools/web/package_osrs_inferno.py" +SOURCE_COMMIT = "a" * 40 +GAME_FILES = ( + "game.html", + "game.js", + "game.wasm", + "game.wasm.map", + "game.data", +) +OUTPUT_FILES = { + "game.html", + "game.js", + "game.wasm", + "game.wasm.map", + "game.data", + "bundle.json", + "models/osrs_inferno.bin", +} + + +def write_build(build_dir: Path, html: bytes = b"before __OSRS_BUNDLE_VERSION__ after\n") -> None: + build_dir.mkdir() + contents = { + "game.html": html, + "game.js": b"javascript\n", + "game.wasm": b"wasm\x00bytes", + "game.wasm.map": b'{"version": 3}\n', + "game.data": b"data\x00bytes", + } + for name, content in contents.items(): + (build_dir / name).write_bytes(content) + + +def run_package( + build_dir: Path, + model: Path, + output_dir: Path, + *, + source_commit: str = SOURCE_COMMIT, + hidden_size: str = "512", + num_layers: str = "2", + entity_encoder: str = "0", +) -> subprocess.CompletedProcess[str]: + return subprocess.run( + [ + sys.executable, + str(PACKAGE_SCRIPT), + "--build-dir", + str(build_dir), + "--model", + str(model), + "--out", + str(output_dir), + "--source-commit", + source_commit, + "--hidden-size", + hidden_size, + "--num-layers", + num_layers, + "--entity-encoder", + entity_encoder, + ], + capture_output=True, + text=True, + check=False, + cwd=REPOSITORY_ROOT, + ) + + +def output_file_paths(output_dir: Path) -> set[str]: + return { + path.relative_to(output_dir).as_posix() + for path in output_dir.rglob("*") + if path.is_file() + } + + +def sha256(path: Path) -> str: + return hashlib.sha256(path.read_bytes()).hexdigest() + + +def test_missing_required_build_file_does_not_replace_existing_output(tmp_path: Path) -> None: + build_dir = tmp_path / "build" + write_build(build_dir) + (build_dir / "game.data").unlink() + model = tmp_path / "policy.bin" + model.write_bytes(b"model") + output_dir = tmp_path / "site" + output_dir.mkdir() + sentinel = output_dir / "keep.txt" + sentinel.write_text("keep") + + result = run_package(build_dir, model, output_dir) + + assert result.returncode != 0 + assert "game.data" in result.stderr + assert sentinel.read_text() == "keep" + assert output_file_paths(output_dir) == {"keep.txt"} + + +def test_missing_model_does_not_replace_existing_output(tmp_path: Path) -> None: + build_dir = tmp_path / "build" + write_build(build_dir) + output_dir = tmp_path / "site" + output_dir.mkdir() + sentinel = output_dir / "keep.txt" + sentinel.write_text("keep") + + result = run_package(build_dir, tmp_path / "missing.bin", output_dir) + + assert result.returncode != 0 + assert "missing.bin" in result.stderr + assert sentinel.read_text() == "keep" + assert output_file_paths(output_dir) == {"keep.txt"} + + +@pytest.mark.parametrize( + ("overrides", "invalid_value"), + [ + ({"source_commit": "A" * 40}, "source commit"), + ({"source_commit": "a" * 39}, "source commit"), + ({"hidden_size": "0"}, "hidden size"), + ({"hidden_size": "not-an-int"}, "hidden size"), + ({"num_layers": "0"}, "num layers"), + ({"entity_encoder": "2"}, "entity encoder"), + ], +) +def test_invalid_metadata_fails( + tmp_path: Path, + overrides: dict[str, str], + invalid_value: str, +) -> None: + build_dir = tmp_path / "build" + write_build(build_dir) + model = tmp_path / "policy.bin" + model.write_bytes(b"model") + output_dir = tmp_path / "site" + + result = run_package(build_dir, model, output_dir, **overrides) + + assert result.returncode != 0 + assert invalid_value in result.stderr.lower() + assert not output_dir.exists() + + +@pytest.mark.parametrize( + "html", + [ + b"no token\n", + b"__OSRS_BUNDLE_VERSION__ and __OSRS_BUNDLE_VERSION__\n", + ], +) +def test_html_requires_exactly_one_version_token(tmp_path: Path, html: bytes) -> None: + build_dir = tmp_path / "build" + write_build(build_dir, html) + model = tmp_path / "policy.bin" + model.write_bytes(b"model") + output_dir = tmp_path / "site" + + result = run_package(build_dir, model, output_dir) + + assert result.returncode != 0 + assert "exactly one" in result.stderr.lower() + assert not output_dir.exists() + + +def test_output_cannot_replace_build_input(tmp_path: Path) -> None: + build_dir = tmp_path / "build" + write_build(build_dir) + original_build = {name: (build_dir / name).read_bytes() for name in GAME_FILES} + model = tmp_path / "policy.bin" + model.write_bytes(b"model") + + result = run_package(build_dir, model, build_dir) + + assert result.returncode != 0 + assert {name: (build_dir / name).read_bytes() for name in GAME_FILES} == original_build + + +def test_output_cannot_replace_model_input(tmp_path: Path) -> None: + build_dir = tmp_path / "build" + write_build(build_dir) + output_dir = tmp_path / "site" + output_dir.mkdir() + model = output_dir / "policy.bin" + model.write_bytes(b"model") + + result = run_package(build_dir, model, output_dir) + + assert result.returncode != 0 + assert model.read_bytes() == b"model" + + +def test_success_replaces_output_and_writes_complete_verified_bundle(tmp_path: Path) -> None: + build_dir = tmp_path / "build" + write_build(build_dir) + original_build = {name: (build_dir / name).read_bytes() for name in GAME_FILES} + model = tmp_path / "xbeeukiz-policy.bin" + model.write_bytes(b"policy\x00weights") + original_model = model.read_bytes() + output_dir = tmp_path / "site" + output_dir.mkdir() + (output_dir / "stale.txt").write_text("stale") + + result = run_package(build_dir, model, output_dir) + + assert result.returncode == 0, result.stderr + assert output_file_paths(output_dir) == OUTPUT_FILES + assert (output_dir / "models/osrs_inferno.bin").read_bytes() == original_model + final_html = (output_dir / "game.html").read_text() + assert "__OSRS_BUNDLE_VERSION__" not in final_html + manifest_bytes = (output_dir / "bundle.json").read_bytes() + assert manifest_bytes.endswith(b"\n") + assert manifest_bytes == json.dumps( + json.loads(manifest_bytes), indent=2, sort_keys=True + ).encode() + b"\n" + manifest = json.loads(manifest_bytes) + assert manifest["format"] == "puffer-osrs-inferno-web-v1" + assert re.fullmatch(r"[0-9a-f]{16}", manifest["version"]) + assert manifest["version"] in final_html + assert manifest["source_commit"] == SOURCE_COMMIT + assert manifest["model"] == { + "path": "models/osrs_inferno.bin", + "hidden_size": 512, + "num_layers": 2, + "entity_encoder": 0, + } + for relative_path in OUTPUT_FILES - {"bundle.json"}: + packaged_file = output_dir / relative_path + assert manifest["files"][relative_path] == { + "sha256": sha256(packaged_file), + "size": packaged_file.stat().st_size, + } + assert set(manifest["files"]) == OUTPUT_FILES - {"bundle.json"} + assert {name: (build_dir / name).read_bytes() for name in GAME_FILES} == original_build + assert model.read_bytes() == original_model + + +def test_repeated_package_is_deterministic(tmp_path: Path) -> None: + build_dir = tmp_path / "build" + write_build(build_dir) + model = tmp_path / "policy.bin" + model.write_bytes(b"model") + output_dir = tmp_path / "site" + + first = run_package(build_dir, model, output_dir) + first_manifest = (output_dir / "bundle.json").read_bytes() + first_version = json.loads(first_manifest)["version"] + second = run_package(build_dir, model, output_dir) + second_manifest = (output_dir / "bundle.json").read_bytes() + + assert first.returncode == 0, first.stderr + assert second.returncode == 0, second.stderr + assert json.loads(second_manifest)["version"] == first_version + assert second_manifest == first_manifest + + +def test_model_bytes_contribute_to_bundle_version(tmp_path: Path) -> None: + build_dir = tmp_path / "build" + write_build(build_dir) + model = tmp_path / "policy.bin" + model.write_bytes(b"first model") + output_dir = tmp_path / "site" + + first = run_package(build_dir, model, output_dir) + first_version = json.loads((output_dir / "bundle.json").read_bytes())["version"] + model.write_bytes(b"second model") + second = run_package(build_dir, model, output_dir) + second_version = json.loads((output_dir / "bundle.json").read_bytes())["version"] + + assert first.returncode == 0, first.stderr + assert second.returncode == 0, second.stderr + assert second_version != first_version diff --git a/tools/web/package_osrs_inferno.py b/tools/web/package_osrs_inferno.py new file mode 100644 index 0000000000..8bf57c96de --- /dev/null +++ b/tools/web/package_osrs_inferno.py @@ -0,0 +1,210 @@ +import argparse +import hashlib +import json +import re +import shutil +import tempfile +from dataclasses import dataclass +from pathlib import Path +from typing import Callable, Sequence + + +BUNDLE_FORMAT = "puffer-osrs-inferno-web-v1" +VERSION_TOKEN = b"__OSRS_BUNDLE_VERSION__" +GAME_FILE_NAMES = ( + "game.html", + "game.js", + "game.wasm", + "game.wasm.map", + "game.data", +) +MODEL_OUTPUT_PATH = "models/osrs_inferno.bin" +SOURCE_COMMIT_PATTERN = re.compile(r"[0-9a-f]{40}") + + +@dataclass(frozen=True) +class PackageMetadata: + source_commit: str + hidden_size: int + num_layers: int + entity_encoder: int + + +def sha256_bytes(content: bytes) -> str: + return hashlib.sha256(content).hexdigest() + + +def file_record(content: bytes) -> dict[str, int | str]: + return {"sha256": sha256_bytes(content), "size": len(content)} + + +def derive_bundle_version( + ordered_hashes: Sequence[tuple[str, str]], metadata: PackageMetadata +) -> str: + version_input = { + "files": ordered_hashes, + "source_commit": metadata.source_commit, + "hidden_size": metadata.hidden_size, + "num_layers": metadata.num_layers, + "entity_encoder": metadata.entity_encoder, + } + encoded = json.dumps(version_input, separators=(",", ":")).encode() + return sha256_bytes(encoded)[:16] + + +def build_manifest( + version: str, + metadata: PackageMetadata, + files: dict[str, dict[str, int | str]], +) -> dict[str, object]: + return { + "format": BUNDLE_FORMAT, + "version": version, + "source_commit": metadata.source_commit, + "files": files, + "model": { + "path": MODEL_OUTPUT_PATH, + "hidden_size": metadata.hidden_size, + "num_layers": metadata.num_layers, + "entity_encoder": metadata.entity_encoder, + }, + } + + +def paths_overlap(first: Path, second: Path) -> bool: + return ( + first == second + or first in second.parents + or second in first.parents + ) + + +def package_bundle( + build_dir: Path, + model_path: Path, + output_dir: Path, + metadata: PackageMetadata, +) -> None: + build_dir = build_dir.resolve() + model_path = model_path.resolve() + output_dir = output_dir.resolve() + if paths_overlap(build_dir, output_dir): + raise ValueError("output directory must not overlap the build directory") + if paths_overlap(model_path, output_dir): + raise ValueError("output directory must not overlap the model path") + source_contents = { + name: (build_dir / name).read_bytes() for name in GAME_FILE_NAMES + } + model_content = model_path.read_bytes() + source_html = source_contents["game.html"] + if source_html.count(VERSION_TOKEN) != 1: + raise ValueError("game.html must contain exactly one __OSRS_BUNDLE_VERSION__ token") + + source_records = { + name: file_record(source_contents[name]) for name in GAME_FILE_NAMES + } + model_record = file_record(model_content) + ordered_hashes = tuple( + (name, str(source_records[name]["sha256"])) for name in GAME_FILE_NAMES + ) + ((MODEL_OUTPUT_PATH, str(model_record["sha256"])),) + version = derive_bundle_version(ordered_hashes, metadata) + + packaged_contents = dict(source_contents) + packaged_contents["game.html"] = source_html.replace(VERSION_TOKEN, version.encode()) + packaged_contents[MODEL_OUTPUT_PATH] = model_content + final_records = dict(source_records) + final_records["game.html"] = file_record(packaged_contents["game.html"]) + final_records[MODEL_OUTPUT_PATH] = model_record + manifest = build_manifest(version, metadata, final_records) + manifest_content = (json.dumps(manifest, indent=2, sort_keys=True) + "\n").encode() + + if output_dir.exists() and (not output_dir.is_dir() or output_dir.is_symlink()): + raise NotADirectoryError(f"output path is not a dedicated directory: {output_dir}") + output_dir.parent.mkdir(parents=True, exist_ok=True) + staged_dir = Path( + tempfile.mkdtemp(prefix=f".{output_dir.name}.", dir=output_dir.parent) + ) + backup_dir = staged_dir.with_name(f"{staged_dir.name}.previous") + try: + (staged_dir / "models").mkdir() + for relative_path, content in packaged_contents.items(): + (staged_dir / relative_path).write_bytes(content) + (staged_dir / "bundle.json").write_bytes(manifest_content) + + if output_dir.exists(): + output_dir.replace(backup_dir) + try: + staged_dir.replace(output_dir) + except BaseException: + if backup_dir.exists(): + backup_dir.replace(output_dir) + raise + if backup_dir.exists(): + shutil.rmtree(backup_dir) + finally: + if staged_dir.exists(): + shutil.rmtree(staged_dir) + + +def source_commit(value: str) -> str: + if SOURCE_COMMIT_PATTERN.fullmatch(value) is None: + raise argparse.ArgumentTypeError( + "source commit must be exactly 40 lowercase hexadecimal characters" + ) + return value + + +def positive_integer(label: str) -> Callable[[str], int]: + def parse(value: str) -> int: + try: + parsed = int(value) + except ValueError as error: + raise argparse.ArgumentTypeError( + f"{label} must be a positive integer" + ) from error + if parsed <= 0: + raise argparse.ArgumentTypeError(f"{label} must be a positive integer") + return parsed + + return parse + + +def entity_encoder(value: str) -> int: + try: + parsed = int(value) + except ValueError as error: + raise argparse.ArgumentTypeError("entity encoder must be 0 or 1") from error + if parsed not in (0, 1): + raise argparse.ArgumentTypeError("entity encoder must be 0 or 1") + return parsed + + +def parse_arguments(argv: Sequence[str] | None = None) -> argparse.Namespace: + parser = argparse.ArgumentParser() + parser.add_argument("--build-dir", type=Path, required=True) + parser.add_argument("--model", type=Path, required=True) + parser.add_argument("--out", type=Path, required=True) + parser.add_argument("--source-commit", type=source_commit, required=True) + parser.add_argument( + "--hidden-size", type=positive_integer("hidden size"), required=True + ) + parser.add_argument( + "--num-layers", type=positive_integer("num layers"), required=True + ) + parser.add_argument("--entity-encoder", type=entity_encoder, required=True) + return parser.parse_args(argv) + + +def main(argv: Sequence[str] | None = None) -> None: + arguments = parse_arguments(argv) + metadata = PackageMetadata( + source_commit=arguments.source_commit, + hidden_size=arguments.hidden_size, + num_layers=arguments.num_layers, + entity_encoder=arguments.entity_encoder, + ) + package_bundle(arguments.build_dir, arguments.model, arguments.out, metadata) + + +if __name__ == "__main__": + main() From 058460b1320f2389e9a2116d421ce68d8ad8a2ee Mon Sep 17 00:00:00 2001 From: Valtteri Valo Date: Sun, 16 Aug 2026 11:49:44 +0300 Subject: [PATCH 04/15] Fix Inferno viewer title --- ocean/osrs/osrs_render.h | 3 +++ ocean/osrs_inferno/osrs_inferno.c | 1 + 2 files changed, 4 insertions(+) diff --git a/ocean/osrs/osrs_render.h b/ocean/osrs/osrs_render.h index 4a889af9f3..b018c735dc 100644 --- a/ocean/osrs/osrs_render.h +++ b/ocean/osrs/osrs_render.h @@ -29,6 +29,9 @@ typedef float obs_t; #include #include +#ifndef OSRS_VISUAL_WINDOW_TITLE +#define OSRS_VISUAL_WINDOW_TITLE "OSRS Debug Viewer" +#endif #define RENDER_TILE_SIZE 20 #define RENDER_WINDOW_W 1240 #define RENDER_WINDOW_H 840 diff --git a/ocean/osrs_inferno/osrs_inferno.c b/ocean/osrs_inferno/osrs_inferno.c index abbbff01b3..2d2a0d84de 100644 --- a/ocean/osrs_inferno/osrs_inferno.c +++ b/ocean/osrs_inferno/osrs_inferno.c @@ -1,4 +1,5 @@ #define OSRS_VISUAL #define OSRS_VISUAL_DEFAULT_ENCOUNTER "inferno" +#define OSRS_VISUAL_WINDOW_TITLE "OSRS Inferno Simulator" #include "inferno_profile.h" #include "../osrs/osrs_visual.c" From 5331f739d08f0b22dd83fc38e0de901390d82aee Mon Sep 17 00:00:00 2001 From: Valtteri Valo Date: Sun, 16 Aug 2026 12:52:34 +0300 Subject: [PATCH 05/15] Remove OSRS visual asset fallbacks --- build.sh | 23 +- ocean/osrs/asset_manifest.json | 1551 +++++++++++++++++++- ocean/osrs/osrs_assets_generated.h | 1549 ++++++++++++++++++- ocean/osrs/osrs_combat_visuals_generated.h | 2 + ocean/osrs/osrs_encounter_visual_events.h | 5 + ocean/osrs/osrs_gui.h | 469 +++--- ocean/osrs/osrs_human_input.h | 17 +- ocean/osrs/osrs_render.h | 212 +-- tests/test_osrs_asset_manifest_preload.py | 34 +- tests/test_package_osrs_inferno.py | 28 +- tools/web/package_osrs_inferno.py | 11 +- 11 files changed, 3449 insertions(+), 452 deletions(-) diff --git a/build.sh b/build.sh index 32c89fb3ad..888f9717d5 100755 --- a/build.sh +++ b/build.sh @@ -114,16 +114,27 @@ download() { esac } -RAYLIB_URL="https://github.com/raysan5/raylib/releases/download/5.5" +RAYLIB_RELEASE_URL="https://github.com/raysan5/raylib/releases/download/5.5" if [ "$MODE" = "web" ]; then - RAYLIB_NAME='raylib-5.5_webassembly' - download "$RAYLIB_NAME" "$RAYLIB_URL/$RAYLIB_NAME.zip" + RAYLIB_NAME='raylib-5.5' + download "$RAYLIB_NAME" "https://github.com/raysan5/raylib/archive/refs/tags/5.5.zip" + RAYLIB_A="$RAYLIB_NAME/src/libraylib.a" + RAYLIB_WEB_MARKER="$RAYLIB_NAME/src/.puffer-web-es3" + if [ ! -f "$RAYLIB_A" ] || [ ! -f "$RAYLIB_WEB_MARKER" ]; then + emmake make -C "$RAYLIB_NAME/src" clean + emmake make -C "$RAYLIB_NAME/src" \ + PLATFORM=PLATFORM_WEB \ + GRAPHICS=GRAPHICS_API_OPENGL_ES3 \ + RAYLIB_LIBTYPE=STATIC + touch "$RAYLIB_WEB_MARKER" + fi + INCLUDES=(-I./$RAYLIB_NAME/src -I./src -I./vendor) else - download "$RAYLIB_NAME" "$RAYLIB_URL/$RAYLIB_NAME.tar.gz" + download "$RAYLIB_NAME" "$RAYLIB_RELEASE_URL/$RAYLIB_NAME.tar.gz" + RAYLIB_A="$RAYLIB_NAME/lib/libraylib.a" + INCLUDES=(-I./$RAYLIB_NAME/include -I./src -I./vendor) fi -RAYLIB_A="$RAYLIB_NAME/lib/libraylib.a" -INCLUDES=(-I./$RAYLIB_NAME/include -I./src -I./vendor) LINK_ARCHIVES=("$RAYLIB_A") EXTRA_SRC="" EXTRA_LDFLAGS=() diff --git a/ocean/osrs/asset_manifest.json b/ocean/osrs/asset_manifest.json index 08b2060d9e..3580e1565b 100644 --- a/ocean/osrs/asset_manifest.json +++ b/ocean/osrs/asset_manifest.json @@ -100,30 +100,1555 @@ { "name": "gui", "files": [ + "sprites/gui/0.png", + "sprites/gui/1.png", + "sprites/gui/10.png", + "sprites/gui/100.png", + "sprites/gui/101.png", + "sprites/gui/1017.png", + "sprites/gui/1018.png", + "sprites/gui/102.png", + "sprites/gui/1026.png", + "sprites/gui/1027.png", + "sprites/gui/1028.png", + "sprites/gui/1029.png", + "sprites/gui/103.png", + "sprites/gui/1030.png", + "sprites/gui/1031.png", + "sprites/gui/1032.png", + "sprites/gui/1033.png", + "sprites/gui/1034.png", + "sprites/gui/1035.png", + "sprites/gui/1036.png", + "sprites/gui/1037.png", + "sprites/gui/1038.png", + "sprites/gui/104.png", + "sprites/gui/105.png", + "sprites/gui/1052.png", + "sprites/gui/1053.png", + "sprites/gui/1058.png", + "sprites/gui/1059.png", + "sprites/gui/106.png", + "sprites/gui/1060.png", + "sprites/gui/1061.png", + "sprites/gui/1062.png", + "sprites/gui/1063.png", + "sprites/gui/1064.png", + "sprites/gui/1065.png", + "sprites/gui/1066.png", + "sprites/gui/1067.png", + "sprites/gui/1068.png", + "sprites/gui/1069.png", + "sprites/gui/107.png", + "sprites/gui/1070.png", + "sprites/gui/1071.png", + "sprites/gui/1072.png", + "sprites/gui/108.png", + "sprites/gui/109.png", + "sprites/gui/1090.png", + "sprites/gui/1092.png", + "sprites/gui/1098.png", + "sprites/gui/1099.png", + "sprites/gui/11.png", + "sprites/gui/110.png", + "sprites/gui/1100.png", + "sprites/gui/1102.png", + "sprites/gui/111.png", + "sprites/gui/112.png", + "sprites/gui/113.png", + "sprites/gui/114.png", + "sprites/gui/115.png", + "sprites/gui/116.png", + "sprites/gui/117.png", + "sprites/gui/1173.png", + "sprites/gui/1174.png", + "sprites/gui/1175.png", + "sprites/gui/1176.png", + "sprites/gui/1177.png", + "sprites/gui/1178.png", + "sprites/gui/1179.png", + "sprites/gui/118.png", + "sprites/gui/1182.png", + "sprites/gui/1183.png", + "sprites/gui/1184.png", + "sprites/gui/119.png", + "sprites/gui/1196.png", + "sprites/gui/120.png", + "sprites/gui/1200.png", + "sprites/gui/121.png", + "sprites/gui/122.png", + "sprites/gui/123.png", + "sprites/gui/124.png", + "sprites/gui/125.png", + "sprites/gui/126.png", + "sprites/gui/127.png", + "sprites/gui/128.png", + "sprites/gui/129.png", + "sprites/gui/1299.png", + "sprites/gui/13.png", + "sprites/gui/130.png", + "sprites/gui/131.png", + "sprites/gui/132.png", + "sprites/gui/133.png", + "sprites/gui/134.png", + "sprites/gui/1343.png", + "sprites/gui/135.png", + "sprites/gui/136.png", + "sprites/gui/137.png", + "sprites/gui/138.png", + "sprites/gui/139.png", + "sprites/gui/14.png", + "sprites/gui/140.png", + "sprites/gui/141.png", + "sprites/gui/142.png", + "sprites/gui/1420.png", + "sprites/gui/1421.png", + "sprites/gui/1424.png", + "sprites/gui/1425.png", + "sprites/gui/143.png", + "sprites/gui/1438.png", + "sprites/gui/1439.png", + "sprites/gui/144.png", + "sprites/gui/1441.png", + "sprites/gui/145.png", + "sprites/gui/146.png", + "sprites/gui/147.png", + "sprites/gui/148.png", + "sprites/gui/149.png", + "sprites/gui/15.png", + "sprites/gui/150.png", + "sprites/gui/151.png", + "sprites/gui/152.png", + "sprites/gui/153.png", + "sprites/gui/154.png", + "sprites/gui/156.png", + "sprites/gui/157.png", + "sprites/gui/158.png", + "sprites/gui/1583.png", + "sprites/gui/159.png", + "sprites/gui/16.png", + "sprites/gui/160.png", + "sprites/gui/1607.png", + "sprites/gui/1608.png", + "sprites/gui/1609.png", + "sprites/gui/161.png", + "sprites/gui/1610.png", + "sprites/gui/1611.png", + "sprites/gui/162.png", + "sprites/gui/163.png", + "sprites/gui/1636.png", + "sprites/gui/1637.png", + "sprites/gui/164.png", + "sprites/gui/165.png", + "sprites/gui/166.png", + "sprites/gui/1668.png", + "sprites/gui/167.png", + "sprites/gui/168.png", + "sprites/gui/169.png", + "sprites/gui/17.png", + "sprites/gui/170.png", + "sprites/gui/1709.png", + "sprites/gui/171.png", + "sprites/gui/172.png", + "sprites/gui/173.png", + "sprites/gui/174.png", + "sprites/gui/175.png", + "sprites/gui/1751.png", + "sprites/gui/1752.png", + "sprites/gui/1753.png", + "sprites/gui/1754.png", + "sprites/gui/1755.png", + "sprites/gui/1756.png", + "sprites/gui/1757.png", + "sprites/gui/1758.png", + "sprites/gui/1759.png", + "sprites/gui/176.png", + "sprites/gui/1760.png", + "sprites/gui/1761.png", + "sprites/gui/1762.png", + "sprites/gui/1763.png", + "sprites/gui/1764.png", + "sprites/gui/1765.png", + "sprites/gui/1766.png", + "sprites/gui/1767.png", + "sprites/gui/1768.png", + "sprites/gui/1769.png", + "sprites/gui/177.png", + "sprites/gui/1770.png", + "sprites/gui/1771.png", + "sprites/gui/1772.png", + "sprites/gui/1773.png", + "sprites/gui/1774.png", + "sprites/gui/1775.png", + "sprites/gui/1776.png", + "sprites/gui/1777.png", + "sprites/gui/1778.png", + "sprites/gui/1779.png", + "sprites/gui/178.png", + "sprites/gui/1780.png", + "sprites/gui/1781.png", + "sprites/gui/1782.png", + "sprites/gui/1783.png", + "sprites/gui/1784.png", + "sprites/gui/1785.png", + "sprites/gui/1786.png", + "sprites/gui/1787.png", + "sprites/gui/1788.png", + "sprites/gui/1789.png", + "sprites/gui/179.png", + "sprites/gui/1790.png", + "sprites/gui/1791.png", + "sprites/gui/1792.png", + "sprites/gui/1793.png", + "sprites/gui/1794.png", + "sprites/gui/1795.png", + "sprites/gui/1796.png", + "sprites/gui/1797.png", + "sprites/gui/1798.png", + "sprites/gui/1799.png", + "sprites/gui/18.png", + "sprites/gui/180.png", + "sprites/gui/1800.png", + "sprites/gui/1801.png", + "sprites/gui/1802.png", + "sprites/gui/1803.png", + "sprites/gui/1804.png", + "sprites/gui/1805.png", + "sprites/gui/1806.png", + "sprites/gui/1807.png", + "sprites/gui/1808.png", + "sprites/gui/1809.png", + "sprites/gui/181.png", + "sprites/gui/1810.png", + "sprites/gui/1811.png", + "sprites/gui/1812.png", + "sprites/gui/1813.png", + "sprites/gui/1814.png", + "sprites/gui/1815.png", + "sprites/gui/1816.png", + "sprites/gui/1817.png", + "sprites/gui/1818.png", + "sprites/gui/1819.png", + "sprites/gui/182.png", + "sprites/gui/1820.png", + "sprites/gui/1821.png", + "sprites/gui/1822.png", + "sprites/gui/1823.png", + "sprites/gui/1824.png", + "sprites/gui/1825.png", + "sprites/gui/1826.png", + "sprites/gui/1827.png", + "sprites/gui/1828.png", + "sprites/gui/1829.png", + "sprites/gui/183.png", + "sprites/gui/1830.png", + "sprites/gui/1831.png", + "sprites/gui/1832.png", + "sprites/gui/1833.png", + "sprites/gui/1834.png", + "sprites/gui/1835.png", + "sprites/gui/1836.png", + "sprites/gui/1837.png", + "sprites/gui/1838.png", + "sprites/gui/1839.png", + "sprites/gui/184.png", + "sprites/gui/1840.png", + "sprites/gui/1841.png", + "sprites/gui/1842.png", + "sprites/gui/1843.png", + "sprites/gui/1844.png", + "sprites/gui/1845.png", + "sprites/gui/1846.png", + "sprites/gui/1847.png", + "sprites/gui/1848.png", + "sprites/gui/1849.png", + "sprites/gui/1850.png", + "sprites/gui/1851.png", + "sprites/gui/1852.png", + "sprites/gui/1853.png", + "sprites/gui/1854.png", + "sprites/gui/1855.png", + "sprites/gui/1856.png", + "sprites/gui/1857.png", + "sprites/gui/1858.png", + "sprites/gui/1859.png", + "sprites/gui/1860.png", + "sprites/gui/1861.png", + "sprites/gui/1862.png", + "sprites/gui/1863.png", + "sprites/gui/1864.png", + "sprites/gui/1865.png", + "sprites/gui/1866.png", + "sprites/gui/1867.png", + "sprites/gui/1868.png", + "sprites/gui/1869.png", + "sprites/gui/1870.png", + "sprites/gui/1871.png", + "sprites/gui/1872.png", + "sprites/gui/1873.png", + "sprites/gui/1874.png", + "sprites/gui/1875.png", + "sprites/gui/1876.png", + "sprites/gui/1877.png", + "sprites/gui/1878.png", + "sprites/gui/1879.png", + "sprites/gui/1880.png", + "sprites/gui/1881.png", + "sprites/gui/1882.png", + "sprites/gui/1883.png", + "sprites/gui/1884.png", + "sprites/gui/1885.png", + "sprites/gui/1886.png", + "sprites/gui/1887.png", + "sprites/gui/1888.png", + "sprites/gui/1889.png", + "sprites/gui/189.png", + "sprites/gui/1890.png", + "sprites/gui/1891.png", + "sprites/gui/19.png", + "sprites/gui/190.png", + "sprites/gui/191.png", + "sprites/gui/197.png", + "sprites/gui/198.png", + "sprites/gui/199.png", + "sprites/gui/2.png", + "sprites/gui/20.png", + "sprites/gui/200.png", + "sprites/gui/201.png", + "sprites/gui/202.png", + "sprites/gui/203.png", + "sprites/gui/204.png", + "sprites/gui/205.png", + "sprites/gui/206.png", + "sprites/gui/207.png", + "sprites/gui/208.png", + "sprites/gui/209.png", + "sprites/gui/21.png", + "sprites/gui/210.png", + "sprites/gui/211.png", + "sprites/gui/212.png", + "sprites/gui/213.png", + "sprites/gui/2138.png", + "sprites/gui/214.png", + "sprites/gui/2140.png", + "sprites/gui/215.png", + "sprites/gui/216.png", + "sprites/gui/217.png", + "sprites/gui/218.png", + "sprites/gui/219.png", + "sprites/gui/22.png", + "sprites/gui/220.png", + "sprites/gui/2208.png", + "sprites/gui/221.png", + "sprites/gui/222.png", + "sprites/gui/23.png", + "sprites/gui/233.png", + "sprites/gui/234.png", + "sprites/gui/235.png", + "sprites/gui/236.png", + "sprites/gui/237.png", + "sprites/gui/238.png", + "sprites/gui/239.png", + "sprites/gui/24.png", + "sprites/gui/240.png", + "sprites/gui/241.png", + "sprites/gui/242.png", + "sprites/gui/2420.png", + "sprites/gui/243.png", + "sprites/gui/244.png", + "sprites/gui/245.png", + "sprites/gui/246.png", + "sprites/gui/247.png", + "sprites/gui/248.png", + "sprites/gui/249.png", + "sprites/gui/25.png", + "sprites/gui/250.png", + "sprites/gui/251.png", + "sprites/gui/252.png", + "sprites/gui/253.png", + "sprites/gui/254.png", + "sprites/gui/255.png", + "sprites/gui/256.png", + "sprites/gui/257.png", + "sprites/gui/258.png", + "sprites/gui/259.png", + "sprites/gui/26.png", + "sprites/gui/260.png", + "sprites/gui/261.png", + "sprites/gui/262.png", + "sprites/gui/263.png", + "sprites/gui/264.png", + "sprites/gui/265.png", + "sprites/gui/266.png", + "sprites/gui/267.png", + "sprites/gui/268.png", + "sprites/gui/269.png", + "sprites/gui/27.png", + "sprites/gui/270.png", + "sprites/gui/271.png", + "sprites/gui/272.png", + "sprites/gui/273.png", + "sprites/gui/274.png", + "sprites/gui/275.png", + "sprites/gui/276.png", + "sprites/gui/277.png", + "sprites/gui/278.png", + "sprites/gui/279.png", + "sprites/gui/28.png", + "sprites/gui/280.png", + "sprites/gui/281.png", + "sprites/gui/282.png", + "sprites/gui/283.png", + "sprites/gui/284.png", + "sprites/gui/285.png", + "sprites/gui/286.png", + "sprites/gui/287.png", + "sprites/gui/288.png", + "sprites/gui/289.png", + "sprites/gui/29.png", + "sprites/gui/290.png", + "sprites/gui/291.png", + "sprites/gui/292.png", + "sprites/gui/293.png", + "sprites/gui/294.png", + "sprites/gui/295.png", + "sprites/gui/296.png", + "sprites/gui/3.png", + "sprites/gui/30.png", + "sprites/gui/3015.png", + "sprites/gui/3016.png", + "sprites/gui/3017.png", + "sprites/gui/3018.png", + "sprites/gui/3019.png", + "sprites/gui/3020.png", + "sprites/gui/3021.png", + "sprites/gui/3022.png", + "sprites/gui/305.png", + "sprites/gui/3051.png", + "sprites/gui/3052.png", + "sprites/gui/3053.png", + "sprites/gui/3054.png", + "sprites/gui/3055.png", + "sprites/gui/3056.png", + "sprites/gui/306.png", + "sprites/gui/307.png", + "sprites/gui/31.png", + "sprites/gui/32.png", + "sprites/gui/325.png", + "sprites/gui/326.png", + "sprites/gui/327.png", + "sprites/gui/328.png", + "sprites/gui/329.png", + "sprites/gui/33.png", + "sprites/gui/330.png", + "sprites/gui/331.png", + "sprites/gui/332.png", + "sprites/gui/333.png", + "sprites/gui/334.png", + "sprites/gui/335.png", + "sprites/gui/336.png", + "sprites/gui/337.png", + "sprites/gui/338.png", + "sprites/gui/339.png", + "sprites/gui/34.png", + "sprites/gui/340.png", + "sprites/gui/341.png", + "sprites/gui/342.png", + "sprites/gui/343.png", + "sprites/gui/344.png", + "sprites/gui/345.png", + "sprites/gui/346.png", + "sprites/gui/347.png", + "sprites/gui/348.png", + "sprites/gui/35.png", + "sprites/gui/3560.png", + "sprites/gui/36.png", + "sprites/gui/37.png", + "sprites/gui/375.png", + "sprites/gui/376.png", + "sprites/gui/377.png", + "sprites/gui/378.png", + "sprites/gui/379.png", + "sprites/gui/38.png", + "sprites/gui/380.png", + "sprites/gui/381.png", + "sprites/gui/382.png", + "sprites/gui/383.png", + "sprites/gui/384.png", + "sprites/gui/385.png", + "sprites/gui/386.png", + "sprites/gui/387.png", + "sprites/gui/388.png", + "sprites/gui/389.png", + "sprites/gui/39.png", + "sprites/gui/390.png", + "sprites/gui/391.png", + "sprites/gui/392.png", + "sprites/gui/393.png", + "sprites/gui/394.png", + "sprites/gui/395.png", + "sprites/gui/396.png", + "sprites/gui/397.png", + "sprites/gui/398.png", + "sprites/gui/40.png", + "sprites/gui/41.png", + "sprites/gui/42.png", + "sprites/gui/43.png", + "sprites/gui/44.png", + "sprites/gui/45.png", + "sprites/gui/46.png", + "sprites/gui/47.png", + "sprites/gui/48.png", + "sprites/gui/4892.png", + "sprites/gui/4893.png", + "sprites/gui/49.png", + "sprites/gui/5.png", + "sprites/gui/50.png", + "sprites/gui/502.png", + "sprites/gui/503.png", + "sprites/gui/504.png", + "sprites/gui/505.png", + "sprites/gui/506.png", + "sprites/gui/507.png", + "sprites/gui/508.png", + "sprites/gui/509.png", + "sprites/gui/51.png", + "sprites/gui/52.png", + "sprites/gui/53.png", + "sprites/gui/54.png", + "sprites/gui/55.png", + "sprites/gui/557.png", + "sprites/gui/56.png", + "sprites/gui/561.png", + "sprites/gui/564.png", + "sprites/gui/57.png", + "sprites/gui/5791.png", + "sprites/gui/5792.png", + "sprites/gui/5793.png", + "sprites/gui/5794.png", + "sprites/gui/5795.png", + "sprites/gui/5796.png", + "sprites/gui/58.png", + "sprites/gui/5813.png", + "sprites/gui/5832.png", + "sprites/gui/59.png", + "sprites/gui/6.png", + "sprites/gui/60.png", + "sprites/gui/607.png", + "sprites/gui/61.png", + "sprites/gui/611.png", + "sprites/gui/614.png", + "sprites/gui/62.png", + "sprites/gui/63.png", + "sprites/gui/64.png", + "sprites/gui/65.png", + "sprites/gui/653.png", + "sprites/gui/654.png", + "sprites/gui/655.png", + "sprites/gui/656.png", + "sprites/gui/657.png", + "sprites/gui/66.png", + "sprites/gui/67.png", + "sprites/gui/675.png", + "sprites/gui/68.png", + "sprites/gui/69.png", + "sprites/gui/7.png", + "sprites/gui/70.png", + "sprites/gui/71.png", + "sprites/gui/72.png", + "sprites/gui/73.png", + "sprites/gui/74.png", + "sprites/gui/75.png", + "sprites/gui/76.png", + "sprites/gui/760.png", + "sprites/gui/77.png", + "sprites/gui/774.png", + "sprites/gui/775.png", + "sprites/gui/776.png", + "sprites/gui/777.png", + "sprites/gui/778.png", + "sprites/gui/779.png", + "sprites/gui/78.png", + "sprites/gui/780.png", + "sprites/gui/781.png", + "sprites/gui/782.png", + "sprites/gui/783.png", + "sprites/gui/784.png", + "sprites/gui/785.png", + "sprites/gui/786.png", + "sprites/gui/787.png", + "sprites/gui/79.png", + "sprites/gui/8.png", + "sprites/gui/80.png", + "sprites/gui/81.png", + "sprites/gui/82.png", + "sprites/gui/83.png", + "sprites/gui/84.png", + "sprites/gui/85.png", + "sprites/gui/86.png", + "sprites/gui/87.png", + "sprites/gui/88.png", + "sprites/gui/89.png", + "sprites/gui/897.png", + "sprites/gui/898.png", + "sprites/gui/899.png", + "sprites/gui/9.png", + "sprites/gui/90.png", + "sprites/gui/900.png", + "sprites/gui/901.png", + "sprites/gui/902.png", + "sprites/gui/903.png", + "sprites/gui/904.png", + "sprites/gui/905.png", + "sprites/gui/907.png", + "sprites/gui/908.png", + "sprites/gui/909.png", + "sprites/gui/91.png", + "sprites/gui/910.png", + "sprites/gui/912.png", + "sprites/gui/92.png", + "sprites/gui/93.png", + "sprites/gui/94.png", + "sprites/gui/944.png", + "sprites/gui/945.png", + "sprites/gui/946.png", + "sprites/gui/947.png", + "sprites/gui/948.png", + "sprites/gui/949.png", + "sprites/gui/95.png", + "sprites/gui/950.png", + "sprites/gui/951.png", + "sprites/gui/96.png", + "sprites/gui/97.png", + "sprites/gui/98.png", + "sprites/gui/99.png", + "sprites/gui/border_map_compass.png", + "sprites/gui/chat_tab_button_0.png", + "sprites/gui/chat_tab_button_1.png", + "sprites/gui/chat_tab_button_2.png", + "sprites/gui/chat_tab_button_3.png", + "sprites/gui/chat_tab_button_4.png", + "sprites/gui/chat_tab_button_5.png", + "sprites/gui/chatbox_bg.png", + "sprites/gui/chatbox_stones.png", + "sprites/gui/combat_shield.png", + "sprites/gui/combatboxes_0.png", + "sprites/gui/combatboxes_1.png", + "sprites/gui/combatboxes_2.png", + "sprites/gui/combatboxes_3.png", + "sprites/gui/combatboxes_large_0.png", + "sprites/gui/combatboxes_large_1.png", + "sprites/gui/combatboxes_special_attack.png", + "sprites/gui/combatboxes_very_large_0.png", + "sprites/gui/combatboxes_very_large_1.png", + "sprites/gui/combaticons2_0.png", + "sprites/gui/combaticons2_1.png", + "sprites/gui/combaticons2_10.png", + "sprites/gui/combaticons2_11.png", + "sprites/gui/combaticons2_12.png", + "sprites/gui/combaticons2_13.png", + "sprites/gui/combaticons2_14.png", + "sprites/gui/combaticons2_15.png", + "sprites/gui/combaticons2_16.png", + "sprites/gui/combaticons2_17.png", + "sprites/gui/combaticons2_18.png", + "sprites/gui/combaticons2_19.png", + "sprites/gui/combaticons2_2.png", + "sprites/gui/combaticons2_3.png", + "sprites/gui/combaticons2_4.png", + "sprites/gui/combaticons2_5.png", + "sprites/gui/combaticons2_6.png", + "sprites/gui/combaticons2_7.png", + "sprites/gui/combaticons2_8.png", + "sprites/gui/combaticons2_9.png", + "sprites/gui/combaticons3_0.png", + "sprites/gui/combaticons3_1.png", + "sprites/gui/combaticons3_10.png", + "sprites/gui/combaticons3_11.png", + "sprites/gui/combaticons3_12.png", + "sprites/gui/combaticons3_13.png", + "sprites/gui/combaticons3_14.png", + "sprites/gui/combaticons3_15.png", + "sprites/gui/combaticons3_16.png", + "sprites/gui/combaticons3_17.png", + "sprites/gui/combaticons3_18.png", + "sprites/gui/combaticons3_19.png", + "sprites/gui/combaticons3_2.png", + "sprites/gui/combaticons3_3.png", + "sprites/gui/combaticons3_4.png", + "sprites/gui/combaticons3_5.png", + "sprites/gui/combaticons3_6.png", + "sprites/gui/combaticons3_7.png", + "sprites/gui/combaticons3_8.png", + "sprites/gui/combaticons3_9.png", + "sprites/gui/combaticons_0.png", + "sprites/gui/combaticons_1.png", + "sprites/gui/combaticons_10.png", + "sprites/gui/combaticons_11.png", + "sprites/gui/combaticons_12.png", + "sprites/gui/combaticons_13.png", + "sprites/gui/combaticons_14.png", + "sprites/gui/combaticons_15.png", + "sprites/gui/combaticons_16.png", + "sprites/gui/combaticons_17.png", + "sprites/gui/combaticons_18.png", + "sprites/gui/combaticons_19.png", + "sprites/gui/combaticons_2.png", + "sprites/gui/combaticons_3.png", + "sprites/gui/combaticons_4.png", + "sprites/gui/combaticons_5.png", + "sprites/gui/combaticons_6.png", + "sprites/gui/combaticons_7.png", + "sprites/gui/combaticons_8.png", + "sprites/gui/combaticons_9.png", "sprites/gui/compass.png", - "sprites/gui/side_panel_bg.png", - "sprites/gui/orb_frame.png", + "sprites/gui/compass_alpha_mask.png", + "sprites/gui/compass_outline.png", + "sprites/gui/cross_red_1.png", + "sprites/gui/cross_red_2.png", + "sprites/gui/cross_red_3.png", + "sprites/gui/cross_red_4.png", + "sprites/gui/cross_yellow_1.png", + "sprites/gui/cross_yellow_2.png", + "sprites/gui/cross_yellow_3.png", + "sprites/gui/cross_yellow_4.png", + "sprites/gui/fixed_compass_mask.png", + "sprites/gui/fixed_map_clickmask.png", + "sprites/gui/fixed_map_mask.png", + "sprites/gui/fixed_minimap_cover.png", "sprites/gui/headicons_prayer_0.png", + "sprites/gui/headicons_prayer_1.png", + "sprites/gui/headicons_prayer_10.png", + "sprites/gui/headicons_prayer_11.png", + "sprites/gui/headicons_prayer_12.png", + "sprites/gui/headicons_prayer_13.png", + "sprites/gui/headicons_prayer_14.png", + "sprites/gui/headicons_prayer_15.png", + "sprites/gui/headicons_prayer_16.png", + "sprites/gui/headicons_prayer_17.png", + "sprites/gui/headicons_prayer_18.png", + "sprites/gui/headicons_prayer_19.png", + "sprites/gui/headicons_prayer_2.png", + "sprites/gui/headicons_prayer_20.png", + "sprites/gui/headicons_prayer_21.png", + "sprites/gui/headicons_prayer_22.png", + "sprites/gui/headicons_prayer_23.png", + "sprites/gui/headicons_prayer_3.png", + "sprites/gui/headicons_prayer_4.png", + "sprites/gui/headicons_prayer_5.png", + "sprites/gui/headicons_prayer_6.png", + "sprites/gui/headicons_prayer_7.png", + "sprites/gui/headicons_prayer_8.png", + "sprites/gui/headicons_prayer_9.png", "sprites/gui/hitmarks_0.png", - "sprites/gui/cross_yellow_1.png", - "sprites/gui/side_icon_inventory.png", - "sprites/gui/tradebacking_dark.png", + "sprites/gui/hitmarks_1.png", + "sprites/gui/hitmarks_2.png", + "sprites/gui/hitmarks_3.png", + "sprites/gui/hitmarks_4.png", + "sprites/gui/magicoff_0.png", + "sprites/gui/magicoff_1.png", + "sprites/gui/magicoff_10.png", + "sprites/gui/magicoff_11.png", + "sprites/gui/magicoff_12.png", + "sprites/gui/magicoff_13.png", + "sprites/gui/magicoff_14.png", + "sprites/gui/magicoff_15.png", + "sprites/gui/magicoff_16.png", + "sprites/gui/magicoff_17.png", + "sprites/gui/magicoff_18.png", + "sprites/gui/magicoff_19.png", + "sprites/gui/magicoff_2.png", + "sprites/gui/magicoff_20.png", + "sprites/gui/magicoff_21.png", + "sprites/gui/magicoff_22.png", + "sprites/gui/magicoff_23.png", + "sprites/gui/magicoff_24.png", + "sprites/gui/magicoff_25.png", + "sprites/gui/magicoff_26.png", + "sprites/gui/magicoff_27.png", + "sprites/gui/magicoff_28.png", + "sprites/gui/magicoff_29.png", + "sprites/gui/magicoff_3.png", + "sprites/gui/magicoff_30.png", + "sprites/gui/magicoff_31.png", + "sprites/gui/magicoff_32.png", + "sprites/gui/magicoff_33.png", + "sprites/gui/magicoff_34.png", + "sprites/gui/magicoff_35.png", + "sprites/gui/magicoff_36.png", + "sprites/gui/magicoff_37.png", + "sprites/gui/magicoff_38.png", + "sprites/gui/magicoff_39.png", + "sprites/gui/magicoff_4.png", + "sprites/gui/magicoff_40.png", + "sprites/gui/magicoff_41.png", + "sprites/gui/magicoff_42.png", + "sprites/gui/magicoff_43.png", + "sprites/gui/magicoff_44.png", + "sprites/gui/magicoff_45.png", + "sprites/gui/magicoff_46.png", + "sprites/gui/magicoff_47.png", + "sprites/gui/magicoff_48.png", + "sprites/gui/magicoff_49.png", + "sprites/gui/magicoff_5.png", + "sprites/gui/magicoff_6.png", + "sprites/gui/magicoff_7.png", + "sprites/gui/magicoff_8.png", + "sprites/gui/magicoff_9.png", + "sprites/gui/magicon_0.png", + "sprites/gui/magicon_1.png", + "sprites/gui/magicon_10.png", + "sprites/gui/magicon_11.png", + "sprites/gui/magicon_12.png", + "sprites/gui/magicon_13.png", + "sprites/gui/magicon_14.png", + "sprites/gui/magicon_15.png", + "sprites/gui/magicon_16.png", + "sprites/gui/magicon_17.png", + "sprites/gui/magicon_18.png", + "sprites/gui/magicon_19.png", + "sprites/gui/magicon_2.png", + "sprites/gui/magicon_20.png", + "sprites/gui/magicon_21.png", + "sprites/gui/magicon_22.png", + "sprites/gui/magicon_23.png", + "sprites/gui/magicon_24.png", + "sprites/gui/magicon_25.png", + "sprites/gui/magicon_26.png", + "sprites/gui/magicon_27.png", + "sprites/gui/magicon_28.png", + "sprites/gui/magicon_29.png", + "sprites/gui/magicon_3.png", + "sprites/gui/magicon_30.png", + "sprites/gui/magicon_31.png", + "sprites/gui/magicon_32.png", + "sprites/gui/magicon_33.png", + "sprites/gui/magicon_34.png", + "sprites/gui/magicon_35.png", + "sprites/gui/magicon_36.png", + "sprites/gui/magicon_37.png", + "sprites/gui/magicon_38.png", + "sprites/gui/magicon_39.png", + "sprites/gui/magicon_4.png", + "sprites/gui/magicon_40.png", + "sprites/gui/magicon_41.png", + "sprites/gui/magicon_42.png", + "sprites/gui/magicon_43.png", + "sprites/gui/magicon_44.png", + "sprites/gui/magicon_45.png", + "sprites/gui/magicon_46.png", + "sprites/gui/magicon_47.png", + "sprites/gui/magicon_48.png", + "sprites/gui/magicon_49.png", + "sprites/gui/magicon_5.png", + "sprites/gui/magicon_6.png", + "sprites/gui/magicon_7.png", + "sprites/gui/magicon_8.png", + "sprites/gui/magicon_9.png", + "sprites/gui/main_stones_bottom.png", + "sprites/gui/mini_bottom.png", + "sprites/gui/mini_left.png", + "sprites/gui/mini_right.png", + "sprites/gui/mini_topright.png", + "sprites/gui/minimap_alpha_mask.png", + "sprites/gui/minimap_and_compass_frame.png", + "sprites/gui/minimap_dest_flag_0.png", + "sprites/gui/minimap_dest_flag_1.png", + "sprites/gui/minimap_dest_flag_2.png", + "sprites/gui/minimap_dest_flag_3.png", + "sprites/gui/minimap_dot_friend.png", + "sprites/gui/minimap_dot_item.png", + "sprites/gui/minimap_dot_npc.png", + "sprites/gui/minimap_dot_player.png", + "sprites/gui/minimap_edge_left.png", + "sprites/gui/minimap_edge_right.png", + "sprites/gui/minimap_guide_arrow_0.png", + "sprites/gui/minimap_guide_arrow_1.png", + "sprites/gui/minimap_guide_arrow_2.png", + "sprites/gui/minimap_guide_arrow_3.png", + "sprites/gui/minimap_guide_arrow_4.png", + "sprites/gui/minimap_guide_arrow_5.png", + "sprites/gui/miscgraphics_0.png", + "sprites/gui/miscgraphics_1.png", + "sprites/gui/miscgraphics_10.png", + "sprites/gui/miscgraphics_11.png", + "sprites/gui/miscgraphics_12.png", + "sprites/gui/miscgraphics_13.png", + "sprites/gui/miscgraphics_14.png", + "sprites/gui/miscgraphics_2.png", + "sprites/gui/miscgraphics_3.png", + "sprites/gui/miscgraphics_4.png", + "sprites/gui/miscgraphics_5.png", + "sprites/gui/miscgraphics_6.png", + "sprites/gui/miscgraphics_7.png", + "sprites/gui/miscgraphics_8.png", + "sprites/gui/miscgraphics_9.png", + "sprites/gui/options_icons_16.png", + "sprites/gui/options_icons_18.png", + "sprites/gui/options_icons_28.png", + "sprites/gui/orb_empty.png", + "sprites/gui/orb_filler_0.png", + "sprites/gui/orb_filler_1.png", + "sprites/gui/orb_filler_10.png", + "sprites/gui/orb_filler_11.png", + "sprites/gui/orb_filler_12.png", + "sprites/gui/orb_filler_13.png", + "sprites/gui/orb_filler_14.png", + "sprites/gui/orb_filler_2.png", + "sprites/gui/orb_filler_3.png", + "sprites/gui/orb_filler_4.png", + "sprites/gui/orb_filler_5.png", + "sprites/gui/orb_filler_6.png", + "sprites/gui/orb_filler_7.png", + "sprites/gui/orb_filler_8.png", + "sprites/gui/orb_filler_9.png", + "sprites/gui/orb_frame.png", + "sprites/gui/orb_frame_0.png", + "sprites/gui/orb_frame_1.png", + "sprites/gui/orb_frame_2.png", + "sprites/gui/orb_frame_hover.png", + "sprites/gui/orb_hp.png", + "sprites/gui/orb_icon_0.png", + "sprites/gui/orb_icon_1.png", + "sprites/gui/orb_icon_10.png", + "sprites/gui/orb_icon_11.png", + "sprites/gui/orb_icon_12.png", + "sprites/gui/orb_icon_13.png", + "sprites/gui/orb_icon_14.png", + "sprites/gui/orb_icon_15.png", + "sprites/gui/orb_icon_2.png", + "sprites/gui/orb_icon_3.png", + "sprites/gui/orb_icon_4.png", + "sprites/gui/orb_icon_5.png", + "sprites/gui/orb_icon_6.png", + "sprites/gui/orb_icon_7.png", + "sprites/gui/orb_icon_8.png", + "sprites/gui/orb_icon_9.png", + "sprites/gui/orb_icon_hp.png", + "sprites/gui/orb_icon_prayer.png", + "sprites/gui/orb_icon_prayer_active.png", + "sprites/gui/orb_icon_run.png", + "sprites/gui/orb_icon_walk.png", + "sprites/gui/orb_prayer.png", + "sprites/gui/orb_prayer_active.png", + "sprites/gui/orb_run.png", + "sprites/gui/orb_run_active.png", + "sprites/gui/orb_xp_0.png", + "sprites/gui/osrs_stretch_mapsurround.png", + "sprites/gui/osrs_stretch_side_columns_0.png", + "sprites/gui/osrs_stretch_side_columns_1.png", "sprites/gui/osrs_stretch_side_topbottom_0.png", - "sprites/gui/wornicons_11.png", - "sprites/gui/skill_icon_23.png", + "sprites/gui/osrs_stretch_side_topbottom_1.png", + "sprites/gui/pray_augury.png", + "sprites/gui/pray_chivalry.png", + "sprites/gui/pray_eagle_eye.png", + "sprites/gui/pray_mage.png", + "sprites/gui/pray_melee.png", + "sprites/gui/pray_mystic_might.png", + "sprites/gui/pray_piety.png", + "sprites/gui/pray_preserve.png", + "sprites/gui/pray_range.png", + "sprites/gui/pray_redemption.png", + "sprites/gui/pray_retribution.png", + "sprites/gui/pray_rigour.png", + "sprites/gui/pray_smite.png", + "sprites/gui/prayerglow_0.png", + "sprites/gui/prayerglow_1.png", + "sprites/gui/prayeroff_0.png", + "sprites/gui/prayeroff_1.png", + "sprites/gui/prayeroff_10.png", + "sprites/gui/prayeroff_11.png", + "sprites/gui/prayeroff_12.png", + "sprites/gui/prayeroff_13.png", + "sprites/gui/prayeroff_14.png", + "sprites/gui/prayeroff_15.png", + "sprites/gui/prayeroff_16.png", + "sprites/gui/prayeroff_17.png", + "sprites/gui/prayeroff_18.png", + "sprites/gui/prayeroff_19.png", + "sprites/gui/prayeroff_2.png", + "sprites/gui/prayeroff_20.png", + "sprites/gui/prayeroff_21.png", + "sprites/gui/prayeroff_22.png", + "sprites/gui/prayeroff_23.png", + "sprites/gui/prayeroff_24.png", + "sprites/gui/prayeroff_3.png", + "sprites/gui/prayeroff_4.png", + "sprites/gui/prayeroff_5.png", + "sprites/gui/prayeroff_6.png", + "sprites/gui/prayeroff_7.png", + "sprites/gui/prayeroff_8.png", + "sprites/gui/prayeroff_9.png", + "sprites/gui/prayeron_0.png", + "sprites/gui/prayeron_1.png", + "sprites/gui/prayeron_10.png", + "sprites/gui/prayeron_11.png", + "sprites/gui/prayeron_12.png", + "sprites/gui/prayeron_13.png", + "sprites/gui/prayeron_14.png", + "sprites/gui/prayeron_15.png", + "sprites/gui/prayeron_16.png", + "sprites/gui/prayeron_17.png", + "sprites/gui/prayeron_18.png", + "sprites/gui/prayeron_19.png", + "sprites/gui/prayeron_2.png", + "sprites/gui/prayeron_20.png", + "sprites/gui/prayeron_21.png", + "sprites/gui/prayeron_22.png", + "sprites/gui/prayeron_23.png", "sprites/gui/prayeron_24.png", - "sprites/gui/magicon_47.png", + "sprites/gui/prayeron_3.png", + "sprites/gui/prayeron_4.png", + "sprites/gui/prayeron_5.png", + "sprites/gui/prayeron_6.png", + "sprites/gui/prayeron_7.png", + "sprites/gui/prayeron_8.png", + "sprites/gui/prayeron_9.png", + "sprites/gui/resize_compass_mask.png", + "sprites/gui/resize_map_mask.png", + "sprites/gui/ring_30.png", + "sprites/gui/ring_34_0.png", + "sprites/gui/rivets_horizontal.png", + "sprites/gui/rivets_square.png", + "sprites/gui/rivets_vertical.png", + "sprites/gui/rm_compass_alpha_mask.png", + "sprites/gui/rm_minimap_alpha_mask.png", + "sprites/gui/rm_minimap_and_compass_frame.png", + "sprites/gui/rm_side_panel_bg.png", + "sprites/gui/rm_side_panel_edge_left.png", + "sprites/gui/rm_side_panel_edge_right.png", + "sprites/gui/rm_tab_stone_middle.png", + "sprites/gui/rm_tab_stone_middle_selected.png", + "sprites/gui/rm_tabs_bottom_row.png", + "sprites/gui/rm_tabs_top_row.png", + "sprites/gui/side_background.png", + "sprites/gui/side_background_bottom.png", + "sprites/gui/side_background_left1.png", + "sprites/gui/side_background_left2.png", + "sprites/gui/side_background_right.png", + "sprites/gui/side_background_top.png", + "sprites/gui/side_icon_clan.png", + "sprites/gui/side_icon_combat.png", + "sprites/gui/side_icon_emotes.png", + "sprites/gui/side_icon_equipment.png", + "sprites/gui/side_icon_friends.png", + "sprites/gui/side_icon_grouping.png", + "sprites/gui/side_icon_inventory.png", + "sprites/gui/side_icon_logout.png", + "sprites/gui/side_icon_logout_modern.png", + "sprites/gui/side_icon_magic.png", + "sprites/gui/side_icon_magic_ancient.png", + "sprites/gui/side_icon_music.png", + "sprites/gui/side_icon_options.png", + "sprites/gui/side_icon_prayer.png", + "sprites/gui/side_icon_quests.png", + "sprites/gui/side_icon_stats.png", + "sprites/gui/side_icons_0.png", + "sprites/gui/side_icons_1.png", + "sprites/gui/side_icons_10.png", + "sprites/gui/side_icons_11.png", + "sprites/gui/side_icons_12.png", + "sprites/gui/side_icons_13.png", + "sprites/gui/side_icons_2.png", + "sprites/gui/side_icons_22.png", + "sprites/gui/side_icons_3.png", + "sprites/gui/side_icons_39.png", + "sprites/gui/side_icons_4.png", + "sprites/gui/side_icons_5.png", + "sprites/gui/side_icons_6.png", + "sprites/gui/side_icons_7.png", + "sprites/gui/side_icons_8.png", + "sprites/gui/side_panel_bg.png", + "sprites/gui/side_stone_highlights_0.png", + "sprites/gui/side_stone_highlights_1.png", + "sprites/gui/side_stone_highlights_2.png", + "sprites/gui/side_stone_highlights_3.png", + "sprites/gui/side_stone_highlights_4.png", + "sprites/gui/sideicons_interface_0.png", + "sprites/gui/sideicons_interface_1.png", + "sprites/gui/sideicons_interface_10.png", + "sprites/gui/sideicons_interface_11.png", + "sprites/gui/sideicons_interface_12.png", + "sprites/gui/sideicons_interface_13.png", + "sprites/gui/sideicons_interface_14.png", + "sprites/gui/sideicons_interface_15.png", + "sprites/gui/sideicons_interface_16.png", + "sprites/gui/sideicons_interface_2.png", + "sprites/gui/sideicons_interface_3.png", + "sprites/gui/sideicons_interface_4.png", + "sprites/gui/sideicons_interface_5.png", + "sprites/gui/sideicons_interface_6.png", + "sprites/gui/sideicons_interface_7.png", + "sprites/gui/sideicons_interface_8.png", + "sprites/gui/sideicons_interface_9.png", + "sprites/gui/skill_attack.png", + "sprites/gui/skill_defence.png", + "sprites/gui/skill_hitpoints.png", + "sprites/gui/skill_icon_0.png", + "sprites/gui/skill_icon_1.png", + "sprites/gui/skill_icon_10.png", + "sprites/gui/skill_icon_11.png", + "sprites/gui/skill_icon_12.png", + "sprites/gui/skill_icon_13.png", + "sprites/gui/skill_icon_14.png", + "sprites/gui/skill_icon_15.png", + "sprites/gui/skill_icon_16.png", + "sprites/gui/skill_icon_17.png", + "sprites/gui/skill_icon_18.png", + "sprites/gui/skill_icon_19.png", + "sprites/gui/skill_icon_2.png", + "sprites/gui/skill_icon_20.png", + "sprites/gui/skill_icon_21.png", + "sprites/gui/skill_icon_22.png", + "sprites/gui/skill_icon_23.png", + "sprites/gui/skill_icon_3.png", + "sprites/gui/skill_icon_4.png", + "sprites/gui/skill_icon_5.png", + "sprites/gui/skill_icon_6.png", + "sprites/gui/skill_icon_7.png", + "sprites/gui/skill_icon_8.png", + "sprites/gui/skill_icon_9.png", + "sprites/gui/skill_magic.png", + "sprites/gui/skill_prayer.png", + "sprites/gui/skill_ranged.png", + "sprites/gui/skill_strength.png", + "sprites/gui/slanted_tab.png", + "sprites/gui/slanted_tab_hover.png", + "sprites/gui/slot_ammo.png", + "sprites/gui/slot_body.png", + "sprites/gui/slot_cape.png", + "sprites/gui/slot_feet.png", + "sprites/gui/slot_hands.png", + "sprites/gui/slot_head.png", + "sprites/gui/slot_legs.png", + "sprites/gui/slot_neck.png", + "sprites/gui/slot_ring.png", + "sprites/gui/slot_selected.png", + "sprites/gui/slot_shield.png", + "sprites/gui/slot_tile.png", + "sprites/gui/slot_weapon.png", + "sprites/gui/special_attack.png", + "sprites/gui/spell_blood_barrage.png", + "sprites/gui/spell_blood_blitz.png", + "sprites/gui/spell_blood_burst.png", + "sprites/gui/spell_blood_rush.png", + "sprites/gui/spell_ice_barrage.png", + "sprites/gui/spell_ice_blitz.png", + "sprites/gui/spell_ice_burst.png", + "sprites/gui/spell_ice_rush.png", + "sprites/gui/spell_vengeance.png", + "sprites/gui/standard_spell_off_0.png", + "sprites/gui/standard_spell_off_1.png", + "sprites/gui/standard_spell_off_10.png", + "sprites/gui/standard_spell_off_11.png", + "sprites/gui/standard_spell_off_12.png", + "sprites/gui/standard_spell_off_13.png", + "sprites/gui/standard_spell_off_14.png", + "sprites/gui/standard_spell_off_15.png", + "sprites/gui/standard_spell_off_16.png", + "sprites/gui/standard_spell_off_17.png", + "sprites/gui/standard_spell_off_18.png", + "sprites/gui/standard_spell_off_19.png", + "sprites/gui/standard_spell_off_2.png", + "sprites/gui/standard_spell_off_20.png", + "sprites/gui/standard_spell_off_21.png", + "sprites/gui/standard_spell_off_22.png", + "sprites/gui/standard_spell_off_23.png", + "sprites/gui/standard_spell_off_24.png", + "sprites/gui/standard_spell_off_25.png", + "sprites/gui/standard_spell_off_26.png", + "sprites/gui/standard_spell_off_27.png", + "sprites/gui/standard_spell_off_28.png", + "sprites/gui/standard_spell_off_29.png", + "sprites/gui/standard_spell_off_3.png", + "sprites/gui/standard_spell_off_30.png", + "sprites/gui/standard_spell_off_31.png", + "sprites/gui/standard_spell_off_32.png", + "sprites/gui/standard_spell_off_33.png", + "sprites/gui/standard_spell_off_34.png", + "sprites/gui/standard_spell_off_35.png", + "sprites/gui/standard_spell_off_36.png", + "sprites/gui/standard_spell_off_37.png", + "sprites/gui/standard_spell_off_38.png", + "sprites/gui/standard_spell_off_39.png", + "sprites/gui/standard_spell_off_4.png", + "sprites/gui/standard_spell_off_40.png", + "sprites/gui/standard_spell_off_41.png", + "sprites/gui/standard_spell_off_42.png", + "sprites/gui/standard_spell_off_43.png", + "sprites/gui/standard_spell_off_44.png", + "sprites/gui/standard_spell_off_45.png", + "sprites/gui/standard_spell_off_46.png", + "sprites/gui/standard_spell_off_47.png", + "sprites/gui/standard_spell_off_48.png", + "sprites/gui/standard_spell_off_49.png", + "sprites/gui/standard_spell_off_5.png", + "sprites/gui/standard_spell_off_50.png", + "sprites/gui/standard_spell_off_51.png", + "sprites/gui/standard_spell_off_52.png", + "sprites/gui/standard_spell_off_53.png", + "sprites/gui/standard_spell_off_54.png", + "sprites/gui/standard_spell_off_55.png", + "sprites/gui/standard_spell_off_56.png", + "sprites/gui/standard_spell_off_57.png", + "sprites/gui/standard_spell_off_58.png", + "sprites/gui/standard_spell_off_59.png", + "sprites/gui/standard_spell_off_6.png", + "sprites/gui/standard_spell_off_60.png", + "sprites/gui/standard_spell_off_61.png", + "sprites/gui/standard_spell_off_62.png", + "sprites/gui/standard_spell_off_63.png", + "sprites/gui/standard_spell_off_64.png", + "sprites/gui/standard_spell_off_65.png", + "sprites/gui/standard_spell_off_66.png", + "sprites/gui/standard_spell_off_67.png", + "sprites/gui/standard_spell_off_68.png", + "sprites/gui/standard_spell_off_69.png", + "sprites/gui/standard_spell_off_7.png", + "sprites/gui/standard_spell_off_70.png", + "sprites/gui/standard_spell_off_71.png", + "sprites/gui/standard_spell_off_72.png", + "sprites/gui/standard_spell_off_73.png", + "sprites/gui/standard_spell_off_74.png", + "sprites/gui/standard_spell_off_75.png", + "sprites/gui/standard_spell_off_76.png", + "sprites/gui/standard_spell_off_77.png", + "sprites/gui/standard_spell_off_78.png", + "sprites/gui/standard_spell_off_79.png", + "sprites/gui/standard_spell_off_8.png", + "sprites/gui/standard_spell_off_9.png", + "sprites/gui/standard_spell_on_0.png", + "sprites/gui/standard_spell_on_1.png", + "sprites/gui/standard_spell_on_10.png", + "sprites/gui/standard_spell_on_11.png", + "sprites/gui/standard_spell_on_12.png", + "sprites/gui/standard_spell_on_13.png", + "sprites/gui/standard_spell_on_14.png", + "sprites/gui/standard_spell_on_15.png", + "sprites/gui/standard_spell_on_16.png", + "sprites/gui/standard_spell_on_17.png", + "sprites/gui/standard_spell_on_18.png", + "sprites/gui/standard_spell_on_19.png", + "sprites/gui/standard_spell_on_2.png", + "sprites/gui/standard_spell_on_20.png", + "sprites/gui/standard_spell_on_21.png", + "sprites/gui/standard_spell_on_22.png", + "sprites/gui/standard_spell_on_23.png", + "sprites/gui/standard_spell_on_24.png", + "sprites/gui/standard_spell_on_25.png", + "sprites/gui/standard_spell_on_26.png", + "sprites/gui/standard_spell_on_27.png", + "sprites/gui/standard_spell_on_28.png", + "sprites/gui/standard_spell_on_29.png", + "sprites/gui/standard_spell_on_3.png", + "sprites/gui/standard_spell_on_30.png", + "sprites/gui/standard_spell_on_31.png", + "sprites/gui/standard_spell_on_32.png", + "sprites/gui/standard_spell_on_33.png", + "sprites/gui/standard_spell_on_34.png", + "sprites/gui/standard_spell_on_35.png", + "sprites/gui/standard_spell_on_36.png", + "sprites/gui/standard_spell_on_37.png", + "sprites/gui/standard_spell_on_38.png", + "sprites/gui/standard_spell_on_39.png", + "sprites/gui/standard_spell_on_4.png", + "sprites/gui/standard_spell_on_40.png", + "sprites/gui/standard_spell_on_41.png", + "sprites/gui/standard_spell_on_42.png", + "sprites/gui/standard_spell_on_43.png", + "sprites/gui/standard_spell_on_44.png", + "sprites/gui/standard_spell_on_45.png", + "sprites/gui/standard_spell_on_46.png", + "sprites/gui/standard_spell_on_47.png", + "sprites/gui/standard_spell_on_48.png", + "sprites/gui/standard_spell_on_49.png", + "sprites/gui/standard_spell_on_5.png", + "sprites/gui/standard_spell_on_50.png", + "sprites/gui/standard_spell_on_51.png", + "sprites/gui/standard_spell_on_52.png", + "sprites/gui/standard_spell_on_53.png", + "sprites/gui/standard_spell_on_54.png", + "sprites/gui/standard_spell_on_55.png", + "sprites/gui/standard_spell_on_56.png", + "sprites/gui/standard_spell_on_57.png", + "sprites/gui/standard_spell_on_58.png", + "sprites/gui/standard_spell_on_59.png", + "sprites/gui/standard_spell_on_6.png", + "sprites/gui/standard_spell_on_60.png", + "sprites/gui/standard_spell_on_61.png", + "sprites/gui/standard_spell_on_62.png", + "sprites/gui/standard_spell_on_63.png", + "sprites/gui/standard_spell_on_64.png", + "sprites/gui/standard_spell_on_65.png", + "sprites/gui/standard_spell_on_66.png", + "sprites/gui/standard_spell_on_67.png", + "sprites/gui/standard_spell_on_68.png", + "sprites/gui/standard_spell_on_69.png", + "sprites/gui/standard_spell_on_7.png", + "sprites/gui/standard_spell_on_70.png", + "sprites/gui/standard_spell_on_71.png", + "sprites/gui/standard_spell_on_72.png", + "sprites/gui/standard_spell_on_73.png", + "sprites/gui/standard_spell_on_74.png", + "sprites/gui/standard_spell_on_75.png", + "sprites/gui/standard_spell_on_76.png", + "sprites/gui/standard_spell_on_77.png", + "sprites/gui/standard_spell_on_78.png", "sprites/gui/standard_spell_on_79.png", - "sprites/gui/minimap_alpha_mask.png", - "sprites/gui/prayerglow_0.png" + "sprites/gui/standard_spell_on_8.png", + "sprites/gui/standard_spell_on_9.png", + "sprites/gui/staticons2_0.png", + "sprites/gui/staticons2_1.png", + "sprites/gui/staticons2_2.png", + "sprites/gui/staticons2_3.png", + "sprites/gui/staticons2_4.png", + "sprites/gui/staticons2_5.png", + "sprites/gui/staticons2_6.png", + "sprites/gui/staticons2_7.png", + "sprites/gui/staticons_0.png", + "sprites/gui/staticons_1.png", + "sprites/gui/staticons_10.png", + "sprites/gui/staticons_11.png", + "sprites/gui/staticons_12.png", + "sprites/gui/staticons_13.png", + "sprites/gui/staticons_14.png", + "sprites/gui/staticons_15.png", + "sprites/gui/staticons_16.png", + "sprites/gui/staticons_17.png", + "sprites/gui/staticons_2.png", + "sprites/gui/staticons_3.png", + "sprites/gui/staticons_4.png", + "sprites/gui/staticons_5.png", + "sprites/gui/staticons_6.png", + "sprites/gui/staticons_7.png", + "sprites/gui/staticons_8.png", + "sprites/gui/staticons_9.png", + "sprites/gui/stats_total_left.png", + "sprites/gui/stats_total_middle.png", + "sprites/gui/stats_total_right.png", + "sprites/gui/tab_combat.png", + "sprites/gui/tab_equipment.png", + "sprites/gui/tab_inventory.png", + "sprites/gui/tab_magic.png", + "sprites/gui/tab_prayer.png", + "sprites/gui/tab_quests.png", + "sprites/gui/tab_quests2.png", + "sprites/gui/tab_stats.png", + "sprites/gui/tab_stone_bl_sel.png", + "sprites/gui/tab_stone_br_sel.png", + "sprites/gui/tab_stone_mid_sel.png", + "sprites/gui/tab_stone_tl_sel.png", + "sprites/gui/tab_stone_tr_sel.png", + "sprites/gui/tabs_row_bottom.png", + "sprites/gui/tabs_row_top.png", + "sprites/gui/tli_button01_orb01_34x34_0.png", + "sprites/gui/tli_button01_orb01_34x34_1.png", + "sprites/gui/tli_button01_orb01_34x34_2.png", + "sprites/gui/tli_button01_orbinfo_65x34_0.png", + "sprites/gui/tli_button01_orbinfo_65x34_1.png", + "sprites/gui/tli_button01_orbinfo_65x34_2.png", + "sprites/gui/tradebacking_dark.png", + "sprites/gui/whistle.png", + "sprites/gui/wiki_icon_0.png", + "sprites/gui/worldmap_icon_0.png", + "sprites/gui/wornicons_0.png", + "sprites/gui/wornicons_1.png", + "sprites/gui/wornicons_10.png", + "sprites/gui/wornicons_11.png", + "sprites/gui/wornicons_2.png", + "sprites/gui/wornicons_3.png", + "sprites/gui/wornicons_4.png", + "sprites/gui/wornicons_5.png", + "sprites/gui/wornicons_6.png", + "sprites/gui/wornicons_7.png", + "sprites/gui/wornicons_8.png", + "sprites/gui/wornicons_9.png" ] }, { "name": "items", "files": [ - "sprites/items/30070.png", - "sprites/items/28945.png", + "sprites/items/10382.png", + "sprites/items/10499.png", + "sprites/items/10551.png", + "sprites/items/1079.png", + "sprites/items/10828.png", + "sprites/items/10925.png", + "sprites/items/10927.png", + "sprites/items/10929.png", + "sprites/items/10931.png", + "sprites/items/11212.png", + "sprites/items/11230.png", + "sprites/items/11235.png", + "sprites/items/11770.png", + "sprites/items/11773.png", + "sprites/items/11785.png", + "sprites/items/11791.png", + "sprites/items/11802.png", + "sprites/items/11806.png", + "sprites/items/11834.png", + "sprites/items/12002.png", + "sprites/items/12006.png", + "sprites/items/12612.png", + "sprites/items/12625.png", + "sprites/items/12627.png", + "sprites/items/12629.png", + "sprites/items/12631.png", + "sprites/items/12695.png", + "sprites/items/12697.png", + "sprites/items/12699.png", + "sprites/items/12701.png", + "sprites/items/12788.png", + "sprites/items/12817.png", + "sprites/items/12829.png", + "sprites/items/12831.png", + "sprites/items/12899.png", + "sprites/items/12913.png", + "sprites/items/12915.png", + "sprites/items/12917.png", + "sprites/items/12919.png", + "sprites/items/12926.png", + "sprites/items/12931.png", + "sprites/items/12954.png", + "sprites/items/13235.png", + "sprites/items/13237.png", + "sprites/items/13652.png", + "sprites/items/13867.png", + "sprites/items/139.png", + "sprites/items/141.png", + "sprites/items/143.png", + "sprites/items/169.png", + "sprites/items/171.png", + "sprites/items/1712.png", + "sprites/items/173.png", + "sprites/items/19481.png", + "sprites/items/19544.png", + "sprites/items/19547.png", + "sprites/items/19921.png", + "sprites/items/20220.png", + "sprites/items/20657.png", + "sprites/items/20997.png", + "sprites/items/21003.png", + "sprites/items/21006.png", + "sprites/items/21018.png", + "sprites/items/21021.png", + "sprites/items/21024.png", + "sprites/items/21295.png", + "sprites/items/21326.png", + "sprites/items/21791.png", + "sprites/items/21795.png", + "sprites/items/21932.png", + "sprites/items/22109.png", + "sprites/items/22324.png", + "sprites/items/22325.png", + "sprites/items/22326.png", + "sprites/items/22327.png", + "sprites/items/22328.png", + "sprites/items/22461.png", + "sprites/items/22464.png", + "sprites/items/22467.png", + "sprites/items/22470.png", + "sprites/items/22481.png", + "sprites/items/22613.png", + "sprites/items/22622.png", + "sprites/items/22636.png", + "sprites/items/22981.png", + "sprites/items/23617.png", + "sprites/items/23685.png", + "sprites/items/23688.png", + "sprites/items/23691.png", + "sprites/items/23694.png", + "sprites/items/23733.png", + "sprites/items/23736.png", + "sprites/items/23739.png", + "sprites/items/23742.png", + "sprites/items/23971.png", + "sprites/items/23975.png", + "sprites/items/23979.png", + "sprites/items/2434.png", + "sprites/items/24417.png", + "sprites/items/24424.png", + "sprites/items/2444.png", + "sprites/items/24780.png", + "sprites/items/2497.png", + "sprites/items/2503.png", + "sprites/items/2550.png", + "sprites/items/25730.png", + "sprites/items/25865.png", + "sprites/items/25975.png", + "sprites/items/26219.png", + "sprites/items/26233.png", + "sprites/items/26235.png", + "sprites/items/26243.png", + "sprites/items/26245.png", + "sprites/items/26374.png", + "sprites/items/26382.png", + "sprites/items/27235.png", + "sprites/items/27238.png", + "sprites/items/27241.png", + "sprites/items/27251.png", + "sprites/items/27275.png", + "sprites/items/27281.png", + "sprites/items/27610.png", "sprites/items/27641.png", + "sprites/items/27690.png", + "sprites/items/28307.png", + "sprites/items/28310.png", + "sprites/items/28945.png", + "sprites/items/28947.png", + "sprites/items/29801.png", + "sprites/items/30070.png", + "sprites/items/3024.png", + "sprites/items/3026.png", + "sprites/items/3028.png", + "sprites/items/3030.png", + "sprites/items/30753.png", + "sprites/items/30756.png", + "sprites/items/30875.png", + "sprites/items/30878.png", + "sprites/items/30881.png", + "sprites/items/30884.png", + "sprites/items/3105.png", + "sprites/items/31097.png", + "sprites/items/31106.png", + "sprites/items/31113.png", + "sprites/items/3144.png", + "sprites/items/385.png", + "sprites/items/4089.png", + "sprites/items/4091.png", + "sprites/items/4093.png", + "sprites/items/4097.png", + "sprites/items/4151.png", + "sprites/items/4153.png", + "sprites/items/4224.png", + "sprites/items/4417.png", + "sprites/items/4419.png", + "sprites/items/4421.png", + "sprites/items/4423.png", + "sprites/items/4708.png", + "sprites/items/4710.png", + "sprites/items/4712.png", + "sprites/items/4714.png", + "sprites/items/4716.png", + "sprites/items/4722.png", + "sprites/items/4724.png", + "sprites/items/4736.png", + "sprites/items/4745.png", + "sprites/items/4751.png", + "sprites/items/4753.png", + "sprites/items/4759.png", + "sprites/items/5698.png", + "sprites/items/6585.png", + "sprites/items/6685.png", + "sprites/items/6687.png", + "sprites/items/6689.png", + "sprites/items/6691.png", + "sprites/items/6737.png", + "sprites/items/6889.png", + "sprites/items/6920.png", + "sprites/items/7462.png", + "sprites/items/9185.png", + "sprites/items/9243.png", "sprites/items/item_stack_variants.tsv" ] }, @@ -179,4 +1704,4 @@ ] } ] -} \ No newline at end of file +} diff --git a/ocean/osrs/osrs_assets_generated.h b/ocean/osrs/osrs_assets_generated.h index f0aa4ae2b9..92cbf838ab 100644 --- a/ocean/osrs/osrs_assets_generated.h +++ b/ocean/osrs/osrs_assets_generated.h @@ -106,28 +106,1553 @@ static const char* const OSRS_ASSET_COLOSSEUM_PATHS[] = { }; static const char* const OSRS_ASSET_GUI_PATHS[] = { + "sprites/gui/0.png", + "sprites/gui/1.png", + "sprites/gui/10.png", + "sprites/gui/100.png", + "sprites/gui/101.png", + "sprites/gui/1017.png", + "sprites/gui/1018.png", + "sprites/gui/102.png", + "sprites/gui/1026.png", + "sprites/gui/1027.png", + "sprites/gui/1028.png", + "sprites/gui/1029.png", + "sprites/gui/103.png", + "sprites/gui/1030.png", + "sprites/gui/1031.png", + "sprites/gui/1032.png", + "sprites/gui/1033.png", + "sprites/gui/1034.png", + "sprites/gui/1035.png", + "sprites/gui/1036.png", + "sprites/gui/1037.png", + "sprites/gui/1038.png", + "sprites/gui/104.png", + "sprites/gui/105.png", + "sprites/gui/1052.png", + "sprites/gui/1053.png", + "sprites/gui/1058.png", + "sprites/gui/1059.png", + "sprites/gui/106.png", + "sprites/gui/1060.png", + "sprites/gui/1061.png", + "sprites/gui/1062.png", + "sprites/gui/1063.png", + "sprites/gui/1064.png", + "sprites/gui/1065.png", + "sprites/gui/1066.png", + "sprites/gui/1067.png", + "sprites/gui/1068.png", + "sprites/gui/1069.png", + "sprites/gui/107.png", + "sprites/gui/1070.png", + "sprites/gui/1071.png", + "sprites/gui/1072.png", + "sprites/gui/108.png", + "sprites/gui/109.png", + "sprites/gui/1090.png", + "sprites/gui/1092.png", + "sprites/gui/1098.png", + "sprites/gui/1099.png", + "sprites/gui/11.png", + "sprites/gui/110.png", + "sprites/gui/1100.png", + "sprites/gui/1102.png", + "sprites/gui/111.png", + "sprites/gui/112.png", + "sprites/gui/113.png", + "sprites/gui/114.png", + "sprites/gui/115.png", + "sprites/gui/116.png", + "sprites/gui/117.png", + "sprites/gui/1173.png", + "sprites/gui/1174.png", + "sprites/gui/1175.png", + "sprites/gui/1176.png", + "sprites/gui/1177.png", + "sprites/gui/1178.png", + "sprites/gui/1179.png", + "sprites/gui/118.png", + "sprites/gui/1182.png", + "sprites/gui/1183.png", + "sprites/gui/1184.png", + "sprites/gui/119.png", + "sprites/gui/1196.png", + "sprites/gui/120.png", + "sprites/gui/1200.png", + "sprites/gui/121.png", + "sprites/gui/122.png", + "sprites/gui/123.png", + "sprites/gui/124.png", + "sprites/gui/125.png", + "sprites/gui/126.png", + "sprites/gui/127.png", + "sprites/gui/128.png", + "sprites/gui/129.png", + "sprites/gui/1299.png", + "sprites/gui/13.png", + "sprites/gui/130.png", + "sprites/gui/131.png", + "sprites/gui/132.png", + "sprites/gui/133.png", + "sprites/gui/134.png", + "sprites/gui/1343.png", + "sprites/gui/135.png", + "sprites/gui/136.png", + "sprites/gui/137.png", + "sprites/gui/138.png", + "sprites/gui/139.png", + "sprites/gui/14.png", + "sprites/gui/140.png", + "sprites/gui/141.png", + "sprites/gui/142.png", + "sprites/gui/1420.png", + "sprites/gui/1421.png", + "sprites/gui/1424.png", + "sprites/gui/1425.png", + "sprites/gui/143.png", + "sprites/gui/1438.png", + "sprites/gui/1439.png", + "sprites/gui/144.png", + "sprites/gui/1441.png", + "sprites/gui/145.png", + "sprites/gui/146.png", + "sprites/gui/147.png", + "sprites/gui/148.png", + "sprites/gui/149.png", + "sprites/gui/15.png", + "sprites/gui/150.png", + "sprites/gui/151.png", + "sprites/gui/152.png", + "sprites/gui/153.png", + "sprites/gui/154.png", + "sprites/gui/156.png", + "sprites/gui/157.png", + "sprites/gui/158.png", + "sprites/gui/1583.png", + "sprites/gui/159.png", + "sprites/gui/16.png", + "sprites/gui/160.png", + "sprites/gui/1607.png", + "sprites/gui/1608.png", + "sprites/gui/1609.png", + "sprites/gui/161.png", + "sprites/gui/1610.png", + "sprites/gui/1611.png", + "sprites/gui/162.png", + "sprites/gui/163.png", + "sprites/gui/1636.png", + "sprites/gui/1637.png", + "sprites/gui/164.png", + "sprites/gui/165.png", + "sprites/gui/166.png", + "sprites/gui/1668.png", + "sprites/gui/167.png", + "sprites/gui/168.png", + "sprites/gui/169.png", + "sprites/gui/17.png", + "sprites/gui/170.png", + "sprites/gui/1709.png", + "sprites/gui/171.png", + "sprites/gui/172.png", + "sprites/gui/173.png", + "sprites/gui/174.png", + "sprites/gui/175.png", + "sprites/gui/1751.png", + "sprites/gui/1752.png", + "sprites/gui/1753.png", + "sprites/gui/1754.png", + "sprites/gui/1755.png", + "sprites/gui/1756.png", + "sprites/gui/1757.png", + "sprites/gui/1758.png", + "sprites/gui/1759.png", + "sprites/gui/176.png", + "sprites/gui/1760.png", + "sprites/gui/1761.png", + "sprites/gui/1762.png", + "sprites/gui/1763.png", + "sprites/gui/1764.png", + "sprites/gui/1765.png", + "sprites/gui/1766.png", + "sprites/gui/1767.png", + "sprites/gui/1768.png", + "sprites/gui/1769.png", + "sprites/gui/177.png", + "sprites/gui/1770.png", + "sprites/gui/1771.png", + "sprites/gui/1772.png", + "sprites/gui/1773.png", + "sprites/gui/1774.png", + "sprites/gui/1775.png", + "sprites/gui/1776.png", + "sprites/gui/1777.png", + "sprites/gui/1778.png", + "sprites/gui/1779.png", + "sprites/gui/178.png", + "sprites/gui/1780.png", + "sprites/gui/1781.png", + "sprites/gui/1782.png", + "sprites/gui/1783.png", + "sprites/gui/1784.png", + "sprites/gui/1785.png", + "sprites/gui/1786.png", + "sprites/gui/1787.png", + "sprites/gui/1788.png", + "sprites/gui/1789.png", + "sprites/gui/179.png", + "sprites/gui/1790.png", + "sprites/gui/1791.png", + "sprites/gui/1792.png", + "sprites/gui/1793.png", + "sprites/gui/1794.png", + "sprites/gui/1795.png", + "sprites/gui/1796.png", + "sprites/gui/1797.png", + "sprites/gui/1798.png", + "sprites/gui/1799.png", + "sprites/gui/18.png", + "sprites/gui/180.png", + "sprites/gui/1800.png", + "sprites/gui/1801.png", + "sprites/gui/1802.png", + "sprites/gui/1803.png", + "sprites/gui/1804.png", + "sprites/gui/1805.png", + "sprites/gui/1806.png", + "sprites/gui/1807.png", + "sprites/gui/1808.png", + "sprites/gui/1809.png", + "sprites/gui/181.png", + "sprites/gui/1810.png", + "sprites/gui/1811.png", + "sprites/gui/1812.png", + "sprites/gui/1813.png", + "sprites/gui/1814.png", + "sprites/gui/1815.png", + "sprites/gui/1816.png", + "sprites/gui/1817.png", + "sprites/gui/1818.png", + "sprites/gui/1819.png", + "sprites/gui/182.png", + "sprites/gui/1820.png", + "sprites/gui/1821.png", + "sprites/gui/1822.png", + "sprites/gui/1823.png", + "sprites/gui/1824.png", + "sprites/gui/1825.png", + "sprites/gui/1826.png", + "sprites/gui/1827.png", + "sprites/gui/1828.png", + "sprites/gui/1829.png", + "sprites/gui/183.png", + "sprites/gui/1830.png", + "sprites/gui/1831.png", + "sprites/gui/1832.png", + "sprites/gui/1833.png", + "sprites/gui/1834.png", + "sprites/gui/1835.png", + "sprites/gui/1836.png", + "sprites/gui/1837.png", + "sprites/gui/1838.png", + "sprites/gui/1839.png", + "sprites/gui/184.png", + "sprites/gui/1840.png", + "sprites/gui/1841.png", + "sprites/gui/1842.png", + "sprites/gui/1843.png", + "sprites/gui/1844.png", + "sprites/gui/1845.png", + "sprites/gui/1846.png", + "sprites/gui/1847.png", + "sprites/gui/1848.png", + "sprites/gui/1849.png", + "sprites/gui/1850.png", + "sprites/gui/1851.png", + "sprites/gui/1852.png", + "sprites/gui/1853.png", + "sprites/gui/1854.png", + "sprites/gui/1855.png", + "sprites/gui/1856.png", + "sprites/gui/1857.png", + "sprites/gui/1858.png", + "sprites/gui/1859.png", + "sprites/gui/1860.png", + "sprites/gui/1861.png", + "sprites/gui/1862.png", + "sprites/gui/1863.png", + "sprites/gui/1864.png", + "sprites/gui/1865.png", + "sprites/gui/1866.png", + "sprites/gui/1867.png", + "sprites/gui/1868.png", + "sprites/gui/1869.png", + "sprites/gui/1870.png", + "sprites/gui/1871.png", + "sprites/gui/1872.png", + "sprites/gui/1873.png", + "sprites/gui/1874.png", + "sprites/gui/1875.png", + "sprites/gui/1876.png", + "sprites/gui/1877.png", + "sprites/gui/1878.png", + "sprites/gui/1879.png", + "sprites/gui/1880.png", + "sprites/gui/1881.png", + "sprites/gui/1882.png", + "sprites/gui/1883.png", + "sprites/gui/1884.png", + "sprites/gui/1885.png", + "sprites/gui/1886.png", + "sprites/gui/1887.png", + "sprites/gui/1888.png", + "sprites/gui/1889.png", + "sprites/gui/189.png", + "sprites/gui/1890.png", + "sprites/gui/1891.png", + "sprites/gui/19.png", + "sprites/gui/190.png", + "sprites/gui/191.png", + "sprites/gui/197.png", + "sprites/gui/198.png", + "sprites/gui/199.png", + "sprites/gui/2.png", + "sprites/gui/20.png", + "sprites/gui/200.png", + "sprites/gui/201.png", + "sprites/gui/202.png", + "sprites/gui/203.png", + "sprites/gui/204.png", + "sprites/gui/205.png", + "sprites/gui/206.png", + "sprites/gui/207.png", + "sprites/gui/208.png", + "sprites/gui/209.png", + "sprites/gui/21.png", + "sprites/gui/210.png", + "sprites/gui/211.png", + "sprites/gui/212.png", + "sprites/gui/213.png", + "sprites/gui/2138.png", + "sprites/gui/214.png", + "sprites/gui/2140.png", + "sprites/gui/215.png", + "sprites/gui/216.png", + "sprites/gui/217.png", + "sprites/gui/218.png", + "sprites/gui/219.png", + "sprites/gui/22.png", + "sprites/gui/220.png", + "sprites/gui/2208.png", + "sprites/gui/221.png", + "sprites/gui/222.png", + "sprites/gui/23.png", + "sprites/gui/233.png", + "sprites/gui/234.png", + "sprites/gui/235.png", + "sprites/gui/236.png", + "sprites/gui/237.png", + "sprites/gui/238.png", + "sprites/gui/239.png", + "sprites/gui/24.png", + "sprites/gui/240.png", + "sprites/gui/241.png", + "sprites/gui/242.png", + "sprites/gui/2420.png", + "sprites/gui/243.png", + "sprites/gui/244.png", + "sprites/gui/245.png", + "sprites/gui/246.png", + "sprites/gui/247.png", + "sprites/gui/248.png", + "sprites/gui/249.png", + "sprites/gui/25.png", + "sprites/gui/250.png", + "sprites/gui/251.png", + "sprites/gui/252.png", + "sprites/gui/253.png", + "sprites/gui/254.png", + "sprites/gui/255.png", + "sprites/gui/256.png", + "sprites/gui/257.png", + "sprites/gui/258.png", + "sprites/gui/259.png", + "sprites/gui/26.png", + "sprites/gui/260.png", + "sprites/gui/261.png", + "sprites/gui/262.png", + "sprites/gui/263.png", + "sprites/gui/264.png", + "sprites/gui/265.png", + "sprites/gui/266.png", + "sprites/gui/267.png", + "sprites/gui/268.png", + "sprites/gui/269.png", + "sprites/gui/27.png", + "sprites/gui/270.png", + "sprites/gui/271.png", + "sprites/gui/272.png", + "sprites/gui/273.png", + "sprites/gui/274.png", + "sprites/gui/275.png", + "sprites/gui/276.png", + "sprites/gui/277.png", + "sprites/gui/278.png", + "sprites/gui/279.png", + "sprites/gui/28.png", + "sprites/gui/280.png", + "sprites/gui/281.png", + "sprites/gui/282.png", + "sprites/gui/283.png", + "sprites/gui/284.png", + "sprites/gui/285.png", + "sprites/gui/286.png", + "sprites/gui/287.png", + "sprites/gui/288.png", + "sprites/gui/289.png", + "sprites/gui/29.png", + "sprites/gui/290.png", + "sprites/gui/291.png", + "sprites/gui/292.png", + "sprites/gui/293.png", + "sprites/gui/294.png", + "sprites/gui/295.png", + "sprites/gui/296.png", + "sprites/gui/3.png", + "sprites/gui/30.png", + "sprites/gui/3015.png", + "sprites/gui/3016.png", + "sprites/gui/3017.png", + "sprites/gui/3018.png", + "sprites/gui/3019.png", + "sprites/gui/3020.png", + "sprites/gui/3021.png", + "sprites/gui/3022.png", + "sprites/gui/305.png", + "sprites/gui/3051.png", + "sprites/gui/3052.png", + "sprites/gui/3053.png", + "sprites/gui/3054.png", + "sprites/gui/3055.png", + "sprites/gui/3056.png", + "sprites/gui/306.png", + "sprites/gui/307.png", + "sprites/gui/31.png", + "sprites/gui/32.png", + "sprites/gui/325.png", + "sprites/gui/326.png", + "sprites/gui/327.png", + "sprites/gui/328.png", + "sprites/gui/329.png", + "sprites/gui/33.png", + "sprites/gui/330.png", + "sprites/gui/331.png", + "sprites/gui/332.png", + "sprites/gui/333.png", + "sprites/gui/334.png", + "sprites/gui/335.png", + "sprites/gui/336.png", + "sprites/gui/337.png", + "sprites/gui/338.png", + "sprites/gui/339.png", + "sprites/gui/34.png", + "sprites/gui/340.png", + "sprites/gui/341.png", + "sprites/gui/342.png", + "sprites/gui/343.png", + "sprites/gui/344.png", + "sprites/gui/345.png", + "sprites/gui/346.png", + "sprites/gui/347.png", + "sprites/gui/348.png", + "sprites/gui/35.png", + "sprites/gui/3560.png", + "sprites/gui/36.png", + "sprites/gui/37.png", + "sprites/gui/375.png", + "sprites/gui/376.png", + "sprites/gui/377.png", + "sprites/gui/378.png", + "sprites/gui/379.png", + "sprites/gui/38.png", + "sprites/gui/380.png", + "sprites/gui/381.png", + "sprites/gui/382.png", + "sprites/gui/383.png", + "sprites/gui/384.png", + "sprites/gui/385.png", + "sprites/gui/386.png", + "sprites/gui/387.png", + "sprites/gui/388.png", + "sprites/gui/389.png", + "sprites/gui/39.png", + "sprites/gui/390.png", + "sprites/gui/391.png", + "sprites/gui/392.png", + "sprites/gui/393.png", + "sprites/gui/394.png", + "sprites/gui/395.png", + "sprites/gui/396.png", + "sprites/gui/397.png", + "sprites/gui/398.png", + "sprites/gui/40.png", + "sprites/gui/41.png", + "sprites/gui/42.png", + "sprites/gui/43.png", + "sprites/gui/44.png", + "sprites/gui/45.png", + "sprites/gui/46.png", + "sprites/gui/47.png", + "sprites/gui/48.png", + "sprites/gui/4892.png", + "sprites/gui/4893.png", + "sprites/gui/49.png", + "sprites/gui/5.png", + "sprites/gui/50.png", + "sprites/gui/502.png", + "sprites/gui/503.png", + "sprites/gui/504.png", + "sprites/gui/505.png", + "sprites/gui/506.png", + "sprites/gui/507.png", + "sprites/gui/508.png", + "sprites/gui/509.png", + "sprites/gui/51.png", + "sprites/gui/52.png", + "sprites/gui/53.png", + "sprites/gui/54.png", + "sprites/gui/55.png", + "sprites/gui/557.png", + "sprites/gui/56.png", + "sprites/gui/561.png", + "sprites/gui/564.png", + "sprites/gui/57.png", + "sprites/gui/5791.png", + "sprites/gui/5792.png", + "sprites/gui/5793.png", + "sprites/gui/5794.png", + "sprites/gui/5795.png", + "sprites/gui/5796.png", + "sprites/gui/58.png", + "sprites/gui/5813.png", + "sprites/gui/5832.png", + "sprites/gui/59.png", + "sprites/gui/6.png", + "sprites/gui/60.png", + "sprites/gui/607.png", + "sprites/gui/61.png", + "sprites/gui/611.png", + "sprites/gui/614.png", + "sprites/gui/62.png", + "sprites/gui/63.png", + "sprites/gui/64.png", + "sprites/gui/65.png", + "sprites/gui/653.png", + "sprites/gui/654.png", + "sprites/gui/655.png", + "sprites/gui/656.png", + "sprites/gui/657.png", + "sprites/gui/66.png", + "sprites/gui/67.png", + "sprites/gui/675.png", + "sprites/gui/68.png", + "sprites/gui/69.png", + "sprites/gui/7.png", + "sprites/gui/70.png", + "sprites/gui/71.png", + "sprites/gui/72.png", + "sprites/gui/73.png", + "sprites/gui/74.png", + "sprites/gui/75.png", + "sprites/gui/76.png", + "sprites/gui/760.png", + "sprites/gui/77.png", + "sprites/gui/774.png", + "sprites/gui/775.png", + "sprites/gui/776.png", + "sprites/gui/777.png", + "sprites/gui/778.png", + "sprites/gui/779.png", + "sprites/gui/78.png", + "sprites/gui/780.png", + "sprites/gui/781.png", + "sprites/gui/782.png", + "sprites/gui/783.png", + "sprites/gui/784.png", + "sprites/gui/785.png", + "sprites/gui/786.png", + "sprites/gui/787.png", + "sprites/gui/79.png", + "sprites/gui/8.png", + "sprites/gui/80.png", + "sprites/gui/81.png", + "sprites/gui/82.png", + "sprites/gui/83.png", + "sprites/gui/84.png", + "sprites/gui/85.png", + "sprites/gui/86.png", + "sprites/gui/87.png", + "sprites/gui/88.png", + "sprites/gui/89.png", + "sprites/gui/897.png", + "sprites/gui/898.png", + "sprites/gui/899.png", + "sprites/gui/9.png", + "sprites/gui/90.png", + "sprites/gui/900.png", + "sprites/gui/901.png", + "sprites/gui/902.png", + "sprites/gui/903.png", + "sprites/gui/904.png", + "sprites/gui/905.png", + "sprites/gui/907.png", + "sprites/gui/908.png", + "sprites/gui/909.png", + "sprites/gui/91.png", + "sprites/gui/910.png", + "sprites/gui/912.png", + "sprites/gui/92.png", + "sprites/gui/93.png", + "sprites/gui/94.png", + "sprites/gui/944.png", + "sprites/gui/945.png", + "sprites/gui/946.png", + "sprites/gui/947.png", + "sprites/gui/948.png", + "sprites/gui/949.png", + "sprites/gui/95.png", + "sprites/gui/950.png", + "sprites/gui/951.png", + "sprites/gui/96.png", + "sprites/gui/97.png", + "sprites/gui/98.png", + "sprites/gui/99.png", + "sprites/gui/border_map_compass.png", + "sprites/gui/chat_tab_button_0.png", + "sprites/gui/chat_tab_button_1.png", + "sprites/gui/chat_tab_button_2.png", + "sprites/gui/chat_tab_button_3.png", + "sprites/gui/chat_tab_button_4.png", + "sprites/gui/chat_tab_button_5.png", + "sprites/gui/chatbox_bg.png", + "sprites/gui/chatbox_stones.png", + "sprites/gui/combat_shield.png", + "sprites/gui/combatboxes_0.png", + "sprites/gui/combatboxes_1.png", + "sprites/gui/combatboxes_2.png", + "sprites/gui/combatboxes_3.png", + "sprites/gui/combatboxes_large_0.png", + "sprites/gui/combatboxes_large_1.png", + "sprites/gui/combatboxes_special_attack.png", + "sprites/gui/combatboxes_very_large_0.png", + "sprites/gui/combatboxes_very_large_1.png", + "sprites/gui/combaticons2_0.png", + "sprites/gui/combaticons2_1.png", + "sprites/gui/combaticons2_10.png", + "sprites/gui/combaticons2_11.png", + "sprites/gui/combaticons2_12.png", + "sprites/gui/combaticons2_13.png", + "sprites/gui/combaticons2_14.png", + "sprites/gui/combaticons2_15.png", + "sprites/gui/combaticons2_16.png", + "sprites/gui/combaticons2_17.png", + "sprites/gui/combaticons2_18.png", + "sprites/gui/combaticons2_19.png", + "sprites/gui/combaticons2_2.png", + "sprites/gui/combaticons2_3.png", + "sprites/gui/combaticons2_4.png", + "sprites/gui/combaticons2_5.png", + "sprites/gui/combaticons2_6.png", + "sprites/gui/combaticons2_7.png", + "sprites/gui/combaticons2_8.png", + "sprites/gui/combaticons2_9.png", + "sprites/gui/combaticons3_0.png", + "sprites/gui/combaticons3_1.png", + "sprites/gui/combaticons3_10.png", + "sprites/gui/combaticons3_11.png", + "sprites/gui/combaticons3_12.png", + "sprites/gui/combaticons3_13.png", + "sprites/gui/combaticons3_14.png", + "sprites/gui/combaticons3_15.png", + "sprites/gui/combaticons3_16.png", + "sprites/gui/combaticons3_17.png", + "sprites/gui/combaticons3_18.png", + "sprites/gui/combaticons3_19.png", + "sprites/gui/combaticons3_2.png", + "sprites/gui/combaticons3_3.png", + "sprites/gui/combaticons3_4.png", + "sprites/gui/combaticons3_5.png", + "sprites/gui/combaticons3_6.png", + "sprites/gui/combaticons3_7.png", + "sprites/gui/combaticons3_8.png", + "sprites/gui/combaticons3_9.png", + "sprites/gui/combaticons_0.png", + "sprites/gui/combaticons_1.png", + "sprites/gui/combaticons_10.png", + "sprites/gui/combaticons_11.png", + "sprites/gui/combaticons_12.png", + "sprites/gui/combaticons_13.png", + "sprites/gui/combaticons_14.png", + "sprites/gui/combaticons_15.png", + "sprites/gui/combaticons_16.png", + "sprites/gui/combaticons_17.png", + "sprites/gui/combaticons_18.png", + "sprites/gui/combaticons_19.png", + "sprites/gui/combaticons_2.png", + "sprites/gui/combaticons_3.png", + "sprites/gui/combaticons_4.png", + "sprites/gui/combaticons_5.png", + "sprites/gui/combaticons_6.png", + "sprites/gui/combaticons_7.png", + "sprites/gui/combaticons_8.png", + "sprites/gui/combaticons_9.png", "sprites/gui/compass.png", - "sprites/gui/side_panel_bg.png", - "sprites/gui/orb_frame.png", + "sprites/gui/compass_alpha_mask.png", + "sprites/gui/compass_outline.png", + "sprites/gui/cross_red_1.png", + "sprites/gui/cross_red_2.png", + "sprites/gui/cross_red_3.png", + "sprites/gui/cross_red_4.png", + "sprites/gui/cross_yellow_1.png", + "sprites/gui/cross_yellow_2.png", + "sprites/gui/cross_yellow_3.png", + "sprites/gui/cross_yellow_4.png", + "sprites/gui/fixed_compass_mask.png", + "sprites/gui/fixed_map_clickmask.png", + "sprites/gui/fixed_map_mask.png", + "sprites/gui/fixed_minimap_cover.png", "sprites/gui/headicons_prayer_0.png", + "sprites/gui/headicons_prayer_1.png", + "sprites/gui/headicons_prayer_10.png", + "sprites/gui/headicons_prayer_11.png", + "sprites/gui/headicons_prayer_12.png", + "sprites/gui/headicons_prayer_13.png", + "sprites/gui/headicons_prayer_14.png", + "sprites/gui/headicons_prayer_15.png", + "sprites/gui/headicons_prayer_16.png", + "sprites/gui/headicons_prayer_17.png", + "sprites/gui/headicons_prayer_18.png", + "sprites/gui/headicons_prayer_19.png", + "sprites/gui/headicons_prayer_2.png", + "sprites/gui/headicons_prayer_20.png", + "sprites/gui/headicons_prayer_21.png", + "sprites/gui/headicons_prayer_22.png", + "sprites/gui/headicons_prayer_23.png", + "sprites/gui/headicons_prayer_3.png", + "sprites/gui/headicons_prayer_4.png", + "sprites/gui/headicons_prayer_5.png", + "sprites/gui/headicons_prayer_6.png", + "sprites/gui/headicons_prayer_7.png", + "sprites/gui/headicons_prayer_8.png", + "sprites/gui/headicons_prayer_9.png", "sprites/gui/hitmarks_0.png", - "sprites/gui/cross_yellow_1.png", - "sprites/gui/side_icon_inventory.png", - "sprites/gui/tradebacking_dark.png", - "sprites/gui/osrs_stretch_side_topbottom_0.png", - "sprites/gui/wornicons_11.png", - "sprites/gui/skill_icon_23.png", - "sprites/gui/prayeron_24.png", + "sprites/gui/hitmarks_1.png", + "sprites/gui/hitmarks_2.png", + "sprites/gui/hitmarks_3.png", + "sprites/gui/hitmarks_4.png", + "sprites/gui/magicoff_0.png", + "sprites/gui/magicoff_1.png", + "sprites/gui/magicoff_10.png", + "sprites/gui/magicoff_11.png", + "sprites/gui/magicoff_12.png", + "sprites/gui/magicoff_13.png", + "sprites/gui/magicoff_14.png", + "sprites/gui/magicoff_15.png", + "sprites/gui/magicoff_16.png", + "sprites/gui/magicoff_17.png", + "sprites/gui/magicoff_18.png", + "sprites/gui/magicoff_19.png", + "sprites/gui/magicoff_2.png", + "sprites/gui/magicoff_20.png", + "sprites/gui/magicoff_21.png", + "sprites/gui/magicoff_22.png", + "sprites/gui/magicoff_23.png", + "sprites/gui/magicoff_24.png", + "sprites/gui/magicoff_25.png", + "sprites/gui/magicoff_26.png", + "sprites/gui/magicoff_27.png", + "sprites/gui/magicoff_28.png", + "sprites/gui/magicoff_29.png", + "sprites/gui/magicoff_3.png", + "sprites/gui/magicoff_30.png", + "sprites/gui/magicoff_31.png", + "sprites/gui/magicoff_32.png", + "sprites/gui/magicoff_33.png", + "sprites/gui/magicoff_34.png", + "sprites/gui/magicoff_35.png", + "sprites/gui/magicoff_36.png", + "sprites/gui/magicoff_37.png", + "sprites/gui/magicoff_38.png", + "sprites/gui/magicoff_39.png", + "sprites/gui/magicoff_4.png", + "sprites/gui/magicoff_40.png", + "sprites/gui/magicoff_41.png", + "sprites/gui/magicoff_42.png", + "sprites/gui/magicoff_43.png", + "sprites/gui/magicoff_44.png", + "sprites/gui/magicoff_45.png", + "sprites/gui/magicoff_46.png", + "sprites/gui/magicoff_47.png", + "sprites/gui/magicoff_48.png", + "sprites/gui/magicoff_49.png", + "sprites/gui/magicoff_5.png", + "sprites/gui/magicoff_6.png", + "sprites/gui/magicoff_7.png", + "sprites/gui/magicoff_8.png", + "sprites/gui/magicoff_9.png", + "sprites/gui/magicon_0.png", + "sprites/gui/magicon_1.png", + "sprites/gui/magicon_10.png", + "sprites/gui/magicon_11.png", + "sprites/gui/magicon_12.png", + "sprites/gui/magicon_13.png", + "sprites/gui/magicon_14.png", + "sprites/gui/magicon_15.png", + "sprites/gui/magicon_16.png", + "sprites/gui/magicon_17.png", + "sprites/gui/magicon_18.png", + "sprites/gui/magicon_19.png", + "sprites/gui/magicon_2.png", + "sprites/gui/magicon_20.png", + "sprites/gui/magicon_21.png", + "sprites/gui/magicon_22.png", + "sprites/gui/magicon_23.png", + "sprites/gui/magicon_24.png", + "sprites/gui/magicon_25.png", + "sprites/gui/magicon_26.png", + "sprites/gui/magicon_27.png", + "sprites/gui/magicon_28.png", + "sprites/gui/magicon_29.png", + "sprites/gui/magicon_3.png", + "sprites/gui/magicon_30.png", + "sprites/gui/magicon_31.png", + "sprites/gui/magicon_32.png", + "sprites/gui/magicon_33.png", + "sprites/gui/magicon_34.png", + "sprites/gui/magicon_35.png", + "sprites/gui/magicon_36.png", + "sprites/gui/magicon_37.png", + "sprites/gui/magicon_38.png", + "sprites/gui/magicon_39.png", + "sprites/gui/magicon_4.png", + "sprites/gui/magicon_40.png", + "sprites/gui/magicon_41.png", + "sprites/gui/magicon_42.png", + "sprites/gui/magicon_43.png", + "sprites/gui/magicon_44.png", + "sprites/gui/magicon_45.png", + "sprites/gui/magicon_46.png", "sprites/gui/magicon_47.png", - "sprites/gui/standard_spell_on_79.png", + "sprites/gui/magicon_48.png", + "sprites/gui/magicon_49.png", + "sprites/gui/magicon_5.png", + "sprites/gui/magicon_6.png", + "sprites/gui/magicon_7.png", + "sprites/gui/magicon_8.png", + "sprites/gui/magicon_9.png", + "sprites/gui/main_stones_bottom.png", + "sprites/gui/mini_bottom.png", + "sprites/gui/mini_left.png", + "sprites/gui/mini_right.png", + "sprites/gui/mini_topright.png", "sprites/gui/minimap_alpha_mask.png", + "sprites/gui/minimap_and_compass_frame.png", + "sprites/gui/minimap_dest_flag_0.png", + "sprites/gui/minimap_dest_flag_1.png", + "sprites/gui/minimap_dest_flag_2.png", + "sprites/gui/minimap_dest_flag_3.png", + "sprites/gui/minimap_dot_friend.png", + "sprites/gui/minimap_dot_item.png", + "sprites/gui/minimap_dot_npc.png", + "sprites/gui/minimap_dot_player.png", + "sprites/gui/minimap_edge_left.png", + "sprites/gui/minimap_edge_right.png", + "sprites/gui/minimap_guide_arrow_0.png", + "sprites/gui/minimap_guide_arrow_1.png", + "sprites/gui/minimap_guide_arrow_2.png", + "sprites/gui/minimap_guide_arrow_3.png", + "sprites/gui/minimap_guide_arrow_4.png", + "sprites/gui/minimap_guide_arrow_5.png", + "sprites/gui/miscgraphics_0.png", + "sprites/gui/miscgraphics_1.png", + "sprites/gui/miscgraphics_10.png", + "sprites/gui/miscgraphics_11.png", + "sprites/gui/miscgraphics_12.png", + "sprites/gui/miscgraphics_13.png", + "sprites/gui/miscgraphics_14.png", + "sprites/gui/miscgraphics_2.png", + "sprites/gui/miscgraphics_3.png", + "sprites/gui/miscgraphics_4.png", + "sprites/gui/miscgraphics_5.png", + "sprites/gui/miscgraphics_6.png", + "sprites/gui/miscgraphics_7.png", + "sprites/gui/miscgraphics_8.png", + "sprites/gui/miscgraphics_9.png", + "sprites/gui/options_icons_16.png", + "sprites/gui/options_icons_18.png", + "sprites/gui/options_icons_28.png", + "sprites/gui/orb_empty.png", + "sprites/gui/orb_filler_0.png", + "sprites/gui/orb_filler_1.png", + "sprites/gui/orb_filler_10.png", + "sprites/gui/orb_filler_11.png", + "sprites/gui/orb_filler_12.png", + "sprites/gui/orb_filler_13.png", + "sprites/gui/orb_filler_14.png", + "sprites/gui/orb_filler_2.png", + "sprites/gui/orb_filler_3.png", + "sprites/gui/orb_filler_4.png", + "sprites/gui/orb_filler_5.png", + "sprites/gui/orb_filler_6.png", + "sprites/gui/orb_filler_7.png", + "sprites/gui/orb_filler_8.png", + "sprites/gui/orb_filler_9.png", + "sprites/gui/orb_frame.png", + "sprites/gui/orb_frame_0.png", + "sprites/gui/orb_frame_1.png", + "sprites/gui/orb_frame_2.png", + "sprites/gui/orb_frame_hover.png", + "sprites/gui/orb_hp.png", + "sprites/gui/orb_icon_0.png", + "sprites/gui/orb_icon_1.png", + "sprites/gui/orb_icon_10.png", + "sprites/gui/orb_icon_11.png", + "sprites/gui/orb_icon_12.png", + "sprites/gui/orb_icon_13.png", + "sprites/gui/orb_icon_14.png", + "sprites/gui/orb_icon_15.png", + "sprites/gui/orb_icon_2.png", + "sprites/gui/orb_icon_3.png", + "sprites/gui/orb_icon_4.png", + "sprites/gui/orb_icon_5.png", + "sprites/gui/orb_icon_6.png", + "sprites/gui/orb_icon_7.png", + "sprites/gui/orb_icon_8.png", + "sprites/gui/orb_icon_9.png", + "sprites/gui/orb_icon_hp.png", + "sprites/gui/orb_icon_prayer.png", + "sprites/gui/orb_icon_prayer_active.png", + "sprites/gui/orb_icon_run.png", + "sprites/gui/orb_icon_walk.png", + "sprites/gui/orb_prayer.png", + "sprites/gui/orb_prayer_active.png", + "sprites/gui/orb_run.png", + "sprites/gui/orb_run_active.png", + "sprites/gui/orb_xp_0.png", + "sprites/gui/osrs_stretch_mapsurround.png", + "sprites/gui/osrs_stretch_side_columns_0.png", + "sprites/gui/osrs_stretch_side_columns_1.png", + "sprites/gui/osrs_stretch_side_topbottom_0.png", + "sprites/gui/osrs_stretch_side_topbottom_1.png", + "sprites/gui/pray_augury.png", + "sprites/gui/pray_chivalry.png", + "sprites/gui/pray_eagle_eye.png", + "sprites/gui/pray_mage.png", + "sprites/gui/pray_melee.png", + "sprites/gui/pray_mystic_might.png", + "sprites/gui/pray_piety.png", + "sprites/gui/pray_preserve.png", + "sprites/gui/pray_range.png", + "sprites/gui/pray_redemption.png", + "sprites/gui/pray_retribution.png", + "sprites/gui/pray_rigour.png", + "sprites/gui/pray_smite.png", "sprites/gui/prayerglow_0.png", + "sprites/gui/prayerglow_1.png", + "sprites/gui/prayeroff_0.png", + "sprites/gui/prayeroff_1.png", + "sprites/gui/prayeroff_10.png", + "sprites/gui/prayeroff_11.png", + "sprites/gui/prayeroff_12.png", + "sprites/gui/prayeroff_13.png", + "sprites/gui/prayeroff_14.png", + "sprites/gui/prayeroff_15.png", + "sprites/gui/prayeroff_16.png", + "sprites/gui/prayeroff_17.png", + "sprites/gui/prayeroff_18.png", + "sprites/gui/prayeroff_19.png", + "sprites/gui/prayeroff_2.png", + "sprites/gui/prayeroff_20.png", + "sprites/gui/prayeroff_21.png", + "sprites/gui/prayeroff_22.png", + "sprites/gui/prayeroff_23.png", + "sprites/gui/prayeroff_24.png", + "sprites/gui/prayeroff_3.png", + "sprites/gui/prayeroff_4.png", + "sprites/gui/prayeroff_5.png", + "sprites/gui/prayeroff_6.png", + "sprites/gui/prayeroff_7.png", + "sprites/gui/prayeroff_8.png", + "sprites/gui/prayeroff_9.png", + "sprites/gui/prayeron_0.png", + "sprites/gui/prayeron_1.png", + "sprites/gui/prayeron_10.png", + "sprites/gui/prayeron_11.png", + "sprites/gui/prayeron_12.png", + "sprites/gui/prayeron_13.png", + "sprites/gui/prayeron_14.png", + "sprites/gui/prayeron_15.png", + "sprites/gui/prayeron_16.png", + "sprites/gui/prayeron_17.png", + "sprites/gui/prayeron_18.png", + "sprites/gui/prayeron_19.png", + "sprites/gui/prayeron_2.png", + "sprites/gui/prayeron_20.png", + "sprites/gui/prayeron_21.png", + "sprites/gui/prayeron_22.png", + "sprites/gui/prayeron_23.png", + "sprites/gui/prayeron_24.png", + "sprites/gui/prayeron_3.png", + "sprites/gui/prayeron_4.png", + "sprites/gui/prayeron_5.png", + "sprites/gui/prayeron_6.png", + "sprites/gui/prayeron_7.png", + "sprites/gui/prayeron_8.png", + "sprites/gui/prayeron_9.png", + "sprites/gui/resize_compass_mask.png", + "sprites/gui/resize_map_mask.png", + "sprites/gui/ring_30.png", + "sprites/gui/ring_34_0.png", + "sprites/gui/rivets_horizontal.png", + "sprites/gui/rivets_square.png", + "sprites/gui/rivets_vertical.png", + "sprites/gui/rm_compass_alpha_mask.png", + "sprites/gui/rm_minimap_alpha_mask.png", + "sprites/gui/rm_minimap_and_compass_frame.png", + "sprites/gui/rm_side_panel_bg.png", + "sprites/gui/rm_side_panel_edge_left.png", + "sprites/gui/rm_side_panel_edge_right.png", + "sprites/gui/rm_tab_stone_middle.png", + "sprites/gui/rm_tab_stone_middle_selected.png", + "sprites/gui/rm_tabs_bottom_row.png", + "sprites/gui/rm_tabs_top_row.png", + "sprites/gui/side_background.png", + "sprites/gui/side_background_bottom.png", + "sprites/gui/side_background_left1.png", + "sprites/gui/side_background_left2.png", + "sprites/gui/side_background_right.png", + "sprites/gui/side_background_top.png", + "sprites/gui/side_icon_clan.png", + "sprites/gui/side_icon_combat.png", + "sprites/gui/side_icon_emotes.png", + "sprites/gui/side_icon_equipment.png", + "sprites/gui/side_icon_friends.png", + "sprites/gui/side_icon_grouping.png", + "sprites/gui/side_icon_inventory.png", + "sprites/gui/side_icon_logout.png", + "sprites/gui/side_icon_logout_modern.png", + "sprites/gui/side_icon_magic.png", + "sprites/gui/side_icon_magic_ancient.png", + "sprites/gui/side_icon_music.png", + "sprites/gui/side_icon_options.png", + "sprites/gui/side_icon_prayer.png", + "sprites/gui/side_icon_quests.png", + "sprites/gui/side_icon_stats.png", + "sprites/gui/side_icons_0.png", + "sprites/gui/side_icons_1.png", + "sprites/gui/side_icons_10.png", + "sprites/gui/side_icons_11.png", + "sprites/gui/side_icons_12.png", + "sprites/gui/side_icons_13.png", + "sprites/gui/side_icons_2.png", + "sprites/gui/side_icons_22.png", + "sprites/gui/side_icons_3.png", + "sprites/gui/side_icons_39.png", + "sprites/gui/side_icons_4.png", + "sprites/gui/side_icons_5.png", + "sprites/gui/side_icons_6.png", + "sprites/gui/side_icons_7.png", + "sprites/gui/side_icons_8.png", + "sprites/gui/side_panel_bg.png", + "sprites/gui/side_stone_highlights_0.png", + "sprites/gui/side_stone_highlights_1.png", + "sprites/gui/side_stone_highlights_2.png", + "sprites/gui/side_stone_highlights_3.png", + "sprites/gui/side_stone_highlights_4.png", + "sprites/gui/sideicons_interface_0.png", + "sprites/gui/sideicons_interface_1.png", + "sprites/gui/sideicons_interface_10.png", + "sprites/gui/sideicons_interface_11.png", + "sprites/gui/sideicons_interface_12.png", + "sprites/gui/sideicons_interface_13.png", + "sprites/gui/sideicons_interface_14.png", + "sprites/gui/sideicons_interface_15.png", + "sprites/gui/sideicons_interface_16.png", + "sprites/gui/sideicons_interface_2.png", + "sprites/gui/sideicons_interface_3.png", + "sprites/gui/sideicons_interface_4.png", + "sprites/gui/sideicons_interface_5.png", + "sprites/gui/sideicons_interface_6.png", + "sprites/gui/sideicons_interface_7.png", + "sprites/gui/sideicons_interface_8.png", + "sprites/gui/sideicons_interface_9.png", + "sprites/gui/skill_attack.png", + "sprites/gui/skill_defence.png", + "sprites/gui/skill_hitpoints.png", + "sprites/gui/skill_icon_0.png", + "sprites/gui/skill_icon_1.png", + "sprites/gui/skill_icon_10.png", + "sprites/gui/skill_icon_11.png", + "sprites/gui/skill_icon_12.png", + "sprites/gui/skill_icon_13.png", + "sprites/gui/skill_icon_14.png", + "sprites/gui/skill_icon_15.png", + "sprites/gui/skill_icon_16.png", + "sprites/gui/skill_icon_17.png", + "sprites/gui/skill_icon_18.png", + "sprites/gui/skill_icon_19.png", + "sprites/gui/skill_icon_2.png", + "sprites/gui/skill_icon_20.png", + "sprites/gui/skill_icon_21.png", + "sprites/gui/skill_icon_22.png", + "sprites/gui/skill_icon_23.png", + "sprites/gui/skill_icon_3.png", + "sprites/gui/skill_icon_4.png", + "sprites/gui/skill_icon_5.png", + "sprites/gui/skill_icon_6.png", + "sprites/gui/skill_icon_7.png", + "sprites/gui/skill_icon_8.png", + "sprites/gui/skill_icon_9.png", + "sprites/gui/skill_magic.png", + "sprites/gui/skill_prayer.png", + "sprites/gui/skill_ranged.png", + "sprites/gui/skill_strength.png", + "sprites/gui/slanted_tab.png", + "sprites/gui/slanted_tab_hover.png", + "sprites/gui/slot_ammo.png", + "sprites/gui/slot_body.png", + "sprites/gui/slot_cape.png", + "sprites/gui/slot_feet.png", + "sprites/gui/slot_hands.png", + "sprites/gui/slot_head.png", + "sprites/gui/slot_legs.png", + "sprites/gui/slot_neck.png", + "sprites/gui/slot_ring.png", + "sprites/gui/slot_selected.png", + "sprites/gui/slot_shield.png", + "sprites/gui/slot_tile.png", + "sprites/gui/slot_weapon.png", + "sprites/gui/special_attack.png", + "sprites/gui/spell_blood_barrage.png", + "sprites/gui/spell_blood_blitz.png", + "sprites/gui/spell_blood_burst.png", + "sprites/gui/spell_blood_rush.png", + "sprites/gui/spell_ice_barrage.png", + "sprites/gui/spell_ice_blitz.png", + "sprites/gui/spell_ice_burst.png", + "sprites/gui/spell_ice_rush.png", + "sprites/gui/spell_vengeance.png", + "sprites/gui/standard_spell_off_0.png", + "sprites/gui/standard_spell_off_1.png", + "sprites/gui/standard_spell_off_10.png", + "sprites/gui/standard_spell_off_11.png", + "sprites/gui/standard_spell_off_12.png", + "sprites/gui/standard_spell_off_13.png", + "sprites/gui/standard_spell_off_14.png", + "sprites/gui/standard_spell_off_15.png", + "sprites/gui/standard_spell_off_16.png", + "sprites/gui/standard_spell_off_17.png", + "sprites/gui/standard_spell_off_18.png", + "sprites/gui/standard_spell_off_19.png", + "sprites/gui/standard_spell_off_2.png", + "sprites/gui/standard_spell_off_20.png", + "sprites/gui/standard_spell_off_21.png", + "sprites/gui/standard_spell_off_22.png", + "sprites/gui/standard_spell_off_23.png", + "sprites/gui/standard_spell_off_24.png", + "sprites/gui/standard_spell_off_25.png", + "sprites/gui/standard_spell_off_26.png", + "sprites/gui/standard_spell_off_27.png", + "sprites/gui/standard_spell_off_28.png", + "sprites/gui/standard_spell_off_29.png", + "sprites/gui/standard_spell_off_3.png", + "sprites/gui/standard_spell_off_30.png", + "sprites/gui/standard_spell_off_31.png", + "sprites/gui/standard_spell_off_32.png", + "sprites/gui/standard_spell_off_33.png", + "sprites/gui/standard_spell_off_34.png", + "sprites/gui/standard_spell_off_35.png", + "sprites/gui/standard_spell_off_36.png", + "sprites/gui/standard_spell_off_37.png", + "sprites/gui/standard_spell_off_38.png", + "sprites/gui/standard_spell_off_39.png", + "sprites/gui/standard_spell_off_4.png", + "sprites/gui/standard_spell_off_40.png", + "sprites/gui/standard_spell_off_41.png", + "sprites/gui/standard_spell_off_42.png", + "sprites/gui/standard_spell_off_43.png", + "sprites/gui/standard_spell_off_44.png", + "sprites/gui/standard_spell_off_45.png", + "sprites/gui/standard_spell_off_46.png", + "sprites/gui/standard_spell_off_47.png", + "sprites/gui/standard_spell_off_48.png", + "sprites/gui/standard_spell_off_49.png", + "sprites/gui/standard_spell_off_5.png", + "sprites/gui/standard_spell_off_50.png", + "sprites/gui/standard_spell_off_51.png", + "sprites/gui/standard_spell_off_52.png", + "sprites/gui/standard_spell_off_53.png", + "sprites/gui/standard_spell_off_54.png", + "sprites/gui/standard_spell_off_55.png", + "sprites/gui/standard_spell_off_56.png", + "sprites/gui/standard_spell_off_57.png", + "sprites/gui/standard_spell_off_58.png", + "sprites/gui/standard_spell_off_59.png", + "sprites/gui/standard_spell_off_6.png", + "sprites/gui/standard_spell_off_60.png", + "sprites/gui/standard_spell_off_61.png", + "sprites/gui/standard_spell_off_62.png", + "sprites/gui/standard_spell_off_63.png", + "sprites/gui/standard_spell_off_64.png", + "sprites/gui/standard_spell_off_65.png", + "sprites/gui/standard_spell_off_66.png", + "sprites/gui/standard_spell_off_67.png", + "sprites/gui/standard_spell_off_68.png", + "sprites/gui/standard_spell_off_69.png", + "sprites/gui/standard_spell_off_7.png", + "sprites/gui/standard_spell_off_70.png", + "sprites/gui/standard_spell_off_71.png", + "sprites/gui/standard_spell_off_72.png", + "sprites/gui/standard_spell_off_73.png", + "sprites/gui/standard_spell_off_74.png", + "sprites/gui/standard_spell_off_75.png", + "sprites/gui/standard_spell_off_76.png", + "sprites/gui/standard_spell_off_77.png", + "sprites/gui/standard_spell_off_78.png", + "sprites/gui/standard_spell_off_79.png", + "sprites/gui/standard_spell_off_8.png", + "sprites/gui/standard_spell_off_9.png", + "sprites/gui/standard_spell_on_0.png", + "sprites/gui/standard_spell_on_1.png", + "sprites/gui/standard_spell_on_10.png", + "sprites/gui/standard_spell_on_11.png", + "sprites/gui/standard_spell_on_12.png", + "sprites/gui/standard_spell_on_13.png", + "sprites/gui/standard_spell_on_14.png", + "sprites/gui/standard_spell_on_15.png", + "sprites/gui/standard_spell_on_16.png", + "sprites/gui/standard_spell_on_17.png", + "sprites/gui/standard_spell_on_18.png", + "sprites/gui/standard_spell_on_19.png", + "sprites/gui/standard_spell_on_2.png", + "sprites/gui/standard_spell_on_20.png", + "sprites/gui/standard_spell_on_21.png", + "sprites/gui/standard_spell_on_22.png", + "sprites/gui/standard_spell_on_23.png", + "sprites/gui/standard_spell_on_24.png", + "sprites/gui/standard_spell_on_25.png", + "sprites/gui/standard_spell_on_26.png", + "sprites/gui/standard_spell_on_27.png", + "sprites/gui/standard_spell_on_28.png", + "sprites/gui/standard_spell_on_29.png", + "sprites/gui/standard_spell_on_3.png", + "sprites/gui/standard_spell_on_30.png", + "sprites/gui/standard_spell_on_31.png", + "sprites/gui/standard_spell_on_32.png", + "sprites/gui/standard_spell_on_33.png", + "sprites/gui/standard_spell_on_34.png", + "sprites/gui/standard_spell_on_35.png", + "sprites/gui/standard_spell_on_36.png", + "sprites/gui/standard_spell_on_37.png", + "sprites/gui/standard_spell_on_38.png", + "sprites/gui/standard_spell_on_39.png", + "sprites/gui/standard_spell_on_4.png", + "sprites/gui/standard_spell_on_40.png", + "sprites/gui/standard_spell_on_41.png", + "sprites/gui/standard_spell_on_42.png", + "sprites/gui/standard_spell_on_43.png", + "sprites/gui/standard_spell_on_44.png", + "sprites/gui/standard_spell_on_45.png", + "sprites/gui/standard_spell_on_46.png", + "sprites/gui/standard_spell_on_47.png", + "sprites/gui/standard_spell_on_48.png", + "sprites/gui/standard_spell_on_49.png", + "sprites/gui/standard_spell_on_5.png", + "sprites/gui/standard_spell_on_50.png", + "sprites/gui/standard_spell_on_51.png", + "sprites/gui/standard_spell_on_52.png", + "sprites/gui/standard_spell_on_53.png", + "sprites/gui/standard_spell_on_54.png", + "sprites/gui/standard_spell_on_55.png", + "sprites/gui/standard_spell_on_56.png", + "sprites/gui/standard_spell_on_57.png", + "sprites/gui/standard_spell_on_58.png", + "sprites/gui/standard_spell_on_59.png", + "sprites/gui/standard_spell_on_6.png", + "sprites/gui/standard_spell_on_60.png", + "sprites/gui/standard_spell_on_61.png", + "sprites/gui/standard_spell_on_62.png", + "sprites/gui/standard_spell_on_63.png", + "sprites/gui/standard_spell_on_64.png", + "sprites/gui/standard_spell_on_65.png", + "sprites/gui/standard_spell_on_66.png", + "sprites/gui/standard_spell_on_67.png", + "sprites/gui/standard_spell_on_68.png", + "sprites/gui/standard_spell_on_69.png", + "sprites/gui/standard_spell_on_7.png", + "sprites/gui/standard_spell_on_70.png", + "sprites/gui/standard_spell_on_71.png", + "sprites/gui/standard_spell_on_72.png", + "sprites/gui/standard_spell_on_73.png", + "sprites/gui/standard_spell_on_74.png", + "sprites/gui/standard_spell_on_75.png", + "sprites/gui/standard_spell_on_76.png", + "sprites/gui/standard_spell_on_77.png", + "sprites/gui/standard_spell_on_78.png", + "sprites/gui/standard_spell_on_79.png", + "sprites/gui/standard_spell_on_8.png", + "sprites/gui/standard_spell_on_9.png", + "sprites/gui/staticons2_0.png", + "sprites/gui/staticons2_1.png", + "sprites/gui/staticons2_2.png", + "sprites/gui/staticons2_3.png", + "sprites/gui/staticons2_4.png", + "sprites/gui/staticons2_5.png", + "sprites/gui/staticons2_6.png", + "sprites/gui/staticons2_7.png", + "sprites/gui/staticons_0.png", + "sprites/gui/staticons_1.png", + "sprites/gui/staticons_10.png", + "sprites/gui/staticons_11.png", + "sprites/gui/staticons_12.png", + "sprites/gui/staticons_13.png", + "sprites/gui/staticons_14.png", + "sprites/gui/staticons_15.png", + "sprites/gui/staticons_16.png", + "sprites/gui/staticons_17.png", + "sprites/gui/staticons_2.png", + "sprites/gui/staticons_3.png", + "sprites/gui/staticons_4.png", + "sprites/gui/staticons_5.png", + "sprites/gui/staticons_6.png", + "sprites/gui/staticons_7.png", + "sprites/gui/staticons_8.png", + "sprites/gui/staticons_9.png", + "sprites/gui/stats_total_left.png", + "sprites/gui/stats_total_middle.png", + "sprites/gui/stats_total_right.png", + "sprites/gui/tab_combat.png", + "sprites/gui/tab_equipment.png", + "sprites/gui/tab_inventory.png", + "sprites/gui/tab_magic.png", + "sprites/gui/tab_prayer.png", + "sprites/gui/tab_quests.png", + "sprites/gui/tab_quests2.png", + "sprites/gui/tab_stats.png", + "sprites/gui/tab_stone_bl_sel.png", + "sprites/gui/tab_stone_br_sel.png", + "sprites/gui/tab_stone_mid_sel.png", + "sprites/gui/tab_stone_tl_sel.png", + "sprites/gui/tab_stone_tr_sel.png", + "sprites/gui/tabs_row_bottom.png", + "sprites/gui/tabs_row_top.png", + "sprites/gui/tli_button01_orb01_34x34_0.png", + "sprites/gui/tli_button01_orb01_34x34_1.png", + "sprites/gui/tli_button01_orb01_34x34_2.png", + "sprites/gui/tli_button01_orbinfo_65x34_0.png", + "sprites/gui/tli_button01_orbinfo_65x34_1.png", + "sprites/gui/tli_button01_orbinfo_65x34_2.png", + "sprites/gui/tradebacking_dark.png", + "sprites/gui/whistle.png", + "sprites/gui/wiki_icon_0.png", + "sprites/gui/worldmap_icon_0.png", + "sprites/gui/wornicons_0.png", + "sprites/gui/wornicons_1.png", + "sprites/gui/wornicons_10.png", + "sprites/gui/wornicons_11.png", + "sprites/gui/wornicons_2.png", + "sprites/gui/wornicons_3.png", + "sprites/gui/wornicons_4.png", + "sprites/gui/wornicons_5.png", + "sprites/gui/wornicons_6.png", + "sprites/gui/wornicons_7.png", + "sprites/gui/wornicons_8.png", + "sprites/gui/wornicons_9.png", }; static const char* const OSRS_ASSET_ITEMS_PATHS[] = { - "sprites/items/30070.png", - "sprites/items/28945.png", + "sprites/items/10382.png", + "sprites/items/10499.png", + "sprites/items/10551.png", + "sprites/items/1079.png", + "sprites/items/10828.png", + "sprites/items/10925.png", + "sprites/items/10927.png", + "sprites/items/10929.png", + "sprites/items/10931.png", + "sprites/items/11212.png", + "sprites/items/11230.png", + "sprites/items/11235.png", + "sprites/items/11770.png", + "sprites/items/11773.png", + "sprites/items/11785.png", + "sprites/items/11791.png", + "sprites/items/11802.png", + "sprites/items/11806.png", + "sprites/items/11834.png", + "sprites/items/12002.png", + "sprites/items/12006.png", + "sprites/items/12612.png", + "sprites/items/12625.png", + "sprites/items/12627.png", + "sprites/items/12629.png", + "sprites/items/12631.png", + "sprites/items/12695.png", + "sprites/items/12697.png", + "sprites/items/12699.png", + "sprites/items/12701.png", + "sprites/items/12788.png", + "sprites/items/12817.png", + "sprites/items/12829.png", + "sprites/items/12831.png", + "sprites/items/12899.png", + "sprites/items/12913.png", + "sprites/items/12915.png", + "sprites/items/12917.png", + "sprites/items/12919.png", + "sprites/items/12926.png", + "sprites/items/12931.png", + "sprites/items/12954.png", + "sprites/items/13235.png", + "sprites/items/13237.png", + "sprites/items/13652.png", + "sprites/items/13867.png", + "sprites/items/139.png", + "sprites/items/141.png", + "sprites/items/143.png", + "sprites/items/169.png", + "sprites/items/171.png", + "sprites/items/1712.png", + "sprites/items/173.png", + "sprites/items/19481.png", + "sprites/items/19544.png", + "sprites/items/19547.png", + "sprites/items/19921.png", + "sprites/items/20220.png", + "sprites/items/20657.png", + "sprites/items/20997.png", + "sprites/items/21003.png", + "sprites/items/21006.png", + "sprites/items/21018.png", + "sprites/items/21021.png", + "sprites/items/21024.png", + "sprites/items/21295.png", + "sprites/items/21326.png", + "sprites/items/21791.png", + "sprites/items/21795.png", + "sprites/items/21932.png", + "sprites/items/22109.png", + "sprites/items/22324.png", + "sprites/items/22325.png", + "sprites/items/22326.png", + "sprites/items/22327.png", + "sprites/items/22328.png", + "sprites/items/22461.png", + "sprites/items/22464.png", + "sprites/items/22467.png", + "sprites/items/22470.png", + "sprites/items/22481.png", + "sprites/items/22613.png", + "sprites/items/22622.png", + "sprites/items/22636.png", + "sprites/items/22981.png", + "sprites/items/23617.png", + "sprites/items/23685.png", + "sprites/items/23688.png", + "sprites/items/23691.png", + "sprites/items/23694.png", + "sprites/items/23733.png", + "sprites/items/23736.png", + "sprites/items/23739.png", + "sprites/items/23742.png", + "sprites/items/23971.png", + "sprites/items/23975.png", + "sprites/items/23979.png", + "sprites/items/2434.png", + "sprites/items/24417.png", + "sprites/items/24424.png", + "sprites/items/2444.png", + "sprites/items/24780.png", + "sprites/items/2497.png", + "sprites/items/2503.png", + "sprites/items/2550.png", + "sprites/items/25730.png", + "sprites/items/25865.png", + "sprites/items/25975.png", + "sprites/items/26219.png", + "sprites/items/26233.png", + "sprites/items/26235.png", + "sprites/items/26243.png", + "sprites/items/26245.png", + "sprites/items/26374.png", + "sprites/items/26382.png", + "sprites/items/27235.png", + "sprites/items/27238.png", + "sprites/items/27241.png", + "sprites/items/27251.png", + "sprites/items/27275.png", + "sprites/items/27281.png", + "sprites/items/27610.png", "sprites/items/27641.png", + "sprites/items/27690.png", + "sprites/items/28307.png", + "sprites/items/28310.png", + "sprites/items/28945.png", + "sprites/items/28947.png", + "sprites/items/29801.png", + "sprites/items/30070.png", + "sprites/items/3024.png", + "sprites/items/3026.png", + "sprites/items/3028.png", + "sprites/items/3030.png", + "sprites/items/30753.png", + "sprites/items/30756.png", + "sprites/items/30875.png", + "sprites/items/30878.png", + "sprites/items/30881.png", + "sprites/items/30884.png", + "sprites/items/3105.png", + "sprites/items/31097.png", + "sprites/items/31106.png", + "sprites/items/31113.png", + "sprites/items/3144.png", + "sprites/items/385.png", + "sprites/items/4089.png", + "sprites/items/4091.png", + "sprites/items/4093.png", + "sprites/items/4097.png", + "sprites/items/4151.png", + "sprites/items/4153.png", + "sprites/items/4224.png", + "sprites/items/4417.png", + "sprites/items/4419.png", + "sprites/items/4421.png", + "sprites/items/4423.png", + "sprites/items/4708.png", + "sprites/items/4710.png", + "sprites/items/4712.png", + "sprites/items/4714.png", + "sprites/items/4716.png", + "sprites/items/4722.png", + "sprites/items/4724.png", + "sprites/items/4736.png", + "sprites/items/4745.png", + "sprites/items/4751.png", + "sprites/items/4753.png", + "sprites/items/4759.png", + "sprites/items/5698.png", + "sprites/items/6585.png", + "sprites/items/6685.png", + "sprites/items/6687.png", + "sprites/items/6689.png", + "sprites/items/6691.png", + "sprites/items/6737.png", + "sprites/items/6889.png", + "sprites/items/6920.png", + "sprites/items/7462.png", + "sprites/items/9185.png", + "sprites/items/9243.png", "sprites/items/item_stack_variants.tsv", }; diff --git a/ocean/osrs/osrs_combat_visuals_generated.h b/ocean/osrs/osrs_combat_visuals_generated.h index 07409c549d..4eb659f33c 100644 --- a/ocean/osrs/osrs_combat_visuals_generated.h +++ b/ocean/osrs/osrs_combat_visuals_generated.h @@ -1224,6 +1224,8 @@ static const OsrsCombatVisualRow OSRS_COMBAT_VISUAL_ROWS[] = { {OSRS_COMBAT_VISUAL_KIND_NPC, 7693, "", ATTACK_STYLE_MELEE, OSRS_COMBAT_PROJECTILE_MISSING, 7582, {OSRS_COMBAT_PROJECTILE_MISSING, 1382, OSRS_COMBAT_PROJECTILE_MISSING, 33017, 7614, OSRS_COMBAT_PROJECTILE_MISSING, OSRS_COMBAT_PROJECTILE_MISSING, OSRS_COMBAT_PROJECTILE_MISSING, OSRS_COMBAT_PROJECTILE_MISSING, OSRS_COMBAT_PROJECTILE_MISSING, OSRS_COMBAT_PROJECTILE_MISSING, OSRS_COMBAT_PROJECTILE_MISSING, OSRS_COMBAT_PROJECTILE_MISSING, OSRS_COMBAT_PROJECTILE_MISSING, 1}, {OSRS_COMBAT_PROJECTILE_MISSING, OSRS_COMBAT_PROJECTILE_MISSING, OSRS_COMBAT_PROJECTILE_MISSING, OSRS_COMBAT_PROJECTILE_MISSING, OSRS_COMBAT_PROJECTILE_MISSING, OSRS_COMBAT_PROJECTILE_MISSING, OSRS_COMBAT_PROJECTILE_MISSING}, OSRS_COMBAT_PROJECTILE_MISSING, OSRS_COMBAT_PROJECTILE_MISSING, OSRS_COMBAT_PROJECTILE_MISSING, OSRS_COMBAT_PROJECTILE_MISSING, 0, OSRS_COMBAT_PROJECTILE_MISSING}, {OSRS_COMBAT_VISUAL_KIND_NPC, 7693, "", ATTACK_STYLE_RANGED, OSRS_COMBAT_PROJECTILE_MISSING, 7583, {OSRS_COMBAT_PROJECTILE_MISSING, 1383, OSRS_COMBAT_PROJECTILE_MISSING, 853351, 366, OSRS_COMBAT_PROJECTILE_MISSING, OSRS_COMBAT_PROJECTILE_MISSING, OSRS_COMBAT_PROJECTILE_MISSING, OSRS_COMBAT_PROJECTILE_MISSING, OSRS_COMBAT_PROJECTILE_MISSING, OSRS_COMBAT_PROJECTILE_MISSING, OSRS_COMBAT_PROJECTILE_MISSING, OSRS_COMBAT_PROJECTILE_MISSING, OSRS_COMBAT_PROJECTILE_MISSING, 1}, {OSRS_COMBAT_PROJECTILE_MISSING, OSRS_COMBAT_PROJECTILE_MISSING, OSRS_COMBAT_PROJECTILE_MISSING, OSRS_COMBAT_PROJECTILE_MISSING, OSRS_COMBAT_PROJECTILE_MISSING, OSRS_COMBAT_PROJECTILE_MISSING, OSRS_COMBAT_PROJECTILE_MISSING}, OSRS_COMBAT_PROJECTILE_MISSING, OSRS_COMBAT_PROJECTILE_MISSING, OSRS_COMBAT_PROJECTILE_MISSING, OSRS_COMBAT_PROJECTILE_MISSING, 0, OSRS_COMBAT_PROJECTILE_MISSING}, {OSRS_COMBAT_VISUAL_KIND_NPC, 7693, "", ATTACK_STYLE_MAGIC, OSRS_COMBAT_PROJECTILE_MISSING, 7581, {OSRS_COMBAT_PROJECTILE_MISSING, 1384, OSRS_COMBAT_PROJECTILE_MISSING, 853352, OSRS_COMBAT_PROJECTILE_MISSING, OSRS_COMBAT_PROJECTILE_MISSING, OSRS_COMBAT_PROJECTILE_MISSING, OSRS_COMBAT_PROJECTILE_MISSING, OSRS_COMBAT_PROJECTILE_MISSING, OSRS_COMBAT_PROJECTILE_MISSING, OSRS_COMBAT_PROJECTILE_MISSING, OSRS_COMBAT_PROJECTILE_MISSING, OSRS_COMBAT_PROJECTILE_MISSING, OSRS_COMBAT_PROJECTILE_MISSING, 1}, {OSRS_COMBAT_PROJECTILE_MISSING, OSRS_COMBAT_PROJECTILE_MISSING, OSRS_COMBAT_PROJECTILE_MISSING, OSRS_COMBAT_PROJECTILE_MISSING, OSRS_COMBAT_PROJECTILE_MISSING, OSRS_COMBAT_PROJECTILE_MISSING, OSRS_COMBAT_PROJECTILE_MISSING}, OSRS_COMBAT_PROJECTILE_MISSING, OSRS_COMBAT_PROJECTILE_MISSING, OSRS_COMBAT_PROJECTILE_MISSING, OSRS_COMBAT_PROJECTILE_MISSING, 0, OSRS_COMBAT_PROJECTILE_MISSING}, + {OSRS_COMBAT_VISUAL_KIND_NPC, 7694, "", ATTACK_STYLE_MAGIC, OSRS_COMBAT_PROJECTILE_MISSING, 7581, {OSRS_COMBAT_PROJECTILE_MISSING, 1384, OSRS_COMBAT_PROJECTILE_MISSING, 853352, OSRS_COMBAT_PROJECTILE_MISSING, OSRS_COMBAT_PROJECTILE_MISSING, OSRS_COMBAT_PROJECTILE_MISSING, OSRS_COMBAT_PROJECTILE_MISSING, OSRS_COMBAT_PROJECTILE_MISSING, OSRS_COMBAT_PROJECTILE_MISSING, OSRS_COMBAT_PROJECTILE_MISSING, OSRS_COMBAT_PROJECTILE_MISSING, OSRS_COMBAT_PROJECTILE_MISSING, OSRS_COMBAT_PROJECTILE_MISSING, 1}, {OSRS_COMBAT_PROJECTILE_MISSING, OSRS_COMBAT_PROJECTILE_MISSING, OSRS_COMBAT_PROJECTILE_MISSING, OSRS_COMBAT_PROJECTILE_MISSING, OSRS_COMBAT_PROJECTILE_MISSING, OSRS_COMBAT_PROJECTILE_MISSING, OSRS_COMBAT_PROJECTILE_MISSING}, OSRS_COMBAT_PROJECTILE_MISSING, OSRS_COMBAT_PROJECTILE_MISSING, OSRS_COMBAT_PROJECTILE_MISSING, OSRS_COMBAT_PROJECTILE_MISSING, 0, OSRS_COMBAT_PROJECTILE_MISSING}, + {OSRS_COMBAT_VISUAL_KIND_NPC, 7695, "", ATTACK_STYLE_RANGED, OSRS_COMBAT_PROJECTILE_MISSING, 7583, {OSRS_COMBAT_PROJECTILE_MISSING, 1383, OSRS_COMBAT_PROJECTILE_MISSING, 853351, 366, OSRS_COMBAT_PROJECTILE_MISSING, OSRS_COMBAT_PROJECTILE_MISSING, OSRS_COMBAT_PROJECTILE_MISSING, OSRS_COMBAT_PROJECTILE_MISSING, OSRS_COMBAT_PROJECTILE_MISSING, OSRS_COMBAT_PROJECTILE_MISSING, OSRS_COMBAT_PROJECTILE_MISSING, OSRS_COMBAT_PROJECTILE_MISSING, OSRS_COMBAT_PROJECTILE_MISSING, 1}, {OSRS_COMBAT_PROJECTILE_MISSING, OSRS_COMBAT_PROJECTILE_MISSING, OSRS_COMBAT_PROJECTILE_MISSING, OSRS_COMBAT_PROJECTILE_MISSING, OSRS_COMBAT_PROJECTILE_MISSING, OSRS_COMBAT_PROJECTILE_MISSING, OSRS_COMBAT_PROJECTILE_MISSING}, OSRS_COMBAT_PROJECTILE_MISSING, OSRS_COMBAT_PROJECTILE_MISSING, OSRS_COMBAT_PROJECTILE_MISSING, OSRS_COMBAT_PROJECTILE_MISSING, 0, OSRS_COMBAT_PROJECTILE_MISSING}, {OSRS_COMBAT_VISUAL_KIND_NPC, 7698, "", ATTACK_STYLE_RANGED, OSRS_COMBAT_PROJECTILE_MISSING, 7605, {OSRS_COMBAT_PROJECTILE_MISSING, 1377, 1378, 33013, OSRS_COMBAT_PROJECTILE_MISSING, OSRS_COMBAT_PROJECTILE_MISSING, OSRS_COMBAT_PROJECTILE_MISSING, OSRS_COMBAT_PROJECTILE_MISSING, OSRS_COMBAT_PROJECTILE_MISSING, OSRS_COMBAT_PROJECTILE_MISSING, OSRS_COMBAT_PROJECTILE_MISSING, OSRS_COMBAT_PROJECTILE_MISSING, OSRS_COMBAT_PROJECTILE_MISSING, OSRS_COMBAT_PROJECTILE_MISSING, 1}, {OSRS_COMBAT_PROJECTILE_MISSING, OSRS_COMBAT_PROJECTILE_MISSING, OSRS_COMBAT_PROJECTILE_MISSING, OSRS_COMBAT_PROJECTILE_MISSING, OSRS_COMBAT_PROJECTILE_MISSING, OSRS_COMBAT_PROJECTILE_MISSING, OSRS_COMBAT_PROJECTILE_MISSING}, OSRS_COMBAT_PROJECTILE_MISSING, OSRS_COMBAT_PROJECTILE_MISSING, OSRS_COMBAT_PROJECTILE_MISSING, OSRS_COMBAT_PROJECTILE_MISSING, 0, OSRS_COMBAT_PROJECTILE_MISSING}, {OSRS_COMBAT_VISUAL_KIND_NPC, 7699, "", ATTACK_STYLE_MAGIC, OSRS_COMBAT_PROJECTILE_MISSING, 7610, {OSRS_COMBAT_PROJECTILE_MISSING, 1376, OSRS_COMBAT_PROJECTILE_MISSING, 33007, 7571, OSRS_COMBAT_PROJECTILE_MISSING, OSRS_COMBAT_PROJECTILE_MISSING, OSRS_COMBAT_PROJECTILE_MISSING, OSRS_COMBAT_PROJECTILE_MISSING, OSRS_COMBAT_PROJECTILE_MISSING, OSRS_COMBAT_PROJECTILE_MISSING, OSRS_COMBAT_PROJECTILE_MISSING, OSRS_COMBAT_PROJECTILE_MISSING, OSRS_COMBAT_PROJECTILE_MISSING, 1}, {OSRS_COMBAT_PROJECTILE_MISSING, OSRS_COMBAT_PROJECTILE_MISSING, OSRS_COMBAT_PROJECTILE_MISSING, OSRS_COMBAT_PROJECTILE_MISSING, OSRS_COMBAT_PROJECTILE_MISSING, OSRS_COMBAT_PROJECTILE_MISSING, OSRS_COMBAT_PROJECTILE_MISSING}, OSRS_COMBAT_PROJECTILE_MISSING, OSRS_COMBAT_PROJECTILE_MISSING, OSRS_COMBAT_PROJECTILE_MISSING, OSRS_COMBAT_PROJECTILE_MISSING, 0, OSRS_COMBAT_PROJECTILE_MISSING}, {OSRS_COMBAT_VISUAL_KIND_NPC, 7700, "", ATTACK_STYLE_MAGIC, OSRS_COMBAT_PROJECTILE_MISSING, 7592, {OSRS_COMBAT_PROJECTILE_MISSING, 448, OSRS_COMBAT_PROJECTILE_MISSING, 9337, 2659, OSRS_COMBAT_PROJECTILE_MISSING, OSRS_COMBAT_PROJECTILE_MISSING, OSRS_COMBAT_PROJECTILE_MISSING, OSRS_COMBAT_PROJECTILE_MISSING, OSRS_COMBAT_PROJECTILE_MISSING, OSRS_COMBAT_PROJECTILE_MISSING, OSRS_COMBAT_PROJECTILE_MISSING, OSRS_COMBAT_PROJECTILE_MISSING, OSRS_COMBAT_PROJECTILE_MISSING, 1}, {OSRS_COMBAT_PROJECTILE_MISSING, OSRS_COMBAT_PROJECTILE_MISSING, OSRS_COMBAT_PROJECTILE_MISSING, OSRS_COMBAT_PROJECTILE_MISSING, OSRS_COMBAT_PROJECTILE_MISSING, OSRS_COMBAT_PROJECTILE_MISSING, OSRS_COMBAT_PROJECTILE_MISSING}, OSRS_COMBAT_PROJECTILE_MISSING, OSRS_COMBAT_PROJECTILE_MISSING, OSRS_COMBAT_PROJECTILE_MISSING, OSRS_COMBAT_PROJECTILE_MISSING, 0, OSRS_COMBAT_PROJECTILE_MISSING}, diff --git a/ocean/osrs/osrs_encounter_visual_events.h b/ocean/osrs/osrs_encounter_visual_events.h index 18724501a8..554236529a 100644 --- a/ocean/osrs/osrs_encounter_visual_events.h +++ b/ocean/osrs/osrs_encounter_visual_events.h @@ -227,6 +227,11 @@ static inline int osrs_emit_projectile_with_spec( fprintf(stderr, "invalid projectile event input\n"); abort(); } + if (spec->model_id == 0) { + fprintf(stderr, "missing combat projectile model for style %d\n", + spec->style); + abort(); + } int idx = encounter_emit_projectile( overlay, spec->src_x, diff --git a/ocean/osrs/osrs_gui.h b/ocean/osrs/osrs_gui.h index eb1f14cd1d..d613916fa5 100644 --- a/ocean/osrs/osrs_gui.h +++ b/ocean/osrs/osrs_gui.h @@ -301,14 +301,11 @@ typedef struct { void* encounter_state; const void* encounter_def; - int sprites_loaded; GuiNamedAsset named_assets[GUI_MAX_NAMED_ASSETS]; int named_asset_count; OsrsUiInterfaceStore ui_interfaces; Font font; Font small_font; - int font_loaded; - int small_font_loaded; GuiItemStackVariant item_stack_variants[GUI_ITEM_STACK_VARIANT_MAX]; int item_stack_variant_count; @@ -333,7 +330,6 @@ typedef struct { Texture2D rm_tabs_top_row; Texture2D minimap_dot_player; Texture2D minimap_dot_npc; - int minimap_chrome_loaded; #define GUI_MAX_ITEM_SPRITES 256 int item_sprite_ids[GUI_MAX_ITEM_SPRITES]; @@ -395,18 +391,20 @@ static inline void gui_mouse_to_minimap_space( *out_y = (int)lroundf((float)my / k); } -static int gui_try_load(Texture2D* tex, const char* path) { - if (osrs_asset_exists(path)) { - *tex = osrs_asset_load_texture(path); - return 1; - } - return 0; +static Texture2D gui_require_texture(const char* path) { + Texture2D tex = osrs_asset_load_texture(path); + if (tex.id != 0) return tex; + + fprintf(stderr, "GUI: failed to load required texture %s\n", path); + abort(); } -static int gui_try_load_masked_compass(Texture2D* tex, const char* path) { - if (!osrs_asset_exists(path)) return 0; +static Texture2D gui_require_masked_compass(const char* path) { Image image = osrs_asset_load_image(path); - if (!image.data) return 0; + if (!image.data) { + fprintf(stderr, "GUI: failed to load required compass image %s\n", path); + abort(); + } ImageFormat(&image, PIXELFORMAT_UNCOMPRESSED_R8G8B8A8); Color* pixels = (Color*)image.data; @@ -425,9 +423,12 @@ static int gui_try_load_masked_compass(Texture2D* tex, const char* path) { } } - *tex = LoadTextureFromImage(image); + Texture2D tex = LoadTextureFromImage(image); UnloadImage(image); - return tex->id != 0; + if (tex.id != 0) return tex; + + fprintf(stderr, "GUI: failed to create required compass texture from %s\n", path); + abort(); } static int gui_rect_has_area(Rectangle rect) { @@ -483,52 +484,85 @@ static void gui_pop_clip( } static Font gui_font_for_size(const GuiState* gs, int size) { - if (gs && size <= 12 && gs->small_font_loaded) return gs->small_font; - if (gs && gs->font_loaded) return gs->font; - return GetFontDefault(); + return size <= 12 ? gs->small_font : gs->font; } static int gui_measure_text(const GuiState* gs, const char* text, int size) { if (!text || !text[0]) return 0; Font font = gui_font_for_size(gs, size); - if (font.texture.id == 0) return MeasureText(text, size); Vector2 measured = MeasureTextEx(font, text, (float)size, 0.0f); return (int)(measured.x + 0.5f); } +static Font gui_require_font(const char* path, int size) { + Font font = osrs_asset_load_font(path, size); + if (font.texture.id != 0) return font; + + fprintf(stderr, "GUI: failed to load required font %s\n", path); + abort(); +} + static void gui_load_fonts(GuiState* gs) { - gs->font = osrs_asset_load_font("fonts/runescape.ttf", 14); - gs->font_loaded = gs->font.texture.id != 0; - if (gs->font_loaded) SetTextureFilter(gs->font.texture, TEXTURE_FILTER_POINT); - gs->small_font = osrs_asset_load_font("fonts/runescape_small.ttf", 12); - gs->small_font_loaded = gs->small_font.texture.id != 0; - if (gs->small_font_loaded) SetTextureFilter(gs->small_font.texture, TEXTURE_FILTER_POINT); + gs->font = gui_require_font(OSRS_ASSET("fonts/runescape.ttf"), 14); + SetTextureFilter(gs->font.texture, TEXTURE_FILTER_POINT); + gs->small_font = gui_require_font(OSRS_ASSET("fonts/runescape_small.ttf"), 12); + SetTextureFilter(gs->small_font.texture, TEXTURE_FILTER_POINT); } static void gui_load_item_stack_variants(GuiState* gs) { + const char* path = OSRS_ASSET("sprites/items/item_stack_variants.tsv"); gs->item_stack_variant_count = 0; - FILE* f = osrs_asset_fopen("sprites/items/item_stack_variants.tsv", "rb"); - if (!f) return; + FILE* f = osrs_asset_fopen(path, "rb"); + if (!f) { + fprintf(stderr, "GUI: failed to load required item stack table %s\n", path); + abort(); + } + char line[128]; + int line_number = 0; while (fgets(line, sizeof(line), f)) { + line_number++; + if (!strchr(line, '\n') && !feof(f)) { + fprintf(stderr, "GUI: malformed item stack row at %s:%d\n", path, line_number); + abort(); + } if (line[0] == '#' || line[0] == '\n' || line[0] == '\0') continue; + GuiItemStackVariant variant = {0}; - if (sscanf(line, "%d\t%d\t%d", + int consumed = 0; + if (sscanf(line, "%d\t%d\t%d%n", &variant.base_item_id, &variant.threshold, - &variant.display_item_id) != 3) { - continue; + &variant.display_item_id, + &consumed) != 3) { + fprintf(stderr, "GUI: malformed item stack row at %s:%d\n", path, line_number); + abort(); + } + while (line[consumed] == ' ' || line[consumed] == '\t' + || line[consumed] == '\r' || line[consumed] == '\n') { + consumed++; + } + if (line[consumed] != '\0' + || variant.base_item_id <= 0 + || variant.threshold <= 0 + || variant.display_item_id <= 0) { + fprintf(stderr, "GUI: malformed item stack row at %s:%d\n", path, line_number); + abort(); } if (gs->item_stack_variant_count >= GUI_ITEM_STACK_VARIANT_MAX) { - fprintf(stderr, "too many item stack variants\n"); + fprintf(stderr, "GUI: too many item stack rows in %s\n", path); abort(); } gs->item_stack_variants[gs->item_stack_variant_count++] = variant; } + if (ferror(f)) { + fprintf(stderr, "GUI: failed while reading required item stack table %s\n", path); + abort(); + } fclose(f); } -static Texture2D gui_asset(const GuiState* gs, const char* name) { +static Texture2D gui_find_asset(const GuiState* gs, const char* name) { for (int i = 0; i < gs->named_asset_count; i++) { if (strcmp(gs->named_assets[i].name, name) == 0) { return gs->named_assets[i].tex; @@ -537,15 +571,28 @@ static Texture2D gui_asset(const GuiState* gs, const char* name) { return (Texture2D){0}; } +static Texture2D gui_asset(const GuiState* gs, const char* name) { + Texture2D tex = gui_find_asset(gs, name); + if (tex.id != 0) return tex; + + if (name[0] == '#') { + fprintf(stderr, "GUI: required sprite raw asset ID %s was not loaded\n", name + 1); + } else { + char logical_path[128]; + snprintf(logical_path, sizeof(logical_path), "sprites/gui/%s.png", name); + fprintf(stderr, "GUI: required named sprite was not loaded at %s\n", + OSRS_ASSET(logical_path)); + } + abort(); +} + static Texture2D gui_load_named_asset_path(GuiState* gs, const char* name, const char* path) { if (gs->named_asset_count >= GUI_MAX_NAMED_ASSETS) { - fprintf(stderr, "GUI named asset capacity exceeded\n"); + fprintf(stderr, "GUI: named asset capacity exceeded while loading %s\n", path); abort(); } - Texture2D tex = {0}; - if (!gui_try_load(&tex, path)) return tex; - + Texture2D tex = gui_require_texture(path); GuiNamedAsset* asset = &gs->named_assets[gs->named_asset_count++]; snprintf(asset->name, sizeof(asset->name), "%s", name); asset->tex = tex; @@ -553,22 +600,25 @@ static Texture2D gui_load_named_asset_path(GuiState* gs, const char* name, const } static void gui_load_named_asset(GuiState* gs, const char* name) { - char path[160]; - snprintf(path, sizeof(path), OSRS_ASSET("sprites/gui/%s.png"), name); - gui_load_named_asset_path(gs, name, path); + char logical_path[128]; + snprintf(logical_path, sizeof(logical_path), "sprites/gui/%s.png", name); + gui_load_named_asset_path(gs, name, OSRS_ASSET(logical_path)); } static Texture2D gui_sprite_asset(GuiState* gs, int sprite_id) { - if (sprite_id < 0) return (Texture2D){0}; + if (sprite_id < 0) { + fprintf(stderr, "GUI: invalid required sprite raw asset ID %d\n", sprite_id); + abort(); + } char name[32]; snprintf(name, sizeof(name), "#%d", sprite_id); - Texture2D tex = gui_asset(gs, name); + Texture2D tex = gui_find_asset(gs, name); if (tex.id != 0) return tex; - char path[160]; - snprintf(path, sizeof(path), OSRS_ASSET("sprites/gui/%d.png"), sprite_id); - return gui_load_named_asset_path(gs, name, path); + char logical_path[64]; + snprintf(logical_path, sizeof(logical_path), "sprites/gui/%d.png", sprite_id); + return gui_load_named_asset_path(gs, name, OSRS_ASSET(logical_path)); } static void gui_load_named_asset_range(GuiState* gs, const char* prefix, int first, int last) { @@ -630,18 +680,26 @@ static int gui_find_sprite_index_by_osrs_id(const GuiState* gs, int osrs_id) { return -1; } -static Texture2D gui_load_sprite_by_osrs_id_if_present(GuiState* gs, int osrs_id) { - Texture2D empty = {0}; +static Texture2D gui_load_required_sprite_by_osrs_id(GuiState* gs, int osrs_id) { + if (osrs_id <= 0) { + fprintf(stderr, "GUI: invalid required item sprite raw asset ID %d\n", osrs_id); + abort(); + } + int existing_idx = gui_find_sprite_index_by_osrs_id(gs, osrs_id); if (existing_idx >= 0) return gs->item_sprite_tex[existing_idx]; - if (osrs_id <= 0 || gs->item_sprite_count >= GUI_MAX_ITEM_SPRITES) return empty; - const char* path = TextFormat(OSRS_ASSET("sprites/items/%d.png"), osrs_id); - if (!osrs_asset_exists(path)) return empty; - - Texture2D tex = osrs_asset_load_texture(path); - if (tex.id == 0) return empty; + char logical_path[64]; + snprintf(logical_path, sizeof(logical_path), "sprites/items/%d.png", osrs_id); + const char* path = OSRS_ASSET(logical_path); + if (gs->item_sprite_count >= GUI_MAX_ITEM_SPRITES) { + fprintf(stderr, + "GUI: item sprite capacity exceeded while loading raw asset ID %d at %s\n", + osrs_id, path); + abort(); + } + Texture2D tex = gui_require_texture(path); int idx = gs->item_sprite_count++; gs->item_sprite_ids[idx] = osrs_id; gs->item_sprite_tex[idx] = tex; @@ -649,20 +707,16 @@ static Texture2D gui_load_sprite_by_osrs_id_if_present(GuiState* gs, int osrs_id } static void gui_require_sprite_by_osrs_id(GuiState* gs, int osrs_id) { - Texture2D tex = gui_load_sprite_by_osrs_id_if_present(gs, osrs_id); - if (tex.id != 0) return; - - fprintf(stderr, "GUI: missing required item sprite raw id %d at %s\n", - osrs_id, - TextFormat(OSRS_ASSET("sprites/items/%d.png"), osrs_id)); - abort(); + (void)gui_load_required_sprite_by_osrs_id(gs, osrs_id); } static void gui_load_sprites(GuiState* gs) { - gs->sprites_loaded = 1; - int ok = 1; gs->named_asset_count = 0; - osrs_ui_interfaces_load(&gs->ui_interfaces, OSRS_ASSET("ui/interfaces.bin")); + const char* interfaces_path = OSRS_ASSET("ui/interfaces.bin"); + if (!osrs_ui_interfaces_load(&gs->ui_interfaces, interfaces_path)) { + fprintf(stderr, "GUI: failed to load required interfaces at %s\n", interfaces_path); + abort(); + } gui_load_fonts(gs); gui_load_item_stack_variants(gs); @@ -681,47 +735,49 @@ static void gui_load_sprites(GuiState* gs) { OSRS_ASSET("sprites/gui/slot_tile.png"), }; for (int i = 0; i < GUI_NUM_SLOT_SPRITES; i++) { - ok &= gui_try_load(&gs->slot_sprites[i], slot_files[i]); + gs->slot_sprites[i] = gui_require_texture(slot_files[i]); } for (int i = 0; i < GUI_NUM_PRAYERS; i++) { - const char* on_path = TextFormat(OSRS_ASSET("sprites/gui/%d.png"), + char logical_path[64]; + snprintf(logical_path, sizeof(logical_path), "sprites/gui/%d.png", gui_prayer_on_sprite_id((GuiPrayerIdx)i)); - gui_try_load(&gs->prayer_on[i], on_path); + gs->prayer_on[i] = gui_require_texture(OSRS_ASSET(logical_path)); } for (int i = 0; i < GUI_NUM_SPELLS; i++) { - const char* on_path = TextFormat(OSRS_ASSET("sprites/gui/%d.png"), + char on_logical_path[64]; + char off_logical_path[64]; + snprintf(on_logical_path, sizeof(on_logical_path), "sprites/gui/%d.png", gui_spell_on_sprite_id((GuiSpellIdx)i)); - const char* off_path = TextFormat(OSRS_ASSET("sprites/gui/%d.png"), + snprintf(off_logical_path, sizeof(off_logical_path), "sprites/gui/%d.png", gui_spell_off_sprite_id((GuiSpellIdx)i)); - gui_try_load(&gs->spell_on[i], on_path); - gui_try_load(&gs->spell_off[i], off_path); - } - - gui_try_load(&gs->slot_tile, OSRS_ASSET("sprites/gui/slot_tile.png")); - - gs->minimap_chrome_loaded = 1; - gs->minimap_chrome_loaded &= gui_try_load(&gs->minimap_compass, - OSRS_ASSET("sprites/gui/compass.png")); - gui_try_load_masked_compass(&gs->minimap_compass_masked, - OSRS_ASSET("sprites/gui/compass.png")); - gs->minimap_chrome_loaded &= gui_try_load(&gs->minimap_alpha_mask, - OSRS_ASSET("sprites/gui/minimap_alpha_mask.png")); - gs->minimap_chrome_loaded &= gui_try_load(&gs->minimap_frame, - OSRS_ASSET("sprites/gui/minimap_and_compass_frame.png")); - gui_try_load(&gs->rm_minimap_alpha_mask, - OSRS_ASSET("sprites/gui/rm_minimap_alpha_mask.png")); - gui_try_load(&gs->rm_minimap_frame, - OSRS_ASSET("sprites/gui/rm_minimap_and_compass_frame.png")); - gui_try_load(&gs->rm_compass_alpha_mask, - OSRS_ASSET("sprites/gui/rm_compass_alpha_mask.png")); - gui_try_load(&gs->rm_tabs_top_row, - OSRS_ASSET("sprites/gui/rm_tabs_top_row.png")); - gs->minimap_chrome_loaded &= gui_try_load(&gs->minimap_dot_player, - OSRS_ASSET("sprites/gui/minimap_dot_player.png")); - gs->minimap_chrome_loaded &= gui_try_load(&gs->minimap_dot_npc, - OSRS_ASSET("sprites/gui/minimap_dot_npc.png")); + gs->spell_on[i] = gui_require_texture(OSRS_ASSET(on_logical_path)); + gs->spell_off[i] = gui_require_texture(OSRS_ASSET(off_logical_path)); + } + + gs->slot_tile = gui_require_texture(OSRS_ASSET("sprites/gui/slot_tile.png")); + + gs->minimap_compass = + gui_require_texture(OSRS_ASSET("sprites/gui/compass.png")); + gs->minimap_compass_masked = + gui_require_masked_compass(OSRS_ASSET("sprites/gui/compass.png")); + gs->minimap_alpha_mask = + gui_require_texture(OSRS_ASSET("sprites/gui/minimap_alpha_mask.png")); + gs->minimap_frame = + gui_require_texture(OSRS_ASSET("sprites/gui/minimap_and_compass_frame.png")); + gs->rm_minimap_alpha_mask = + gui_require_texture(OSRS_ASSET("sprites/gui/rm_minimap_alpha_mask.png")); + gs->rm_minimap_frame = + gui_require_texture(OSRS_ASSET("sprites/gui/rm_minimap_and_compass_frame.png")); + gs->rm_compass_alpha_mask = + gui_require_texture(OSRS_ASSET("sprites/gui/rm_compass_alpha_mask.png")); + gs->rm_tabs_top_row = + gui_require_texture(OSRS_ASSET("sprites/gui/rm_tabs_top_row.png")); + gs->minimap_dot_player = + gui_require_texture(OSRS_ASSET("sprites/gui/minimap_dot_player.png")); + gs->minimap_dot_npc = + gui_require_texture(OSRS_ASSET("sprites/gui/minimap_dot_npc.png")); static const char* ui_asset_names[] = { "tradebacking_dark", @@ -730,12 +786,9 @@ static void gui_load_sprites(GuiState* gs) { "osrs_stretch_side_columns_0", "osrs_stretch_side_columns_1", "osrs_stretch_mapsurround", - "compass", "compass_outline", "resize_map_mask", - "resize_compass_mask", "tli_button01_orb01_34x34_0", - "ring_34_0", "orb_xp_0", "ring_30", "worldmap_icon_0", @@ -768,11 +821,6 @@ static void gui_load_sprites(GuiState* gs) { gui_load_named_asset_range(gs, "orb_icon", 0, 15); gui_load_named_asset_range(gs, "wornicons", 0, 11); gui_load_named_asset_range(gs, "skill_icon", 0, 23); - gui_load_named_asset_range(gs, "prayeron", 0, 28); - gui_load_named_asset_range(gs, "prayeroff", 0, 28); - gui_load_named_asset_range(gs, "magicon", 0, 47); - gui_load_named_asset_range(gs, "magicoff", 0, 47); - gui_load_named_asset_range(gs, "standard_spell_on", 0, 79); static const char* side_icon_names[] = { "side_icon_combat", @@ -796,35 +844,7 @@ static void gui_load_sprites(GuiState* gs) { gui_load_named_asset(gs, side_icon_names[i]); } - if (!ok) { - TraceLog(LOG_WARNING, "GUI: some sprites missing from data/sprites/gui/"); - } - gs->item_sprite_count = 0; - for (int i = 0; i < NUM_ITEMS && gs->item_sprite_count < GUI_MAX_ITEM_SPRITES; i++) { - int item_id = ITEM_DATABASE[i].item_id; - if (item_id <= 0) continue; - gui_load_sprite_by_osrs_id_if_present(gs, item_id); - } - - static const int consumable_ids[] = { - OSRS_ID_SHARK, OSRS_ID_KARAMBWAN, - OSRS_ID_BREW_4, OSRS_ID_BREW_3, OSRS_ID_BREW_2, OSRS_ID_BREW_1, - OSRS_ID_RESTORE_4, OSRS_ID_RESTORE_3, OSRS_ID_RESTORE_2, OSRS_ID_RESTORE_1, - OSRS_ID_COMBAT_4, OSRS_ID_COMBAT_3, OSRS_ID_COMBAT_2, OSRS_ID_COMBAT_1, - OSRS_ID_RANGED_4, OSRS_ID_RANGED_3, OSRS_ID_RANGED_2, OSRS_ID_RANGED_1, - OSRS_ID_ANTIVENOM_4, OSRS_ID_ANTIVENOM_3, OSRS_ID_ANTIVENOM_2, OSRS_ID_ANTIVENOM_1, - OSRS_ID_PRAYER_POT_4, OSRS_ID_PRAYER_POT_3, OSRS_ID_PRAYER_POT_2, OSRS_ID_PRAYER_POT_1, - OSRS_ID_BASTION_4, OSRS_ID_BASTION_3, OSRS_ID_BASTION_2, OSRS_ID_BASTION_1, - OSRS_ID_STAMINA_4, OSRS_ID_STAMINA_3, OSRS_ID_STAMINA_2, OSRS_ID_STAMINA_1, - OSRS_ID_SATURATED_HEART, - }; - for (int i = 0; i < (int)(sizeof(consumable_ids)/sizeof(consumable_ids[0])); i++) { - if (gs->item_sprite_count >= GUI_MAX_ITEM_SPRITES) break; - int cid = consumable_ids[i]; - gui_load_sprite_by_osrs_id_if_present(gs, cid); - } - TraceLog(LOG_INFO, "GUI: loaded %d item sprites (incl consumables)", gs->item_sprite_count); } static Texture2D gui_get_sprite_by_osrs_id(GuiState* gs, int osrs_id); @@ -837,9 +857,11 @@ static Texture2D gui_get_item_sprite(GuiState* gs, uint8_t item_idx) { } static Texture2D gui_get_sprite_by_osrs_id(GuiState* gs, int osrs_id) { - Texture2D empty = { 0 }; - if (osrs_id <= 0) return empty; - return gui_load_sprite_by_osrs_id_if_present(gs, osrs_id); + if (osrs_id <= 0) { + fprintf(stderr, "GUI: invalid required item sprite raw asset ID %d\n", osrs_id); + abort(); + } + return gui_load_required_sprite_by_osrs_id(gs, osrs_id); } static int gui_coin_stack_display_id(int quantity) { @@ -875,15 +897,10 @@ static Texture2D gui_get_item_sprite_for_quantity( uint8_t item_idx, int quantity ) { - Texture2D empty = {0}; - if (item_idx == ITEM_NONE || item_idx >= NUM_ITEMS) return empty; + if (item_idx == ITEM_NONE || item_idx >= NUM_ITEMS) return (Texture2D){0}; int item_id = ITEM_DATABASE[item_idx].item_id; int display_id = gui_item_display_id_for_quantity(gs, item_id, quantity); - Texture2D tex = gui_get_sprite_by_osrs_id(gs, display_id); - if (tex.id == 0 && display_id != item_id) { - tex = gui_get_sprite_by_osrs_id(gs, item_id); - } - return tex; + return gui_get_sprite_by_osrs_id(gs, display_id); } static Texture2D gui_get_sprite_by_osrs_id_for_quantity( @@ -892,11 +909,7 @@ static Texture2D gui_get_sprite_by_osrs_id_for_quantity( int quantity ) { int display_id = gui_item_display_id_for_quantity(gs, osrs_id, quantity); - Texture2D tex = gui_get_sprite_by_osrs_id(gs, display_id); - if (tex.id == 0 && display_id != osrs_id) { - tex = gui_get_sprite_by_osrs_id(gs, osrs_id); - } - return tex; + return gui_get_sprite_by_osrs_id(gs, display_id); } static Color gui_stack_text_color(int quantity) { @@ -918,9 +931,8 @@ static void gui_format_stack_quantity(int quantity, char* dst, size_t cap) { static void gui_unload_sprites(GuiState* gs) { osrs_ui_interfaces_unload(&gs->ui_interfaces); - if (!gs->sprites_loaded) return; for (int i = 0; i < gs->named_asset_count; i++) { - if (gs->named_assets[i].tex.id) UnloadTexture(gs->named_assets[i].tex); + UnloadTexture(gs->named_assets[i].tex); } gs->named_asset_count = 0; for (int i = 0; i < GUI_NUM_SLOT_SPRITES; i++) UnloadTexture(gs->slot_sprites[i]); @@ -931,25 +943,22 @@ static void gui_unload_sprites(GuiState* gs) { UnloadTexture(gs->spell_on[i]); UnloadTexture(gs->spell_off[i]); } - if (gs->slot_tile.id) UnloadTexture(gs->slot_tile); - if (gs->minimap_compass.id) UnloadTexture(gs->minimap_compass); - if (gs->minimap_compass_masked.id) UnloadTexture(gs->minimap_compass_masked); - if (gs->minimap_alpha_mask.id) UnloadTexture(gs->minimap_alpha_mask); - if (gs->minimap_frame.id) UnloadTexture(gs->minimap_frame); - if (gs->rm_minimap_alpha_mask.id) UnloadTexture(gs->rm_minimap_alpha_mask); - if (gs->rm_minimap_frame.id) UnloadTexture(gs->rm_minimap_frame); - if (gs->rm_compass_alpha_mask.id) UnloadTexture(gs->rm_compass_alpha_mask); - if (gs->rm_tabs_top_row.id) UnloadTexture(gs->rm_tabs_top_row); - if (gs->minimap_dot_player.id) UnloadTexture(gs->minimap_dot_player); - if (gs->minimap_dot_npc.id) UnloadTexture(gs->minimap_dot_npc); + UnloadTexture(gs->slot_tile); + UnloadTexture(gs->minimap_compass); + UnloadTexture(gs->minimap_compass_masked); + UnloadTexture(gs->minimap_alpha_mask); + UnloadTexture(gs->minimap_frame); + UnloadTexture(gs->rm_minimap_alpha_mask); + UnloadTexture(gs->rm_minimap_frame); + UnloadTexture(gs->rm_compass_alpha_mask); + UnloadTexture(gs->rm_tabs_top_row); + UnloadTexture(gs->minimap_dot_player); + UnloadTexture(gs->minimap_dot_npc); for (int i = 0; i < gs->item_sprite_count; i++) UnloadTexture(gs->item_sprite_tex[i]); - if (gs->font_loaded) UnloadFont(gs->font); - if (gs->small_font_loaded) UnloadFont(gs->small_font); + UnloadFont(gs->font); + UnloadFont(gs->small_font); gs->item_sprite_count = 0; - gs->font_loaded = 0; - gs->small_font_loaded = 0; gs->item_stack_variant_count = 0; - gs->sprites_loaded = 0; } static const char* gui_item_short_name(uint8_t item_idx) { @@ -1079,15 +1088,8 @@ static void gui_text_shadow( DrawTextEx(font, text, pos, (float)size, 0.0f, color); } -static void gui_draw_slot(int x, int y, int w, int h, Color fill) { - DrawRectangle(x, y, w, h, fill); - DrawRectangleLines(x, y, w, h, GUI_BORDER); - DrawLine(x + 1, y + 1, x + w - 2, y + 1, GUI_BORDER_LT); - DrawLine(x + 1, y + 1, x + 1, y + h - 2, GUI_BORDER_LT); -} static void gui_draw_tex_centered(Texture2D tex, int bx, int by, int bw, int bh) { - if (tex.id == 0) return; float sx = (float)(bw - 4) / (float)tex.width; float sy = (float)(bh - 4) / (float)tex.height; float s = (sx < sy) ? sx : sy; @@ -1100,28 +1102,17 @@ static void gui_draw_tex_centered(Texture2D tex, int bx, int by, int bw, int bh) static void gui_draw_equip_slot(GuiState* gs, int x, int y, int w, int h, int gear_slot, uint8_t item_idx) { - if (gs->slot_tile.id != 0) { - Rectangle src = { 0, 0, (float)gs->slot_tile.width, (float)gs->slot_tile.height }; - Rectangle dst = { (float)x, (float)y, (float)w, (float)h }; - DrawTexturePro(gs->slot_tile, src, dst, (Vector2){0,0}, 0.0f, WHITE); - } else { - gui_draw_slot(x, y, w, h, GUI_BG_SLOT); - } + Rectangle src = {0, 0, (float)gs->slot_tile.width, (float)gs->slot_tile.height}; + Rectangle dst = {(float)x, (float)y, (float)w, (float)h}; + DrawTexturePro(gs->slot_tile, src, dst, (Vector2){0, 0}, 0.0f, WHITE); if (item_idx != ITEM_NONE && item_idx < NUM_ITEMS) { - Texture2D item_tex = gui_get_item_sprite(gs, item_idx); - if (item_tex.id != 0) { - gui_draw_tex_centered(item_tex, x, y, w, h); - } else { - const char* name = gui_item_short_name(item_idx); - gui_text_shadow(gs, name, x + 2, y + h / 2 - 4, 7, GUI_TEXT_YELLOW); - } - } else if (gs->sprites_loaded && gear_slot >= 0 && gear_slot < GUI_NUM_SLOT_SPRITES) { - Texture2D bg = gs->slot_sprites[gear_slot]; - if (bg.id != 0) { - gui_draw_tex_centered(bg, x, y, w, h); - } + gui_draw_tex_centered(gui_get_item_sprite(gs, item_idx), x, y, w, h); + return; } + + assert(gear_slot >= 0 && gear_slot < GUI_NUM_SLOT_SPRITES); + gui_draw_tex_centered(gs->slot_sprites[gear_slot], x, y, w, h); } typedef struct { @@ -1182,7 +1173,6 @@ static Rectangle gui_side_component_rect( } static void gui_draw_texture(Texture2D tex, Rectangle dst, Color tint) { - if (tex.id == 0) return; Rectangle src = {0, 0, (float)tex.width, (float)tex.height}; DrawTexturePro(tex, src, dst, (Vector2){0, 0}, 0.0f, tint); } @@ -1217,7 +1207,6 @@ static void gui_draw_texture_centered( float max_h, Color tint ) { - if (tex.id == 0) return; gui_draw_texture(tex, gui_texture_fit_rect(tex.width, tex.height, rect, max_w, max_h), tint); } @@ -1225,7 +1214,7 @@ static void gui_draw_named_asset(GuiState* gs, const char* name, Rectangle dst, gui_draw_texture(gui_asset(gs, name), dst, tint); } -static int gui_draw_named_asset_centered( +static void gui_draw_named_asset_centered( GuiState* gs, const char* name, Rectangle rect, @@ -1234,17 +1223,11 @@ static int gui_draw_named_asset_centered( Color tint ) { Texture2D tex = gui_asset(gs, name); - if (tex.id == 0) return 0; gui_draw_texture_centered(tex, rect, max_w, max_h, tint); - return 1; } static void gui_draw_named_asset_tiled(GuiState* gs, const char* name, Rectangle dst, Color tint) { Texture2D tex = gui_asset(gs, name); - if (tex.id == 0) { - DrawRectangleRec(dst, GUI_BG_DARK); - return; - } for (float y = dst.y; y < dst.y + dst.height; y += (float)tex.height) { for (float x = dst.x; x < dst.x + dst.width; x += (float)tex.width) { float w = (x + tex.width > dst.x + dst.width) ? dst.x + dst.width - x : (float)tex.width; @@ -1320,19 +1303,22 @@ static void gui_draw_ui_item_slot(GuiState* gs, const GuiUiItemSlot* slot, Recta } else { if (!slot->enabled) return; - Texture2D tex = {0}; + Texture2D tex; if (slot->item_db_idx != ITEM_NONE) { tex = gui_get_item_sprite_for_quantity(gs, slot->item_db_idx, slot->quantity); - } else if (slot->osrs_id > 0) { + } else { + if (slot->osrs_id <= 0) { + fprintf(stderr, "GUI: invalid decoded item sprite raw asset ID %d\n", + slot->osrs_id); + abort(); + } tex = gui_get_sprite_by_osrs_id_for_quantity(gs, slot->osrs_id, slot->quantity); } Color tint = WHITE; tint.a = slot->alpha == 0 ? 255 : slot->alpha; - if (tex.id != 0) { - Rectangle src = {0, 0, (float)tex.width, (float)tex.height}; - DrawTexturePro(tex, src, rect, (Vector2){0, 0}, 0.0f, tint); - } + Rectangle src = {0, 0, (float)tex.width, (float)tex.height}; + DrawTexturePro(tex, src, rect, (Vector2){0, 0}, 0.0f, tint); if (slot->quantity > 1) { char text[16]; @@ -1382,7 +1368,6 @@ static void gui_draw_ui_sprite_component( int sprite_id = override && override->sprite_present ? override->sprite_id : component->sprite_id; tex = gui_sprite_asset(gs, sprite_id); } - if (tex.id == 0) return; if (rect.width <= 0) rect.width = (float)tex.width; if (rect.height <= 0) rect.height = (float)tex.height; @@ -2408,20 +2393,15 @@ static GuiUiItemSlot gui_ui_slot_from_inv_slot(const GuiState* gs, const InvSlot static void gui_draw_inventory_drag(GuiState* gs) { if (!(gs->inv_drag_active && gs->inv_drag_src_slot >= 0)) return; InvSlot* drag = &gs->inv_grid[gs->inv_drag_src_slot]; - Texture2D tex = {0}; - if (drag->type == INV_SLOT_EQUIPMENT) { - tex = gui_get_item_sprite(gs, drag->item_db_idx); - } else { - tex = gui_get_sprite_by_osrs_id(gs, drag->osrs_id); - } - if (tex.id != 0) { - int dx = gs->inv_drag_mouse_x - INV_SPRITE_W / 2; - int dy = gs->inv_drag_mouse_y - INV_SPRITE_H / 2; - Rectangle src = {0, 0, (float)tex.width, (float)tex.height}; - Rectangle dst = {(float)dx, (float)dy, (float)INV_SPRITE_W, (float)INV_SPRITE_H}; - DrawTexturePro(tex, src, dst, (Vector2){0, 0}, 0.0f, - CLITERAL(Color){255, 255, 255, 200}); - } + Texture2D tex = drag->type == INV_SLOT_EQUIPMENT + ? gui_get_item_sprite(gs, drag->item_db_idx) + : gui_get_sprite_by_osrs_id(gs, drag->osrs_id); + int dx = gs->inv_drag_mouse_x - INV_SPRITE_W / 2; + int dy = gs->inv_drag_mouse_y - INV_SPRITE_H / 2; + Rectangle src = {0, 0, (float)tex.width, (float)tex.height}; + Rectangle dst = {(float)dx, (float)dy, (float)INV_SPRITE_W, (float)INV_SPRITE_H}; + DrawTexturePro(tex, src, dst, (Vector2){0, 0}, 0.0f, + CLITERAL(Color){255, 255, 255, 200}); } static int gui_draw_inventory_decoded(GuiState* gs) { @@ -2467,25 +2447,15 @@ static void gui_draw_inventory_manual(GuiState* gs) { int dx = cx; int dy = cy; + Rectangle src = {0, 0, (float)tex.width, (float)tex.height}; + Rectangle dst = {(float)dx, (float)dy, (float)INV_SPRITE_W, (float)INV_SPRITE_H}; if (gs->inv_drag_active && slot == gs->inv_drag_src_slot) { - if (tex.id != 0) { - Rectangle src = { 0, 0, (float)tex.width, (float)tex.height }; - Rectangle dst = { (float)dx, (float)dy, (float)INV_SPRITE_W, (float)INV_SPRITE_H }; - DrawTexturePro(tex, src, dst, (Vector2){0,0}, 0.0f, - CLITERAL(Color){ 255, 255, 255, 80 }); - } + DrawTexturePro(tex, src, dst, (Vector2){0, 0}, 0.0f, + CLITERAL(Color){255, 255, 255, 80}); continue; } - if (tex.id != 0) { - Rectangle src = { 0, 0, (float)tex.width, (float)tex.height }; - Rectangle dst = { (float)dx, (float)dy, (float)INV_SPRITE_W, (float)INV_SPRITE_H }; - DrawTexturePro(tex, src, dst, (Vector2){0,0}, 0.0f, tint); - } else { - const char* name = (inv->type == INV_SLOT_EQUIPMENT) - ? gui_item_short_name(inv->item_db_idx) : "???"; - gui_text_shadow(gs, name, cx + 2, cy + 12, 7, GUI_TEXT_YELLOW); - } + DrawTexturePro(tex, src, dst, (Vector2){0, 0}, 0.0f, tint); } gui_draw_inventory_drag(gs); @@ -2606,9 +2576,6 @@ static int gui_draw_equipment_decoded(GuiState* gs, Player* p) { const GuiWornButtonRef* ref = &GUI_WORN_BUTTON_REFS[i]; Rectangle rect = gui_side_component_rect(gs, "wornitems", ref->component_name, ref->rect); gui_draw_named_asset(gs, "combatboxes_0", rect, WHITE); - if (gui_asset(gs, "combatboxes_0").id == 0) { - gui_draw_slot((int)rect.x, (int)rect.y, (int)rect.width, (int)rect.height, GUI_BG_SLOT); - } } return gui_draw_ui_group(gs, "wornitems", gui_side_content_rect(gs), &ui_overrides); @@ -2653,9 +2620,6 @@ static void gui_draw_equipment(GuiState* gs, Player* p) { Rectangle icon = gui_side_component_rect( gs, "wornitems", ref->icon_component_name, ref->icon_rect); gui_draw_named_asset(gs, "combatboxes_0", rect, WHITE); - if (gui_asset(gs, "combatboxes_0").id == 0) { - gui_draw_slot((int)rect.x, (int)rect.y, (int)rect.width, (int)rect.height, GUI_BG_SLOT); - } gui_draw_named_asset_centered(gs, ref->asset, icon, icon.width, icon.height, WHITE); } } @@ -2818,10 +2782,6 @@ static Rectangle gui_combat_category_rect(void) { static void gui_draw_combat_box(GuiState* gs, Rectangle rect, int selected) { gui_draw_named_asset(gs, selected ? "combatboxes_1" : "combatboxes_0", rect, WHITE); - if (gui_asset(gs, selected ? "combatboxes_1" : "combatboxes_0").id == 0) { - DrawRectangleRec(rect, selected ? (Color){83, 61, 43, 245} : (Color){45, 39, 31, 235}); - DrawRectangleLinesEx(rect, 1, selected ? GUI_TEXT_YELLOW : (Color){103, 89, 63, 255}); - } if (selected) { DrawRectangleRec(rect, (Color){120, 27, 20, 54}); } @@ -2978,10 +2938,8 @@ static void gui_draw_prayer(GuiState* gs, Player* p) { gui_draw_named_asset(gs, "prayerglow_0", cell_rect, WHITE); } - if (gs->sprites_loaded) { - gui_draw_texture_centered(gs->prayer_on[pidx], cell_rect, - GUI_PRAYER_ICON_PX, GUI_PRAYER_ICON_PX, WHITE); - } + gui_draw_texture_centered(gs->prayer_on[pidx], cell_rect, + GUI_PRAYER_ICON_PX, GUI_PRAYER_ICON_PX, WHITE); } } @@ -3071,9 +3029,6 @@ static void gui_draw_combat(GuiState* gs, Player* p) { Rectangle spec = gui_side_ref_rect(gs, gui_combat_special_rect()); float spec_pct = (float)p->special_energy / 100.0f; gui_draw_named_asset(gs, "combatboxes_special_attack", spec, WHITE); - if (gui_asset(gs, "combatboxes_special_attack").id == 0) { - DrawRectangleRec(spec, (Color){32, 28, 22, 235}); - } Rectangle empty = {spec.x + 2, spec.y + 7, spec.width - 4, 12}; DrawRectangleRec(empty, (Color){115, 6, 6, 255}); Rectangle fill = empty; @@ -3166,14 +3121,10 @@ static void gui_draw_spellbook(GuiState* gs, Player* p) { Rectangle cell_rect = {(float)ix, (float)iy, (float)GUI_SPELL_ICON_PX, (float)GUI_SPELL_ICON_PX}; - if (gs->sprites_loaded) { - int castable = gui_spell_castable(sidx); - Texture2D tex = castable ? gs->spell_on[sidx] : gs->spell_off[sidx]; - if (tex.id != 0) { - Rectangle src = {0, 0, (float)tex.width, (float)tex.height}; - DrawTexturePro(tex, src, cell_rect, (Vector2){0, 0}, 0.0f, WHITE); - } - } + int castable = gui_spell_castable(sidx); + Texture2D tex = castable ? gs->spell_on[sidx] : gs->spell_off[sidx]; + Rectangle src = {0, 0, (float)tex.width, (float)tex.height}; + DrawTexturePro(tex, src, cell_rect, (Vector2){0, 0}, 0.0f, WHITE); if (targeting) { DrawRectangleLinesEx(cell_rect, 2.0f, YELLOW); } diff --git a/ocean/osrs/osrs_human_input.h b/ocean/osrs/osrs_human_input.h index 094909f087..73c5ad63d5 100644 --- a/ocean/osrs/osrs_human_input.h +++ b/ocean/osrs/osrs_human_input.h @@ -328,7 +328,7 @@ static void human_handle_combat_click(HumanInput* hi, GuiState* gs, Player* p, #define CLICK_CROSS_NUM_FRAMES 4 #define CLICK_CROSS_ANIM_TICKS 20 -static void human_draw_click_cross(HumanInput* hi, Texture2D* cross_sprites, int sprites_loaded) { +static void human_draw_click_cross(HumanInput* hi, Texture2D* cross_sprites) { if (!hi->click_cross_active) return; if (hi->click_cross_timer >= CLICK_CROSS_ANIM_TICKS) { hi->click_cross_active = 0; @@ -341,19 +341,8 @@ static void human_draw_click_cross(HumanInput* hi, Texture2D* cross_sprites, int int cx = hi->click_screen_x; int cy = hi->click_screen_y; - - if (sprites_loaded && cross_sprites[sprite_idx].id > 0) { - Texture2D tex = cross_sprites[sprite_idx]; - DrawTexture(tex, cx - tex.width / 2, cy - tex.height / 2, WHITE); - } else { - float progress = 1.0f - (float)hi->click_cross_timer / CLICK_CROSS_ANIM_TICKS; - int alpha = (int)(progress * 255); - Color c = hi->click_is_attack - ? CLITERAL(Color){ 255, 50, 50, (unsigned char)alpha } - : CLITERAL(Color){ 255, 255, 0, (unsigned char)alpha }; - DrawLine(cx - 6, cy - 6, cx + 6, cy + 6, c); - DrawLine(cx + 6, cy - 6, cx - 6, cy + 6, c); - } + Texture2D tex = cross_sprites[sprite_idx]; + DrawTexture(tex, cx - tex.width / 2, cy - tex.height / 2, WHITE); } static void human_tick_visuals(HumanInput* hi) { diff --git a/ocean/osrs/osrs_render.h b/ocean/osrs/osrs_render.h index b018c735dc..5d39fc4f4d 100644 --- a/ocean/osrs/osrs_render.h +++ b/ocean/osrs/osrs_render.h @@ -395,15 +395,12 @@ typedef struct RenderClient { float model_scale; Texture2D prayer_icons[6]; - int prayer_icons_loaded; Texture2D colosseum_modifier_icons[COLO_NUM_REAL_MODIFIERS][3]; Texture2D hitmark_sprites[5]; - int hitmark_sprites_loaded; Texture2D click_cross_sprites[8]; - int click_cross_loaded; int debug_hit_wx, debug_hit_wy; float debug_ray_hit_x, debug_ray_hit_y, debug_ray_hit_z; @@ -1882,25 +1879,16 @@ static RenderClient* render_make_client(OsrsEnv* env) { OSRS_ASSET("sprites/gui/headicons_prayer_4.png"), OSRS_ASSET("sprites/gui/headicons_prayer_5.png"), }; - rc->prayer_icons_loaded = 1; for (int i = 0; i < 6; i++) { - if (osrs_asset_exists(paths[i])) { - rc->prayer_icons[i] = osrs_asset_load_texture(paths[i]); - } else { - rc->prayer_icons_loaded = 0; - } + rc->prayer_icons[i] = gui_require_texture(paths[i]); } } { - rc->hitmark_sprites_loaded = 1; for (int i = 0; i < 5; i++) { - const char* path = TextFormat(OSRS_ASSET("sprites/gui/hitmarks_%d.png"), i); - if (osrs_asset_exists(path)) { - rc->hitmark_sprites[i] = osrs_asset_load_texture(path); - } else { - rc->hitmark_sprites_loaded = 0; - } + char logical_path[64]; + snprintf(logical_path, sizeof(logical_path), "sprites/gui/hitmarks_%d.png", i); + rc->hitmark_sprites[i] = gui_require_texture(OSRS_ASSET(logical_path)); } } @@ -1909,14 +1897,10 @@ static RenderClient* render_make_client(OsrsEnv* env) { "cross_yellow_1", "cross_yellow_2", "cross_yellow_3", "cross_yellow_4", "cross_red_1", "cross_red_2", "cross_red_3", "cross_red_4", }; - rc->click_cross_loaded = 1; for (int i = 0; i < 8; i++) { - const char* path = TextFormat(OSRS_ASSET("sprites/gui/%s.png"), cross_names[i]); - if (osrs_asset_exists(path)) { - rc->click_cross_sprites[i] = osrs_asset_load_texture(path); - } else { - rc->click_cross_loaded = 0; - } + char logical_path[128]; + snprintf(logical_path, sizeof(logical_path), "sprites/gui/%s.png", cross_names[i]); + rc->click_cross_sprites[i] = gui_require_texture(OSRS_ASSET(logical_path)); } } @@ -2555,10 +2539,8 @@ static void __attribute__((unused)) render_destroy_client(RenderClient* rc) { UnloadRenderTexture(rc->minimap_surface); } gui_unload_sprites(&rc->gui); - if (rc->prayer_icons_loaded) { - for (int i = 0; i < 6; i++) { - UnloadTexture(rc->prayer_icons[i]); - } + for (int i = 0; i < 6; i++) { + UnloadTexture(rc->prayer_icons[i]); } for (int mod = 0; mod < COLO_NUM_REAL_MODIFIERS; mod++) { for (int tier = 0; tier < 3; tier++) { @@ -2566,15 +2548,11 @@ static void __attribute__((unused)) render_destroy_client(RenderClient* rc) { UnloadTexture(rc->colosseum_modifier_icons[mod][tier]); } } - if (rc->hitmark_sprites_loaded) { - for (int i = 0; i < 5; i++) { - UnloadTexture(rc->hitmark_sprites[i]); - } + for (int i = 0; i < 5; i++) { + UnloadTexture(rc->hitmark_sprites[i]); } - if (rc->click_cross_loaded) { - for (int i = 0; i < 8; i++) { - UnloadTexture(rc->click_cross_sprites[i]); - } + for (int i = 0; i < 8; i++) { + UnloadTexture(rc->click_cross_sprites[i]); } if (rc->cloud_model_ready) UnloadModel(rc->cloud_model); if (rc->snakeling_model_ready) UnloadModel(rc->snakeling_model); @@ -3670,22 +3648,15 @@ static void render_push_splat_type(RenderClient* rc, int damage, int pidx, int t static void render_draw_hitmark(RenderClient* rc, int cx, int cy, int damage, int opacity, int type) { unsigned char a = (unsigned char)(opacity > 255 ? 255 : (opacity < 0 ? 0 : opacity)); int sprite_idx = (type >= 0 && type < 5) ? type : ((damage > 0) ? 1 : 0); - - if (rc->hitmark_sprites_loaded) { - Texture2D tex = rc->hitmark_sprites[sprite_idx]; - float draw_x = (float)cx - (float)tex.width / 2.0f; - float draw_y = (float)cy - (float)tex.height / 2.0f; - DrawTexture(tex, (int)draw_x, (int)draw_y, (Color){ 255, 255, 255, a }); - } else { - Color bg = (sprite_idx == 4) ? (Color){ 220, 185, 45, a } : - ((damage > 0) ? (Color){ 175, 25, 25, a } : (Color){ 65, 105, 225, a }); - DrawCircle(cx, cy, 12.0f, bg); - } + Texture2D tex = rc->hitmark_sprites[sprite_idx]; + float draw_x = (float)cx - (float)tex.width / 2.0f; + float draw_y = (float)cy - (float)tex.height / 2.0f; + DrawTexture(tex, (int)draw_x, (int)draw_y, (Color){255, 255, 255, a}); const char* txt = TextFormat("%d", damage); int tw = MeasureText(txt, 10); - DrawText(txt, cx - tw / 2 + 1, cy - 4, 10, (Color){ 0, 0, 0, a }); - DrawText(txt, cx - tw / 2, cy - 5, 10, (Color){ 255, 255, 255, a }); + DrawText(txt, cx - tw / 2 + 1, cy - 4, 10, (Color){0, 0, 0, a}); + DrawText(txt, cx - tw / 2, cy - 5, 10, (Color){255, 255, 255, a}); } static void render_splat_slot_offset(int slot, int* dx, int* dy) { @@ -4921,30 +4892,23 @@ static void render_draw_3d_world(RenderClient* rc, OsrsEnv* env) { proj_model = render_get_proj_model(rc, fp->model_id); } if (!proj_model) { - if (fp->style == 0 && rc->ranged_proj_model_ready) - proj_model = &rc->ranged_proj_model; - else if (fp->style == 1 && rc->magic_proj_model_ready) - proj_model = &rc->magic_proj_model; - else if (fp->style == 3 && rc->cloud_proj_model_ready) - proj_model = &rc->cloud_proj_model; - else if (fp->style == 4 && rc->ranged_proj_model_ready) - proj_model = &rc->ranged_proj_model; + fprintf(stderr, "render: missing projectile model %u\n", + fp->model_id); + abort(); } - if (proj_model) { - rlDisableBackfaceCulling(); - float pms = 1.0f / 128.0f; - if (fp->grow) { - float t = fp->progress; - t = t < 0.0f ? 0.0f : (t > 1.0f ? 1.0f : t); - pms *= 0.15f + 0.85f * (t * t); - } - proj_model->transform = render_projectile_transform_offset( - pms, pms, pms, fp->yaw, fp->pitch, pos, - fp->offset_x, fp->offset_y, fp->offset_z); - DrawModel(*proj_model, (Vector3){0,0,0}, 1.0f, WHITE); - rlEnableBackfaceCulling(); + rlDisableBackfaceCulling(); + float pms = 1.0f / 128.0f; + if (fp->grow) { + float t = fp->progress; + t = t < 0.0f ? 0.0f : (t > 1.0f ? 1.0f : t); + pms *= 0.15f + 0.85f * (t * t); } + proj_model->transform = render_projectile_transform_offset( + pms, pms, pms, fp->yaw, fp->pitch, pos, + fp->offset_x, fp->offset_y, fp->offset_z); + DrawModel(*proj_model, (Vector3){0,0,0}, 1.0f, WHITE); + rlEnableBackfaceCulling(); if (rc->show_debug && fp->motion_mode != ENCOUNTER_PROJECTILE_MOTION_TARGET_ANCHORED) { @@ -5320,16 +5284,14 @@ static void render_draw_overhead_status(RenderClient* rc, OsrsEnv* env) { cursor_y -= (float)(bar_h + 2); } - if (rc->prayer_icons_loaded && - p->prayer > PRAYER_NONE && p->prayer <= PRAYER_REDEMPTION) { + if (p->prayer > PRAYER_NONE && p->prayer <= PRAYER_REDEMPTION) { int icon_idx = prayer_to_headicon[p->prayer]; - if (icon_idx >= 0 && icon_idx < 6) { - Texture2D tex = rc->prayer_icons[icon_idx]; - float scale = 1.0f; - float draw_x = screen_overhead.x - (float)tex.width * scale / 2.0f; - float draw_y = cursor_y - (float)tex.height * scale; - DrawTextureEx(tex, (Vector2){ draw_x, draw_y }, 0.0f, scale, WHITE); - } + assert(icon_idx >= 0 && icon_idx < 6); + Texture2D tex = rc->prayer_icons[icon_idx]; + float scale = 1.0f; + float draw_x = screen_overhead.x - (float)tex.width * scale / 2.0f; + float draw_y = cursor_y - (float)tex.height * scale; + DrawTextureEx(tex, (Vector2){draw_x, draw_y}, 0.0f, scale, WHITE); } if (rc->show_debug && p->entity_type == ENTITY_NPC && @@ -5405,21 +5367,13 @@ static void render_draw_minimap_orb( const char* filler_asset, const char* icon_asset, int value, - int max_value, - Color fallback_fill + int max_value ) { gui_draw_named_asset(gs, "orb_frame_0", rect, WHITE); - if (gui_asset(gs, "orb_frame_0").id == 0) { - DrawRectangleRounded((Rectangle){rect.x, rect.y + 7, 34, 20}, 0.22f, 5, - (Color){50, 46, 37, 235}); - } Rectangle fill = {rect.x + 27, rect.y + 4, 26, 26}; gui_draw_named_asset(gs, "orb_filler_0", fill, WHITE); gui_draw_named_asset(gs, filler_asset, fill, WHITE); - if (gui_asset(gs, filler_asset).id == 0) { - DrawCircle((int)(fill.x + 13), (int)(fill.y + 13), 12, fallback_fill); - } gui_draw_named_asset_centered(gs, icon_asset, fill, 22, 22, WHITE); char text[16]; @@ -5515,17 +5469,16 @@ static float render_minimap_entity_center_y(RenderClient* rc, int entity_idx) { } static void render_draw_minimap_entity_dot( - GuiState* gs, int sx, int sy, int sz_px, - Texture2D sprite, Color fallback + int sx, int sy, int sz_px, Texture2D sprite ) { - if (sprite.id != 0) { - Rectangle src = { 0, 0, (float)sprite.width, (float)sprite.height }; - Rectangle dst = { (float)(sx + sz_px / 2 - 2), - (float)(sy + sz_px / 2 - 2), 4.0f, 4.0f }; - DrawTexturePro(sprite, src, dst, (Vector2){0,0}, 0.0f, WHITE); - } else { - DrawRectangle(sx, sy, sz_px, sz_px, fallback); - } + Rectangle src = {0, 0, (float)sprite.width, (float)sprite.height}; + Rectangle dst = { + (float)(sx + sz_px / 2 - 2), + (float)(sy + sz_px / 2 - 2), + 4.0f, + 4.0f, + }; + DrawTexturePro(sprite, src, dst, (Vector2){0, 0}, 0.0f, WHITE); } static void render_ensure_minimap_surface(RenderClient* rc, int w, int h) { @@ -5550,26 +5503,17 @@ static void render_ensure_minimap_surface(RenderClient* rc, int w, int h) { } static void render_draw_minimap_compass(RenderClient* rc, GuiState* gs, Rectangle compass) { - int masked = gs->minimap_compass_masked.id != 0; - Texture2D comp = masked ? gs->minimap_compass_masked : gui_asset(gs, "compass"); - if (comp.id == 0) comp = gs->minimap_compass; - if (comp.id != 0) { - Rectangle src = {0, 0, (float)comp.width, (float)comp.height}; - float draw_w = masked ? (float)comp.width : compass.width; - float draw_h = masked ? (float)comp.height : compass.height; - Rectangle dst = { - compass.x + compass.width * 0.5f, - compass.y + compass.height * 0.5f, - draw_w, - draw_h, - }; - Vector2 origin = {draw_w * 0.5f, draw_h * 0.5f}; - float angle_deg = rc->cam_yaw * (180.0f / 3.14159265f); - DrawTexturePro(comp, src, dst, origin, angle_deg, WHITE); - } else { - gui_draw_named_asset(gs, "resize_compass_mask", compass, WHITE); - gui_text_shadow(gs, "N", (int)compass.x + 16, (int)compass.y + 12, 14, GUI_TEXT_ORANGE); - } + Texture2D comp = gs->minimap_compass_masked; + Rectangle src = {0, 0, (float)comp.width, (float)comp.height}; + Rectangle dst = { + compass.x + compass.width * 0.5f, + compass.y + compass.height * 0.5f, + (float)comp.width, + (float)comp.height, + }; + Vector2 origin = {(float)comp.width * 0.5f, (float)comp.height * 0.5f}; + float angle_deg = rc->cam_yaw * (180.0f / 3.14159265f); + DrawTexturePro(comp, src, dst, origin, angle_deg, WHITE); } static Rectangle render_minimap_spec_orb_rect(void) { @@ -5643,16 +5587,12 @@ static void render_draw_minimap_area(RenderClient* rc, OsrsEnv* env, Player* p) Texture2D dot_sprite = ent->entity_type == ENTITY_PLAYER ? gs->minimap_dot_player : gs->minimap_dot_npc; - Color fallback = ent->entity_type == ENTITY_PLAYER - ? WHITE - : (Color){220, 60, 60, 255}; int dot_sz = ent->entity_type == ENTITY_PLAYER ? 5 : 4; - render_draw_minimap_entity_dot(gs, + render_draw_minimap_entity_dot( dot_cx - dot_sz / 2, dot_cy - dot_sz / 2, dot_sz, - dot_sprite, - fallback); + dot_sprite); if (player_idx >= 0 && e != player_idx && rc->entities[player_idx].attack_target_entity_idx == e) { @@ -5682,15 +5622,7 @@ static void render_draw_minimap_area(RenderClient* rc, OsrsEnv* env, Player* p) (float)GUI_MAP_SURROUND_W, (float)GUI_MAP_SURROUND_H, }; - if (gui_asset(gs, "osrs_stretch_mapsurround").id != 0) { - gui_draw_named_asset(gs, "osrs_stretch_mapsurround", cover, WHITE); - } else { - Texture2D chrome_sprite = rc->layout_mode == 1 ? gs->rm_minimap_frame : gs->minimap_frame; - if (chrome_sprite.id != 0) { - Rectangle src = {0, 0, (float)chrome_sprite.width, (float)chrome_sprite.height}; - DrawTexturePro(chrome_sprite, src, cover, (Vector2){0, 0}, 0.0f, WHITE); - } - } + gui_draw_named_asset(gs, "osrs_stretch_mapsurround", cover, WHITE); int orbs_x = map_x + GUI_ORBS_X; int orbs_y = map_y + GUI_ORBS_Y; @@ -5703,21 +5635,17 @@ static void render_draw_minimap_area(RenderClient* rc, OsrsEnv* env, Player* p) Rectangle wiki_button = {(float)(map_x + 166), (float)(map_y + 173), 40, 34}; gui_draw_named_asset(gs, "tli_button01_orb01_34x34_0", xp_orb, WHITE); - if (gui_asset(gs, "tli_button01_orb01_34x34_0").id == 0) { - gui_draw_named_asset(gs, "ring_34_0", xp_orb, WHITE); - } gui_draw_named_asset_centered(gs, "orb_xp_0", xp_orb, 24, 24, WHITE); if (p) { render_draw_minimap_orb(gs, hp_orb, "orb_filler_1", "orb_icon_0", - p->current_hitpoints, p->base_hitpoints, (Color){210, 50, 45, 255}); + p->current_hitpoints, p->base_hitpoints); render_draw_minimap_orb(gs, prayer_orb, "orb_filler_4", "orb_icon_1", - p->current_prayer, p->base_prayer, (Color){70, 120, 255, 255}); + p->current_prayer, p->base_prayer); render_draw_minimap_orb(gs, run_orb, "orb_filler_5", "orb_icon_2", - osrs_run_energy_percent(p->run_energy), 100, (Color){60, 210, 80, 255}); + osrs_run_energy_percent(p->run_energy), 100); render_draw_minimap_orb(gs, spec_orb, "orb_filler_9", "orb_icon_6", - p->special_energy, 100, - p->spec_armed ? (Color){80, 220, 90, 255} : (Color){225, 205, 55, 255}); + p->special_energy, 100); } gui_draw_named_asset(gs, "ring_30", worldmap_button, WHITE); @@ -6250,9 +6178,7 @@ void pvp_render(OsrsEnv* env) { rc->gui.encounter_def = env->encounter_def; if (rc->gui.gui_entity_idx >= rc->entity_count) rc->gui.gui_entity_idx = 0; - human_draw_click_cross(&rc->human_input, - rc->click_cross_sprites, - rc->click_cross_loaded); + human_draw_click_cross(&rc->human_input, rc->click_cross_sprites); if (rc->show_debug) { char dbg[256]; diff --git a/tests/test_osrs_asset_manifest_preload.py b/tests/test_osrs_asset_manifest_preload.py index 483533d115..b7bce46009 100644 --- a/tests/test_osrs_asset_manifest_preload.py +++ b/tests/test_osrs_asset_manifest_preload.py @@ -64,7 +64,7 @@ def test_empty_group_selection_emits_every_asset_once() -> None: ] -def test_inferno_web_groups_emit_43_unique_matching_vfs_paths() -> None: +def test_inferno_web_groups_emit_1568_unique_matching_vfs_paths() -> None: root = Path(__file__).resolve().parents[1] manifest = osrs_asset_manifest.load_manifest(root / "ocean/osrs/asset_manifest.json") lines = osrs_asset_manifest.emcc_preload_args( @@ -72,9 +72,37 @@ def test_inferno_web_groups_emit_43_unique_matching_vfs_paths() -> None: ["core", "inferno", "combat_visuals", "gui", "items"], ) - assert len(lines) == 43 - assert len(set(lines)) == 43 + assert len(lines) == 1568 + assert len(set(lines)) == 1568 for line in lines: source, destination = line.removeprefix("--preload-file ").split("@", 1) assert source == destination assert source.startswith("ocean/osrs/data/") + + + +def test_gui_group_contains_every_exported_gui_sprite() -> None: + root = Path(__file__).resolve().parents[1] + manifest = osrs_asset_manifest.load_manifest(root / "ocean/osrs/asset_manifest.json") + gui_group = next(group for group in manifest.required_groups if group.name == "gui") + data_dir = root / "ocean/osrs/data" + expected = { + path.relative_to(data_dir).as_posix() + for path in (data_dir / "sprites/gui").glob("*.png") + } + + assert set(gui_group.files) == expected + + +def test_items_group_contains_every_exported_item_sprite() -> None: + root = Path(__file__).resolve().parents[1] + manifest = osrs_asset_manifest.load_manifest(root / "ocean/osrs/asset_manifest.json") + items_group = next(group for group in manifest.required_groups if group.name == "items") + data_dir = root / "ocean/osrs/data" + expected = { + path.relative_to(data_dir).as_posix() + for path in (data_dir / "sprites/items").glob("*.png") + } + expected.add("sprites/items/item_stack_variants.tsv") + + assert set(items_group.files) == expected \ No newline at end of file diff --git a/tests/test_package_osrs_inferno.py b/tests/test_package_osrs_inferno.py index a9d9b33393..5485c07af8 100644 --- a/tests/test_package_osrs_inferno.py +++ b/tests/test_package_osrs_inferno.py @@ -29,7 +29,10 @@ } -def write_build(build_dir: Path, html: bytes = b"before __OSRS_BUNDLE_VERSION__ after\n") -> None: +def write_build( + build_dir: Path, + html: bytes = b"before __OSRS_BUNDLE_VERSION__ after\n", +) -> None: build_dir.mkdir() contents = { "game.html": html, @@ -174,6 +177,28 @@ def test_html_requires_exactly_one_version_token(tmp_path: Path, html: bytes) -> assert "exactly one" in result.stderr.lower() assert not output_dir.exists() +@pytest.mark.parametrize( + "html", + [ + b"__OSRS_BUNDLE_VERSION__ without script\n", + b"__OSRS_BUNDLE_VERSION__ \n", + ], +) +def test_html_requires_exactly_one_game_script_reference( + tmp_path: Path, html: bytes +) -> None: + build_dir = tmp_path / "build" + write_build(build_dir, html) + model = tmp_path / "policy.bin" + model.write_bytes(b"model") + output_dir = tmp_path / "site" + + result = run_package(build_dir, model, output_dir) + + assert result.returncode != 0 + assert "game.js" in result.stderr + assert not output_dir.exists() + def test_output_cannot_replace_build_input(tmp_path: Path) -> None: build_dir = tmp_path / "build" @@ -229,6 +254,7 @@ def test_success_replaces_output_and_writes_complete_verified_bundle(tmp_path: P assert manifest["format"] == "puffer-osrs-inferno-web-v1" assert re.fullmatch(r"[0-9a-f]{16}", manifest["version"]) assert manifest["version"] in final_html + assert f"src=game.js?v={manifest['version']}" in final_html assert manifest["source_commit"] == SOURCE_COMMIT assert manifest["model"] == { "path": "models/osrs_inferno.bin", diff --git a/tools/web/package_osrs_inferno.py b/tools/web/package_osrs_inferno.py index 8bf57c96de..83b4661387 100644 --- a/tools/web/package_osrs_inferno.py +++ b/tools/web/package_osrs_inferno.py @@ -11,6 +11,7 @@ BUNDLE_FORMAT = "puffer-osrs-inferno-web-v1" VERSION_TOKEN = b"__OSRS_BUNDLE_VERSION__" +GAME_SCRIPT_REFERENCE = b"src=game.js" GAME_FILE_NAMES = ( "game.html", "game.js", @@ -99,6 +100,8 @@ def package_bundle( source_html = source_contents["game.html"] if source_html.count(VERSION_TOKEN) != 1: raise ValueError("game.html must contain exactly one __OSRS_BUNDLE_VERSION__ token") + if source_html.count(GAME_SCRIPT_REFERENCE) != 1: + raise ValueError("game.html must contain exactly one game.js script reference") source_records = { name: file_record(source_contents[name]) for name in GAME_FILE_NAMES @@ -110,7 +113,13 @@ def package_bundle( version = derive_bundle_version(ordered_hashes, metadata) packaged_contents = dict(source_contents) - packaged_contents["game.html"] = source_html.replace(VERSION_TOKEN, version.encode()) + version_bytes = version.encode() + packaged_contents["game.html"] = source_html.replace( + VERSION_TOKEN, version_bytes + ).replace( + GAME_SCRIPT_REFERENCE, + GAME_SCRIPT_REFERENCE + b"?v=" + version_bytes, + ) packaged_contents[MODEL_OUTPUT_PATH] = model_content final_records = dict(source_records) final_records["game.html"] = file_record(packaged_contents["game.html"]) From 2eb8b0918e250a2ccaa5c03ece1d7ab65df169f7 Mon Sep 17 00:00:00 2001 From: Valtteri Valo Date: Tue, 18 Aug 2026 13:18:06 +0300 Subject: [PATCH 06/15] Generalize OSRS web policy bundles --- build.sh | 27 ++++++++++--- ocean/osrs/osrs_visual.c | 5 --- ...e_osrs_inferno.py => test_package_osrs.py} | 40 ++++++++++++++++--- ...srs_inferno_shell.html => osrs_shell.html} | 30 ++++++++++---- ...ackage_osrs_inferno.py => package_osrs.py} | 14 ++++++- 5 files changed, 90 insertions(+), 26 deletions(-) rename tests/{test_package_osrs_inferno.py => test_package_osrs.py} (87%) rename tools/web/{osrs_inferno_shell.html => osrs_shell.html} (82%) rename tools/web/{package_osrs_inferno.py => package_osrs.py} (94%) diff --git a/build.sh b/build.sh index 888f9717d5..db1ff2c4bd 100755 --- a/build.sh +++ b/build.sh @@ -298,12 +298,27 @@ if [ "$MODE" = "cpu" ]; then echo "Built: ./$OUTPUT_NAME" exit 0 elif [ "$MODE" = "web" ]; then - if [ "$ENV" = "osrs_inferno" ]; then + OSRS_ASSET_GROUP="" + case "$ENV" in + osrs_inferno) + OSRS_ASSET_GROUP="inferno" + ;; + osrs_colosseum) + OSRS_ASSET_GROUP="colosseum" + ;; + osrs_zulrah) + OSRS_ASSET_GROUP="zulrah" + ;; + osrs_pvp) + OSRS_ASSET_GROUP="pvp" + ;; + esac + if [ -n "$OSRS_ASSET_GROUP" ]; then mkdir -p "build/web/$ENV" OSRS_PRELOAD_LINES=$(python3 ocean/osrs/scripts/osrs_asset_manifest.py \ emcc-preload-args ocean/osrs/asset_manifest.json \ --group core \ - --group inferno \ + --group "$OSRS_ASSET_GROUP" \ --group combat_visuals \ --group gui \ --group items) @@ -319,15 +334,15 @@ elif [ "$MODE" = "web" ]; then echo "Compiling $ENV for web..." emcc \ -o "build/web/$ENV/game.html" \ - ocean/osrs_inferno/osrs_inferno.c \ + "$SRC_FILE" \ -O3 -Wall -Wno-narrowing \ "${LINK_ARCHIVES[@]}" \ - -I. -Isrc -I$SRC_DIR -Ivendor "${INCLUDES[@]}" \ - -L. -L./$RAYLIB_NAME/lib \ + -I. -Isrc -I"$SRC_DIR" -Ivendor "${INCLUDES[@]}" \ + -L. -L./"$RAYLIB_NAME"/lib \ -sASSERTIONS=2 -gsource-map \ -sUSE_GLFW=3 -sUSE_WEBGL2=1 -sASYNCIFY -sFILESYSTEM -sFORCE_FILESYSTEM=1 \ -sLZ4=1 \ - --shell-file tools/web/osrs_inferno_shell.html \ + --shell-file tools/web/osrs_shell.html \ -sINITIAL_MEMORY=512MB -sALLOW_MEMORY_GROWTH -sSTACK_SIZE=512KB \ -DPLATFORM_WEB -DGRAPHICS_API_OPENGL_ES3 \ "${OSRS_PRELOAD[@]}" \ diff --git a/ocean/osrs/osrs_visual.c b/ocean/osrs/osrs_visual.c index 89c1e8875b..e312b3b003 100644 --- a/ocean/osrs/osrs_visual.c +++ b/ocean/osrs/osrs_visual.c @@ -2321,15 +2321,10 @@ int main(int argc, char** argv) { } } -#ifdef __EMSCRIPTEN__ - if (!encounter_name) encounter_name = "inferno"; - if (encounter_name && strcmp(encounter_name, "pvp") == 0) encounter_name = "nh_pvp"; -#else #ifdef OSRS_VISUAL_DEFAULT_ENCOUNTER if (!encounter_name) encounter_name = OSRS_VISUAL_DEFAULT_ENCOUNTER; #endif if (encounter_name && strcmp(encounter_name, "pvp") == 0) encounter_name = "nh_pvp"; -#endif VisualPolicyMode policy_mode __attribute__((unused)) = visual_policy_parse_mode(policy_mode_name); diff --git a/tests/test_package_osrs_inferno.py b/tests/test_package_osrs.py similarity index 87% rename from tests/test_package_osrs_inferno.py rename to tests/test_package_osrs.py index 5485c07af8..91195642fd 100644 --- a/tests/test_package_osrs_inferno.py +++ b/tests/test_package_osrs.py @@ -9,8 +9,9 @@ REPOSITORY_ROOT = Path(__file__).resolve().parents[1] -PACKAGE_SCRIPT = REPOSITORY_ROOT / "tools/web/package_osrs_inferno.py" +PACKAGE_SCRIPT = REPOSITORY_ROOT / "tools/web/package_osrs.py" SOURCE_COMMIT = "a" * 40 +ENVIRONMENT = "inferno" GAME_FILES = ( "game.html", "game.js", @@ -25,7 +26,7 @@ "game.wasm.map", "game.data", "bundle.json", - "models/osrs_inferno.bin", + "models/policy.bin", } @@ -51,6 +52,7 @@ def run_package( output_dir: Path, *, source_commit: str = SOURCE_COMMIT, + environment: str = ENVIRONMENT, hidden_size: str = "512", num_layers: str = "2", entity_encoder: str = "0", @@ -65,6 +67,8 @@ def run_package( str(model), "--out", str(output_dir), + "--environment", + environment, "--source-commit", source_commit, "--hidden-size", @@ -242,7 +246,7 @@ def test_success_replaces_output_and_writes_complete_verified_bundle(tmp_path: P assert result.returncode == 0, result.stderr assert output_file_paths(output_dir) == OUTPUT_FILES - assert (output_dir / "models/osrs_inferno.bin").read_bytes() == original_model + assert (output_dir / "models/policy.bin").read_bytes() == original_model final_html = (output_dir / "game.html").read_text() assert "__OSRS_BUNDLE_VERSION__" not in final_html manifest_bytes = (output_dir / "bundle.json").read_bytes() @@ -251,13 +255,14 @@ def test_success_replaces_output_and_writes_complete_verified_bundle(tmp_path: P json.loads(manifest_bytes), indent=2, sort_keys=True ).encode() + b"\n" manifest = json.loads(manifest_bytes) - assert manifest["format"] == "puffer-osrs-inferno-web-v1" + assert manifest["format"] == "puffer-osrs-web-v2" assert re.fullmatch(r"[0-9a-f]{16}", manifest["version"]) assert manifest["version"] in final_html assert f"src=game.js?v={manifest['version']}" in final_html assert manifest["source_commit"] == SOURCE_COMMIT + assert manifest["environment"] == ENVIRONMENT assert manifest["model"] == { - "path": "models/osrs_inferno.bin", + "path": "models/policy.bin", "hidden_size": 512, "num_layers": 2, "entity_encoder": 0, @@ -308,3 +313,28 @@ def test_model_bytes_contribute_to_bundle_version(tmp_path: Path) -> None: assert first.returncode == 0, first.stderr assert second.returncode == 0, second.stderr assert second_version != first_version + + + +def test_environment_contributes_to_bundle_version_and_manifest(tmp_path: Path) -> None: + build_dir = tmp_path / "build" + write_build(build_dir) + model = tmp_path / "policy.bin" + model.write_bytes(b"model") + output_dir = tmp_path / "site" + + inferno = run_package(build_dir, model, output_dir, environment="inferno") + inferno_manifest = json.loads((output_dir / "bundle.json").read_bytes()) + colosseum = run_package( + build_dir, + model, + output_dir, + environment="colosseum", + ) + colosseum_manifest = json.loads((output_dir / "bundle.json").read_bytes()) + + assert inferno.returncode == 0, inferno.stderr + assert colosseum.returncode == 0, colosseum.stderr + assert inferno_manifest["environment"] == "inferno" + assert colosseum_manifest["environment"] == "colosseum" + assert inferno_manifest["version"] != colosseum_manifest["version"] \ No newline at end of file diff --git a/tools/web/osrs_inferno_shell.html b/tools/web/osrs_shell.html similarity index 82% rename from tools/web/osrs_inferno_shell.html rename to tools/web/osrs_shell.html index afbdc7f690..31d8b598bf 100644 --- a/tools/web/osrs_inferno_shell.html +++ b/tools/web/osrs_shell.html @@ -3,7 +3,7 @@ - OSRS Inferno Simulator + OSRS reinforcement learning simulator -
-

OSRS

+
+
Loading simulator
-
- - -
-
-
- -
+ +