NeoCodes-dev commited on
Commit
ac5cfba
·
verified ·
1 Parent(s): 00ed797

Upload folder using huggingface_hub

Browse files
.gitattributes CHANGED
@@ -33,3 +33,5 @@ saved_model/**/* filter=lfs diff=lfs merge=lfs -text
33
  *.zip filter=lfs diff=lfs merge=lfs -text
34
  *.zst filter=lfs diff=lfs merge=lfs -text
35
  *tfevents* filter=lfs diff=lfs merge=lfs -text
 
 
 
33
  *.zip filter=lfs diff=lfs merge=lfs -text
34
  *.zst filter=lfs diff=lfs merge=lfs -text
35
  *tfevents* filter=lfs diff=lfs merge=lfs -text
36
+ server/PokemonRed.gb filter=lfs diff=lfs merge=lfs -text
37
+ server/init.state filter=lfs diff=lfs merge=lfs -text
Dockerfile ADDED
@@ -0,0 +1,114 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Copyright (c) Meta Platforms, Inc. and affiliates.
2
+ # All rights reserved.
3
+ #
4
+ # This source code is licensed under the BSD-style license found in the
5
+ # LICENSE file in the root directory of this source tree.
6
+
7
+ # Multi-stage build for Pokemon Red OpenEnv
8
+ # Builds a containerized PyBoy emulator environment for RL training
9
+ #
10
+ # Build: openenv build
11
+ # Run: docker run -p 8000:8000 pokemonred-env:latest
12
+ #
13
+ # Environment variables:
14
+ # POKEMON_HEADLESS: Run without display (default: true)
15
+ # POKEMON_ACTION_FREQ: Emulator ticks per action (default: 24)
16
+ # POKEMON_ROM_PATH: Path to ROM file (default: /app/env/server/PokemonRed.gb)
17
+ # POKEMON_INIT_STATE: Path to save state (default: /app/env/server/init.state)
18
+
19
+ ARG BASE_IMAGE=ghcr.io/meta-pytorch/openenv-base:latest
20
+ FROM ${BASE_IMAGE} AS builder
21
+
22
+ WORKDIR /app
23
+
24
+ # Install build dependencies for PyBoy and SDL2
25
+ RUN apt-get update && apt-get install -y --no-install-recommends \
26
+ git \
27
+ build-essential \
28
+ libsdl2-dev \
29
+ libsdl2-image-dev \
30
+ libsdl2-mixer-dev \
31
+ libsdl2-ttf-dev \
32
+ python3-dev \
33
+ && rm -rf /var/lib/apt/lists/*
34
+
35
+ # Build arguments
36
+ ARG BUILD_MODE=in-repo
37
+ ARG ENV_NAME=pokemonred_env
38
+
39
+ # Copy environment code
40
+ COPY . /app/env
41
+
42
+ WORKDIR /app/env
43
+
44
+ # Ensure uv is available
45
+ RUN if ! command -v uv >/dev/null 2>&1; then \
46
+ curl -LsSf https://astral.sh/uv/install.sh | sh && \
47
+ mv /root/.local/bin/uv /usr/local/bin/uv && \
48
+ mv /root/.local/bin/uvx /usr/local/bin/uvx; \
49
+ fi
50
+
51
+ # Install dependencies using uv sync
52
+ RUN --mount=type=cache,target=/root/.cache/uv \
53
+ if [ -f uv.lock ]; then \
54
+ uv sync --frozen --no-install-project --no-editable; \
55
+ else \
56
+ uv sync --no-install-project --no-editable; \
57
+ fi
58
+
59
+ RUN --mount=type=cache,target=/root/.cache/uv \
60
+ if [ -f uv.lock ]; then \
61
+ uv sync --frozen --no-editable; \
62
+ else \
63
+ uv sync --no-editable; \
64
+ fi
65
+
66
+ # Final runtime stage
67
+ FROM ${BASE_IMAGE}
68
+
69
+ WORKDIR /app
70
+
71
+ # Install runtime dependencies for PyBoy headless operation
72
+ RUN apt-get update && apt-get install -y --no-install-recommends \
73
+ libsdl2-2.0-0 \
74
+ libsdl2-image-2.0-0 \
75
+ curl \
76
+ && rm -rf /var/lib/apt/lists/*
77
+
78
+ # Copy the virtual environment from builder
79
+ COPY --from=builder /app/env/.venv /app/.venv
80
+
81
+ # Copy the environment code
82
+ COPY --from=builder /app/env /app/env
83
+
84
+ # Set PATH to use the virtual environment
85
+ ENV PATH="/app/.venv/bin:$PATH"
86
+
87
+ # Set PYTHONPATH for imports
88
+ ENV PYTHONPATH="/app/env:$PYTHONPATH"
89
+
90
+ # Configure SDL for headless operation (no display, no audio)
91
+ ENV SDL_VIDEODRIVER=dummy
92
+ ENV SDL_AUDIODRIVER=dummy
93
+
94
+ # Default environment configuration
95
+ ENV POKEMON_HEADLESS=true
96
+ ENV POKEMON_ACTION_FREQ=24
97
+ ENV POKEMON_ROM_PATH=/app/env/server/PokemonRed.gb
98
+ ENV POKEMON_INIT_STATE=/app/env/server/init.state
99
+ ENV POKEMON_MAX_STEPS=163840
100
+ ENV POKEMON_SESSION_PATH=/tmp/pokemon_sessions
101
+
102
+ # Create session directory
103
+ RUN mkdir -p /tmp/pokemon_sessions
104
+
105
+ # Health check
106
+ HEALTHCHECK --interval=30s --timeout=10s --start-period=30s --retries=3 \
107
+ CMD curl -f http://localhost:8000/health || exit 1
108
+
109
+ # Expose port
110
+ EXPOSE 8000
111
+
112
+ # Run the FastAPI server
113
+ ENV ENABLE_WEB_INTERFACE=true
114
+ CMD ["sh", "-c", "cd /app/env && uvicorn server.app:app --host 0.0.0.0 --port 8000"]
README.md CHANGED
@@ -1,10 +1,255 @@
1
  ---
2
- title: Pokemonred Env
3
- emoji: 🌖
4
- colorFrom: indigo
5
- colorTo: yellow
6
  sdk: docker
7
  pinned: false
 
 
 
 
8
  ---
9
 
10
- Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
  ---
2
+ title: Pokemonred Env Environment Server
3
+ emoji: 🔈
4
+ colorFrom: red
5
+ colorTo: red
6
  sdk: docker
7
  pinned: false
8
+ app_port: 8000
9
+ base_path: /web
10
+ tags:
11
+ - openenv
12
  ---
13
 
14
+ # Pokemonred Env Environment
15
+
16
+ A simple test environment that echoes back messages. Perfect for testing the env APIs as well as demonstrating environment usage patterns.
17
+
18
+ ## Quick Start
19
+
20
+ The simplest way to use the Pokemonred Env environment is through the `PokemonredEnv` class:
21
+
22
+ ```python
23
+ from pokemonred_env import PokemonredAction, PokemonredEnv
24
+
25
+ try:
26
+ # Create environment from Docker image
27
+ pokemonred_envenv = PokemonredEnv.from_docker_image("pokemonred_env-env:latest")
28
+
29
+ # Reset
30
+ result = pokemonred_envenv.reset()
31
+ print(f"Reset: {result.observation.echoed_message}")
32
+
33
+ # Send multiple messages
34
+ messages = ["Hello, World!", "Testing echo", "Final message"]
35
+
36
+ for msg in messages:
37
+ result = pokemonred_envenv.step(PokemonredAction(message=msg))
38
+ print(f"Sent: '{msg}'")
39
+ print(f" → Echoed: '{result.observation.echoed_message}'")
40
+ print(f" → Length: {result.observation.message_length}")
41
+ print(f" → Reward: {result.reward}")
42
+
43
+ finally:
44
+ # Always clean up
45
+ pokemonred_envenv.close()
46
+ ```
47
+
48
+ That's it! The `PokemonredEnv.from_docker_image()` method handles:
49
+ - Starting the Docker container
50
+ - Waiting for the server to be ready
51
+ - Connecting to the environment
52
+ - Container cleanup when you call `close()`
53
+
54
+ ## Building the Docker Image
55
+
56
+ Before using the environment, you need to build the Docker image:
57
+
58
+ ```bash
59
+ # From project root
60
+ docker build -t pokemonred_env-env:latest -f server/Dockerfile .
61
+ ```
62
+
63
+ ## Deploying to Hugging Face Spaces
64
+
65
+ You can easily deploy your OpenEnv environment to Hugging Face Spaces using the `openenv push` command:
66
+
67
+ ```bash
68
+ # From the environment directory (where openenv.yaml is located)
69
+ openenv push
70
+
71
+ # Or specify options
72
+ openenv push --namespace my-org --private
73
+ ```
74
+
75
+ The `openenv push` command will:
76
+ 1. Validate that the directory is an OpenEnv environment (checks for `openenv.yaml`)
77
+ 2. Prepare a custom build for Hugging Face Docker space (enables web interface)
78
+ 3. Upload to Hugging Face (ensuring you're logged in)
79
+
80
+ ### Prerequisites
81
+
82
+ - Authenticate with Hugging Face: The command will prompt for login if not already authenticated
83
+
84
+ ### Options
85
+
86
+ - `--directory`, `-d`: Directory containing the OpenEnv environment (defaults to current directory)
87
+ - `--repo-id`, `-r`: Repository ID in format 'username/repo-name' (defaults to 'username/env-name' from openenv.yaml)
88
+ - `--base-image`, `-b`: Base Docker image to use (overrides Dockerfile FROM)
89
+ - `--private`: Deploy the space as private (default: public)
90
+
91
+ ### Examples
92
+
93
+ ```bash
94
+ # Push to your personal namespace (defaults to username/env-name from openenv.yaml)
95
+ openenv push
96
+
97
+ # Push to a specific repository
98
+ openenv push --repo-id my-org/my-env
99
+
100
+ # Push with a custom base image
101
+ openenv push --base-image ghcr.io/meta-pytorch/openenv-base:latest
102
+
103
+ # Push as a private space
104
+ openenv push --private
105
+
106
+ # Combine options
107
+ openenv push --repo-id my-org/my-env --base-image custom-base:latest --private
108
+ ```
109
+
110
+ After deployment, your space will be available at:
111
+ `https://huggingface.co/spaces/<repo-id>`
112
+
113
+ The deployed space includes:
114
+ - **Web Interface** at `/web` - Interactive UI for exploring the environment
115
+ - **API Documentation** at `/docs` - Full OpenAPI/Swagger interface
116
+ - **Health Check** at `/health` - Container health monitoring
117
+ - **WebSocket** at `/ws` - Persistent session endpoint for low-latency interactions
118
+
119
+ ## Environment Details
120
+
121
+ ### Action
122
+ **PokemonredAction**: Contains a single field
123
+ - `message` (str) - The message to echo back
124
+
125
+ ### Observation
126
+ **PokemonredObservation**: Contains the echo response and metadata
127
+ - `echoed_message` (str) - The message echoed back
128
+ - `message_length` (int) - Length of the message
129
+ - `reward` (float) - Reward based on message length (length × 0.1)
130
+ - `done` (bool) - Always False for echo environment
131
+ - `metadata` (dict) - Additional info like step count
132
+
133
+ ### Reward
134
+ The reward is calculated as: `message_length × 0.1`
135
+ - "Hi" → reward: 0.2
136
+ - "Hello, World!" → reward: 1.3
137
+ - Empty message → reward: 0.0
138
+
139
+ ## Advanced Usage
140
+
141
+ ### Connecting to an Existing Server
142
+
143
+ If you already have a Pokemonred Env environment server running, you can connect directly:
144
+
145
+ ```python
146
+ from pokemonred_env import PokemonredEnv
147
+
148
+ # Connect to existing server
149
+ pokemonred_envenv = PokemonredEnv(base_url="<ENV_HTTP_URL_HERE>")
150
+
151
+ # Use as normal
152
+ result = pokemonred_envenv.reset()
153
+ result = pokemonred_envenv.step(PokemonredAction(message="Hello!"))
154
+ ```
155
+
156
+ Note: When connecting to an existing server, `pokemonred_envenv.close()` will NOT stop the server.
157
+
158
+ ### Using the Context Manager
159
+
160
+ The client supports context manager usage for automatic connection management:
161
+
162
+ ```python
163
+ from pokemonred_env import PokemonredAction, PokemonredEnv
164
+
165
+ # Connect with context manager (auto-connects and closes)
166
+ with PokemonredEnv(base_url="http://localhost:8000") as env:
167
+ result = env.reset()
168
+ print(f"Reset: {result.observation.echoed_message}")
169
+ # Multiple steps with low latency
170
+ for msg in ["Hello", "World", "!"]:
171
+ result = env.step(PokemonredAction(message=msg))
172
+ print(f"Echoed: {result.observation.echoed_message}")
173
+ ```
174
+
175
+ The client uses WebSocket connections for:
176
+ - **Lower latency**: No HTTP connection overhead per request
177
+ - **Persistent session**: Server maintains your environment state
178
+ - **Efficient for episodes**: Better for many sequential steps
179
+
180
+ ### Concurrent WebSocket Sessions
181
+
182
+ The server supports multiple concurrent WebSocket connections. To enable this,
183
+ modify `server/app.py` to use factory mode:
184
+
185
+ ```python
186
+ # In server/app.py - use factory mode for concurrent sessions
187
+ app = create_app(
188
+ PokemonredEnvironment, # Pass class, not instance
189
+ PokemonredAction,
190
+ PokemonredObservation,
191
+ max_concurrent_envs=4, # Allow 4 concurrent sessions
192
+ )
193
+ ```
194
+
195
+ Then multiple clients can connect simultaneously:
196
+
197
+ ```python
198
+ from pokemonred_env import PokemonredAction, PokemonredEnv
199
+ from concurrent.futures import ThreadPoolExecutor
200
+
201
+ def run_episode(client_id: int):
202
+ with PokemonredEnv(base_url="http://localhost:8000") as env:
203
+ result = env.reset()
204
+ for i in range(10):
205
+ result = env.step(PokemonredAction(message=f"Client {client_id}, step {i}"))
206
+ return client_id, result.observation.message_length
207
+
208
+ # Run 4 episodes concurrently
209
+ with ThreadPoolExecutor(max_workers=4) as executor:
210
+ results = list(executor.map(run_episode, range(4)))
211
+ ```
212
+
213
+ ## Development & Testing
214
+
215
+ ### Direct Environment Testing
216
+
217
+ Test the environment logic directly without starting the HTTP server:
218
+
219
+ ```bash
220
+ # From the server directory
221
+ python3 server/pokemonred_env_environment.py
222
+ ```
223
+
224
+ This verifies that:
225
+ - Environment resets correctly
226
+ - Step executes actions properly
227
+ - State tracking works
228
+ - Rewards are calculated correctly
229
+
230
+ ### Running Locally
231
+
232
+ Run the server locally for development:
233
+
234
+ ```bash
235
+ uvicorn server.app:app --reload
236
+ ```
237
+
238
+ ## Project Structure
239
+
240
+ ```
241
+ pokemonred_env/
242
+ ├── .dockerignore # Docker build exclusions
243
+ ├── __init__.py # Module exports
244
+ ├── README.md # This file
245
+ ├── openenv.yaml # OpenEnv manifest
246
+ ├── pyproject.toml # Project metadata and dependencies
247
+ ├── uv.lock # Locked dependencies (generated)
248
+ ├── client.py # PokemonredEnv client
249
+ ├── models.py # Action and Observation models
250
+ └── server/
251
+ ├── __init__.py # Server module exports
252
+ ├── pokemonred_env_environment.py # Core environment logic
253
+ ├── app.py # FastAPI application (HTTP + WebSocket endpoints)
254
+ └── Dockerfile # Container image definition
255
+ ```
__init__.py ADDED
@@ -0,0 +1,27 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Copyright (c) Meta Platforms, Inc. and affiliates.
2
+ # All rights reserved.
3
+ #
4
+ # This source code is licensed under the BSD-style license found in the
5
+ # LICENSE file in the root directory of this source tree.
6
+
7
+ """
8
+ Pokemon Red OpenEnv Environment.
9
+
10
+ A production-ready RL environment for Pokemon Red using PyBoy emulator,
11
+ designed for the OpenEnv Challenge hackathon.
12
+ """
13
+
14
+ from .client import PokemonRedEnv
15
+ from .models import PokemonRedAction, PokemonRedObservation, PokemonRedState
16
+ from .config import PokemonRedConfig
17
+
18
+ __all__ = [
19
+ # Client
20
+ "PokemonRedEnv",
21
+ # Models
22
+ "PokemonRedAction",
23
+ "PokemonRedObservation",
24
+ "PokemonRedState",
25
+ # Config
26
+ "PokemonRedConfig",
27
+ ]
client.py ADDED
@@ -0,0 +1,125 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Copyright (c) Meta Platforms, Inc. and affiliates.
2
+ # All rights reserved.
3
+ #
4
+ # This source code is licensed under the BSD-style license found in the
5
+ # LICENSE file in the root directory of this source tree.
6
+
7
+ """
8
+ Pokemon Red Environment Client.
9
+
10
+ This module provides the client for connecting to a Pokemon Red Environment server
11
+ via WebSocket for persistent sessions.
12
+ """
13
+
14
+ from __future__ import annotations
15
+
16
+ from typing import Any, Dict, TYPE_CHECKING
17
+
18
+ from openenv.core.client_types import StepResult
19
+ from openenv.core.env_client import EnvClient
20
+
21
+ from .models import PokemonRedAction, PokemonRedObservation, PokemonRedState
22
+
23
+ if TYPE_CHECKING:
24
+ from openenv.core.containers.runtime import ContainerProvider
25
+
26
+
27
+ class PokemonRedEnv(EnvClient[PokemonRedAction, PokemonRedObservation, PokemonRedState]):
28
+ """
29
+ Client for Pokemon Red Environment.
30
+
31
+ This client maintains a persistent WebSocket connection to the environment
32
+ server, enabling efficient multi-step interactions with lower latency.
33
+
34
+ Example:
35
+ >>> # Connect to a running server
36
+ >>> with PokemonRedEnv(base_url="http://localhost:8000") as client:
37
+ ... result = client.reset()
38
+ ... print(result.observation.screen_shape)
39
+ ...
40
+ ... result = client.step(PokemonRedAction(action=4)) # Press A
41
+ ... print(result.reward, result.done)
42
+
43
+ Example with Docker:
44
+ >>> # Automatically start container and connect
45
+ >>> client = PokemonRedEnv.from_docker_image("pokemonred-env:latest")
46
+ >>> try:
47
+ ... result = client.reset()
48
+ ... result = client.step(PokemonRedAction(action=0)) # Press Down
49
+ ... finally:
50
+ ... client.close()
51
+
52
+ Example from HuggingFace Hub:
53
+ >>> # Connect to hosted environment
54
+ >>> client = PokemonRedEnv.from_hub("openenv/pokemonred")
55
+ >>> with client:
56
+ ... result = client.reset()
57
+ ... for _ in range(100):
58
+ ... action = PokemonRedAction(action=random.randint(0, 6))
59
+ ... result = client.step(action)
60
+ """
61
+
62
+ def _step_payload(self, action: PokemonRedAction) -> Dict[str, Any]:
63
+ """
64
+ Convert PokemonRedAction to JSON payload for step request.
65
+
66
+ Args:
67
+ action: PokemonRedAction instance.
68
+
69
+ Returns:
70
+ Dictionary representation suitable for JSON encoding.
71
+ """
72
+ return {"action": action.action}
73
+
74
+ def _parse_result(self, payload: Dict[str, Any]) -> StepResult[PokemonRedObservation]:
75
+ """
76
+ Parse server response into StepResult[PokemonRedObservation].
77
+
78
+ Args:
79
+ payload: JSON response from server.
80
+
81
+ Returns:
82
+ StepResult with PokemonRedObservation.
83
+ """
84
+ obs_data = payload.get("observation", {})
85
+
86
+ observation = PokemonRedObservation(
87
+ screen_b64=obs_data.get("screen_b64", ""),
88
+ screen_shape=obs_data.get("screen_shape", [144, 160, 3]),
89
+ health=obs_data.get("health", 0.0),
90
+ level_sum=obs_data.get("level_sum", 0),
91
+ badges=obs_data.get("badges", [0] * 8),
92
+ position=obs_data.get("position", [0, 0, 0]),
93
+ in_battle=obs_data.get("in_battle", False),
94
+ seen_coords_count=obs_data.get("seen_coords_count", 0),
95
+ legal_actions=obs_data.get("legal_actions", list(range(7))),
96
+ done=payload.get("done", False),
97
+ reward=payload.get("reward"),
98
+ metadata=obs_data.get("metadata", {}),
99
+ )
100
+
101
+ return StepResult(
102
+ observation=observation,
103
+ reward=payload.get("reward"),
104
+ done=payload.get("done", False),
105
+ )
106
+
107
+ def _parse_state(self, payload: Dict[str, Any]) -> PokemonRedState:
108
+ """
109
+ Parse server response into PokemonRedState object.
110
+
111
+ Args:
112
+ payload: JSON response from /state endpoint.
113
+
114
+ Returns:
115
+ PokemonRedState object with environment state information.
116
+ """
117
+ return PokemonRedState(
118
+ episode_id=payload.get("episode_id"),
119
+ step_count=payload.get("step_count", 0),
120
+ total_reward=payload.get("total_reward", 0.0),
121
+ reset_count=payload.get("reset_count", 0),
122
+ badges_obtained=payload.get("badges_obtained", 0),
123
+ max_level_sum=payload.get("max_level_sum", 0),
124
+ events_triggered=payload.get("events_triggered", 0),
125
+ )
config.py ADDED
@@ -0,0 +1,41 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ pokemonred_env/config.py
3
+ --------------------------------
4
+ Configuration schema for Pokemon Red environment.
5
+ """
6
+
7
+ from pydantic import BaseModel, Field
8
+ from typing import Dict, Any
9
+
10
+ class PokemonRedConfig(BaseModel):
11
+ """
12
+ Configuration for Pokemon Red Environment.
13
+ """
14
+ # Core settings
15
+ session_path: str = Field("session_pokemon_vla", description="Path to save session data")
16
+ save_final_state: bool = Field(False, description="Save state at end of episode")
17
+ print_rewards: bool = Field(False, description="Print reward details to stdout")
18
+ headless: bool = Field(True, description="Run emulator without window")
19
+ init_state: str = Field("/app/src/envs/pokemon_red/server/init.state", description="Path to initial save state")
20
+ action_freq: int = Field(24, description="Emulator ticks per action")
21
+ max_steps: int = Field(163840, description="Max steps per episode")
22
+ save_video: bool = Field(False, description="Record video of episodes")
23
+ fast_video: bool = Field(True, description="Optimize video recording speed")
24
+ frame_stacks: int = Field(5, description="Number of recent actions to track")
25
+
26
+ # Paths (relative to possible mount points)
27
+ gb_path: str = Field("pokemonred_env/server/PokemonRed.gb", description="Path to ROM file")
28
+
29
+ # Reward Configuration
30
+ reward_scale: float = Field(1.0, description="Global reward scaling factor")
31
+ explore_weight: float = Field(1.0, description="Weight for exploration reward")
32
+
33
+ # Feature Flags
34
+ include_game_text: bool = Field(True, description="Enable text extraction")
35
+ text_detection_threshold: int = Field(10, description="Min chars to consider text active")
36
+
37
+ # Instance ID
38
+ instance_id: str = Field("default", description="Unique ID for this env instance")
39
+
40
+ # Extra options mapping
41
+ extra: Dict[str, Any] = Field(default_factory=dict, description="Additional backend options")
models.py ADDED
@@ -0,0 +1,100 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Copyright (c) Meta Platforms, Inc. and affiliates.
2
+ # All rights reserved.
3
+ #
4
+ # This source code is licensed under the BSD-style license found in the
5
+ # LICENSE file in the root directory of this source tree.
6
+
7
+ """
8
+ Data models for the Pokemon Red OpenEnv Environment.
9
+
10
+ This module defines the Action, Observation, and State types for the Pokemon Red
11
+ Game Boy emulator environment using PyBoy.
12
+ """
13
+
14
+ from __future__ import annotations
15
+
16
+ from typing import Any, Dict, List, Optional
17
+
18
+ from pydantic import Field
19
+
20
+ from openenv.core.env_server.types import Action, Observation, State
21
+
22
+
23
+ class PokemonRedAction(Action):
24
+ """
25
+ Action for Pokemon Red environment.
26
+
27
+ Represents a single Game Boy button press.
28
+
29
+ Attributes:
30
+ action: Discrete action index (0-6) mapping to:
31
+ 0=Down, 1=Left, 2=Right, 3=Up, 4=A, 5=B, 6=Start
32
+ """
33
+
34
+ action: int = Field(
35
+ default=0,
36
+ ge=0,
37
+ le=6,
38
+ description="Button index: 0=Down, 1=Left, 2=Right, 3=Up, 4=A, 5=B, 6=Start",
39
+ )
40
+
41
+
42
+ class PokemonRedObservation(Observation):
43
+ """
44
+ Multi-modal observation from Pokemon Red environment.
45
+
46
+ Contains the game screen, player stats, and game state information
47
+ suitable for both vision-based and structured RL agents.
48
+
49
+ Attributes:
50
+ screen_b64: Base64-encoded PNG of the current game frame.
51
+ screen_shape: Shape of the screen array [height, width, channels].
52
+ health: Party HP fraction in range [0, 1].
53
+ level_sum: Sum of all party Pokemon levels.
54
+ badges: 8-element list of badge flags (0 or 1).
55
+ position: Current position as [x, y, map_id].
56
+ in_battle: Whether player is currently in a battle.
57
+ seen_coords_count: Number of unique coordinates visited (exploration metric).
58
+ legal_actions: List of valid action indices.
59
+ """
60
+
61
+ screen_b64: str = Field(default="", description="Base64-encoded PNG frame")
62
+ screen_shape: List[int] = Field(
63
+ default_factory=lambda: [144, 160, 3], description="Frame dimensions [H,W,C]"
64
+ )
65
+ health: float = Field(default=0.0, ge=0.0, le=1.0, description="Party HP fraction")
66
+ level_sum: int = Field(default=0, ge=0, description="Sum of party Pokemon levels")
67
+ badges: List[int] = Field(
68
+ default_factory=lambda: [0] * 8, description="8-element badge flags"
69
+ )
70
+ position: List[int] = Field(
71
+ default_factory=lambda: [0, 0, 0], description="Player position [x, y, map_id]"
72
+ )
73
+ in_battle: bool = Field(default=False, description="Whether in battle")
74
+ seen_coords_count: int = Field(
75
+ default=0, description="Unique coordinates visited (exploration)"
76
+ )
77
+ legal_actions: List[int] = Field(
78
+ default_factory=lambda: list(range(7)), description="Valid action indices"
79
+ )
80
+
81
+
82
+ class PokemonRedState(State):
83
+ """
84
+ State for Pokemon Red environment.
85
+
86
+ Tracks episode progress and game state for the server.
87
+
88
+ Attributes:
89
+ total_reward: Cumulative reward for current episode.
90
+ reset_count: Number of times environment has been reset.
91
+ badges_obtained: Number of gym badges obtained (0-8).
92
+ max_level_sum: Maximum level sum achieved this episode.
93
+ events_triggered: Count of game event flags triggered.
94
+ """
95
+
96
+ total_reward: float = Field(default=0.0, description="Cumulative episode reward")
97
+ reset_count: int = Field(default=0, description="Number of resets")
98
+ badges_obtained: int = Field(default=0, ge=0, le=8, description="Badges count")
99
+ max_level_sum: int = Field(default=0, description="Max level sum achieved")
100
+ events_triggered: int = Field(default=0, description="Event flags triggered")
openenv.yaml ADDED
@@ -0,0 +1,7 @@
 
 
 
 
 
 
 
 
1
+ spec_version: 1
2
+ name: pokemonred_env
3
+ type: space
4
+ runtime: fastapi
5
+ app: server.app:app
6
+ port: 8000
7
+
openenv_pokemonred_env.egg-info/PKG-INFO ADDED
@@ -0,0 +1,18 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ Metadata-Version: 2.4
2
+ Name: openenv-pokemonred_env
3
+ Version: 0.1.0
4
+ Summary: Pokemonred Env environment for OpenEnv
5
+ Requires-Python: >=3.10
6
+ Requires-Dist: einops>=0.6.0
7
+ Requires-Dist: fastapi>=0.115.0
8
+ Requires-Dist: numpy>=1.21.0
9
+ Requires-Dist: openenv>=0.1.0
10
+ Requires-Dist: openenv-core@ git+https://github.com/meta-pytorch/OpenEnv.git
11
+ Requires-Dist: pillow>=9.0.0
12
+ Requires-Dist: psutil>=5.9.0
13
+ Requires-Dist: pyboy>=2.0.0
14
+ Requires-Dist: pydantic>=2.0.0
15
+ Requires-Dist: uvicorn>=0.24.0
16
+ Provides-Extra: dev
17
+ Requires-Dist: pytest>=8.0.0; extra == "dev"
18
+ Requires-Dist: pytest-cov>=4.0.0; extra == "dev"
openenv_pokemonred_env.egg-info/SOURCES.txt ADDED
@@ -0,0 +1,29 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ README.md
2
+ __init__.py
3
+ client.py
4
+ config.py
5
+ models.py
6
+ pyproject.toml
7
+ ./__init__.py
8
+ ./client.py
9
+ ./config.py
10
+ ./models.py
11
+ openenv_pokemonred_env.egg-info/PKG-INFO
12
+ openenv_pokemonred_env.egg-info/SOURCES.txt
13
+ openenv_pokemonred_env.egg-info/dependency_links.txt
14
+ openenv_pokemonred_env.egg-info/entry_points.txt
15
+ openenv_pokemonred_env.egg-info/requires.txt
16
+ openenv_pokemonred_env.egg-info/top_level.txt
17
+ rewards/__init__.py
18
+ rewards/badge.py
19
+ rewards/base.py
20
+ rewards/event.py
21
+ rewards/exploration.py
22
+ rewards/level.py
23
+ rewards/manager.py
24
+ server/__init__.py
25
+ server/app.py
26
+ server/global_map.py
27
+ server/pokemonred_env_environment.py
28
+ wrappers/__init__.py
29
+ wrappers/green_agent.py
openenv_pokemonred_env.egg-info/dependency_links.txt ADDED
@@ -0,0 +1 @@
 
 
1
+
openenv_pokemonred_env.egg-info/entry_points.txt ADDED
@@ -0,0 +1,2 @@
 
 
 
1
+ [console_scripts]
2
+ server = pokemonred_env.server.app:main
openenv_pokemonred_env.egg-info/requires.txt ADDED
@@ -0,0 +1,14 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ einops>=0.6.0
2
+ fastapi>=0.115.0
3
+ numpy>=1.21.0
4
+ openenv>=0.1.0
5
+ openenv-core@ git+https://github.com/meta-pytorch/OpenEnv.git
6
+ pillow>=9.0.0
7
+ psutil>=5.9.0
8
+ pyboy>=2.0.0
9
+ pydantic>=2.0.0
10
+ uvicorn>=0.24.0
11
+
12
+ [dev]
13
+ pytest>=8.0.0
14
+ pytest-cov>=4.0.0
openenv_pokemonred_env.egg-info/top_level.txt ADDED
@@ -0,0 +1 @@
 
 
1
+ pokemonred_env
pyproject.toml ADDED
@@ -0,0 +1,53 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Copyright (c) Meta Platforms, Inc. and affiliates.
2
+ # All rights reserved.
3
+ #
4
+ # This source code is licensed under the BSD-style license found in the
5
+ # LICENSE file in the root directory of this source tree.
6
+
7
+ [build-system]
8
+ requires = ["setuptools>=45", "wheel"]
9
+ build-backend = "setuptools.build_meta"
10
+
11
+ [project]
12
+ name = "openenv-pokemonred_env"
13
+ version = "0.1.0"
14
+ description = "Pokemonred Env environment for OpenEnv"
15
+ requires-python = ">=3.10"
16
+ dependencies = [
17
+ "einops>=0.6.0",
18
+ "fastapi>=0.115.0",
19
+ "numpy>=1.21.0",
20
+ # OpenEnv runtime - add both for validation compatibility
21
+ "openenv>=0.1.0", # PyPI package (for validation check)
22
+ "openenv-core @ git+https://github.com/meta-pytorch/OpenEnv.git", # Latest from GitHub
23
+ # Environment-specific dependencies
24
+ # Add all dependencies needed for your environment here
25
+ # Examples:
26
+ # "numpy>=1.19.0",
27
+ # "torch>=2.0.0",
28
+ # "gymnasium>=0.29.0",
29
+ # "openspiel>=1.0.0",
30
+ # "smolagents>=1.22.0,<2",
31
+ "pillow>=9.0.0",
32
+ "psutil>=5.9.0",
33
+ "pyboy>=2.0.0",
34
+ "pydantic>=2.0.0",
35
+ "uvicorn>=0.24.0",
36
+ ]
37
+
38
+ [project.optional-dependencies]
39
+ dev = [
40
+ "pytest>=8.0.0",
41
+ "pytest-cov>=4.0.0",
42
+ ]
43
+
44
+ [project.scripts]
45
+ # Server entry point - enables running via: uv run --project . server
46
+ # or: python -m pokemonred_env.server.app
47
+ server = "pokemonred_env.server.app:main"
48
+
49
+ [tool.setuptools]
50
+ include-package-data = true
51
+ packages = ["pokemonred_env", "pokemonred_env.server", "pokemonred_env.rewards", "pokemonred_env.wrappers"]
52
+ package-dir = { "pokemonred_env" = ".", "pokemonred_env.server" = "server", "pokemonred_env.rewards" = "rewards", "pokemonred_env.wrappers" = "wrappers" }
53
+
rewards/__init__.py ADDED
@@ -0,0 +1,20 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Copyright (c) Meta Platforms, Inc. and affiliates.
2
+ # All rights reserved.
3
+
4
+ """Modular reward system for Pokemon Red OpenEnv."""
5
+
6
+ from .base import BaseRewardComponent
7
+ from .manager import RewardManager
8
+ from .exploration import ExplorationReward
9
+ from .badge import BadgeReward
10
+ from .level import LevelUpReward
11
+ from .event import EventReward
12
+
13
+ __all__ = [
14
+ "BaseRewardComponent",
15
+ "RewardManager",
16
+ "ExplorationReward",
17
+ "BadgeReward",
18
+ "LevelUpReward",
19
+ "EventReward",
20
+ ]
rewards/badge.py ADDED
@@ -0,0 +1,32 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Copyright (c) Meta Platforms, Inc. and affiliates.
2
+ # All rights reserved.
3
+
4
+ """Badge reward component for Pokemon Red."""
5
+
6
+ from typing import Any, Dict
7
+
8
+ from .base import BaseRewardComponent
9
+
10
+
11
+ class BadgeReward(BaseRewardComponent):
12
+ """
13
+ Rewards obtaining gym badges.
14
+
15
+ Provides significant reward for each gym badge obtained,
16
+ as badges represent major game progression milestones.
17
+
18
+ Attributes:
19
+ weight: Reward per badge (default 5.0).
20
+ """
21
+
22
+ def __init__(self, weight: float = 5.0, enabled: bool = True):
23
+ super().__init__(name="badge", weight=weight, enabled=enabled)
24
+
25
+ def calculate(
26
+ self, state: Dict[str, Any], prev_state: Dict[str, Any]
27
+ ) -> float:
28
+ """Calculate reward for badges obtained."""
29
+ current_badges = state.get("badge_count", 0)
30
+ previous_badges = prev_state.get("badge_count", 0)
31
+ new_badges = current_badges - previous_badges
32
+ return max(0.0, float(new_badges))
rewards/base.py ADDED
@@ -0,0 +1,88 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Copyright (c) Meta Platforms, Inc. and affiliates.
2
+ # All rights reserved.
3
+
4
+ """Base class for modular reward components."""
5
+
6
+ from abc import ABC, abstractmethod
7
+ from typing import Any, Dict
8
+
9
+
10
+ class BaseRewardComponent(ABC):
11
+ """
12
+ Abstract base class for reward components.
13
+
14
+ Each reward component calculates a specific aspect of the reward signal
15
+ (exploration, badges, levels, etc.) and can be enabled/weighted via config.
16
+
17
+ Attributes:
18
+ name: Unique identifier for this reward component.
19
+ weight: Scaling factor applied to calculated reward.
20
+ enabled: Whether this component is active.
21
+
22
+ Example:
23
+ >>> class MyReward(BaseRewardComponent):
24
+ ... def calculate(self, state, prev_state):
25
+ ... return state["score"] - prev_state.get("score", 0)
26
+ >>>
27
+ >>> reward = MyReward(weight=2.0)
28
+ >>> reward.calculate({"score": 100}, {"score": 50})
29
+ 100.0 # (100 - 50) * 2.0
30
+ """
31
+
32
+ def __init__(self, name: str, weight: float = 1.0, enabled: bool = True):
33
+ """
34
+ Initialize reward component.
35
+
36
+ Args:
37
+ name: Unique identifier for this component.
38
+ weight: Scaling factor for reward (default 1.0).
39
+ enabled: Whether component is active (default True).
40
+ """
41
+ self.name = name
42
+ self.weight = weight
43
+ self.enabled = enabled
44
+ self._cumulative = 0.0
45
+
46
+ @abstractmethod
47
+ def calculate(
48
+ self, state: Dict[str, Any], prev_state: Dict[str, Any]
49
+ ) -> float:
50
+ """
51
+ Calculate reward for this component.
52
+
53
+ Args:
54
+ state: Current game state dictionary.
55
+ prev_state: Previous game state dictionary.
56
+
57
+ Returns:
58
+ Unweighted reward value for this component.
59
+ """
60
+ pass
61
+
62
+ def get_reward(
63
+ self, state: Dict[str, Any], prev_state: Dict[str, Any]
64
+ ) -> float:
65
+ """
66
+ Get weighted reward if enabled.
67
+
68
+ Args:
69
+ state: Current game state.
70
+ prev_state: Previous game state.
71
+
72
+ Returns:
73
+ Weighted reward if enabled, 0.0 otherwise.
74
+ """
75
+ if not self.enabled:
76
+ return 0.0
77
+ reward = self.calculate(state, prev_state) * self.weight
78
+ self._cumulative += reward
79
+ return reward
80
+
81
+ def reset(self) -> None:
82
+ """Reset component state for new episode."""
83
+ self._cumulative = 0.0
84
+
85
+ @property
86
+ def cumulative_reward(self) -> float:
87
+ """Total reward from this component in current episode."""
88
+ return self._cumulative
rewards/event.py ADDED
@@ -0,0 +1,33 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Copyright (c) Meta Platforms, Inc. and affiliates.
2
+ # All rights reserved.
3
+
4
+ """Event reward component for Pokemon Red."""
5
+
6
+ from typing import Any, Dict
7
+
8
+ from .base import BaseRewardComponent
9
+
10
+
11
+ class EventReward(BaseRewardComponent):
12
+ """
13
+ Rewards triggering in-game event flags.
14
+
15
+ Pokemon Red uses event flags to track story progression,
16
+ item collection, NPC interactions, etc. This component
17
+ rewards activating new event flags.
18
+
19
+ Attributes:
20
+ weight: Reward per event triggered (default 0.1).
21
+ """
22
+
23
+ def __init__(self, weight: float = 0.1, enabled: bool = True):
24
+ super().__init__(name="event", weight=weight, enabled=enabled)
25
+
26
+ def calculate(
27
+ self, state: Dict[str, Any], prev_state: Dict[str, Any]
28
+ ) -> float:
29
+ """Calculate reward for new events triggered."""
30
+ current_events = state.get("event_count", 0)
31
+ previous_events = prev_state.get("event_count", 0)
32
+ new_events = current_events - previous_events
33
+ return max(0.0, float(new_events))
rewards/exploration.py ADDED
@@ -0,0 +1,32 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Copyright (c) Meta Platforms, Inc. and affiliates.
2
+ # All rights reserved.
3
+
4
+ """Exploration reward component for Pokemon Red."""
5
+
6
+ from typing import Any, Dict
7
+
8
+ from .base import BaseRewardComponent
9
+
10
+
11
+ class ExplorationReward(BaseRewardComponent):
12
+ """
13
+ Rewards visiting new map coordinates.
14
+
15
+ Encourages the agent to explore the game world by providing
16
+ reward for each new unique (x, y, map_id) coordinate visited.
17
+
18
+ Attributes:
19
+ weight: Reward per new coordinate (default 0.02).
20
+ """
21
+
22
+ def __init__(self, weight: float = 0.02, enabled: bool = True):
23
+ super().__init__(name="exploration", weight=weight, enabled=enabled)
24
+
25
+ def calculate(
26
+ self, state: Dict[str, Any], prev_state: Dict[str, Any]
27
+ ) -> float:
28
+ """Calculate reward for new coordinates visited."""
29
+ current_count = state.get("seen_coords_count", 0)
30
+ previous_count = prev_state.get("seen_coords_count", 0)
31
+ new_coords = current_count - previous_count
32
+ return max(0.0, float(new_coords))
rewards/level.py ADDED
@@ -0,0 +1,32 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Copyright (c) Meta Platforms, Inc. and affiliates.
2
+ # All rights reserved.
3
+
4
+ """Level up reward component for Pokemon Red."""
5
+
6
+ from typing import Any, Dict
7
+
8
+ from .base import BaseRewardComponent
9
+
10
+
11
+ class LevelUpReward(BaseRewardComponent):
12
+ """
13
+ Rewards party Pokemon level increases.
14
+
15
+ Tracks the sum of all party Pokemon levels and provides
16
+ reward when the total increases (from battles/training).
17
+
18
+ Attributes:
19
+ weight: Reward per level gained (default 1.0).
20
+ """
21
+
22
+ def __init__(self, weight: float = 1.0, enabled: bool = True):
23
+ super().__init__(name="level", weight=weight, enabled=enabled)
24
+
25
+ def calculate(
26
+ self, state: Dict[str, Any], prev_state: Dict[str, Any]
27
+ ) -> float:
28
+ """Calculate reward for level increases."""
29
+ current_levels = state.get("level_sum", 0)
30
+ previous_levels = prev_state.get("level_sum", 0)
31
+ level_gain = current_levels - previous_levels
32
+ return max(0.0, float(level_gain))
rewards/manager.py ADDED
@@ -0,0 +1,125 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Copyright (c) Meta Platforms, Inc. and affiliates.
2
+ # All rights reserved.
3
+
4
+ """Reward manager for aggregating modular reward components."""
5
+
6
+ from typing import Any, Dict, List, Optional, Type
7
+
8
+ from .base import BaseRewardComponent
9
+
10
+
11
+ class RewardManager:
12
+ """
13
+ Manages multiple reward components and aggregates their outputs.
14
+
15
+ Supports dynamic registration, per-component weighting, and
16
+ detailed reward breakdowns for debugging/analysis.
17
+
18
+ Attributes:
19
+ components: List of registered reward components.
20
+ global_scale: Global scaling factor applied to total reward.
21
+
22
+ Example:
23
+ >>> manager = RewardManager(global_scale=1.0)
24
+ >>> manager.register(ExplorationReward(weight=2.0))
25
+ >>> manager.register(BadgeReward(weight=5.0))
26
+ >>>
27
+ >>> reward = manager.calculate(current_state, prev_state)
28
+ >>> breakdown = manager.get_breakdown()
29
+ """
30
+
31
+ def __init__(self, global_scale: float = 1.0):
32
+ """
33
+ Initialize reward manager.
34
+
35
+ Args:
36
+ global_scale: Global scaling factor for total reward.
37
+ """
38
+ self.components: List[BaseRewardComponent] = []
39
+ self.global_scale = global_scale
40
+ self._last_breakdown: Dict[str, float] = {}
41
+
42
+ def register(self, component: BaseRewardComponent) -> "RewardManager":
43
+ """
44
+ Register a reward component.
45
+
46
+ Args:
47
+ component: Reward component to register.
48
+
49
+ Returns:
50
+ Self for method chaining.
51
+ """
52
+ self.components.append(component)
53
+ return self
54
+
55
+ def register_defaults(self, config: Optional[Dict[str, Any]] = None) -> "RewardManager":
56
+ """
57
+ Register default reward components with optional config.
58
+
59
+ Args:
60
+ config: Optional config dict with component weights.
61
+
62
+ Returns:
63
+ Self for method chaining.
64
+ """
65
+ from .exploration import ExplorationReward
66
+ from .badge import BadgeReward
67
+ from .level import LevelUpReward
68
+ from .event import EventReward
69
+
70
+ config = config or {}
71
+
72
+ self.register(ExplorationReward(
73
+ weight=config.get("exploration_weight", 0.02)
74
+ ))
75
+ self.register(BadgeReward(
76
+ weight=config.get("badge_weight", 5.0)
77
+ ))
78
+ self.register(LevelUpReward(
79
+ weight=config.get("level_weight", 1.0)
80
+ ))
81
+ self.register(EventReward(
82
+ weight=config.get("event_weight", 0.1)
83
+ ))
84
+
85
+ return self
86
+
87
+ def calculate(
88
+ self, state: Dict[str, Any], prev_state: Dict[str, Any]
89
+ ) -> float:
90
+ """
91
+ Calculate total reward from all components.
92
+
93
+ Args:
94
+ state: Current game state.
95
+ prev_state: Previous game state.
96
+
97
+ Returns:
98
+ Total weighted and scaled reward.
99
+ """
100
+ self._last_breakdown = {}
101
+ total = 0.0
102
+
103
+ for component in self.components:
104
+ reward = component.get_reward(state, prev_state)
105
+ self._last_breakdown[component.name] = reward
106
+ total += reward
107
+
108
+ return total * self.global_scale
109
+
110
+ def reset(self) -> None:
111
+ """Reset all components for new episode."""
112
+ self._last_breakdown = {}
113
+ for component in self.components:
114
+ component.reset()
115
+
116
+ def get_breakdown(self) -> Dict[str, float]:
117
+ """Get reward breakdown by component from last calculation."""
118
+ return self._last_breakdown.copy()
119
+
120
+ def get_cumulative_breakdown(self) -> Dict[str, float]:
121
+ """Get cumulative rewards by component for current episode."""
122
+ return {
123
+ comp.name: comp.cumulative_reward
124
+ for comp in self.components
125
+ }
server/PokemonRed.gb ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:5ca7ba01642a3b27b0cc0b5349b52792795b62d3ed977e98a09390659af96b7b
3
+ size 1048576
server/__init__.py ADDED
@@ -0,0 +1,11 @@
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Copyright (c) Meta Platforms, Inc. and affiliates.
2
+ # All rights reserved.
3
+ #
4
+ # This source code is licensed under the BSD-style license found in the
5
+ # LICENSE file in the root directory of this source tree.
6
+
7
+ """Pokemon Red environment server components."""
8
+
9
+ from .pokemonred_env_environment import PokemonRedEnvironment
10
+
11
+ __all__ = ["PokemonRedEnvironment"]
server/app.py ADDED
@@ -0,0 +1,103 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Copyright (c) Meta Platforms, Inc. and affiliates.
2
+ # All rights reserved.
3
+ #
4
+ # This source code is licensed under the BSD-style license found in the
5
+ # LICENSE file in the root directory of this source tree.
6
+
7
+ """
8
+ FastAPI application for the Pokemon Red Environment.
9
+
10
+ This module creates an HTTP server that exposes the PokemonRedEnvironment
11
+ over HTTP and WebSocket endpoints, compatible with EnvClient.
12
+
13
+ Endpoints:
14
+ - POST /reset: Reset the environment
15
+ - POST /step: Execute an action
16
+ - GET /state: Get current environment state
17
+ - GET /schema: Get action/observation schemas
18
+ - WS /ws: WebSocket endpoint for persistent sessions
19
+
20
+ Usage:
21
+ # Development (with auto-reload):
22
+ uvicorn server.app:app --reload --host 0.0.0.0 --port 8000
23
+
24
+ # Production:
25
+ uvicorn server.app:app --host 0.0.0.0 --port 8000 --workers 4
26
+
27
+ Environment variables:
28
+ POKEMON_HEADLESS: Run emulator without display (default: "true")
29
+ POKEMON_ACTION_FREQ: Emulator ticks per action (default: "24")
30
+ POKEMON_ROM_PATH: Path to Pokemon Red ROM (default: "/app/env/server/PokemonRed.gb")
31
+ POKEMON_INIT_STATE: Path to initial save state (default: "/app/env/server/init.state")
32
+ POKEMON_MAX_STEPS: Maximum steps per episode (default: "163840")
33
+ """
34
+
35
+ import os
36
+
37
+ from openenv.core.env_server import create_app
38
+
39
+ # Support both package imports (when used as package) and direct imports (Docker/standalone)
40
+ # Try relative imports first (package mode), fall back to absolute (Docker/standalone mode)
41
+ try:
42
+ from ..models import PokemonRedAction, PokemonRedObservation
43
+ from ..config import PokemonRedConfig
44
+ from .pokemonred_env_environment import PokemonRedEnvironment
45
+ except ImportError:
46
+ # Fallback for standalone loading (Docker, openenv validate, etc.)
47
+ from models import PokemonRedAction, PokemonRedObservation
48
+ from config import PokemonRedConfig
49
+ from server.pokemonred_env_environment import PokemonRedEnvironment
50
+
51
+
52
+ def create_pokemon_environment():
53
+ """
54
+ Factory function that creates PokemonRedEnvironment with config from env vars.
55
+
56
+ This enables WebSocket session support where each client gets their own
57
+ environment instance with isolated state.
58
+ """
59
+ config = PokemonRedConfig(
60
+ headless=os.getenv("POKEMON_HEADLESS", "true").lower() == "true",
61
+ action_freq=int(os.getenv("POKEMON_ACTION_FREQ", "24")),
62
+ gb_path=os.getenv("POKEMON_ROM_PATH", "/app/env/server/PokemonRed.gb"),
63
+ init_state=os.getenv("POKEMON_INIT_STATE", "/app/env/server/init.state"),
64
+ max_steps=int(os.getenv("POKEMON_MAX_STEPS", "163840")),
65
+ session_path=os.getenv("POKEMON_SESSION_PATH", "/tmp/pokemon_sessions"),
66
+ )
67
+ return PokemonRedEnvironment(config)
68
+
69
+
70
+ # Create the FastAPI app with web interface and README integration
71
+ # Pass the factory function for WebSocket session support
72
+ app = create_app(
73
+ create_pokemon_environment,
74
+ PokemonRedAction,
75
+ PokemonRedObservation,
76
+ env_name="pokemonred",
77
+ )
78
+
79
+
80
+ def main(host: str = "0.0.0.0", port: int = 8000):
81
+ """
82
+ Entry point for direct execution.
83
+
84
+ This function is required by openenv validate for uv_run and python_module
85
+ deployment modes.
86
+
87
+ Args:
88
+ host: Host address to bind to (default: "0.0.0.0")
89
+ port: Port number to listen on (default: 8000)
90
+ """
91
+ import uvicorn
92
+ uvicorn.run(app, host=host, port=port)
93
+
94
+
95
+ if __name__ == "__main__":
96
+ import argparse
97
+
98
+ parser = argparse.ArgumentParser(description="Pokemon Red OpenEnv Server")
99
+ parser.add_argument("--host", type=str, default="0.0.0.0", help="Host to bind")
100
+ parser.add_argument("--port", type=int, default=8000, help="Port to listen on")
101
+ args = parser.parse_args()
102
+ # Call main() - openenv validate checks for literal 'main()' string
103
+ main()
server/events.json ADDED
@@ -0,0 +1,2560 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "0xD747-0": "Followed Oak Into Lab",
3
+ "0xD747-1": "Event 001",
4
+ "0xD747-2": "002",
5
+ "0xD747-3": "Hall Of Fame Dex Rating",
6
+ "0xD747-4": "004",
7
+ "0xD747-5": "005",
8
+ "0xD747-6": "Pallet After Getting Pokeballs",
9
+ "0xD747-7": "007",
10
+ "0xD748-0": "008",
11
+ "0xD748-1": "009",
12
+ "0xD748-2": "00A",
13
+ "0xD748-3": "00B",
14
+ "0xD748-4": "00C",
15
+ "0xD748-5": "00D",
16
+ "0xD748-6": "00E",
17
+ "0xD748-7": "00F",
18
+ "0xD749-0": "010",
19
+ "0xD749-1": "011",
20
+ "0xD749-2": "012",
21
+ "0xD749-3": "013",
22
+ "0xD749-4": "014",
23
+ "0xD749-5": "015",
24
+ "0xD749-6": "016",
25
+ "0xD749-7": "017",
26
+ "0xD74A-0": "Got Town Map",
27
+ "0xD74A-1": "Entered Blues House",
28
+ "0xD74A-2": "Daisy Walking",
29
+ "0xD74A-3": "01B",
30
+ "0xD74A-4": "01C",
31
+ "0xD74A-5": "01D",
32
+ "0xD74A-6": "01E",
33
+ "0xD74A-7": "01F",
34
+ "0xD74B-0": "Followed Oak Into Lab 2",
35
+ "0xD74B-1": "Oak Asked To Choose Mon",
36
+ "0xD74B-2": "Got Starter",
37
+ "0xD74B-3": "Battled Rival In Oaks Lab",
38
+ "0xD74B-4": "Got Pokeballs From Oak",
39
+ "0xD74B-5": "Got Pokedex",
40
+ "0xD74B-6": "Pallet After Getting Pokeballs 2",
41
+ "0xD74B-7": "Oak Appeared In Pallet",
42
+ "0xD74C-0": "Viridian Gym Open",
43
+ "0xD74C-1": "Got Tm42",
44
+ "0xD74C-2": "02A",
45
+ "0xD74C-3": "02B",
46
+ "0xD74C-4": "02C",
47
+ "0xD74C-5": "02D",
48
+ "0xD74C-6": "02E",
49
+ "0xD74C-7": "02F",
50
+ "0xD74D-0": "030",
51
+ "0xD74D-1": "031",
52
+ "0xD74D-2": "032",
53
+ "0xD74D-3": "033",
54
+ "0xD74D-4": "034",
55
+ "0xD74D-5": "035",
56
+ "0xD74D-6": "036",
57
+ "0xD74D-7": "037",
58
+ "0xD74E-0": "Oak Got Parcel",
59
+ "0xD74E-1": "Got Oaks Parcel",
60
+ "0xD74E-2": "03A",
61
+ "0xD74E-3": "03B",
62
+ "0xD74E-4": "03C",
63
+ "0xD74E-5": "03D",
64
+ "0xD74E-6": "03E",
65
+ "0xD74E-7": "03F",
66
+ "0xD74F-0": "040",
67
+ "0xD74F-1": "041",
68
+ "0xD74F-2": "042",
69
+ "0xD74F-3": "043",
70
+ "0xD74F-4": "044",
71
+ "0xD74F-5": "045",
72
+ "0xD74F-6": "046",
73
+ "0xD74F-7": "047",
74
+ "0xD750-0": "048",
75
+ "0xD750-1": "049",
76
+ "0xD750-2": "04A",
77
+ "0xD750-3": "04B",
78
+ "0xD750-4": "04C",
79
+ "0xD750-5": "04D",
80
+ "0xD750-6": "04E",
81
+ "0xD750-7": "04F",
82
+ "0xD751-0": "Got Tm27",
83
+ "0xD751-1": "Beat Viridian Gym Giovanni",
84
+ "0xD751-2": "Beat Viridian Gym Trainer 0",
85
+ "0xD751-3": "Beat Viridian Gym Trainer 1",
86
+ "0xD751-4": "Beat Viridian Gym Trainer 2",
87
+ "0xD751-5": "Beat Viridian Gym Trainer 3",
88
+ "0xD751-6": "Beat Viridian Gym Trainer 4",
89
+ "0xD751-7": "Beat Viridian Gym Trainer 5",
90
+ "0xD752-0": "Beat Viridian Gym Trainer 6",
91
+ "0xD752-1": "Beat Viridian Gym Trainer 7",
92
+ "0xD752-2": "05A",
93
+ "0xD752-3": "05B",
94
+ "0xD752-4": "05C",
95
+ "0xD752-5": "05D",
96
+ "0xD752-6": "05E",
97
+ "0xD752-7": "05F",
98
+ "0xD753-0": "060",
99
+ "0xD753-1": "061",
100
+ "0xD753-2": "062",
101
+ "0xD753-3": "063",
102
+ "0xD753-4": "064",
103
+ "0xD753-5": "065",
104
+ "0xD753-6": "066",
105
+ "0xD753-7": "067",
106
+ "0xD754-0": "Bought Museum Ticket",
107
+ "0xD754-1": "Got Old Amber",
108
+ "0xD754-2": "06A",
109
+ "0xD754-3": "06B",
110
+ "0xD754-4": "06C",
111
+ "0xD754-5": "06D",
112
+ "0xD754-6": "06E",
113
+ "0xD754-7": "06F",
114
+ "0xD755-0": "070",
115
+ "0xD755-1": "071",
116
+ "0xD755-2": "Beat Pewter Gym Trainer 0",
117
+ "0xD755-3": "073",
118
+ "0xD755-4": "074",
119
+ "0xD755-5": "075",
120
+ "0xD755-6": "Got Tm34",
121
+ "0xD755-7": "Beat Brock",
122
+ "0xD756-0": "078",
123
+ "0xD756-1": "079",
124
+ "0xD756-2": "07A",
125
+ "0xD756-3": "07B",
126
+ "0xD756-4": "07C",
127
+ "0xD756-5": "07D",
128
+ "0xD756-6": "07E",
129
+ "0xD756-7": "07F",
130
+ "0xD757-0": "080",
131
+ "0xD757-1": "081",
132
+ "0xD757-2": "082",
133
+ "0xD757-3": "083",
134
+ "0xD757-4": "084",
135
+ "0xD757-5": "085",
136
+ "0xD757-6": "086",
137
+ "0xD757-7": "087",
138
+ "0xD758-0": "088",
139
+ "0xD758-1": "089",
140
+ "0xD758-2": "08A",
141
+ "0xD758-3": "08B",
142
+ "0xD758-4": "08C",
143
+ "0xD758-5": "08D",
144
+ "0xD758-6": "08E",
145
+ "0xD758-7": "08F",
146
+ "0xD759-0": "090",
147
+ "0xD759-1": "091",
148
+ "0xD759-2": "092",
149
+ "0xD759-3": "093",
150
+ "0xD759-4": "094",
151
+ "0xD759-5": "095",
152
+ "0xD759-6": "096",
153
+ "0xD759-7": "097",
154
+ "0xD75A-0": "Beat Cerulean Rival",
155
+ "0xD75A-1": "099",
156
+ "0xD75A-2": "09A",
157
+ "0xD75A-3": "09B",
158
+ "0xD75A-4": "09C",
159
+ "0xD75A-5": "09D",
160
+ "0xD75A-6": "09E",
161
+ "0xD75A-7": "09F",
162
+ "0xD75B-0": "0A0",
163
+ "0xD75B-1": "0A1",
164
+ "0xD75B-2": "0A2",
165
+ "0xD75B-3": "0A3",
166
+ "0xD75B-4": "0A4",
167
+ "0xD75B-5": "0A5",
168
+ "0xD75B-6": "0A6",
169
+ "0xD75B-7": "Beat Cerulean Rocket Thief",
170
+ "0xD75C-0": "0A8",
171
+ "0xD75C-1": "0A9",
172
+ "0xD75C-2": "0Aa",
173
+ "0xD75C-3": "0Ab",
174
+ "0xD75C-4": "0Ac",
175
+ "0xD75C-5": "0Ad",
176
+ "0xD75C-6": "0Ae",
177
+ "0xD75C-7": "0Af",
178
+ "0xD75D-0": "0B0",
179
+ "0xD75D-1": "0B1",
180
+ "0xD75D-2": "0B2",
181
+ "0xD75D-3": "0B3",
182
+ "0xD75D-4": "0B4",
183
+ "0xD75D-5": "0B5",
184
+ "0xD75D-6": "0B6",
185
+ "0xD75D-7": "0B7",
186
+ "0xD75E-0": "0B8",
187
+ "0xD75E-1": "0B9",
188
+ "0xD75E-2": "Beat Cerulean Gym Trainer 0",
189
+ "0xD75E-3": "Beat Cerulean Gym Trainer 1",
190
+ "0xD75E-4": "0Bc",
191
+ "0xD75E-5": "0Bd",
192
+ "0xD75E-6": "Got Tm11",
193
+ "0xD75E-7": "Beat Misty",
194
+ "0xD75F-0": "Got Bicycle",
195
+ "0xD75F-1": "0C1",
196
+ "0xD75F-2": "0C2",
197
+ "0xD75F-3": "0C3",
198
+ "0xD75F-4": "0C4",
199
+ "0xD75F-5": "0C5",
200
+ "0xD75F-6": "0C6",
201
+ "0xD75F-7": "0C7",
202
+ "0xD760-0": "0C8",
203
+ "0xD760-1": "0C9",
204
+ "0xD760-2": "0Ca",
205
+ "0xD760-3": "0Cb",
206
+ "0xD760-4": "0Cc",
207
+ "0xD760-5": "0Cd",
208
+ "0xD760-6": "0Ce",
209
+ "0xD760-7": "0Cf",
210
+ "0xD761-0": "0D0",
211
+ "0xD761-1": "0D1",
212
+ "0xD761-2": "0D2",
213
+ "0xD761-3": "0D3",
214
+ "0xD761-4": "0D4",
215
+ "0xD761-5": "0D5",
216
+ "0xD761-6": "0D6",
217
+ "0xD761-7": "0D7",
218
+ "0xD762-0": "0D8",
219
+ "0xD762-1": "0D9",
220
+ "0xD762-2": "0Da",
221
+ "0xD762-3": "0Db",
222
+ "0xD762-4": "0Dc",
223
+ "0xD762-5": "0Dd",
224
+ "0xD762-6": "0De",
225
+ "0xD762-7": "0Df",
226
+ "0xD763-0": "0E0",
227
+ "0xD763-1": "0E1",
228
+ "0xD763-2": "0E2",
229
+ "0xD763-3": "0E3",
230
+ "0xD763-4": "0E4",
231
+ "0xD763-5": "0E5",
232
+ "0xD763-6": "0E6",
233
+ "0xD763-7": "0E7",
234
+ "0xD764-0": "0E8",
235
+ "0xD764-1": "0E9",
236
+ "0xD764-2": "0Ea",
237
+ "0xD764-3": "0Eb",
238
+ "0xD764-4": "0Ec",
239
+ "0xD764-5": "0Ed",
240
+ "0xD764-6": "Pokemon Tower Rival On Left",
241
+ "0xD764-7": "Beat Pokemon Tower Rival",
242
+ "0xD765-0": "0F0",
243
+ "0xD765-1": "Beat Pokemontower 3 Trainer 0",
244
+ "0xD765-2": "Beat Pokemontower 3 Trainer 1",
245
+ "0xD765-3": "Beat Pokemontower 3 Trainer 2",
246
+ "0xD765-4": "0F4",
247
+ "0xD765-5": "0F5",
248
+ "0xD765-6": "0F6",
249
+ "0xD765-7": "0F7",
250
+ "0xD766-0": "0F8",
251
+ "0xD766-1": "Beat Pokemontower 4 Trainer 0",
252
+ "0xD766-2": "Beat Pokemontower 4 Trainer 1",
253
+ "0xD766-3": "Beat Pokemontower 4 Trainer 2",
254
+ "0xD766-4": "0Fc",
255
+ "0xD766-5": "0Fd",
256
+ "0xD766-6": "0Fe",
257
+ "0xD766-7": "0Ff",
258
+ "0xD767-0": "100",
259
+ "0xD767-1": "101",
260
+ "0xD767-2": "Beat Pokemontower 5 Trainer 0",
261
+ "0xD767-3": "Beat Pokemontower 5 Trainer 1",
262
+ "0xD767-4": "Beat Pokemontower 5 Trainer 2",
263
+ "0xD767-5": "Beat Pokemontower 5 Trainer 3",
264
+ "0xD767-6": "106",
265
+ "0xD767-7": "In Purified Zone",
266
+ "0xD768-0": "108",
267
+ "0xD768-1": "Beat Pokemontower 6 Trainer 0",
268
+ "0xD768-2": "Beat Pokemontower 6 Trainer 1",
269
+ "0xD768-3": "Beat Pokemontower 6 Trainer 2",
270
+ "0xD768-4": "10C",
271
+ "0xD768-5": "10D",
272
+ "0xD768-6": "10E",
273
+ "0xD768-7": "Beat Ghost Marowak",
274
+ "0xD769-0": "110",
275
+ "0xD769-1": "Beat Pokemontower 7 Trainer 0",
276
+ "0xD769-2": "Beat Pokemontower 7 Trainer 1",
277
+ "0xD769-3": "Beat Pokemontower 7 Trainer 2",
278
+ "0xD769-4": "114",
279
+ "0xD769-5": "115",
280
+ "0xD769-6": "116",
281
+ "0xD769-7": "Rescued Mr Fuji 2",
282
+ "0xD76A-0": "118",
283
+ "0xD76A-1": "119",
284
+ "0xD76A-2": "11A",
285
+ "0xD76A-3": "11B",
286
+ "0xD76A-4": "11C",
287
+ "0xD76A-5": "11D",
288
+ "0xD76A-6": "11E",
289
+ "0xD76A-7": "11F",
290
+ "0xD76B-0": "120",
291
+ "0xD76B-1": "121",
292
+ "0xD76B-2": "122",
293
+ "0xD76B-3": "123",
294
+ "0xD76B-4": "124",
295
+ "0xD76B-5": "125",
296
+ "0xD76B-6": "126",
297
+ "0xD76B-7": "127",
298
+ "0xD76C-0": "Got Poke Flute",
299
+ "0xD76C-1": "129",
300
+ "0xD76C-2": "12A",
301
+ "0xD76C-3": "12B",
302
+ "0xD76C-4": "12C",
303
+ "0xD76C-5": "12D",
304
+ "0xD76C-6": "12E",
305
+ "0xD76C-7": "12F",
306
+ "0xD76D-0": "130",
307
+ "0xD76D-1": "131",
308
+ "0xD76D-2": "132",
309
+ "0xD76D-3": "133",
310
+ "0xD76D-4": "134",
311
+ "0xD76D-5": "135",
312
+ "0xD76D-6": "136",
313
+ "0xD76D-7": "137",
314
+ "0xD76E-0": "138",
315
+ "0xD76E-1": "139",
316
+ "0xD76E-2": "13A",
317
+ "0xD76E-3": "13B",
318
+ "0xD76E-4": "13C",
319
+ "0xD76E-5": "13D",
320
+ "0xD76E-6": "13E",
321
+ "0xD76E-7": "13F",
322
+ "0xD76F-0": "140",
323
+ "0xD76F-1": "141",
324
+ "0xD76F-2": "142",
325
+ "0xD76F-3": "143",
326
+ "0xD76F-4": "144",
327
+ "0xD76F-5": "145",
328
+ "0xD76F-6": "146",
329
+ "0xD76F-7": "147",
330
+ "0xD770-0": "148",
331
+ "0xD770-1": "149",
332
+ "0xD770-2": "14A",
333
+ "0xD770-3": "14B",
334
+ "0xD770-4": "14C",
335
+ "0xD770-5": "14D",
336
+ "0xD770-6": "14E",
337
+ "0xD770-7": "14F",
338
+ "0xD771-0": "150",
339
+ "0xD771-1": "Got Bike Voucher",
340
+ "0xD771-2": "152",
341
+ "0xD771-3": "153",
342
+ "0xD771-4": "154",
343
+ "0xD771-5": "155",
344
+ "0xD771-6": "Seel Fan Boast",
345
+ "0xD771-7": "Pikachu Fan Boast",
346
+ "0xD772-0": "158",
347
+ "0xD772-1": "159",
348
+ "0xD772-2": "15A",
349
+ "0xD772-3": "15B",
350
+ "0xD772-4": "15C",
351
+ "0xD772-5": "15D",
352
+ "0xD772-6": "15E",
353
+ "0xD772-7": "15F",
354
+ "0xD773-0": "2Nd Lock Opened",
355
+ "0xD773-1": "1St Lock Opened",
356
+ "0xD773-2": "Beat Vermilion Gym Trainer 0",
357
+ "0xD773-3": "Beat Vermilion Gym Trainer 1",
358
+ "0xD773-4": "Beat Vermilion Gym Trainer 2",
359
+ "0xD773-5": "165",
360
+ "0xD773-6": "Got Tm24",
361
+ "0xD773-7": "Beat Lt Surge",
362
+ "0xD774-0": "168",
363
+ "0xD774-1": "169",
364
+ "0xD774-2": "16A",
365
+ "0xD774-3": "16B",
366
+ "0xD774-4": "16C",
367
+ "0xD774-5": "16D",
368
+ "0xD774-6": "16E",
369
+ "0xD774-7": "16F",
370
+ "0xD775-0": "170",
371
+ "0xD775-1": "171",
372
+ "0xD775-2": "172",
373
+ "0xD775-3": "173",
374
+ "0xD775-4": "174",
375
+ "0xD775-5": "175",
376
+ "0xD775-6": "176",
377
+ "0xD775-7": "177",
378
+ "0xD776-0": "178",
379
+ "0xD776-1": "179",
380
+ "0xD776-2": "17A",
381
+ "0xD776-3": "17B",
382
+ "0xD776-4": "17C",
383
+ "0xD776-5": "17D",
384
+ "0xD776-6": "17E",
385
+ "0xD776-7": "17F",
386
+ "0xD777-0": "Got Tm41",
387
+ "0xD777-1": "181",
388
+ "0xD777-2": "182",
389
+ "0xD777-3": "183",
390
+ "0xD777-4": "184",
391
+ "0xD777-5": "185",
392
+ "0xD777-6": "186",
393
+ "0xD777-7": "187",
394
+ "0xD778-0": "188",
395
+ "0xD778-1": "189",
396
+ "0xD778-2": "18A",
397
+ "0xD778-3": "18B",
398
+ "0xD778-4": "Got Tm13",
399
+ "0xD778-5": "Got Tm48",
400
+ "0xD778-6": "Got Tm49",
401
+ "0xD778-7": "Got Tm18",
402
+ "0xD779-0": "190",
403
+ "0xD779-1": "191",
404
+ "0xD779-2": "192",
405
+ "0xD779-3": "193",
406
+ "0xD779-4": "194",
407
+ "0xD779-5": "195",
408
+ "0xD779-6": "196",
409
+ "0xD779-7": "197",
410
+ "0xD77A-0": "198",
411
+ "0xD77A-1": "199",
412
+ "0xD77A-2": "19A",
413
+ "0xD77A-3": "19B",
414
+ "0xD77A-4": "19C",
415
+ "0xD77A-5": "19D",
416
+ "0xD77A-6": "19E",
417
+ "0xD77A-7": "19F",
418
+ "0xD77B-0": "1A0",
419
+ "0xD77B-1": "1A1",
420
+ "0xD77B-2": "1A2",
421
+ "0xD77B-3": "1A3",
422
+ "0xD77B-4": "1A4",
423
+ "0xD77B-5": "1A5",
424
+ "0xD77B-6": "1A6",
425
+ "0xD77B-7": "1A7",
426
+ "0xD77C-0": "Got Tm21",
427
+ "0xD77C-1": "Beat Erika",
428
+ "0xD77C-2": "Beat Celadon Gym Trainer 0",
429
+ "0xD77C-3": "Beat Celadon Gym Trainer 1",
430
+ "0xD77C-4": "Beat Celadon Gym Trainer 2",
431
+ "0xD77C-5": "Beat Celadon Gym Trainer 3",
432
+ "0xD77C-6": "Beat Celadon Gym Trainer 4",
433
+ "0xD77C-7": "Beat Celadon Gym Trainer 5",
434
+ "0xD77D-0": "Beat Celadon Gym Trainer 6",
435
+ "0xD77D-1": "1B1",
436
+ "0xD77D-2": "1B2",
437
+ "0xD77D-3": "1B3",
438
+ "0xD77D-4": "1B4",
439
+ "0xD77D-5": "1B5",
440
+ "0xD77D-6": "1B6",
441
+ "0xD77D-7": "1B7",
442
+ "0xD77E-0": "1B8",
443
+ "0xD77E-1": "Found Rocket Hideout",
444
+ "0xD77E-2": "Got 10 Coins",
445
+ "0xD77E-3": "Got 20 Coins",
446
+ "0xD77E-4": "Got 20 Coins 2",
447
+ "0xD77E-5": "1Bd",
448
+ "0xD77E-6": "1Be",
449
+ "0xD77E-7": "1Bf",
450
+ "0xD77F-0": "1C0",
451
+ "0xD77F-1": "1C1",
452
+ "0xD77F-2": "1C2",
453
+ "0xD77F-3": "1C3",
454
+ "0xD77F-4": "1C4",
455
+ "0xD77F-5": "1C5",
456
+ "0xD77F-6": "1C6",
457
+ "0xD77F-7": "1C7",
458
+ "0xD780-0": "1C8",
459
+ "0xD780-1": "1C9",
460
+ "0xD780-2": "1Ca",
461
+ "0xD780-3": "1Cb",
462
+ "0xD780-4": "1Cc",
463
+ "0xD780-5": "1Cd",
464
+ "0xD780-6": "1Ce",
465
+ "0xD780-7": "1Cf",
466
+ "0xD781-0": "1D0",
467
+ "0xD781-1": "1D1",
468
+ "0xD781-2": "1D2",
469
+ "0xD781-3": "1D3",
470
+ "0xD781-4": "1D4",
471
+ "0xD781-5": "1D5",
472
+ "0xD781-6": "1D6",
473
+ "0xD781-7": "1D7",
474
+ "0xD782-0": "1D8",
475
+ "0xD782-1": "1D9",
476
+ "0xD782-2": "1Da",
477
+ "0xD782-3": "1Db",
478
+ "0xD782-4": "1Dc",
479
+ "0xD782-5": "1Dd",
480
+ "0xD782-6": "1De",
481
+ "0xD782-7": "1Df",
482
+ "0xD783-0": "Got Coin Case",
483
+ "0xD783-1": "1E1",
484
+ "0xD783-2": "1E2",
485
+ "0xD783-3": "1E3",
486
+ "0xD783-4": "1E4",
487
+ "0xD783-5": "1E5",
488
+ "0xD783-6": "1E6",
489
+ "0xD783-7": "1E7",
490
+ "0xD784-0": "1E8",
491
+ "0xD784-1": "1E9",
492
+ "0xD784-2": "1Ea",
493
+ "0xD784-3": "1Eb",
494
+ "0xD784-4": "1Ec",
495
+ "0xD784-5": "1Ed",
496
+ "0xD784-6": "1Ee",
497
+ "0xD784-7": "1Ef",
498
+ "0xD785-0": "1F0",
499
+ "0xD785-1": "1F1",
500
+ "0xD785-2": "1F2",
501
+ "0xD785-3": "1F3",
502
+ "0xD785-4": "1F4",
503
+ "0xD785-5": "1F5",
504
+ "0xD785-6": "1F6",
505
+ "0xD785-7": "1F7",
506
+ "0xD786-0": "1F8",
507
+ "0xD786-1": "1F9",
508
+ "0xD786-2": "1Fa",
509
+ "0xD786-3": "1Fb",
510
+ "0xD786-4": "1Fc",
511
+ "0xD786-5": "1Fd",
512
+ "0xD786-6": "1Fe",
513
+ "0xD786-7": "1Ff",
514
+ "0xD787-0": "200",
515
+ "0xD787-1": "201",
516
+ "0xD787-2": "202",
517
+ "0xD787-3": "203",
518
+ "0xD787-4": "204",
519
+ "0xD787-5": "205",
520
+ "0xD787-6": "206",
521
+ "0xD787-7": "207",
522
+ "0xD788-0": "208",
523
+ "0xD788-1": "209",
524
+ "0xD788-2": "20A",
525
+ "0xD788-3": "20B",
526
+ "0xD788-4": "20C",
527
+ "0xD788-5": "20D",
528
+ "0xD788-6": "20E",
529
+ "0xD788-7": "20F",
530
+ "0xD789-0": "210",
531
+ "0xD789-1": "211",
532
+ "0xD789-2": "212",
533
+ "0xD789-3": "213",
534
+ "0xD789-4": "214",
535
+ "0xD789-5": "215",
536
+ "0xD789-6": "216",
537
+ "0xD789-7": "217",
538
+ "0xD78A-0": "218",
539
+ "0xD78A-1": "219",
540
+ "0xD78A-2": "21A",
541
+ "0xD78A-3": "21B",
542
+ "0xD78A-4": "21C",
543
+ "0xD78A-5": "21D",
544
+ "0xD78A-6": "21E",
545
+ "0xD78A-7": "21F",
546
+ "0xD78B-0": "220",
547
+ "0xD78B-1": "221",
548
+ "0xD78B-2": "222",
549
+ "0xD78B-3": "223",
550
+ "0xD78B-4": "224",
551
+ "0xD78B-5": "225",
552
+ "0xD78B-6": "226",
553
+ "0xD78B-7": "227",
554
+ "0xD78C-0": "228",
555
+ "0xD78C-1": "229",
556
+ "0xD78C-2": "22A",
557
+ "0xD78C-3": "22B",
558
+ "0xD78C-4": "22C",
559
+ "0xD78C-5": "22D",
560
+ "0xD78C-6": "22E",
561
+ "0xD78C-7": "22F",
562
+ "0xD78D-0": "230",
563
+ "0xD78D-1": "231",
564
+ "0xD78D-2": "232",
565
+ "0xD78D-3": "233",
566
+ "0xD78D-4": "234",
567
+ "0xD78D-5": "235",
568
+ "0xD78D-6": "236",
569
+ "0xD78D-7": "237",
570
+ "0xD78E-0": "Got Hm04",
571
+ "0xD78E-1": "Gave Gold Teeth",
572
+ "0xD78E-2": "23A",
573
+ "0xD78E-3": "23B",
574
+ "0xD78E-4": "23C",
575
+ "0xD78E-5": "23D",
576
+ "0xD78E-6": "23E",
577
+ "0xD78E-7": "23F",
578
+ "0xD78F-0": "240",
579
+ "0xD78F-1": "241",
580
+ "0xD78F-2": "242",
581
+ "0xD78F-3": "243",
582
+ "0xD78F-4": "244",
583
+ "0xD78F-5": "245",
584
+ "0xD78F-6": "246",
585
+ "0xD78F-7": "247",
586
+ "0xD790-0": "248",
587
+ "0xD790-1": "249",
588
+ "0xD790-2": "24A",
589
+ "0xD790-3": "24B",
590
+ "0xD790-4": "24C",
591
+ "0xD790-5": "24D",
592
+ "0xD790-6": "Safari Game Over",
593
+ "0xD790-7": "In Safari Zone",
594
+ "0xD791-0": "250",
595
+ "0xD791-1": "251",
596
+ "0xD791-2": "252",
597
+ "0xD791-3": "253",
598
+ "0xD791-4": "254",
599
+ "0xD791-5": "255",
600
+ "0xD791-6": "256",
601
+ "0xD791-7": "257",
602
+ "0xD792-0": "Got Tm06",
603
+ "0xD792-1": "Beat Koga",
604
+ "0xD792-2": "Beat Fuchsia Gym Trainer 0",
605
+ "0xD792-3": "Beat Fuchsia Gym Trainer 1",
606
+ "0xD792-4": "Beat Fuchsia Gym Trainer 2",
607
+ "0xD792-5": "Beat Fuchsia Gym Trainer 3",
608
+ "0xD792-6": "Beat Fuchsia Gym Trainer 4",
609
+ "0xD792-7": "Beat Fuchsia Gym Trainer 5",
610
+ "0xD793-0": "260",
611
+ "0xD793-1": "261",
612
+ "0xD793-2": "262",
613
+ "0xD793-3": "263",
614
+ "0xD793-4": "264",
615
+ "0xD793-5": "265",
616
+ "0xD793-6": "266",
617
+ "0xD793-7": "267",
618
+ "0xD794-0": "268",
619
+ "0xD794-1": "269",
620
+ "0xD794-2": "26A",
621
+ "0xD794-3": "26B",
622
+ "0xD794-4": "26C",
623
+ "0xD794-5": "26D",
624
+ "0xD794-6": "26E",
625
+ "0xD794-7": "26F",
626
+ "0xD795-0": "270",
627
+ "0xD795-1": "271",
628
+ "0xD795-2": "272",
629
+ "0xD795-3": "273",
630
+ "0xD795-4": "274",
631
+ "0xD795-5": "275",
632
+ "0xD795-6": "276",
633
+ "0xD795-7": "277",
634
+ "0xD796-0": "Mansion Switch On",
635
+ "0xD796-1": "279",
636
+ "0xD796-2": "27A",
637
+ "0xD796-3": "27B",
638
+ "0xD796-4": "27C",
639
+ "0xD796-5": "27D",
640
+ "0xD796-6": "27E",
641
+ "0xD796-7": "27F",
642
+ "0xD797-0": "280",
643
+ "0xD797-1": "281",
644
+ "0xD797-2": "282",
645
+ "0xD797-3": "283",
646
+ "0xD797-4": "284",
647
+ "0xD797-5": "285",
648
+ "0xD797-6": "286",
649
+ "0xD797-7": "287",
650
+ "0xD798-0": "288",
651
+ "0xD798-1": "Beat Mansion 1 Trainer 0",
652
+ "0xD798-2": "28A",
653
+ "0xD798-3": "28B",
654
+ "0xD798-4": "28C",
655
+ "0xD798-5": "28D",
656
+ "0xD798-6": "28E",
657
+ "0xD798-7": "28F",
658
+ "0xD799-0": "290",
659
+ "0xD799-1": "291",
660
+ "0xD799-2": "292",
661
+ "0xD799-3": "293",
662
+ "0xD799-4": "294",
663
+ "0xD799-5": "295",
664
+ "0xD799-6": "296",
665
+ "0xD799-7": "297",
666
+ "0xD79A-0": "Got Tm38",
667
+ "0xD79A-1": "Beat Blaine",
668
+ "0xD79A-2": "Beat Cinnabar Gym Trainer 0",
669
+ "0xD79A-3": "Beat Cinnabar Gym Trainer 1",
670
+ "0xD79A-4": "Beat Cinnabar Gym Trainer 2",
671
+ "0xD79A-5": "Beat Cinnabar Gym Trainer 3",
672
+ "0xD79A-6": "Beat Cinnabar Gym Trainer 4",
673
+ "0xD79A-7": "Beat Cinnabar Gym Trainer 5",
674
+ "0xD79B-0": "Beat Cinnabar Gym Trainer 6",
675
+ "0xD79B-1": "2A1",
676
+ "0xD79B-2": "2A2",
677
+ "0xD79B-3": "2A3",
678
+ "0xD79B-4": "2A4",
679
+ "0xD79B-5": "2A5",
680
+ "0xD79B-6": "2A6",
681
+ "0xD79B-7": "2A7",
682
+ "0xD79C-0": "Cinnabar Gym Gate0 Unlocked",
683
+ "0xD79C-1": "Cinnabar Gym Gate1 Unlocked",
684
+ "0xD79C-2": "Cinnabar Gym Gate2 Unlocked",
685
+ "0xD79C-3": "Cinnabar Gym Gate3 Unlocked",
686
+ "0xD79C-4": "Cinnabar Gym Gate4 Unlocked",
687
+ "0xD79C-5": "Cinnabar Gym Gate5 Unlocked",
688
+ "0xD79C-6": "Cinnabar Gym Gate6 Unlocked",
689
+ "0xD79C-7": "2Af",
690
+ "0xD79D-0": "2B0",
691
+ "0xD79D-1": "2B1",
692
+ "0xD79D-2": "2B2",
693
+ "0xD79D-3": "2B3",
694
+ "0xD79D-4": "2B4",
695
+ "0xD79D-5": "2B5",
696
+ "0xD79D-6": "2B6",
697
+ "0xD79D-7": "2B7",
698
+ "0xD79E-0": "2B8",
699
+ "0xD79E-1": "2B9",
700
+ "0xD79E-2": "2Ba",
701
+ "0xD79E-3": "2Bb",
702
+ "0xD79E-4": "2Bc",
703
+ "0xD79E-5": "2Bd",
704
+ "0xD79E-6": "2Be",
705
+ "0xD79E-7": "2Bf",
706
+ "0xD79F-0": "2C0",
707
+ "0xD79F-1": "2C1",
708
+ "0xD79F-2": "2C2",
709
+ "0xD79F-3": "2C3",
710
+ "0xD79F-4": "2C4",
711
+ "0xD79F-5": "2C5",
712
+ "0xD79F-6": "2C6",
713
+ "0xD79F-7": "2C7",
714
+ "0xD7A0-0": "2C8",
715
+ "0xD7A0-1": "2C9",
716
+ "0xD7A0-2": "2Ca",
717
+ "0xD7A0-3": "2Cb",
718
+ "0xD7A0-4": "2Cc",
719
+ "0xD7A0-5": "2Cd",
720
+ "0xD7A0-6": "2Ce",
721
+ "0xD7A0-7": "2Cf",
722
+ "0xD7A1-0": "2D0",
723
+ "0xD7A1-1": "2D1",
724
+ "0xD7A1-2": "2D2",
725
+ "0xD7A1-3": "2D3",
726
+ "0xD7A1-4": "2D4",
727
+ "0xD7A1-5": "2D5",
728
+ "0xD7A1-6": "2D6",
729
+ "0xD7A1-7": "Got Tm35",
730
+ "0xD7A2-0": "2D8",
731
+ "0xD7A2-1": "2D9",
732
+ "0xD7A2-2": "2Da",
733
+ "0xD7A2-3": "2Db",
734
+ "0xD7A2-4": "2Dc",
735
+ "0xD7A2-5": "2Dd",
736
+ "0xD7A2-6": "2De",
737
+ "0xD7A2-7": "2Df",
738
+ "0xD7A3-0": "Gave Fossil To Lab",
739
+ "0xD7A3-1": "Lab Still Reviving Fossil",
740
+ "0xD7A3-2": "Lab Handing Over Fossil Mon",
741
+ "0xD7A3-3": "2E3",
742
+ "0xD7A3-4": "2E4",
743
+ "0xD7A3-5": "2E5",
744
+ "0xD7A3-6": "2E6",
745
+ "0xD7A3-7": "2E7",
746
+ "0xD7A4-0": "2E8",
747
+ "0xD7A4-1": "2E9",
748
+ "0xD7A4-2": "2Ea",
749
+ "0xD7A4-3": "2Eb",
750
+ "0xD7A4-4": "2Ec",
751
+ "0xD7A4-5": "2Ed",
752
+ "0xD7A4-6": "2Ee",
753
+ "0xD7A4-7": "2Ef",
754
+ "0xD7A5-0": "2F0",
755
+ "0xD7A5-1": "2F1",
756
+ "0xD7A5-2": "2F2",
757
+ "0xD7A5-3": "2F3",
758
+ "0xD7A5-4": "2F4",
759
+ "0xD7A5-5": "2F5",
760
+ "0xD7A5-6": "2F6",
761
+ "0xD7A5-7": "2F7",
762
+ "0xD7A6-0": "2F8",
763
+ "0xD7A6-1": "2F9",
764
+ "0xD7A6-2": "2Fa",
765
+ "0xD7A6-3": "2Fb",
766
+ "0xD7A6-4": "2Fc",
767
+ "0xD7A6-5": "2Fd",
768
+ "0xD7A6-6": "2Fe",
769
+ "0xD7A6-7": "2Ff",
770
+ "0xD7A7-0": "300",
771
+ "0xD7A7-1": "301",
772
+ "0xD7A7-2": "302",
773
+ "0xD7A7-3": "303",
774
+ "0xD7A7-4": "304",
775
+ "0xD7A7-5": "305",
776
+ "0xD7A7-6": "306",
777
+ "0xD7A7-7": "307",
778
+ "0xD7A8-0": "308",
779
+ "0xD7A8-1": "309",
780
+ "0xD7A8-2": "30A",
781
+ "0xD7A8-3": "30B",
782
+ "0xD7A8-4": "30C",
783
+ "0xD7A8-5": "30D",
784
+ "0xD7A8-6": "30E",
785
+ "0xD7A8-7": "30F",
786
+ "0xD7A9-0": "310",
787
+ "0xD7A9-1": "311",
788
+ "0xD7A9-2": "312",
789
+ "0xD7A9-3": "313",
790
+ "0xD7A9-4": "314",
791
+ "0xD7A9-5": "315",
792
+ "0xD7A9-6": "316",
793
+ "0xD7A9-7": "317",
794
+ "0xD7AA-0": "318",
795
+ "0xD7AA-1": "319",
796
+ "0xD7AA-2": "31A",
797
+ "0xD7AA-3": "31B",
798
+ "0xD7AA-4": "31C",
799
+ "0xD7AA-5": "31D",
800
+ "0xD7AA-6": "31E",
801
+ "0xD7AA-7": "31F",
802
+ "0xD7AB-0": "320",
803
+ "0xD7AB-1": "321",
804
+ "0xD7AB-2": "322",
805
+ "0xD7AB-3": "323",
806
+ "0xD7AB-4": "324",
807
+ "0xD7AB-5": "325",
808
+ "0xD7AB-6": "326",
809
+ "0xD7AB-7": "327",
810
+ "0xD7AC-0": "328",
811
+ "0xD7AC-1": "329",
812
+ "0xD7AC-2": "32A",
813
+ "0xD7AC-3": "32B",
814
+ "0xD7AC-4": "32C",
815
+ "0xD7AC-5": "32D",
816
+ "0xD7AC-6": "32E",
817
+ "0xD7AC-7": "32F",
818
+ "0xD7AD-0": "330",
819
+ "0xD7AD-1": "331",
820
+ "0xD7AD-2": "332",
821
+ "0xD7AD-3": "333",
822
+ "0xD7AD-4": "334",
823
+ "0xD7AD-5": "335",
824
+ "0xD7AD-6": "336",
825
+ "0xD7AD-7": "337",
826
+ "0xD7AE-0": "338",
827
+ "0xD7AE-1": "339",
828
+ "0xD7AE-2": "33A",
829
+ "0xD7AE-3": "33B",
830
+ "0xD7AE-4": "33C",
831
+ "0xD7AE-5": "33D",
832
+ "0xD7AE-6": "33E",
833
+ "0xD7AE-7": "33F",
834
+ "0xD7AF-0": "Got Tm31",
835
+ "0xD7AF-1": "341",
836
+ "0xD7AF-2": "342",
837
+ "0xD7AF-3": "343",
838
+ "0xD7AF-4": "344",
839
+ "0xD7AF-5": "345",
840
+ "0xD7AF-6": "346",
841
+ "0xD7AF-7": "347",
842
+ "0xD7B0-0": "348",
843
+ "0xD7B0-1": "349",
844
+ "0xD7B0-2": "34A",
845
+ "0xD7B0-3": "34B",
846
+ "0xD7B0-4": "34C",
847
+ "0xD7B0-5": "34D",
848
+ "0xD7B0-6": "34E",
849
+ "0xD7B0-7": "34F",
850
+ "0xD7B1-0": "Defeated Fighting Dojo",
851
+ "0xD7B1-1": "Beat Karate Master",
852
+ "0xD7B1-2": "Beat Fighting Dojo Trainer 0",
853
+ "0xD7B1-3": "Beat Fighting Dojo Trainer 1",
854
+ "0xD7B1-4": "Beat Fighting Dojo Trainer 2",
855
+ "0xD7B1-5": "Beat Fighting Dojo Trainer 3",
856
+ "0xD7B1-6": "Got Hitmonlee",
857
+ "0xD7B1-7": "Got Hitmonchan",
858
+ "0xD7B2-0": "358",
859
+ "0xD7B2-1": "359",
860
+ "0xD7B2-2": "35A",
861
+ "0xD7B2-3": "35B",
862
+ "0xD7B2-4": "35C",
863
+ "0xD7B2-5": "35D",
864
+ "0xD7B2-6": "35E",
865
+ "0xD7B2-7": "35F",
866
+ "0xD7B3-0": "Got Tm46",
867
+ "0xD7B3-1": "Beat Sabrina",
868
+ "0xD7B3-2": "Beat Saffron Gym Trainer 0",
869
+ "0xD7B3-3": "Beat Saffron Gym Trainer 1",
870
+ "0xD7B3-4": "Beat Saffron Gym Trainer 2",
871
+ "0xD7B3-5": "Beat Saffron Gym Trainer 3",
872
+ "0xD7B3-6": "Beat Saffron Gym Trainer 4",
873
+ "0xD7B3-7": "Beat Saffron Gym Trainer 5",
874
+ "0xD7B4-0": "Beat Saffron Gym Trainer 6",
875
+ "0xD7B4-1": "369",
876
+ "0xD7B4-2": "36A",
877
+ "0xD7B4-3": "36B",
878
+ "0xD7B4-4": "36C",
879
+ "0xD7B4-5": "36D",
880
+ "0xD7B4-6": "36E",
881
+ "0xD7B4-7": "36F",
882
+ "0xD7B5-0": "370",
883
+ "0xD7B5-1": "371",
884
+ "0xD7B5-2": "372",
885
+ "0xD7B5-3": "373",
886
+ "0xD7B5-4": "374",
887
+ "0xD7B5-5": "375",
888
+ "0xD7B5-6": "376",
889
+ "0xD7B5-7": "377",
890
+ "0xD7B6-0": "378",
891
+ "0xD7B6-1": "379",
892
+ "0xD7B6-2": "37A",
893
+ "0xD7B6-3": "37B",
894
+ "0xD7B6-4": "37C",
895
+ "0xD7B6-5": "37D",
896
+ "0xD7B6-6": "37E",
897
+ "0xD7B6-7": "37F",
898
+ "0xD7B7-0": "380",
899
+ "0xD7B7-1": "381",
900
+ "0xD7B7-2": "382",
901
+ "0xD7B7-3": "383",
902
+ "0xD7B7-4": "384",
903
+ "0xD7B7-5": "385",
904
+ "0xD7B7-6": "386",
905
+ "0xD7B7-7": "387",
906
+ "0xD7B8-0": "388",
907
+ "0xD7B8-1": "389",
908
+ "0xD7B8-2": "38A",
909
+ "0xD7B8-3": "38B",
910
+ "0xD7B8-4": "38C",
911
+ "0xD7B8-5": "38D",
912
+ "0xD7B8-6": "38E",
913
+ "0xD7B8-7": "38F",
914
+ "0xD7B9-0": "390",
915
+ "0xD7B9-1": "391",
916
+ "0xD7B9-2": "392",
917
+ "0xD7B9-3": "393",
918
+ "0xD7B9-4": "394",
919
+ "0xD7B9-5": "395",
920
+ "0xD7B9-6": "396",
921
+ "0xD7B9-7": "Silph Co Receptionist At Desk",
922
+ "0xD7BA-0": "398",
923
+ "0xD7BA-1": "399",
924
+ "0xD7BA-2": "39A",
925
+ "0xD7BA-3": "39B",
926
+ "0xD7BA-4": "39C",
927
+ "0xD7BA-5": "39D",
928
+ "0xD7BA-6": "39E",
929
+ "0xD7BA-7": "39F",
930
+ "0xD7BB-0": "3A0",
931
+ "0xD7BB-1": "3A1",
932
+ "0xD7BB-2": "3A2",
933
+ "0xD7BB-3": "3A3",
934
+ "0xD7BB-4": "3A4",
935
+ "0xD7BB-5": "3A5",
936
+ "0xD7BB-6": "3A6",
937
+ "0xD7BB-7": "3A7",
938
+ "0xD7BC-0": "3A8",
939
+ "0xD7BC-1": "3A9",
940
+ "0xD7BC-2": "3Aa",
941
+ "0xD7BC-3": "3Ab",
942
+ "0xD7BC-4": "3Ac",
943
+ "0xD7BC-5": "3Ad",
944
+ "0xD7BC-6": "3Ae",
945
+ "0xD7BC-7": "3Af",
946
+ "0xD7BD-0": "Got Tm29",
947
+ "0xD7BD-1": "3B1",
948
+ "0xD7BD-2": "3B2",
949
+ "0xD7BD-3": "3B3",
950
+ "0xD7BD-4": "3B4",
951
+ "0xD7BD-5": "3B5",
952
+ "0xD7BD-6": "3B6",
953
+ "0xD7BD-7": "3B7",
954
+ "0xD7BE-0": "3B8",
955
+ "0xD7BE-1": "3B9",
956
+ "0xD7BE-2": "3Ba",
957
+ "0xD7BE-3": "3Bb",
958
+ "0xD7BE-4": "3Bc",
959
+ "0xD7BE-5": "3Bd",
960
+ "0xD7BE-6": "3Be",
961
+ "0xD7BE-7": "3Bf",
962
+ "0xD7BF-0": "Got Potion Sample",
963
+ "0xD7BF-1": "3C1",
964
+ "0xD7BF-2": "3C2",
965
+ "0xD7BF-3": "3C3",
966
+ "0xD7BF-4": "3C4",
967
+ "0xD7BF-5": "3C5",
968
+ "0xD7BF-6": "3C6",
969
+ "0xD7BF-7": "3C7",
970
+ "0xD7C0-0": "3C8",
971
+ "0xD7C0-1": "3C9",
972
+ "0xD7C0-2": "3Ca",
973
+ "0xD7C0-3": "3Cb",
974
+ "0xD7C0-4": "3Cc",
975
+ "0xD7C0-5": "3Cd",
976
+ "0xD7C0-6": "3Ce",
977
+ "0xD7C0-7": "3Cf",
978
+ "0xD7C1-0": "3D0",
979
+ "0xD7C1-1": "3D1",
980
+ "0xD7C1-2": "3D2",
981
+ "0xD7C1-3": "3D3",
982
+ "0xD7C1-4": "3D4",
983
+ "0xD7C1-5": "3D5",
984
+ "0xD7C1-6": "3D6",
985
+ "0xD7C1-7": "3D7",
986
+ "0xD7C2-0": "Got Hm05",
987
+ "0xD7C2-1": "3D9",
988
+ "0xD7C2-2": "3Da",
989
+ "0xD7C2-3": "3Db",
990
+ "0xD7C2-4": "3Dc",
991
+ "0xD7C2-5": "3Dd",
992
+ "0xD7C2-6": "3De",
993
+ "0xD7C2-7": "3Df",
994
+ "0xD7C3-0": "3E0",
995
+ "0xD7C3-1": "3E1",
996
+ "0xD7C3-2": "Beat Route 3 Trainer 0",
997
+ "0xD7C3-3": "Beat Route 3 Trainer 1",
998
+ "0xD7C3-4": "Beat Route 3 Trainer 2",
999
+ "0xD7C3-5": "Beat Route 3 Trainer 3",
1000
+ "0xD7C3-6": "Beat Route 3 Trainer 4",
1001
+ "0xD7C3-7": "Beat Route 3 Trainer 5",
1002
+ "0xD7C4-0": "Beat Route 3 Trainer 6",
1003
+ "0xD7C4-1": "Beat Route 3 Trainer 7",
1004
+ "0xD7C4-2": "3Ea",
1005
+ "0xD7C4-3": "3Eb",
1006
+ "0xD7C4-4": "3Ec",
1007
+ "0xD7C4-5": "3Ed",
1008
+ "0xD7C4-6": "3Ee",
1009
+ "0xD7C4-7": "3Ef",
1010
+ "0xD7C5-0": "3F0",
1011
+ "0xD7C5-1": "3F1",
1012
+ "0xD7C5-2": "Beat Route 4 Trainer 0",
1013
+ "0xD7C5-3": "3F3",
1014
+ "0xD7C5-4": "3F4",
1015
+ "0xD7C5-5": "3F5",
1016
+ "0xD7C5-6": "3F6",
1017
+ "0xD7C5-7": "3F7",
1018
+ "0xD7C6-0": "3F8",
1019
+ "0xD7C6-1": "3F9",
1020
+ "0xD7C6-2": "3Fa",
1021
+ "0xD7C6-3": "3Fb",
1022
+ "0xD7C6-4": "3Fc",
1023
+ "0xD7C6-5": "3Fd",
1024
+ "0xD7C6-6": "3Fe",
1025
+ "0xD7C6-7": "Bought Magikarp",
1026
+ "0xD7C7-0": "400",
1027
+ "0xD7C7-1": "401",
1028
+ "0xD7C7-2": "402",
1029
+ "0xD7C7-3": "403",
1030
+ "0xD7C7-4": "404",
1031
+ "0xD7C7-5": "405",
1032
+ "0xD7C7-6": "406",
1033
+ "0xD7C7-7": "407",
1034
+ "0xD7C8-0": "408",
1035
+ "0xD7C8-1": "409",
1036
+ "0xD7C8-2": "40A",
1037
+ "0xD7C8-3": "40B",
1038
+ "0xD7C8-4": "40C",
1039
+ "0xD7C8-5": "40D",
1040
+ "0xD7C8-6": "40E",
1041
+ "0xD7C8-7": "40F",
1042
+ "0xD7C9-0": "410",
1043
+ "0xD7C9-1": "Beat Route 6 Trainer 0",
1044
+ "0xD7C9-2": "Beat Route 6 Trainer 1",
1045
+ "0xD7C9-3": "Beat Route 6 Trainer 2",
1046
+ "0xD7C9-4": "Beat Route 6 Trainer 3",
1047
+ "0xD7C9-5": "Beat Route 6 Trainer 4",
1048
+ "0xD7C9-6": "Beat Route 6 Trainer 5",
1049
+ "0xD7C9-7": "417",
1050
+ "0xD7CA-0": "418",
1051
+ "0xD7CA-1": "419",
1052
+ "0xD7CA-2": "41A",
1053
+ "0xD7CA-3": "41B",
1054
+ "0xD7CA-4": "41C",
1055
+ "0xD7CA-5": "41D",
1056
+ "0xD7CA-6": "41E",
1057
+ "0xD7CA-7": "41F",
1058
+ "0xD7CB-0": "420",
1059
+ "0xD7CB-1": "421",
1060
+ "0xD7CB-2": "422",
1061
+ "0xD7CB-3": "423",
1062
+ "0xD7CB-4": "424",
1063
+ "0xD7CB-5": "425",
1064
+ "0xD7CB-6": "426",
1065
+ "0xD7CB-7": "427",
1066
+ "0xD7CC-0": "428",
1067
+ "0xD7CC-1": "429",
1068
+ "0xD7CC-2": "42A",
1069
+ "0xD7CC-3": "42B",
1070
+ "0xD7CC-4": "42C",
1071
+ "0xD7CC-5": "42D",
1072
+ "0xD7CC-6": "42E",
1073
+ "0xD7CC-7": "42F",
1074
+ "0xD7CD-0": "430",
1075
+ "0xD7CD-1": "Beat Route 8 Trainer 0",
1076
+ "0xD7CD-2": "Beat Route 8 Trainer 1",
1077
+ "0xD7CD-3": "Beat Route 8 Trainer 2",
1078
+ "0xD7CD-4": "Beat Route 8 Trainer 3",
1079
+ "0xD7CD-5": "Beat Route 8 Trainer 4",
1080
+ "0xD7CD-6": "Beat Route 8 Trainer 5",
1081
+ "0xD7CD-7": "Beat Route 8 Trainer 6",
1082
+ "0xD7CE-0": "Beat Route 8 Trainer 7",
1083
+ "0xD7CE-1": "Beat Route 8 Trainer 8",
1084
+ "0xD7CE-2": "43A",
1085
+ "0xD7CE-3": "43B",
1086
+ "0xD7CE-4": "43C",
1087
+ "0xD7CE-5": "43D",
1088
+ "0xD7CE-6": "43E",
1089
+ "0xD7CE-7": "43F",
1090
+ "0xD7CF-0": "440",
1091
+ "0xD7CF-1": "Beat Route 9 Trainer 0",
1092
+ "0xD7CF-2": "Beat Route 9 Trainer 1",
1093
+ "0xD7CF-3": "Beat Route 9 Trainer 2",
1094
+ "0xD7CF-4": "Beat Route 9 Trainer 3",
1095
+ "0xD7CF-5": "Beat Route 9 Trainer 4",
1096
+ "0xD7CF-6": "Beat Route 9 Trainer 5",
1097
+ "0xD7CF-7": "Beat Route 9 Trainer 6",
1098
+ "0xD7D0-0": "Beat Route 9 Trainer 7",
1099
+ "0xD7D0-1": "Beat Route 9 Trainer 8",
1100
+ "0xD7D0-2": "44A",
1101
+ "0xD7D0-3": "44B",
1102
+ "0xD7D0-4": "44C",
1103
+ "0xD7D0-5": "44D",
1104
+ "0xD7D0-6": "44E",
1105
+ "0xD7D0-7": "44F",
1106
+ "0xD7D1-0": "450",
1107
+ "0xD7D1-1": "Beat Route 10 Trainer 0",
1108
+ "0xD7D1-2": "Beat Route 10 Trainer 1",
1109
+ "0xD7D1-3": "Beat Route 10 Trainer 2",
1110
+ "0xD7D1-4": "Beat Route 10 Trainer 3",
1111
+ "0xD7D1-5": "Beat Route 10 Trainer 4",
1112
+ "0xD7D1-6": "Beat Route 10 Trainer 5",
1113
+ "0xD7D1-7": "457",
1114
+ "0xD7D2-0": "458",
1115
+ "0xD7D2-1": "Beat Rock Tunnel 1 Trainer 0",
1116
+ "0xD7D2-2": "Beat Rock Tunnel 1 Trainer 1",
1117
+ "0xD7D2-3": "Beat Rock Tunnel 1 Trainer 2",
1118
+ "0xD7D2-4": "Beat Rock Tunnel 1 Trainer 3",
1119
+ "0xD7D2-5": "Beat Rock Tunnel 1 Trainer 4",
1120
+ "0xD7D2-6": "Beat Rock Tunnel 1 Trainer 5",
1121
+ "0xD7D2-7": "Beat Rock Tunnel 1 Trainer 6",
1122
+ "0xD7D3-0": "460",
1123
+ "0xD7D3-1": "Beat Power Plant Voltorb 0",
1124
+ "0xD7D3-2": "Beat Power Plant Voltorb 1",
1125
+ "0xD7D3-3": "Beat Power Plant Voltorb 2",
1126
+ "0xD7D3-4": "Beat Power Plant Voltorb 3",
1127
+ "0xD7D3-5": "Beat Power Plant Voltorb 4",
1128
+ "0xD7D3-6": "Beat Power Plant Voltorb 5",
1129
+ "0xD7D3-7": "Beat Power Plant Voltorb 6",
1130
+ "0xD7D4-0": "Beat Power Plant Voltorb 7",
1131
+ "0xD7D4-1": "Beat Zapdos",
1132
+ "0xD7D4-2": "46A",
1133
+ "0xD7D4-3": "46B",
1134
+ "0xD7D4-4": "46C",
1135
+ "0xD7D4-5": "46D",
1136
+ "0xD7D4-6": "46E",
1137
+ "0xD7D4-7": "46F",
1138
+ "0xD7D5-0": "470",
1139
+ "0xD7D5-1": "Beat Route 11 Trainer 0",
1140
+ "0xD7D5-2": "Beat Route 11 Trainer 1",
1141
+ "0xD7D5-3": "Beat Route 11 Trainer 2",
1142
+ "0xD7D5-4": "Beat Route 11 Trainer 3",
1143
+ "0xD7D5-5": "Beat Route 11 Trainer 4",
1144
+ "0xD7D5-6": "Beat Route 11 Trainer 5",
1145
+ "0xD7D5-7": "Beat Route 11 Trainer 6",
1146
+ "0xD7D6-0": "Beat Route 11 Trainer 7",
1147
+ "0xD7D6-1": "Beat Route 11 Trainer 8",
1148
+ "0xD7D6-2": "Beat Route 11 Trainer 9",
1149
+ "0xD7D6-3": "47B",
1150
+ "0xD7D6-4": "47C",
1151
+ "0xD7D6-5": "47D",
1152
+ "0xD7D6-6": "47E",
1153
+ "0xD7D6-7": "Got Itemfinder",
1154
+ "0xD7D7-0": "Got Tm39",
1155
+ "0xD7D7-1": "481",
1156
+ "0xD7D7-2": "Beat Route 12 Trainer 0",
1157
+ "0xD7D7-3": "Beat Route 12 Trainer 1",
1158
+ "0xD7D7-4": "Beat Route 12 Trainer 2",
1159
+ "0xD7D7-5": "Beat Route 12 Trainer 3",
1160
+ "0xD7D7-6": "Beat Route 12 Trainer 4",
1161
+ "0xD7D7-7": "Beat Route 12 Trainer 5",
1162
+ "0xD7D8-0": "Beat Route 12 Trainer 6",
1163
+ "0xD7D8-1": "489",
1164
+ "0xD7D8-2": "48A",
1165
+ "0xD7D8-3": "48B",
1166
+ "0xD7D8-4": "48C",
1167
+ "0xD7D8-5": "48D",
1168
+ "0xD7D8-6": "Fight Route12 Snorlax",
1169
+ "0xD7D8-7": "Beat Route12 Snorlax",
1170
+ "0xD7D9-0": "490",
1171
+ "0xD7D9-1": "Beat Route 13 Trainer 0",
1172
+ "0xD7D9-2": "Beat Route 13 Trainer 1",
1173
+ "0xD7D9-3": "Beat Route 13 Trainer 2",
1174
+ "0xD7D9-4": "Beat Route 13 Trainer 3",
1175
+ "0xD7D9-5": "Beat Route 13 Trainer 4",
1176
+ "0xD7D9-6": "Beat Route 13 Trainer 5",
1177
+ "0xD7D9-7": "Beat Route 13 Trainer 6",
1178
+ "0xD7DA-0": "Beat Route 13 Trainer 7",
1179
+ "0xD7DA-1": "Beat Route 13 Trainer 8",
1180
+ "0xD7DA-2": "Beat Route 13 Trainer 9",
1181
+ "0xD7DA-3": "49B",
1182
+ "0xD7DA-4": "49C",
1183
+ "0xD7DA-5": "49D",
1184
+ "0xD7DA-6": "49E",
1185
+ "0xD7DA-7": "49F",
1186
+ "0xD7DB-0": "4A0",
1187
+ "0xD7DB-1": "Beat Route 14 Trainer 0",
1188
+ "0xD7DB-2": "Beat Route 14 Trainer 1",
1189
+ "0xD7DB-3": "Beat Route 14 Trainer 2",
1190
+ "0xD7DB-4": "Beat Route 14 Trainer 3",
1191
+ "0xD7DB-5": "Beat Route 14 Trainer 4",
1192
+ "0xD7DB-6": "Beat Route 14 Trainer 5",
1193
+ "0xD7DB-7": "Beat Route 14 Trainer 6",
1194
+ "0xD7DC-0": "Beat Route 14 Trainer 7",
1195
+ "0xD7DC-1": "Beat Route 14 Trainer 8",
1196
+ "0xD7DC-2": "Beat Route 14 Trainer 9",
1197
+ "0xD7DC-3": "4Ab",
1198
+ "0xD7DC-4": "4Ac",
1199
+ "0xD7DC-5": "4Ad",
1200
+ "0xD7DC-6": "4Ae",
1201
+ "0xD7DC-7": "4Af",
1202
+ "0xD7DD-0": "Got Exp All",
1203
+ "0xD7DD-1": "Beat Route 15 Trainer 0",
1204
+ "0xD7DD-2": "Beat Route 15 Trainer 1",
1205
+ "0xD7DD-3": "Beat Route 15 Trainer 2",
1206
+ "0xD7DD-4": "Beat Route 15 Trainer 3",
1207
+ "0xD7DD-5": "Beat Route 15 Trainer 4",
1208
+ "0xD7DD-6": "Beat Route 15 Trainer 5",
1209
+ "0xD7DD-7": "Beat Route 15 Trainer 6",
1210
+ "0xD7DE-0": "Beat Route 15 Trainer 7",
1211
+ "0xD7DE-1": "Beat Route 15 Trainer 8",
1212
+ "0xD7DE-2": "Beat Route 15 Trainer 9",
1213
+ "0xD7DE-3": "4Bb",
1214
+ "0xD7DE-4": "4Bc",
1215
+ "0xD7DE-5": "4Bd",
1216
+ "0xD7DE-6": "4Be",
1217
+ "0xD7DE-7": "4Bf",
1218
+ "0xD7DF-0": "4C0",
1219
+ "0xD7DF-1": "Beat Route 16 Trainer 0",
1220
+ "0xD7DF-2": "Beat Route 16 Trainer 1",
1221
+ "0xD7DF-3": "Beat Route 16 Trainer 2",
1222
+ "0xD7DF-4": "Beat Route 16 Trainer 3",
1223
+ "0xD7DF-5": "Beat Route 16 Trainer 4",
1224
+ "0xD7DF-6": "Beat Route 16 Trainer 5",
1225
+ "0xD7DF-7": "4C7",
1226
+ "0xD7E0-0": "Fight Route16 Snorlax",
1227
+ "0xD7E0-1": "Beat Route16 Snorlax",
1228
+ "0xD7E0-2": "4Ca",
1229
+ "0xD7E0-3": "4Cb",
1230
+ "0xD7E0-4": "4Cc",
1231
+ "0xD7E0-5": "4Cd",
1232
+ "0xD7E0-6": "Got Hm02",
1233
+ "0xD7E0-7": "Rescued Mr Fuji",
1234
+ "0xD7E1-0": "4D0",
1235
+ "0xD7E1-1": "Beat Route 17 Trainer 0",
1236
+ "0xD7E1-2": "Beat Route 17 Trainer 1",
1237
+ "0xD7E1-3": "Beat Route 17 Trainer 2",
1238
+ "0xD7E1-4": "Beat Route 17 Trainer 3",
1239
+ "0xD7E1-5": "Beat Route 17 Trainer 4",
1240
+ "0xD7E1-6": "Beat Route 17 Trainer 5",
1241
+ "0xD7E1-7": "Beat Route 17 Trainer 6",
1242
+ "0xD7E2-0": "Beat Route 17 Trainer 7",
1243
+ "0xD7E2-1": "Beat Route 17 Trainer 8",
1244
+ "0xD7E2-2": "Beat Route 17 Trainer 9",
1245
+ "0xD7E2-3": "4Db",
1246
+ "0xD7E2-4": "4Dc",
1247
+ "0xD7E2-5": "4Dd",
1248
+ "0xD7E2-6": "4De",
1249
+ "0xD7E2-7": "4Df",
1250
+ "0xD7E3-0": "4E0",
1251
+ "0xD7E3-1": "Beat Route 18 Trainer 0",
1252
+ "0xD7E3-2": "Beat Route 18 Trainer 1",
1253
+ "0xD7E3-3": "Beat Route 18 Trainer 2",
1254
+ "0xD7E3-4": "4E4",
1255
+ "0xD7E3-5": "4E5",
1256
+ "0xD7E3-6": "4E6",
1257
+ "0xD7E3-7": "4E7",
1258
+ "0xD7E4-0": "4E8",
1259
+ "0xD7E4-1": "4E9",
1260
+ "0xD7E4-2": "4Ea",
1261
+ "0xD7E4-3": "4Eb",
1262
+ "0xD7E4-4": "4Ec",
1263
+ "0xD7E4-5": "4Ed",
1264
+ "0xD7E4-6": "4Ee",
1265
+ "0xD7E4-7": "4Ef",
1266
+ "0xD7E5-0": "4F0",
1267
+ "0xD7E5-1": "Beat Route 19 Trainer 0",
1268
+ "0xD7E5-2": "Beat Route 19 Trainer 1",
1269
+ "0xD7E5-3": "Beat Route 19 Trainer 2",
1270
+ "0xD7E5-4": "Beat Route 19 Trainer 3",
1271
+ "0xD7E5-5": "Beat Route 19 Trainer 4",
1272
+ "0xD7E5-6": "Beat Route 19 Trainer 5",
1273
+ "0xD7E5-7": "Beat Route 19 Trainer 6",
1274
+ "0xD7E6-0": "Beat Route 19 Trainer 7",
1275
+ "0xD7E6-1": "Beat Route 19 Trainer 8",
1276
+ "0xD7E6-2": "Beat Route 19 Trainer 9",
1277
+ "0xD7E6-3": "4Fb",
1278
+ "0xD7E6-4": "4Fc",
1279
+ "0xD7E6-5": "4Fd",
1280
+ "0xD7E6-6": "4Fe",
1281
+ "0xD7E6-7": "4Ff",
1282
+ "0xD7E7-0": "In Seafoam Islands",
1283
+ "0xD7E7-1": "Beat Route 20 Trainer 0",
1284
+ "0xD7E7-2": "Beat Route 20 Trainer 1",
1285
+ "0xD7E7-3": "Beat Route 20 Trainer 2",
1286
+ "0xD7E7-4": "Beat Route 20 Trainer 3",
1287
+ "0xD7E7-5": "Beat Route 20 Trainer 4",
1288
+ "0xD7E7-6": "Beat Route 20 Trainer 5",
1289
+ "0xD7E7-7": "Beat Route 20 Trainer 6",
1290
+ "0xD7E8-0": "Beat Route 20 Trainer 7",
1291
+ "0xD7E8-1": "Beat Route 20 Trainer 8",
1292
+ "0xD7E8-2": "Beat Route 20 Trainer 9",
1293
+ "0xD7E8-3": "50B",
1294
+ "0xD7E8-4": "50C",
1295
+ "0xD7E8-5": "50D",
1296
+ "0xD7E8-6": "Seafoam1 Boulder1 Down Hole",
1297
+ "0xD7E8-7": "Seafoam1 Boulder2 Down Hole",
1298
+ "0xD7E9-0": "510",
1299
+ "0xD7E9-1": "Beat Route 21 Trainer 0",
1300
+ "0xD7E9-2": "Beat Route 21 Trainer 1",
1301
+ "0xD7E9-3": "Beat Route 21 Trainer 2",
1302
+ "0xD7E9-4": "Beat Route 21 Trainer 3",
1303
+ "0xD7E9-5": "Beat Route 21 Trainer 4",
1304
+ "0xD7E9-6": "Beat Route 21 Trainer 5",
1305
+ "0xD7E9-7": "Beat Route 21 Trainer 6",
1306
+ "0xD7EA-0": "Beat Route 21 Trainer 7",
1307
+ "0xD7EA-1": "Beat Route 21 Trainer 8",
1308
+ "0xD7EA-2": "51A",
1309
+ "0xD7EA-3": "51B",
1310
+ "0xD7EA-4": "51C",
1311
+ "0xD7EA-5": "51D",
1312
+ "0xD7EA-6": "51E",
1313
+ "0xD7EA-7": "51F",
1314
+ "0xD7EB-0": "1St Route22 Rival Battle",
1315
+ "0xD7EB-1": "2Nd Route22 Rival Battle",
1316
+ "0xD7EB-2": "522",
1317
+ "0xD7EB-3": "523",
1318
+ "0xD7EB-4": "524",
1319
+ "0xD7EB-5": "Beat Route22 Rival 1St Battle",
1320
+ "0xD7EB-6": "Beat Route22 Rival 2Nd Battle",
1321
+ "0xD7EB-7": "Route22 Rival Wants Battle",
1322
+ "0xD7EC-0": "528",
1323
+ "0xD7EC-1": "529",
1324
+ "0xD7EC-2": "52A",
1325
+ "0xD7EC-3": "52B",
1326
+ "0xD7EC-4": "52C",
1327
+ "0xD7EC-5": "52D",
1328
+ "0xD7EC-6": "52E",
1329
+ "0xD7EC-7": "52F",
1330
+ "0xD7ED-0": "Passed Cascadebadge Check",
1331
+ "0xD7ED-1": "Passed Thunderbadge Check",
1332
+ "0xD7ED-2": "Passed Rainbowbadge Check",
1333
+ "0xD7ED-3": "Passed Soulbadge Check",
1334
+ "0xD7ED-4": "Passed Marshbadge Check",
1335
+ "0xD7ED-5": "Passed Volcanobadge Check",
1336
+ "0xD7ED-6": "Passed Earthbadge Check",
1337
+ "0xD7ED-7": "537",
1338
+ "0xD7EE-0": "Victory Road 2 Boulder On Switch1",
1339
+ "0xD7EE-1": "Beat Victory Road 2 Trainer 0",
1340
+ "0xD7EE-2": "Beat Victory Road 2 Trainer 1",
1341
+ "0xD7EE-3": "Beat Victory Road 2 Trainer 2",
1342
+ "0xD7EE-4": "Beat Victory Road 2 Trainer 3",
1343
+ "0xD7EE-5": "Beat Victory Road 2 Trainer 4",
1344
+ "0xD7EE-6": "Beat Moltres",
1345
+ "0xD7EE-7": "Victory Road 2 Boulder On Switch2",
1346
+ "0xD7EF-0": "Got Nugget",
1347
+ "0xD7EF-1": "Beat Route24 Rocket",
1348
+ "0xD7EF-2": "Beat Route 24 Trainer 0",
1349
+ "0xD7EF-3": "Beat Route 24 Trainer 1",
1350
+ "0xD7EF-4": "Beat Route 24 Trainer 2",
1351
+ "0xD7EF-5": "Beat Route 24 Trainer 3",
1352
+ "0xD7EF-6": "Beat Route 24 Trainer 4",
1353
+ "0xD7EF-7": "Beat Route 24 Trainer 5",
1354
+ "0xD7F0-0": "548",
1355
+ "0xD7F0-1": "Nugget Reward Available",
1356
+ "0xD7F0-2": "54A",
1357
+ "0xD7F0-3": "54B",
1358
+ "0xD7F0-4": "54C",
1359
+ "0xD7F0-5": "54D",
1360
+ "0xD7F0-6": "54E",
1361
+ "0xD7F0-7": "54F",
1362
+ "0xD7F1-0": "Met Bill",
1363
+ "0xD7F1-1": "Beat Route 25 Trainer 0",
1364
+ "0xD7F1-2": "Beat Route 25 Trainer 1",
1365
+ "0xD7F1-3": "Beat Route 25 Trainer 2",
1366
+ "0xD7F1-4": "Beat Route 25 Trainer 3",
1367
+ "0xD7F1-5": "Beat Route 25 Trainer 4",
1368
+ "0xD7F1-6": "Beat Route 25 Trainer 5",
1369
+ "0xD7F1-7": "Beat Route 25 Trainer 6",
1370
+ "0xD7F2-0": "Beat Route 25 Trainer 7",
1371
+ "0xD7F2-1": "Beat Route 25 Trainer 8",
1372
+ "0xD7F2-2": "55A",
1373
+ "0xD7F2-3": "Used Cell Separator On Bill",
1374
+ "0xD7F2-4": "Got Ss Ticket",
1375
+ "0xD7F2-5": "Met Bill 2",
1376
+ "0xD7F2-6": "Bill Said Use Cell Separator",
1377
+ "0xD7F2-7": "Left Bills House After Helping",
1378
+ "0xD7F3-0": "560",
1379
+ "0xD7F3-1": "561",
1380
+ "0xD7F3-2": "Beat Viridian Forest Trainer 0",
1381
+ "0xD7F3-3": "Beat Viridian Forest Trainer 1",
1382
+ "0xD7F3-4": "Beat Viridian Forest Trainer 2",
1383
+ "0xD7F3-5": "565",
1384
+ "0xD7F3-6": "566",
1385
+ "0xD7F3-7": "567",
1386
+ "0xD7F4-0": "568",
1387
+ "0xD7F4-1": "569",
1388
+ "0xD7F4-2": "56A",
1389
+ "0xD7F4-3": "56B",
1390
+ "0xD7F4-4": "56C",
1391
+ "0xD7F4-5": "56D",
1392
+ "0xD7F4-6": "56E",
1393
+ "0xD7F4-7": "56F",
1394
+ "0xD7F5-0": "570",
1395
+ "0xD7F5-1": "Beat Mt Moon 1 Trainer 0",
1396
+ "0xD7F5-2": "Beat Mt Moon 1 Trainer 1",
1397
+ "0xD7F5-3": "Beat Mt Moon 1 Trainer 2",
1398
+ "0xD7F5-4": "Beat Mt Moon 1 Trainer 3",
1399
+ "0xD7F5-5": "Beat Mt Moon 1 Trainer 4",
1400
+ "0xD7F5-6": "Beat Mt Moon 1 Trainer 5",
1401
+ "0xD7F5-7": "Beat Mt Moon 1 Trainer 6",
1402
+ "0xD7F6-0": "578",
1403
+ "0xD7F6-1": "Beat Mt Moon Exit Super Nerd",
1404
+ "0xD7F6-2": "Beat Mt Moon 3 Trainer 0",
1405
+ "0xD7F6-3": "Beat Mt Moon 3 Trainer 1",
1406
+ "0xD7F6-4": "Beat Mt Moon 3 Trainer 2",
1407
+ "0xD7F6-5": "Beat Mt Moon 3 Trainer 3",
1408
+ "0xD7F6-6": "Got Dome Fossil",
1409
+ "0xD7F6-7": "Got Helix Fossil",
1410
+ "0xD7F7-0": "580",
1411
+ "0xD7F7-1": "581",
1412
+ "0xD7F7-2": "582",
1413
+ "0xD7F7-3": "583",
1414
+ "0xD7F7-4": "584",
1415
+ "0xD7F7-5": "585",
1416
+ "0xD7F7-6": "586",
1417
+ "0xD7F7-7": "587",
1418
+ "0xD7F8-0": "588",
1419
+ "0xD7F8-1": "589",
1420
+ "0xD7F8-2": "58A",
1421
+ "0xD7F8-3": "58B",
1422
+ "0xD7F8-4": "58C",
1423
+ "0xD7F8-5": "58D",
1424
+ "0xD7F8-6": "58E",
1425
+ "0xD7F8-7": "58F",
1426
+ "0xD7F9-0": "590",
1427
+ "0xD7F9-1": "591",
1428
+ "0xD7F9-2": "592",
1429
+ "0xD7F9-3": "593",
1430
+ "0xD7F9-4": "594",
1431
+ "0xD7F9-5": "595",
1432
+ "0xD7F9-6": "596",
1433
+ "0xD7F9-7": "597",
1434
+ "0xD7FA-0": "598",
1435
+ "0xD7FA-1": "599",
1436
+ "0xD7FA-2": "59A",
1437
+ "0xD7FA-3": "59B",
1438
+ "0xD7FA-4": "59C",
1439
+ "0xD7FA-5": "59D",
1440
+ "0xD7FA-6": "59E",
1441
+ "0xD7FA-7": "59F",
1442
+ "0xD7FB-0": "5A0",
1443
+ "0xD7FB-1": "5A1",
1444
+ "0xD7FB-2": "5A2",
1445
+ "0xD7FB-3": "5A3",
1446
+ "0xD7FB-4": "5A4",
1447
+ "0xD7FB-5": "5A5",
1448
+ "0xD7FB-6": "5A6",
1449
+ "0xD7FB-7": "5A7",
1450
+ "0xD7FC-0": "5A8",
1451
+ "0xD7FC-1": "5A9",
1452
+ "0xD7FC-2": "5Aa",
1453
+ "0xD7FC-3": "5Ab",
1454
+ "0xD7FC-4": "5Ac",
1455
+ "0xD7FC-5": "5Ad",
1456
+ "0xD7FC-6": "5Ae",
1457
+ "0xD7FC-7": "5Af",
1458
+ "0xD7FD-0": "5B0",
1459
+ "0xD7FD-1": "5B1",
1460
+ "0xD7FD-2": "5B2",
1461
+ "0xD7FD-3": "5B3",
1462
+ "0xD7FD-4": "5B4",
1463
+ "0xD7FD-5": "5B5",
1464
+ "0xD7FD-6": "5B6",
1465
+ "0xD7FD-7": "5B7",
1466
+ "0xD7FE-0": "5B8",
1467
+ "0xD7FE-1": "5B9",
1468
+ "0xD7FE-2": "5Ba",
1469
+ "0xD7FE-3": "5Bb",
1470
+ "0xD7FE-4": "5Bc",
1471
+ "0xD7FE-5": "5Bd",
1472
+ "0xD7FE-6": "5Be",
1473
+ "0xD7FE-7": "5Bf",
1474
+ "0xD7FF-0": "5C0",
1475
+ "0xD7FF-1": "5C1",
1476
+ "0xD7FF-2": "5C2",
1477
+ "0xD7FF-3": "5C3",
1478
+ "0xD7FF-4": "Beat Ss Anne 5 Trainer 0",
1479
+ "0xD7FF-5": "Beat Ss Anne 5 Trainer 1",
1480
+ "0xD7FF-6": "5C6",
1481
+ "0xD7FF-7": "5C7",
1482
+ "0xD800-0": "5C8",
1483
+ "0xD800-1": "5C9",
1484
+ "0xD800-2": "5Ca",
1485
+ "0xD800-3": "5Cb",
1486
+ "0xD800-4": "5Cc",
1487
+ "0xD800-5": "5Cd",
1488
+ "0xD800-6": "5Ce",
1489
+ "0xD800-7": "5Cf",
1490
+ "0xD801-0": "5D0",
1491
+ "0xD801-1": "5D1",
1492
+ "0xD801-2": "5D2",
1493
+ "0xD801-3": "5D3",
1494
+ "0xD801-4": "5D4",
1495
+ "0xD801-5": "5D5",
1496
+ "0xD801-6": "5D6",
1497
+ "0xD801-7": "5D7",
1498
+ "0xD802-0": "5D8",
1499
+ "0xD802-1": "5D9",
1500
+ "0xD802-2": "5Da",
1501
+ "0xD802-3": "5Db",
1502
+ "0xD802-4": "5Dc",
1503
+ "0xD802-5": "5Dd",
1504
+ "0xD802-6": "5De",
1505
+ "0xD802-7": "5Df",
1506
+ "0xD803-0": "Got Hm01",
1507
+ "0xD803-1": "Rubbed Captains Back",
1508
+ "0xD803-2": "Ss Anne Left",
1509
+ "0xD803-3": "Walked Past Guard After Ss Anne Left",
1510
+ "0xD803-4": "Started Walking Out Of Dock",
1511
+ "0xD803-5": "Walked Out Of Dock",
1512
+ "0xD803-6": "5E6",
1513
+ "0xD803-7": "5E7",
1514
+ "0xD804-0": "5E8",
1515
+ "0xD804-1": "5E9",
1516
+ "0xD804-2": "5Ea",
1517
+ "0xD804-3": "5Eb",
1518
+ "0xD804-4": "5Ec",
1519
+ "0xD804-5": "5Ed",
1520
+ "0xD804-6": "5Ee",
1521
+ "0xD804-7": "5Ef",
1522
+ "0xD805-0": "5F0",
1523
+ "0xD805-1": "Beat Ss Anne 8 Trainer 0",
1524
+ "0xD805-2": "Beat Ss Anne 8 Trainer 1",
1525
+ "0xD805-3": "Beat Ss Anne 8 Trainer 2",
1526
+ "0xD805-4": "Beat Ss Anne 8 Trainer 3",
1527
+ "0xD805-5": "5F5",
1528
+ "0xD805-6": "5F6",
1529
+ "0xD805-7": "5F7",
1530
+ "0xD806-0": "5F8",
1531
+ "0xD806-1": "5F9",
1532
+ "0xD806-2": "5Fa",
1533
+ "0xD806-3": "5Fb",
1534
+ "0xD806-4": "5Fc",
1535
+ "0xD806-5": "5Fd",
1536
+ "0xD806-6": "5Fe",
1537
+ "0xD806-7": "5Ff",
1538
+ "0xD807-0": "600",
1539
+ "0xD807-1": "Beat Ss Anne 9 Trainer 0",
1540
+ "0xD807-2": "Beat Ss Anne 9 Trainer 1",
1541
+ "0xD807-3": "Beat Ss Anne 9 Trainer 2",
1542
+ "0xD807-4": "Beat Ss Anne 9 Trainer 3",
1543
+ "0xD807-5": "605",
1544
+ "0xD807-6": "606",
1545
+ "0xD807-7": "607",
1546
+ "0xD808-0": "608",
1547
+ "0xD808-1": "609",
1548
+ "0xD808-2": "60A",
1549
+ "0xD808-3": "60B",
1550
+ "0xD808-4": "60C",
1551
+ "0xD808-5": "60D",
1552
+ "0xD808-6": "60E",
1553
+ "0xD808-7": "60F",
1554
+ "0xD809-0": "610",
1555
+ "0xD809-1": "Beat Ss Anne 10 Trainer 0",
1556
+ "0xD809-2": "Beat Ss Anne 10 Trainer 1",
1557
+ "0xD809-3": "Beat Ss Anne 10 Trainer 2",
1558
+ "0xD809-4": "Beat Ss Anne 10 Trainer 3",
1559
+ "0xD809-5": "Beat Ss Anne 10 Trainer 4",
1560
+ "0xD809-6": "Beat Ss Anne 10 Trainer 5",
1561
+ "0xD809-7": "617",
1562
+ "0xD80A-0": "618",
1563
+ "0xD80A-1": "619",
1564
+ "0xD80A-2": "61A",
1565
+ "0xD80A-3": "61B",
1566
+ "0xD80A-4": "61C",
1567
+ "0xD80A-5": "61D",
1568
+ "0xD80A-6": "61E",
1569
+ "0xD80A-7": "61F",
1570
+ "0xD80B-0": "620",
1571
+ "0xD80B-1": "621",
1572
+ "0xD80B-2": "622",
1573
+ "0xD80B-3": "623",
1574
+ "0xD80B-4": "624",
1575
+ "0xD80B-5": "625",
1576
+ "0xD80B-6": "626",
1577
+ "0xD80B-7": "627",
1578
+ "0xD80C-0": "628",
1579
+ "0xD80C-1": "629",
1580
+ "0xD80C-2": "62A",
1581
+ "0xD80C-3": "62B",
1582
+ "0xD80C-4": "62C",
1583
+ "0xD80C-5": "62D",
1584
+ "0xD80C-6": "62E",
1585
+ "0xD80C-7": "62F",
1586
+ "0xD80D-0": "630",
1587
+ "0xD80D-1": "631",
1588
+ "0xD80D-2": "632",
1589
+ "0xD80D-3": "633",
1590
+ "0xD80D-4": "634",
1591
+ "0xD80D-5": "635",
1592
+ "0xD80D-6": "636",
1593
+ "0xD80D-7": "637",
1594
+ "0xD80E-0": "638",
1595
+ "0xD80E-1": "639",
1596
+ "0xD80E-2": "63A",
1597
+ "0xD80E-3": "63B",
1598
+ "0xD80E-4": "63C",
1599
+ "0xD80E-5": "63D",
1600
+ "0xD80E-6": "63E",
1601
+ "0xD80E-7": "63F",
1602
+ "0xD80F-0": "640",
1603
+ "0xD80F-1": "641",
1604
+ "0xD80F-2": "642",
1605
+ "0xD80F-3": "643",
1606
+ "0xD80F-4": "644",
1607
+ "0xD80F-5": "645",
1608
+ "0xD80F-6": "646",
1609
+ "0xD80F-7": "647",
1610
+ "0xD810-0": "648",
1611
+ "0xD810-1": "649",
1612
+ "0xD810-2": "64A",
1613
+ "0xD810-3": "64B",
1614
+ "0xD810-4": "64C",
1615
+ "0xD810-5": "64D",
1616
+ "0xD810-6": "64E",
1617
+ "0xD810-7": "64F",
1618
+ "0xD811-0": "650",
1619
+ "0xD811-1": "651",
1620
+ "0xD811-2": "652",
1621
+ "0xD811-3": "653",
1622
+ "0xD811-4": "654",
1623
+ "0xD811-5": "655",
1624
+ "0xD811-6": "656",
1625
+ "0xD811-7": "657",
1626
+ "0xD812-0": "658",
1627
+ "0xD812-1": "659",
1628
+ "0xD812-2": "65A",
1629
+ "0xD812-3": "65B",
1630
+ "0xD812-4": "65C",
1631
+ "0xD812-5": "65D",
1632
+ "0xD812-6": "65E",
1633
+ "0xD812-7": "65F",
1634
+ "0xD813-0": "Victory Road 3 Boulder On Switch1",
1635
+ "0xD813-1": "Beat Victory Road 3 Trainer 0",
1636
+ "0xD813-2": "Beat Victory Road 3 Trainer 1",
1637
+ "0xD813-3": "Beat Victory Road 3 Trainer 2",
1638
+ "0xD813-4": "Beat Victory Road 3 Trainer 3",
1639
+ "0xD813-5": "665",
1640
+ "0xD813-6": "Victory Road 3 Boulder On Switch2",
1641
+ "0xD813-7": "667",
1642
+ "0xD814-0": "668",
1643
+ "0xD814-1": "669",
1644
+ "0xD814-2": "66A",
1645
+ "0xD814-3": "66B",
1646
+ "0xD814-4": "66C",
1647
+ "0xD814-5": "66D",
1648
+ "0xD814-6": "66E",
1649
+ "0xD814-7": "66F",
1650
+ "0xD815-0": "670",
1651
+ "0xD815-1": "Beat Rocket Hideout 1 Trainer 0",
1652
+ "0xD815-2": "Beat Rocket Hideout 1 Trainer 1",
1653
+ "0xD815-3": "Beat Rocket Hideout 1 Trainer 2",
1654
+ "0xD815-4": "Beat Rocket Hideout 1 Trainer 3",
1655
+ "0xD815-5": "Beat Rocket Hideout 1 Trainer 4",
1656
+ "0xD815-6": "676",
1657
+ "0xD815-7": "677",
1658
+ "0xD816-0": "678",
1659
+ "0xD816-1": "679",
1660
+ "0xD816-2": "67A",
1661
+ "0xD816-3": "67B",
1662
+ "0xD816-4": "67C",
1663
+ "0xD816-5": "67D",
1664
+ "0xD816-6": "67E",
1665
+ "0xD816-7": "67F",
1666
+ "0xD817-0": "680",
1667
+ "0xD817-1": "Beat Rocket Hideout 2 Trainer 0",
1668
+ "0xD817-2": "682",
1669
+ "0xD817-3": "683",
1670
+ "0xD817-4": "684",
1671
+ "0xD817-5": "685",
1672
+ "0xD817-6": "686",
1673
+ "0xD817-7": "687",
1674
+ "0xD818-0": "688",
1675
+ "0xD818-1": "689",
1676
+ "0xD818-2": "68A",
1677
+ "0xD818-3": "68B",
1678
+ "0xD818-4": "68C",
1679
+ "0xD818-5": "68D",
1680
+ "0xD818-6": "68E",
1681
+ "0xD818-7": "68F",
1682
+ "0xD819-0": "690",
1683
+ "0xD819-1": "Beat Rocket Hideout 3 Trainer 0",
1684
+ "0xD819-2": "Beat Rocket Hideout 3 Trainer 1",
1685
+ "0xD819-3": "693",
1686
+ "0xD819-4": "694",
1687
+ "0xD819-5": "695",
1688
+ "0xD819-6": "696",
1689
+ "0xD819-7": "697",
1690
+ "0xD81A-0": "698",
1691
+ "0xD81A-1": "699",
1692
+ "0xD81A-2": "69A",
1693
+ "0xD81A-3": "69B",
1694
+ "0xD81A-4": "69C",
1695
+ "0xD81A-5": "69D",
1696
+ "0xD81A-6": "69E",
1697
+ "0xD81A-7": "69F",
1698
+ "0xD81B-0": "6A0",
1699
+ "0xD81B-1": "6A1",
1700
+ "0xD81B-2": "Beat Rocket Hideout 4 Trainer 0",
1701
+ "0xD81B-3": "Beat Rocket Hideout 4 Trainer 1",
1702
+ "0xD81B-4": "Beat Rocket Hideout 4 Trainer 2",
1703
+ "0xD81B-5": "Rocket Hideout 4 Door Unlocked",
1704
+ "0xD81B-6": "Rocket Dropped Lift Key",
1705
+ "0xD81B-7": "Beat Rocket Hideout Giovanni",
1706
+ "0xD81C-0": "6A8",
1707
+ "0xD81C-1": "6A9",
1708
+ "0xD81C-2": "6Aa",
1709
+ "0xD81C-3": "6Ab",
1710
+ "0xD81C-4": "6Ac",
1711
+ "0xD81C-5": "6Ad",
1712
+ "0xD81C-6": "6Ae",
1713
+ "0xD81C-7": "6Af",
1714
+ "0xD81D-0": "6B0",
1715
+ "0xD81D-1": "6B1",
1716
+ "0xD81D-2": "6B2",
1717
+ "0xD81D-3": "6B3",
1718
+ "0xD81D-4": "6B4",
1719
+ "0xD81D-5": "6B5",
1720
+ "0xD81D-6": "6B6",
1721
+ "0xD81D-7": "6B7",
1722
+ "0xD81E-0": "6B8",
1723
+ "0xD81E-1": "6B9",
1724
+ "0xD81E-2": "6Ba",
1725
+ "0xD81E-3": "6Bb",
1726
+ "0xD81E-4": "6Bc",
1727
+ "0xD81E-5": "6Bd",
1728
+ "0xD81E-6": "6Be",
1729
+ "0xD81E-7": "6Bf",
1730
+ "0xD81F-0": "6C0",
1731
+ "0xD81F-1": "6C1",
1732
+ "0xD81F-2": "6C2",
1733
+ "0xD81F-3": "6C3",
1734
+ "0xD81F-4": "6C4",
1735
+ "0xD81F-5": "6C5",
1736
+ "0xD81F-6": "6C6",
1737
+ "0xD81F-7": "6C7",
1738
+ "0xD820-0": "6C8",
1739
+ "0xD820-1": "6C9",
1740
+ "0xD820-2": "6Ca",
1741
+ "0xD820-3": "6Cb",
1742
+ "0xD820-4": "6Cc",
1743
+ "0xD820-5": "6Cd",
1744
+ "0xD820-6": "6Ce",
1745
+ "0xD820-7": "6Cf",
1746
+ "0xD821-0": "6D0",
1747
+ "0xD821-1": "6D1",
1748
+ "0xD821-2": "6D2",
1749
+ "0xD821-3": "6D3",
1750
+ "0xD821-4": "6D4",
1751
+ "0xD821-5": "6D5",
1752
+ "0xD821-6": "6D6",
1753
+ "0xD821-7": "6D7",
1754
+ "0xD822-0": "6D8",
1755
+ "0xD822-1": "6D9",
1756
+ "0xD822-2": "6Da",
1757
+ "0xD822-3": "6Db",
1758
+ "0xD822-4": "6Dc",
1759
+ "0xD822-5": "6Dd",
1760
+ "0xD822-6": "6De",
1761
+ "0xD822-7": "6Df",
1762
+ "0xD823-0": "6E0",
1763
+ "0xD823-1": "6E1",
1764
+ "0xD823-2": "6E2",
1765
+ "0xD823-3": "6E3",
1766
+ "0xD823-4": "6E4",
1767
+ "0xD823-5": "6E5",
1768
+ "0xD823-6": "6E6",
1769
+ "0xD823-7": "6E7",
1770
+ "0xD824-0": "6E8",
1771
+ "0xD824-1": "6E9",
1772
+ "0xD824-2": "6Ea",
1773
+ "0xD824-3": "6Eb",
1774
+ "0xD824-4": "6Ec",
1775
+ "0xD824-5": "6Ed",
1776
+ "0xD824-6": "6Ee",
1777
+ "0xD824-7": "6Ef",
1778
+ "0xD825-0": "6F0",
1779
+ "0xD825-1": "6F1",
1780
+ "0xD825-2": "Beat Silph Co 2F Trainer 0",
1781
+ "0xD825-3": "Beat Silph Co 2F Trainer 1",
1782
+ "0xD825-4": "Beat Silph Co 2F Trainer 2",
1783
+ "0xD825-5": "Beat Silph Co 2F Trainer 3",
1784
+ "0xD825-6": "6F6",
1785
+ "0xD825-7": "6F7",
1786
+ "0xD826-0": "6F8",
1787
+ "0xD826-1": "6F9",
1788
+ "0xD826-2": "6Fa",
1789
+ "0xD826-3": "6Fb",
1790
+ "0xD826-4": "6Fc",
1791
+ "0xD826-5": "Silph Co 2 Unlocked Door1",
1792
+ "0xD826-6": "Silph Co 2 Unlocked Door2",
1793
+ "0xD826-7": "Got Tm36",
1794
+ "0xD827-0": "700",
1795
+ "0xD827-1": "701",
1796
+ "0xD827-2": "Beat Silph Co 3F Trainer 0",
1797
+ "0xD827-3": "Beat Silph Co 3F Trainer 1",
1798
+ "0xD827-4": "704",
1799
+ "0xD827-5": "705",
1800
+ "0xD827-6": "706",
1801
+ "0xD827-7": "707",
1802
+ "0xD828-0": "Silph Co 3 Unlocked Door1",
1803
+ "0xD828-1": "Silph Co 3 Unlocked Door2",
1804
+ "0xD828-2": "70A",
1805
+ "0xD828-3": "70B",
1806
+ "0xD828-4": "70C",
1807
+ "0xD828-5": "70D",
1808
+ "0xD828-6": "70E",
1809
+ "0xD828-7": "70F",
1810
+ "0xD829-0": "710",
1811
+ "0xD829-1": "711",
1812
+ "0xD829-2": "Beat Silph Co 4F Trainer 0",
1813
+ "0xD829-3": "Beat Silph Co 4F Trainer 1",
1814
+ "0xD829-4": "Beat Silph Co 4F Trainer 2",
1815
+ "0xD829-5": "715",
1816
+ "0xD829-6": "716",
1817
+ "0xD829-7": "717",
1818
+ "0xD82A-0": "Silph Co 4 Unlocked Door1",
1819
+ "0xD82A-1": "Silph Co 4 Unlocked Door2",
1820
+ "0xD82A-2": "71A",
1821
+ "0xD82A-3": "71B",
1822
+ "0xD82A-4": "71C",
1823
+ "0xD82A-5": "71D",
1824
+ "0xD82A-6": "71E",
1825
+ "0xD82A-7": "71F",
1826
+ "0xD82B-0": "720",
1827
+ "0xD82B-1": "721",
1828
+ "0xD82B-2": "Beat Silph Co 5F Trainer 0",
1829
+ "0xD82B-3": "Beat Silph Co 5F Trainer 1",
1830
+ "0xD82B-4": "Beat Silph Co 5F Trainer 2",
1831
+ "0xD82B-5": "Beat Silph Co 5F Trainer 3",
1832
+ "0xD82B-6": "726",
1833
+ "0xD82B-7": "727",
1834
+ "0xD82C-0": "Silph Co 5 Unlocked Door1",
1835
+ "0xD82C-1": "Silph Co 5 Unlocked Door2",
1836
+ "0xD82C-2": "Silph Co 5 Unlocked Door3",
1837
+ "0xD82C-3": "72B",
1838
+ "0xD82C-4": "72C",
1839
+ "0xD82C-5": "72D",
1840
+ "0xD82C-6": "72E",
1841
+ "0xD82C-7": "72F",
1842
+ "0xD82D-0": "730",
1843
+ "0xD82D-1": "731",
1844
+ "0xD82D-2": "732",
1845
+ "0xD82D-3": "733",
1846
+ "0xD82D-4": "734",
1847
+ "0xD82D-5": "735",
1848
+ "0xD82D-6": "Beat Silph Co 6F Trainer 0",
1849
+ "0xD82D-7": "Beat Silph Co 6F Trainer 1",
1850
+ "0xD82E-0": "Beat Silph Co 6F Trainer 2",
1851
+ "0xD82E-1": "739",
1852
+ "0xD82E-2": "73A",
1853
+ "0xD82E-3": "73B",
1854
+ "0xD82E-4": "73C",
1855
+ "0xD82E-5": "73D",
1856
+ "0xD82E-6": "73E",
1857
+ "0xD82E-7": "Silph Co 6 Unlocked Door",
1858
+ "0xD82F-0": "Beat Silph Co Rival",
1859
+ "0xD82F-1": "741",
1860
+ "0xD82F-2": "742",
1861
+ "0xD82F-3": "743",
1862
+ "0xD82F-4": "744",
1863
+ "0xD82F-5": "Beat Silph Co 7F Trainer 0",
1864
+ "0xD82F-6": "Beat Silph Co 7F Trainer 1",
1865
+ "0xD82F-7": "Beat Silph Co 7F Trainer 2",
1866
+ "0xD830-0": "Beat Silph Co 7F Trainer 3",
1867
+ "0xD830-1": "749",
1868
+ "0xD830-2": "74A",
1869
+ "0xD830-3": "74B",
1870
+ "0xD830-4": "Silph Co 7 Unlocked Door1",
1871
+ "0xD830-5": "Silph Co 7 Unlocked Door2",
1872
+ "0xD830-6": "Silph Co 7 Unlocked Door3",
1873
+ "0xD830-7": "74F",
1874
+ "0xD831-0": "750",
1875
+ "0xD831-1": "751",
1876
+ "0xD831-2": "Beat Silph Co 8F Trainer 0",
1877
+ "0xD831-3": "Beat Silph Co 8F Trainer 1",
1878
+ "0xD831-4": "Beat Silph Co 8F Trainer 2",
1879
+ "0xD831-5": "755",
1880
+ "0xD831-6": "756",
1881
+ "0xD831-7": "757",
1882
+ "0xD832-0": "Silph Co 8 Unlocked Door",
1883
+ "0xD832-1": "759",
1884
+ "0xD832-2": "75A",
1885
+ "0xD832-3": "75B",
1886
+ "0xD832-4": "75C",
1887
+ "0xD832-5": "75D",
1888
+ "0xD832-6": "75E",
1889
+ "0xD832-7": "75F",
1890
+ "0xD833-0": "760",
1891
+ "0xD833-1": "761",
1892
+ "0xD833-2": "Beat Silph Co 9F Trainer 0",
1893
+ "0xD833-3": "Beat Silph Co 9F Trainer 1",
1894
+ "0xD833-4": "Beat Silph Co 9F Trainer 2",
1895
+ "0xD833-5": "765",
1896
+ "0xD833-6": "766",
1897
+ "0xD833-7": "767",
1898
+ "0xD834-0": "Silph Co 9 Unlocked Door1",
1899
+ "0xD834-1": "Silph Co 9 Unlocked Door2",
1900
+ "0xD834-2": "Silph Co 9 Unlocked Door3",
1901
+ "0xD834-3": "Silph Co 9 Unlocked Door4",
1902
+ "0xD834-4": "76C",
1903
+ "0xD834-5": "76D",
1904
+ "0xD834-6": "76E",
1905
+ "0xD834-7": "76F",
1906
+ "0xD835-0": "770",
1907
+ "0xD835-1": "Beat Silph Co 10F Trainer 0",
1908
+ "0xD835-2": "Beat Silph Co 10F Trainer 1",
1909
+ "0xD835-3": "773",
1910
+ "0xD835-4": "774",
1911
+ "0xD835-5": "775",
1912
+ "0xD835-6": "776",
1913
+ "0xD835-7": "777",
1914
+ "0xD836-0": "Silph Co 10 Unlocked Door",
1915
+ "0xD836-1": "779",
1916
+ "0xD836-2": "77A",
1917
+ "0xD836-3": "77B",
1918
+ "0xD836-4": "77C",
1919
+ "0xD836-5": "77D",
1920
+ "0xD836-6": "77E",
1921
+ "0xD836-7": "77F",
1922
+ "0xD837-0": "780",
1923
+ "0xD837-1": "781",
1924
+ "0xD837-2": "782",
1925
+ "0xD837-3": "783",
1926
+ "0xD837-4": "Beat Silph Co 11F Trainer 0",
1927
+ "0xD837-5": "Beat Silph Co 11F Trainer 1",
1928
+ "0xD837-6": "786",
1929
+ "0xD837-7": "787",
1930
+ "0xD838-0": "Silph Co 11 Unlocked Door",
1931
+ "0xD838-1": "789",
1932
+ "0xD838-2": "78A",
1933
+ "0xD838-3": "78B",
1934
+ "0xD838-4": "78C",
1935
+ "0xD838-5": "Got Master Ball",
1936
+ "0xD838-6": "78E",
1937
+ "0xD838-7": "Beat Silph Co Giovanni",
1938
+ "0xD839-0": "790",
1939
+ "0xD839-1": "791",
1940
+ "0xD839-2": "792",
1941
+ "0xD839-3": "793",
1942
+ "0xD839-4": "794",
1943
+ "0xD839-5": "795",
1944
+ "0xD839-6": "796",
1945
+ "0xD839-7": "797",
1946
+ "0xD83A-0": "798",
1947
+ "0xD83A-1": "799",
1948
+ "0xD83A-2": "79A",
1949
+ "0xD83A-3": "79B",
1950
+ "0xD83A-4": "79C",
1951
+ "0xD83A-5": "79D",
1952
+ "0xD83A-6": "79E",
1953
+ "0xD83A-7": "79F",
1954
+ "0xD83B-0": "7A0",
1955
+ "0xD83B-1": "7A1",
1956
+ "0xD83B-2": "7A2",
1957
+ "0xD83B-3": "7A3",
1958
+ "0xD83B-4": "7A4",
1959
+ "0xD83B-5": "7A5",
1960
+ "0xD83B-6": "7A6",
1961
+ "0xD83B-7": "7A7",
1962
+ "0xD83C-0": "7A8",
1963
+ "0xD83C-1": "7A9",
1964
+ "0xD83C-2": "7Aa",
1965
+ "0xD83C-3": "7Ab",
1966
+ "0xD83C-4": "7Ac",
1967
+ "0xD83C-5": "7Ad",
1968
+ "0xD83C-6": "7Ae",
1969
+ "0xD83C-7": "7Af",
1970
+ "0xD83D-0": "7B0",
1971
+ "0xD83D-1": "7B1",
1972
+ "0xD83D-2": "7B2",
1973
+ "0xD83D-3": "7B3",
1974
+ "0xD83D-4": "7B4",
1975
+ "0xD83D-5": "7B5",
1976
+ "0xD83D-6": "7B6",
1977
+ "0xD83D-7": "7B7",
1978
+ "0xD83E-0": "7B8",
1979
+ "0xD83E-1": "7B9",
1980
+ "0xD83E-2": "7Ba",
1981
+ "0xD83E-3": "7Bb",
1982
+ "0xD83E-4": "7Bc",
1983
+ "0xD83E-5": "7Bd",
1984
+ "0xD83E-6": "7Be",
1985
+ "0xD83E-7": "7Bf",
1986
+ "0xD83F-0": "7C0",
1987
+ "0xD83F-1": "7C1",
1988
+ "0xD83F-2": "7C2",
1989
+ "0xD83F-3": "7C3",
1990
+ "0xD83F-4": "7C4",
1991
+ "0xD83F-5": "7C5",
1992
+ "0xD83F-6": "7C6",
1993
+ "0xD83F-7": "7C7",
1994
+ "0xD840-0": "7C8",
1995
+ "0xD840-1": "7C9",
1996
+ "0xD840-2": "7Ca",
1997
+ "0xD840-3": "7Cb",
1998
+ "0xD840-4": "7Cc",
1999
+ "0xD840-5": "7Cd",
2000
+ "0xD840-6": "7Ce",
2001
+ "0xD840-7": "7Cf",
2002
+ "0xD841-0": "7D0",
2003
+ "0xD841-1": "7D1",
2004
+ "0xD841-2": "7D2",
2005
+ "0xD841-3": "7D3",
2006
+ "0xD841-4": "7D4",
2007
+ "0xD841-5": "7D5",
2008
+ "0xD841-6": "7D6",
2009
+ "0xD841-7": "7D7",
2010
+ "0xD842-0": "7D8",
2011
+ "0xD842-1": "7D9",
2012
+ "0xD842-2": "7Da",
2013
+ "0xD842-3": "7Db",
2014
+ "0xD842-4": "7Dc",
2015
+ "0xD842-5": "7Dd",
2016
+ "0xD842-6": "7De",
2017
+ "0xD842-7": "7Df",
2018
+ "0xD843-0": "7E0",
2019
+ "0xD843-1": "7E1",
2020
+ "0xD843-2": "7E2",
2021
+ "0xD843-3": "7E3",
2022
+ "0xD843-4": "7E4",
2023
+ "0xD843-5": "7E5",
2024
+ "0xD843-6": "7E6",
2025
+ "0xD843-7": "7E7",
2026
+ "0xD844-0": "7E8",
2027
+ "0xD844-1": "7E9",
2028
+ "0xD844-2": "7Ea",
2029
+ "0xD844-3": "7Eb",
2030
+ "0xD844-4": "7Ec",
2031
+ "0xD844-5": "7Ed",
2032
+ "0xD844-6": "7Ee",
2033
+ "0xD844-7": "7Ef",
2034
+ "0xD845-0": "7F0",
2035
+ "0xD845-1": "7F1",
2036
+ "0xD845-2": "7F2",
2037
+ "0xD845-3": "7F3",
2038
+ "0xD845-4": "7F4",
2039
+ "0xD845-5": "7F5",
2040
+ "0xD845-6": "7F6",
2041
+ "0xD845-7": "7F7",
2042
+ "0xD846-0": "7F8",
2043
+ "0xD846-1": "7F9",
2044
+ "0xD846-2": "7Fa",
2045
+ "0xD846-3": "7Fb",
2046
+ "0xD846-4": "7Fc",
2047
+ "0xD846-5": "7Fd",
2048
+ "0xD846-6": "7Fe",
2049
+ "0xD846-7": "7Ff",
2050
+ "0xD847-0": "800",
2051
+ "0xD847-1": "Beat Mansion 2 Trainer 0",
2052
+ "0xD847-2": "802",
2053
+ "0xD847-3": "803",
2054
+ "0xD847-4": "804",
2055
+ "0xD847-5": "805",
2056
+ "0xD847-6": "806",
2057
+ "0xD847-7": "807",
2058
+ "0xD848-0": "808",
2059
+ "0xD848-1": "809",
2060
+ "0xD848-2": "80A",
2061
+ "0xD848-3": "80B",
2062
+ "0xD848-4": "80C",
2063
+ "0xD848-5": "80D",
2064
+ "0xD848-6": "80E",
2065
+ "0xD848-7": "80F",
2066
+ "0xD849-0": "810",
2067
+ "0xD849-1": "Beat Mansion 3 Trainer 0",
2068
+ "0xD849-2": "Beat Mansion 3 Trainer 1",
2069
+ "0xD849-3": "813",
2070
+ "0xD849-4": "814",
2071
+ "0xD849-5": "815",
2072
+ "0xD849-6": "816",
2073
+ "0xD849-7": "817",
2074
+ "0xD84A-0": "818",
2075
+ "0xD84A-1": "819",
2076
+ "0xD84A-2": "81A",
2077
+ "0xD84A-3": "81B",
2078
+ "0xD84A-4": "81C",
2079
+ "0xD84A-5": "81D",
2080
+ "0xD84A-6": "81E",
2081
+ "0xD84A-7": "81F",
2082
+ "0xD84B-0": "820",
2083
+ "0xD84B-1": "Beat Mansion 4 Trainer 0",
2084
+ "0xD84B-2": "Beat Mansion 4 Trainer 1",
2085
+ "0xD84B-3": "823",
2086
+ "0xD84B-4": "824",
2087
+ "0xD84B-5": "825",
2088
+ "0xD84B-6": "826",
2089
+ "0xD84B-7": "827",
2090
+ "0xD84C-0": "828",
2091
+ "0xD84C-1": "829",
2092
+ "0xD84C-2": "82A",
2093
+ "0xD84C-3": "82B",
2094
+ "0xD84C-4": "82C",
2095
+ "0xD84C-5": "82D",
2096
+ "0xD84C-6": "82E",
2097
+ "0xD84C-7": "82F",
2098
+ "0xD84D-0": "830",
2099
+ "0xD84D-1": "831",
2100
+ "0xD84D-2": "832",
2101
+ "0xD84D-3": "833",
2102
+ "0xD84D-4": "834",
2103
+ "0xD84D-5": "835",
2104
+ "0xD84D-6": "836",
2105
+ "0xD84D-7": "837",
2106
+ "0xD84E-0": "838",
2107
+ "0xD84E-1": "839",
2108
+ "0xD84E-2": "83A",
2109
+ "0xD84E-3": "83B",
2110
+ "0xD84E-4": "83C",
2111
+ "0xD84E-5": "83D",
2112
+ "0xD84E-6": "83E",
2113
+ "0xD84E-7": "83F",
2114
+ "0xD84F-0": "840",
2115
+ "0xD84F-1": "841",
2116
+ "0xD84F-2": "842",
2117
+ "0xD84F-3": "843",
2118
+ "0xD84F-4": "844",
2119
+ "0xD84F-5": "845",
2120
+ "0xD84F-6": "846",
2121
+ "0xD84F-7": "847",
2122
+ "0xD850-0": "848",
2123
+ "0xD850-1": "849",
2124
+ "0xD850-2": "84A",
2125
+ "0xD850-3": "84B",
2126
+ "0xD850-4": "84C",
2127
+ "0xD850-5": "84D",
2128
+ "0xD850-6": "84E",
2129
+ "0xD850-7": "84F",
2130
+ "0xD851-0": "850",
2131
+ "0xD851-1": "851",
2132
+ "0xD851-2": "852",
2133
+ "0xD851-3": "853",
2134
+ "0xD851-4": "854",
2135
+ "0xD851-5": "855",
2136
+ "0xD851-6": "856",
2137
+ "0xD851-7": "857",
2138
+ "0xD852-0": "858",
2139
+ "0xD852-1": "859",
2140
+ "0xD852-2": "85A",
2141
+ "0xD852-3": "85B",
2142
+ "0xD852-4": "85C",
2143
+ "0xD852-5": "85D",
2144
+ "0xD852-6": "85E",
2145
+ "0xD852-7": "85F",
2146
+ "0xD853-0": "860",
2147
+ "0xD853-1": "861",
2148
+ "0xD853-2": "862",
2149
+ "0xD853-3": "863",
2150
+ "0xD853-4": "864",
2151
+ "0xD853-5": "865",
2152
+ "0xD853-6": "866",
2153
+ "0xD853-7": "867",
2154
+ "0xD854-0": "868",
2155
+ "0xD854-1": "869",
2156
+ "0xD854-2": "86A",
2157
+ "0xD854-3": "86B",
2158
+ "0xD854-4": "86C",
2159
+ "0xD854-5": "86D",
2160
+ "0xD854-6": "86E",
2161
+ "0xD854-7": "86F",
2162
+ "0xD855-0": "870",
2163
+ "0xD855-1": "871",
2164
+ "0xD855-2": "872",
2165
+ "0xD855-3": "873",
2166
+ "0xD855-4": "874",
2167
+ "0xD855-5": "875",
2168
+ "0xD855-6": "876",
2169
+ "0xD855-7": "877",
2170
+ "0xD856-0": "878",
2171
+ "0xD856-1": "879",
2172
+ "0xD856-2": "87A",
2173
+ "0xD856-3": "87B",
2174
+ "0xD856-4": "87C",
2175
+ "0xD856-5": "87D",
2176
+ "0xD856-6": "87E",
2177
+ "0xD856-7": "87F",
2178
+ "0xD857-0": "Got Hm03",
2179
+ "0xD857-1": "881",
2180
+ "0xD857-2": "882",
2181
+ "0xD857-3": "883",
2182
+ "0xD857-4": "884",
2183
+ "0xD857-5": "885",
2184
+ "0xD857-6": "886",
2185
+ "0xD857-7": "887",
2186
+ "0xD858-0": "888",
2187
+ "0xD858-1": "889",
2188
+ "0xD858-2": "88A",
2189
+ "0xD858-3": "88B",
2190
+ "0xD858-4": "88C",
2191
+ "0xD858-5": "88D",
2192
+ "0xD858-6": "88E",
2193
+ "0xD858-7": "88F",
2194
+ "0xD859-0": "890",
2195
+ "0xD859-1": "891",
2196
+ "0xD859-2": "892",
2197
+ "0xD859-3": "893",
2198
+ "0xD859-4": "894",
2199
+ "0xD859-5": "895",
2200
+ "0xD859-6": "896",
2201
+ "0xD859-7": "897",
2202
+ "0xD85A-0": "898",
2203
+ "0xD85A-1": "899",
2204
+ "0xD85A-2": "89A",
2205
+ "0xD85A-3": "89B",
2206
+ "0xD85A-4": "89C",
2207
+ "0xD85A-5": "89D",
2208
+ "0xD85A-6": "89E",
2209
+ "0xD85A-7": "89F",
2210
+ "0xD85B-0": "8A0",
2211
+ "0xD85B-1": "8A1",
2212
+ "0xD85B-2": "8A2",
2213
+ "0xD85B-3": "8A3",
2214
+ "0xD85B-4": "8A4",
2215
+ "0xD85B-5": "8A5",
2216
+ "0xD85B-6": "8A6",
2217
+ "0xD85B-7": "8A7",
2218
+ "0xD85C-0": "8A8",
2219
+ "0xD85C-1": "8A9",
2220
+ "0xD85C-2": "8Aa",
2221
+ "0xD85C-3": "8Ab",
2222
+ "0xD85C-4": "8Ac",
2223
+ "0xD85C-5": "8Ad",
2224
+ "0xD85C-6": "8Ae",
2225
+ "0xD85C-7": "8Af",
2226
+ "0xD85D-0": "8B0",
2227
+ "0xD85D-1": "8B1",
2228
+ "0xD85D-2": "8B2",
2229
+ "0xD85D-3": "8B3",
2230
+ "0xD85D-4": "8B4",
2231
+ "0xD85D-5": "8B5",
2232
+ "0xD85D-6": "8B6",
2233
+ "0xD85D-7": "8B7",
2234
+ "0xD85E-0": "8B8",
2235
+ "0xD85E-1": "8B9",
2236
+ "0xD85E-2": "8Ba",
2237
+ "0xD85E-3": "8Bb",
2238
+ "0xD85E-4": "8Bc",
2239
+ "0xD85E-5": "8Bd",
2240
+ "0xD85E-6": "8Be",
2241
+ "0xD85E-7": "8Bf",
2242
+ "0xD85F-0": "8C0",
2243
+ "0xD85F-1": "Beat Mewtwo",
2244
+ "0xD85F-2": "8C2",
2245
+ "0xD85F-3": "8C3",
2246
+ "0xD85F-4": "8C4",
2247
+ "0xD85F-5": "8C5",
2248
+ "0xD85F-6": "8C6",
2249
+ "0xD85F-7": "8C7",
2250
+ "0xD860-0": "8C8",
2251
+ "0xD860-1": "8C9",
2252
+ "0xD860-2": "8Ca",
2253
+ "0xD860-3": "8Cb",
2254
+ "0xD860-4": "8Cc",
2255
+ "0xD860-5": "8Cd",
2256
+ "0xD860-6": "8Ce",
2257
+ "0xD860-7": "8Cf",
2258
+ "0xD861-0": "8D0",
2259
+ "0xD861-1": "8D1",
2260
+ "0xD861-2": "8D2",
2261
+ "0xD861-3": "8D3",
2262
+ "0xD861-4": "8D4",
2263
+ "0xD861-5": "8D5",
2264
+ "0xD861-6": "8D6",
2265
+ "0xD861-7": "8D7",
2266
+ "0xD862-0": "8D8",
2267
+ "0xD862-1": "8D9",
2268
+ "0xD862-2": "8Da",
2269
+ "0xD862-3": "8Db",
2270
+ "0xD862-4": "8Dc",
2271
+ "0xD862-5": "8Dd",
2272
+ "0xD862-6": "8De",
2273
+ "0xD862-7": "8Df",
2274
+ "0xD863-1": "Beat Loreleis Room Trainer 0",
2275
+ "0xD863-2": "8E2",
2276
+ "0xD863-3": "8E3",
2277
+ "0xD863-4": "8E4",
2278
+ "0xD863-5": "8E5",
2279
+ "0xD863-6": "Autowalked Into Loreleis Room",
2280
+ "0xD863-7": "8E7",
2281
+ "0xD864-0": "8E8",
2282
+ "0xD864-1": "Beat Brunos Room Trainer 0",
2283
+ "0xD864-2": "8Ea",
2284
+ "0xD864-3": "8Eb",
2285
+ "0xD864-4": "8Ec",
2286
+ "0xD864-5": "8Ed",
2287
+ "0xD864-6": "Autowalked Into Brunos Room",
2288
+ "0xD864-7": "8Ef",
2289
+ "0xD865-0": "8F0",
2290
+ "0xD865-1": "Beat Agathas Room Trainer 0",
2291
+ "0xD865-2": "8F2",
2292
+ "0xD865-3": "8F3",
2293
+ "0xD865-4": "8F4",
2294
+ "0xD865-5": "8F5",
2295
+ "0xD865-6": "Autowalked Into Agathas Room",
2296
+ "0xD865-7": "8F7",
2297
+ "0xD866-0": "8F8",
2298
+ "0xD866-1": "Beat Lances Room Trainer 0",
2299
+ "0xD866-2": "8Fa",
2300
+ "0xD866-3": "8Fb",
2301
+ "0xD866-4": "8Fc",
2302
+ "0xD866-5": "8Fd",
2303
+ "0xD866-6": "Beat Lance",
2304
+ "0xD866-7": "Lances Room Lock Door",
2305
+ "0xD867-0": "900",
2306
+ "0xD867-1": "Beat Champion Rival",
2307
+ "0xD867-2": "902",
2308
+ "0xD867-3": "903",
2309
+ "0xD867-4": "904",
2310
+ "0xD867-5": "905",
2311
+ "0xD867-6": "906",
2312
+ "0xD868-0": "908",
2313
+ "0xD868-1": "909",
2314
+ "0xD868-2": "90A",
2315
+ "0xD868-3": "90B",
2316
+ "0xD868-4": "90C",
2317
+ "0xD868-5": "90D",
2318
+ "0xD868-6": "90E",
2319
+ "0xD868-7": "90F",
2320
+ "0xD869-0": "910",
2321
+ "0xD869-1": "Beat Victory Road 1 Trainer 0",
2322
+ "0xD869-2": "Beat Victory Road 1 Trainer 1",
2323
+ "0xD869-3": "913",
2324
+ "0xD869-4": "914",
2325
+ "0xD869-5": "915",
2326
+ "0xD869-6": "916",
2327
+ "0xD869-7": "Victory Road 1 Boulder On Switch",
2328
+ "0xD86A-0": "918",
2329
+ "0xD86A-1": "919",
2330
+ "0xD86A-2": "91A",
2331
+ "0xD86A-3": "91B",
2332
+ "0xD86A-4": "91C",
2333
+ "0xD86A-5": "91D",
2334
+ "0xD86A-6": "91E",
2335
+ "0xD86A-7": "91F",
2336
+ "0xD86B-0": "920",
2337
+ "0xD86B-1": "921",
2338
+ "0xD86B-2": "922",
2339
+ "0xD86B-3": "923",
2340
+ "0xD86B-4": "924",
2341
+ "0xD86B-5": "925",
2342
+ "0xD86B-6": "926",
2343
+ "0xD86B-7": "927",
2344
+ "0xD86C-0": "928",
2345
+ "0xD86C-1": "929",
2346
+ "0xD86C-2": "92A",
2347
+ "0xD86C-3": "92B",
2348
+ "0xD86C-4": "92C",
2349
+ "0xD86C-5": "92D",
2350
+ "0xD86C-6": "92E",
2351
+ "0xD86C-7": "92F",
2352
+ "0xD86D-0": "930",
2353
+ "0xD86D-1": "931",
2354
+ "0xD86D-2": "932",
2355
+ "0xD86D-3": "933",
2356
+ "0xD86D-4": "934",
2357
+ "0xD86D-5": "935",
2358
+ "0xD86D-6": "936",
2359
+ "0xD86D-7": "937",
2360
+ "0xD86E-0": "938",
2361
+ "0xD86E-1": "939",
2362
+ "0xD86E-2": "93A",
2363
+ "0xD86E-3": "93B",
2364
+ "0xD86E-4": "93C",
2365
+ "0xD86E-5": "93D",
2366
+ "0xD86E-6": "93E",
2367
+ "0xD86E-7": "93F",
2368
+ "0xD86F-0": "940",
2369
+ "0xD86F-1": "941",
2370
+ "0xD86F-2": "942",
2371
+ "0xD86F-3": "943",
2372
+ "0xD86F-4": "944",
2373
+ "0xD86F-5": "945",
2374
+ "0xD86F-6": "946",
2375
+ "0xD86F-7": "947",
2376
+ "0xD870-0": "948",
2377
+ "0xD870-1": "949",
2378
+ "0xD870-2": "94A",
2379
+ "0xD870-3": "94B",
2380
+ "0xD870-4": "94C",
2381
+ "0xD870-5": "94D",
2382
+ "0xD870-6": "94E",
2383
+ "0xD870-7": "94F",
2384
+ "0xD871-0": "950",
2385
+ "0xD871-1": "951",
2386
+ "0xD871-2": "952",
2387
+ "0xD871-3": "953",
2388
+ "0xD871-4": "954",
2389
+ "0xD871-5": "955",
2390
+ "0xD871-6": "956",
2391
+ "0xD871-7": "957",
2392
+ "0xD872-0": "958",
2393
+ "0xD872-1": "959",
2394
+ "0xD872-2": "95A",
2395
+ "0xD872-3": "95B",
2396
+ "0xD872-4": "95C",
2397
+ "0xD872-5": "95D",
2398
+ "0xD872-6": "95E",
2399
+ "0xD872-7": "95F",
2400
+ "0xD873-0": "960",
2401
+ "0xD873-1": "961",
2402
+ "0xD873-2": "962",
2403
+ "0xD873-3": "963",
2404
+ "0xD873-4": "964",
2405
+ "0xD873-5": "965",
2406
+ "0xD873-6": "966",
2407
+ "0xD873-7": "967",
2408
+ "0xD874-0": "968",
2409
+ "0xD874-1": "969",
2410
+ "0xD874-2": "96A",
2411
+ "0xD874-3": "96B",
2412
+ "0xD874-4": "96C",
2413
+ "0xD874-5": "96D",
2414
+ "0xD874-6": "96E",
2415
+ "0xD874-7": "96F",
2416
+ "0xD875-0": "970",
2417
+ "0xD875-1": "971",
2418
+ "0xD875-2": "972",
2419
+ "0xD875-3": "973",
2420
+ "0xD875-4": "974",
2421
+ "0xD875-5": "975",
2422
+ "0xD875-6": "976",
2423
+ "0xD875-7": "977",
2424
+ "0xD876-0": "978",
2425
+ "0xD876-1": "979",
2426
+ "0xD876-2": "97A",
2427
+ "0xD876-3": "97B",
2428
+ "0xD876-4": "97C",
2429
+ "0xD876-5": "97D",
2430
+ "0xD876-6": "97E",
2431
+ "0xD876-7": "97F",
2432
+ "0xD877-0": "980",
2433
+ "0xD877-1": "981",
2434
+ "0xD877-2": "982",
2435
+ "0xD877-3": "983",
2436
+ "0xD877-4": "984",
2437
+ "0xD877-5": "985",
2438
+ "0xD877-6": "986",
2439
+ "0xD877-7": "987",
2440
+ "0xD878-0": "988",
2441
+ "0xD878-1": "989",
2442
+ "0xD878-2": "98A",
2443
+ "0xD878-3": "98B",
2444
+ "0xD878-4": "98C",
2445
+ "0xD878-5": "98D",
2446
+ "0xD878-6": "98E",
2447
+ "0xD878-7": "98F",
2448
+ "0xD879-0": "990",
2449
+ "0xD879-1": "991",
2450
+ "0xD879-2": "992",
2451
+ "0xD879-3": "993",
2452
+ "0xD879-4": "994",
2453
+ "0xD879-5": "995",
2454
+ "0xD879-6": "996",
2455
+ "0xD879-7": "997",
2456
+ "0xD87A-0": "998",
2457
+ "0xD87A-1": "999",
2458
+ "0xD87A-2": "99A",
2459
+ "0xD87A-3": "99B",
2460
+ "0xD87A-4": "99C",
2461
+ "0xD87A-5": "99D",
2462
+ "0xD87A-6": "99E",
2463
+ "0xD87A-7": "99F",
2464
+ "0xD87B-0": "9A0",
2465
+ "0xD87B-1": "9A1",
2466
+ "0xD87B-2": "9A2",
2467
+ "0xD87B-3": "9A3",
2468
+ "0xD87B-4": "9A4",
2469
+ "0xD87B-5": "9A5",
2470
+ "0xD87B-6": "9A6",
2471
+ "0xD87B-7": "9A7",
2472
+ "0xD87C-0": "9A8",
2473
+ "0xD87C-1": "9A9",
2474
+ "0xD87C-2": "9Aa",
2475
+ "0xD87C-3": "9Ab",
2476
+ "0xD87C-4": "9Ac",
2477
+ "0xD87C-5": "9Ad",
2478
+ "0xD87C-6": "9Ae",
2479
+ "0xD87C-7": "9Af",
2480
+ "0xD87D-0": "9B0",
2481
+ "0xD87D-1": "Beat Rock Tunnel 2 Trainer 0",
2482
+ "0xD87D-2": "Beat Rock Tunnel 2 Trainer 1",
2483
+ "0xD87D-3": "Beat Rock Tunnel 2 Trainer 2",
2484
+ "0xD87D-4": "Beat Rock Tunnel 2 Trainer 3",
2485
+ "0xD87D-5": "Beat Rock Tunnel 2 Trainer 4",
2486
+ "0xD87D-6": "Beat Rock Tunnel 2 Trainer 5",
2487
+ "0xD87D-7": "Beat Rock Tunnel 2 Trainer 6",
2488
+ "0xD87E-0": "Beat Rock Tunnel 2 Trainer 7",
2489
+ "0xD87E-1": "9B9",
2490
+ "0xD87E-2": "9Ba",
2491
+ "0xD87E-3": "9Bb",
2492
+ "0xD87E-4": "9Bc",
2493
+ "0xD87E-5": "9Bd",
2494
+ "0xD87E-6": "9Be",
2495
+ "0xD87E-7": "9Bf",
2496
+ "0xD87F-0": "Seafoam2 Boulder1 Down Hole",
2497
+ "0xD87F-1": "Seafoam2 Boulder2 Down Hole",
2498
+ "0xD87F-2": "9C2",
2499
+ "0xD87F-3": "9C3",
2500
+ "0xD87F-4": "9C4",
2501
+ "0xD87F-5": "9C5",
2502
+ "0xD87F-6": "9C6",
2503
+ "0xD87F-7": "9C7",
2504
+ "0xD880-0": "Seafoam3 Boulder1 Down Hole",
2505
+ "0xD880-1": "Seafoam3 Boulder2 Down Hole",
2506
+ "0xD880-2": "9Ca",
2507
+ "0xD880-3": "9Cb",
2508
+ "0xD880-4": "9Cc",
2509
+ "0xD880-5": "9Cd",
2510
+ "0xD880-6": "9Ce",
2511
+ "0xD880-7": "9Cf",
2512
+ "0xD881-0": "Seafoam4 Boulder1 Down Hole",
2513
+ "0xD881-1": "Seafoam4 Boulder2 Down Hole",
2514
+ "0xD881-2": "9D2",
2515
+ "0xD881-3": "9D3",
2516
+ "0xD881-4": "9D4",
2517
+ "0xD881-5": "9D5",
2518
+ "0xD881-6": "9D6",
2519
+ "0xD881-7": "9D7",
2520
+ "0xD882-0": "9D8",
2521
+ "0xD882-1": "9D9",
2522
+ "0xD882-2": "Beat Articuno",
2523
+ "0xD882-3": "9Db",
2524
+ "0xD882-4": "9Dc",
2525
+ "0xD882-5": "9Dd",
2526
+ "0xD882-6": "9De",
2527
+ "0xD882-7": "9Df",
2528
+ "0xD883-0": "9E0",
2529
+ "0xD883-1": "9E1",
2530
+ "0xD883-2": "9E2",
2531
+ "0xD883-3": "9E3",
2532
+ "0xD883-4": "9E4",
2533
+ "0xD883-5": "9E5",
2534
+ "0xD883-6": "9E6",
2535
+ "0xD883-7": "9E7",
2536
+ "0xD884-0": "9E8",
2537
+ "0xD884-1": "9E9",
2538
+ "0xD884-2": "9Ea",
2539
+ "0xD884-3": "9Eb",
2540
+ "0xD884-4": "9Ec",
2541
+ "0xD884-5": "9Ed",
2542
+ "0xD884-6": "9Ee",
2543
+ "0xD884-7": "9Ef",
2544
+ "0xD885-0": "9F0",
2545
+ "0xD885-1": "9F1",
2546
+ "0xD885-2": "9F2",
2547
+ "0xD885-3": "9F3",
2548
+ "0xD885-4": "9F4",
2549
+ "0xD885-5": "9F5",
2550
+ "0xD885-6": "9F6",
2551
+ "0xD885-7": "9F7",
2552
+ "0xD886-0": "9F8",
2553
+ "0xD886-1": "9F9",
2554
+ "0xD886-2": "9Fa",
2555
+ "0xD886-3": "9Fb",
2556
+ "0xD886-4": "9Fc",
2557
+ "0xD886-5": "9Fd",
2558
+ "0xD886-6": "9Fe",
2559
+ "0xD886-7": "9Ff"
2560
+ }
server/global_map.py ADDED
@@ -0,0 +1,31 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # adapted from https://github.com/thatguy11325/pokemonred_puffer/blob/main/pokemonred_puffer/global_map.py
2
+
3
+ import os
4
+ import json
5
+
6
+ MAP_PATH = os.path.join(os.path.dirname(__file__), "map_data.json")
7
+ PAD = 20
8
+ GLOBAL_MAP_SHAPE = (444 + PAD * 2, 436 + PAD * 2)
9
+ MAP_ROW_OFFSET = PAD
10
+ MAP_COL_OFFSET = PAD
11
+
12
+ with open(MAP_PATH) as map_data:
13
+ MAP_DATA = json.load(map_data)["regions"]
14
+ MAP_DATA = {int(e["id"]): e for e in MAP_DATA}
15
+
16
+ # Handle KeyErrors
17
+ def local_to_global(r: int, c: int, map_n: int):
18
+ try:
19
+ (
20
+ map_x,
21
+ map_y,
22
+ ) = MAP_DATA[map_n]["coordinates"]
23
+ gy = r + map_y + MAP_ROW_OFFSET
24
+ gx = c + map_x + MAP_COL_OFFSET
25
+ if 0 <= gy < GLOBAL_MAP_SHAPE[0] and 0 <= gx < GLOBAL_MAP_SHAPE[1]:
26
+ return gy, gx
27
+ print(f"coord out of bounds! global: ({gx}, {gy}) game: ({r}, {c}, {map_n})")
28
+ return GLOBAL_MAP_SHAPE[0] // 2, GLOBAL_MAP_SHAPE[1] // 2
29
+ except KeyError:
30
+ print(f"Map id {map_n} not found in map_data.json.")
31
+ return GLOBAL_MAP_SHAPE[0] // 2, GLOBAL_MAP_SHAPE[1] // 2
server/init.state ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:ef978b1668d2fad22a7b809a45fec37f3dd3fc5ef37d996f65b4ac93041afcb8
3
+ size 142586
server/map_data.json ADDED
@@ -0,0 +1,2716 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "regions": [
3
+ {
4
+ "id": "-1",
5
+ "name": "Kanto",
6
+ "coordinates": [
7
+ 0,
8
+ 0
9
+ ],
10
+ "tileSize": [
11
+ 436,
12
+ 444
13
+ ]
14
+ },
15
+ {
16
+ "id": "0",
17
+ "name": "Pallet Town",
18
+ "coordinates": [
19
+ 64,
20
+ 318
21
+ ],
22
+ "tileSize": [
23
+ 20,
24
+ 18
25
+ ]
26
+ },
27
+ {
28
+ "id": "1",
29
+ "name": "Viridian City",
30
+ "coordinates": [
31
+ 54,
32
+ 246
33
+ ],
34
+ "tileSize": [
35
+ 40,
36
+ 36
37
+ ]
38
+ },
39
+ {
40
+ "id": "2",
41
+ "name": "Pewter City",
42
+ "coordinates": [
43
+ 54,
44
+ 138
45
+ ],
46
+ "tileSize": [
47
+ 40,
48
+ 36
49
+ ]
50
+ },
51
+ {
52
+ "id": "3",
53
+ "name": "Cerulean City",
54
+ "coordinates": [
55
+ 234,
56
+ 120
57
+ ],
58
+ "tileSize": [
59
+ 40,
60
+ 36
61
+ ]
62
+ },
63
+ {
64
+ "id": "4",
65
+ "name": "Lavender Town",
66
+ "coordinates": [
67
+ 334,
68
+ 200
69
+ ],
70
+ "tileSize": [
71
+ 20,
72
+ 18
73
+ ]
74
+ },
75
+ {
76
+ "id": "5",
77
+ "name": "Vermilion City",
78
+ "coordinates": [
79
+ 234,
80
+ 264
81
+ ],
82
+ "tileSize": [
83
+ 40,
84
+ 36
85
+ ]
86
+ },
87
+ {
88
+ "id": "6",
89
+ "name": "Celadon City",
90
+ "coordinates": [
91
+ 164,
92
+ 192
93
+ ],
94
+ "tileSize": [
95
+ 50,
96
+ 36
97
+ ]
98
+ },
99
+ {
100
+ "id": "7",
101
+ "name": "Fuchsia City",
102
+ "coordinates": [
103
+ 174,
104
+ 354
105
+ ],
106
+ "tileSize": [
107
+ 40,
108
+ 36
109
+ ]
110
+ },
111
+ {
112
+ "id": "8",
113
+ "name": "Cinnabar island",
114
+ "coordinates": [
115
+ 64,
116
+ 426
117
+ ],
118
+ "tileSize": [
119
+ 20,
120
+ 18
121
+ ]
122
+ },
123
+ {
124
+ "id": "9",
125
+ "name": "Indigo Plateau",
126
+ "coordinates": [
127
+ 14,
128
+ 84
129
+ ],
130
+ "tileSize": [
131
+ 20,
132
+ 18
133
+ ]
134
+ },
135
+ {
136
+ "id": "10",
137
+ "name": "Saffron City",
138
+ "coordinates": [
139
+ 234,
140
+ 192
141
+ ],
142
+ "tileSize": [
143
+ 40,
144
+ 36
145
+ ]
146
+ },
147
+ {
148
+ "id": "12",
149
+ "name": "Route 1",
150
+ "coordinates": [
151
+ 64,
152
+ 282
153
+ ],
154
+ "tileSize": [
155
+ 20,
156
+ 36
157
+ ]
158
+ },
159
+ {
160
+ "id": "13",
161
+ "name": "Route 2",
162
+ "coordinates": [
163
+ 64,
164
+ 174
165
+ ],
166
+ "tileSize": [
167
+ 20,
168
+ 72
169
+ ]
170
+ },
171
+ {
172
+ "id": "14",
173
+ "name": "Route 3",
174
+ "coordinates": [
175
+ 94,
176
+ 146
177
+ ],
178
+ "tileSize": [
179
+ 70,
180
+ 18
181
+ ]
182
+ },
183
+ {
184
+ "id": "15",
185
+ "name": "Route 4",
186
+ "coordinates": [
187
+ 144,
188
+ 128
189
+ ],
190
+ "tileSize": [
191
+ 90,
192
+ 18
193
+ ]
194
+ },
195
+ {
196
+ "id": "16",
197
+ "name": "Route 5",
198
+ "coordinates": [
199
+ 244,
200
+ 156
201
+ ],
202
+ "tileSize": [
203
+ 20,
204
+ 36
205
+ ]
206
+ },
207
+ {
208
+ "id": "17",
209
+ "name": "Route 6",
210
+ "coordinates": [
211
+ 244,
212
+ 228
213
+ ],
214
+ "tileSize": [
215
+ 20,
216
+ 36
217
+ ]
218
+ },
219
+ {
220
+ "id": "18",
221
+ "name": "Route 7",
222
+ "coordinates": [
223
+ 214,
224
+ 200
225
+ ],
226
+ "tileSize": [
227
+ 20,
228
+ 18
229
+ ]
230
+ },
231
+ {
232
+ "id": "19",
233
+ "name": "Route 8",
234
+ "coordinates": [
235
+ 274,
236
+ 200
237
+ ],
238
+ "tileSize": [
239
+ 60,
240
+ 18
241
+ ]
242
+ },
243
+ {
244
+ "id": "20",
245
+ "name": "Route 9",
246
+ "coordinates": [
247
+ 274,
248
+ 128
249
+ ],
250
+ "tileSize": [
251
+ 60,
252
+ 18
253
+ ]
254
+ },
255
+ {
256
+ "id": "21",
257
+ "name": "Route 10",
258
+ "coordinates": [
259
+ 334,
260
+ 128
261
+ ],
262
+ "tileSize": [
263
+ 20,
264
+ 72
265
+ ]
266
+ },
267
+ {
268
+ "id": "22",
269
+ "name": "Route 11",
270
+ "coordinates": [
271
+ 274,
272
+ 272
273
+ ],
274
+ "tileSize": [
275
+ 60,
276
+ 18
277
+ ]
278
+ },
279
+ {
280
+ "id": "23",
281
+ "name": "Route 12",
282
+ "coordinates": [
283
+ 334,
284
+ 218
285
+ ],
286
+ "tileSize": [
287
+ 20,
288
+ 108
289
+ ]
290
+ },
291
+ {
292
+ "id": "24",
293
+ "name": "Route 13",
294
+ "coordinates": [
295
+ 294,
296
+ 326
297
+ ],
298
+ "tileSize": [
299
+ 60,
300
+ 18
301
+ ]
302
+ },
303
+ {
304
+ "id": "25",
305
+ "name": "Route 14",
306
+ "coordinates": [
307
+ 274,
308
+ 326
309
+ ],
310
+ "tileSize": [
311
+ 20,
312
+ 54
313
+ ]
314
+ },
315
+ {
316
+ "id": "26",
317
+ "name": "Route 15",
318
+ "coordinates": [
319
+ 214,
320
+ 362
321
+ ],
322
+ "tileSize": [
323
+ 60,
324
+ 18
325
+ ]
326
+ },
327
+ {
328
+ "id": "27",
329
+ "name": "Route 16",
330
+ "coordinates": [
331
+ 124,
332
+ 200
333
+ ],
334
+ "tileSize": [
335
+ 40,
336
+ 18
337
+ ]
338
+ },
339
+ {
340
+ "id": "28",
341
+ "name": "Route 17",
342
+ "coordinates": [
343
+ 124,
344
+ 218
345
+ ],
346
+ "tileSize": [
347
+ 20,
348
+ 144
349
+ ]
350
+ },
351
+ {
352
+ "id": "29",
353
+ "name": "Route 18",
354
+ "coordinates": [
355
+ 124,
356
+ 362
357
+ ],
358
+ "tileSize": [
359
+ 50,
360
+ 18
361
+ ]
362
+ },
363
+ {
364
+ "id": "30",
365
+ "name": "Sea Route 19",
366
+ "coordinates": [
367
+ 184,
368
+ 390
369
+ ],
370
+ "tileSize": [
371
+ 20,
372
+ 54
373
+ ]
374
+ },
375
+ {
376
+ "id": "31",
377
+ "name": "Sea Route 20",
378
+ "coordinates": [
379
+ 84,
380
+ 426
381
+ ],
382
+ "tileSize": [
383
+ 100,
384
+ 18
385
+ ]
386
+ },
387
+ {
388
+ "id": "32",
389
+ "name": "Sea Route 21",
390
+ "coordinates": [
391
+ 64,
392
+ 336
393
+ ],
394
+ "tileSize": [
395
+ 20,
396
+ 90
397
+ ]
398
+ },
399
+ {
400
+ "id": "33",
401
+ "name": "Route 22",
402
+ "coordinates": [
403
+ 14,
404
+ 254
405
+ ],
406
+ "tileSize": [
407
+ 40,
408
+ 18
409
+ ]
410
+ },
411
+ {
412
+ "id": "34",
413
+ "name": "Route 23",
414
+ "coordinates": [
415
+ 14,
416
+ 102
417
+ ],
418
+ "tileSize": [
419
+ 20,
420
+ 144
421
+ ]
422
+ },
423
+ {
424
+ "id": "35",
425
+ "name": "Route 24",
426
+ "coordinates": [
427
+ 244,
428
+ 84
429
+ ],
430
+ "tileSize": [
431
+ 20,
432
+ 36
433
+ ]
434
+ },
435
+ {
436
+ "id": "36",
437
+ "name": "Route 25",
438
+ "coordinates": [
439
+ 264,
440
+ 84
441
+ ],
442
+ "tileSize": [
443
+ 60,
444
+ 18
445
+ ]
446
+ },
447
+ {
448
+ "id": "37",
449
+ "name": "Players House First Floor",
450
+ "coordinates": [
451
+ 55,
452
+ 328
453
+ ],
454
+ "tileSize": [
455
+ 8,
456
+ 8
457
+ ]
458
+ },
459
+ {
460
+ "id": "38",
461
+ "name": "Players House Second Floor",
462
+ "coordinates": [
463
+ 55,
464
+ 319
465
+ ],
466
+ "tileSize": [
467
+ 8,
468
+ 8
469
+ ]
470
+ },
471
+ {
472
+ "id": "39",
473
+ "name": "Rivals House",
474
+ "coordinates": [
475
+ 85,
476
+ 316
477
+ ],
478
+ "tileSize": [
479
+ 8,
480
+ 8
481
+ ]
482
+ },
483
+ {
484
+ "id": "40",
485
+ "name": "Oaks Lab",
486
+ "coordinates": [
487
+ 85,
488
+ 325
489
+ ],
490
+ "tileSize": [
491
+ 10,
492
+ 12
493
+ ]
494
+ },
495
+ {
496
+ "id": "41",
497
+ "name": "Pokemon Center Viridian",
498
+ "coordinates": [
499
+ 95,
500
+ 274
501
+ ],
502
+ "tileSize": [
503
+ 14,
504
+ 8
505
+ ]
506
+ },
507
+ {
508
+ "id": "42",
509
+ "name": "Pokemart Viridian",
510
+ "coordinates": [
511
+ 110,
512
+ 274
513
+ ],
514
+ "tileSize": [
515
+ 8,
516
+ 8
517
+ ]
518
+ },
519
+ {
520
+ "id": "43",
521
+ "name": "Pokemon Academy",
522
+ "coordinates": [
523
+ 95,
524
+ 265
525
+ ],
526
+ "tileSize": [
527
+ 8,
528
+ 8
529
+ ]
530
+ },
531
+ {
532
+ "id": "44",
533
+ "name": "Nickname House",
534
+ "coordinates": [
535
+ 104,
536
+ 265
537
+ ],
538
+ "tileSize": [
539
+ 8,
540
+ 8
541
+ ]
542
+ },
543
+ {
544
+ "id": "45",
545
+ "name": "Viridian Gym",
546
+ "coordinates": [
547
+ 95,
548
+ 246
549
+ ],
550
+ "tileSize": [
551
+ 20,
552
+ 18
553
+ ]
554
+ },
555
+ {
556
+ "id": "46",
557
+ "name": "Digletts Cave Entrance",
558
+ "coordinates": [
559
+ 55,
560
+ 184
561
+ ],
562
+ "tileSize": [
563
+ 8,
564
+ 8
565
+ ]
566
+ },
567
+ {
568
+ "id": "47",
569
+ "name": "Route 2 Gate Pewter",
570
+ "coordinates": [
571
+ 85,
572
+ 180
573
+ ],
574
+ "tileSize": [
575
+ 10,
576
+ 8
577
+ ]
578
+ },
579
+ {
580
+ "id": "48",
581
+ "name": "Trader House Mr Mime Trade",
582
+ "coordinates": [
583
+ 55,
584
+ 193
585
+ ],
586
+ "tileSize": [
587
+ 8,
588
+ 8
589
+ ]
590
+ },
591
+ {
592
+ "id": "49",
593
+ "name": "Route 2 Gate Oaks Aid",
594
+ "coordinates": [
595
+ 53,
596
+ 202
597
+ ],
598
+ "tileSize": [
599
+ 10,
600
+ 8
601
+ ]
602
+ },
603
+ {
604
+ "id": "50",
605
+ "name": "Route 2 Gate Viridian",
606
+ "coordinates": [
607
+ 100,
608
+ 236
609
+ ],
610
+ "tileSize": [
611
+ 10,
612
+ 8
613
+ ]
614
+ },
615
+ {
616
+ "id": "51",
617
+ "name": "Viridian Forest",
618
+ "coordinates": [
619
+ 88,
620
+ 188
621
+ ],
622
+ "tileSize": [
623
+ 34,
624
+ 48
625
+ ]
626
+ },
627
+ {
628
+ "id": "52",
629
+ "name": "Museum F1",
630
+ "coordinates": [
631
+ 57,
632
+ 130
633
+ ],
634
+ "tileSize": [
635
+ 20,
636
+ 8
637
+ ]
638
+ },
639
+ {
640
+ "id": "53",
641
+ "name": "Museum F2",
642
+ "coordinates": [
643
+ 57,
644
+ 122
645
+ ],
646
+ "tileSize": [
647
+ 14,
648
+ 8
649
+ ]
650
+ },
651
+ {
652
+ "id": "54",
653
+ "name": "Pewter Gym",
654
+ "coordinates": [
655
+ 43,
656
+ 145
657
+ ],
658
+ "tileSize": [
659
+ 10,
660
+ 14
661
+ ]
662
+ },
663
+ {
664
+ "id": "55",
665
+ "name": "Trainer House Trading Tips",
666
+ "coordinates": [
667
+ 45,
668
+ 161
669
+ ],
670
+ "tileSize": [
671
+ 8,
672
+ 8
673
+ ]
674
+ },
675
+ {
676
+ "id": "56",
677
+ "name": "Pokemart",
678
+ "coordinates": [
679
+ 36,
680
+ 161
681
+ ],
682
+ "tileSize": [
683
+ 8,
684
+ 8
685
+ ]
686
+ },
687
+ {
688
+ "id": "57",
689
+ "name": "Trainer House Catching Tips",
690
+ "coordinates": [
691
+ 55,
692
+ 175
693
+ ],
694
+ "tileSize": [
695
+ 8,
696
+ 8
697
+ ]
698
+ },
699
+ {
700
+ "id": "58",
701
+ "name": "Pokemon Center Pewter",
702
+ "coordinates": [
703
+ 39,
704
+ 170
705
+ ],
706
+ "tileSize": [
707
+ 14,
708
+ 8
709
+ ]
710
+ },
711
+ {
712
+ "id": "59",
713
+ "name": "Mt Moon Route 3",
714
+ "coordinates": [
715
+ 147,
716
+ 92
717
+ ],
718
+ "tileSize": [
719
+ 40,
720
+ 36
721
+ ]
722
+ },
723
+ {
724
+ "id": "60",
725
+ "name": "Mt Moon B1F",
726
+ "coordinates": [
727
+ 147,
728
+ 63
729
+ ],
730
+ "tileSize": [
731
+ 28,
732
+ 28
733
+ ]
734
+ },
735
+ {
736
+ "id": "61",
737
+ "name": "Mt Moon B2F",
738
+ "coordinates": [
739
+ 147,
740
+ 26
741
+ ],
742
+ "tileSize": [
743
+ 40,
744
+ 36
745
+ ]
746
+ },
747
+ {
748
+ "id": "62",
749
+ "name": "House Breakin",
750
+ "coordinates": [
751
+ 280,
752
+ 104
753
+ ],
754
+ "tileSize": [
755
+ 8,
756
+ 8
757
+ ]
758
+ },
759
+ {
760
+ "id": "63",
761
+ "name": "Trader House Jynx",
762
+ "coordinates": [
763
+ 225,
764
+ 119
765
+ ],
766
+ "tileSize": [
767
+ 8,
768
+ 8
769
+ ]
770
+ },
771
+ {
772
+ "id": "64",
773
+ "name": "Pokemon Center Cerulean",
774
+ "coordinates": [
775
+ 265,
776
+ 104
777
+ ],
778
+ "tileSize": [
779
+ 14,
780
+ 8
781
+ ]
782
+ },
783
+ {
784
+ "id": "65",
785
+ "name": "Cerulean Gym",
786
+ "coordinates": [
787
+ 275,
788
+ 113
789
+ ],
790
+ "tileSize": [
791
+ 10,
792
+ 14
793
+ ]
794
+ },
795
+ {
796
+ "id": "66",
797
+ "name": "Bike Shop",
798
+ "coordinates": [
799
+ 225,
800
+ 147
801
+ ],
802
+ "tileSize": [
803
+ 8,
804
+ 8
805
+ ]
806
+ },
807
+ {
808
+ "id": "67",
809
+ "name": "Pokemart Cerulean",
810
+ "coordinates": [
811
+ 225,
812
+ 156
813
+ ],
814
+ "tileSize": [
815
+ 8,
816
+ 8
817
+ ]
818
+ },
819
+ {
820
+ "id": "68",
821
+ "name": "Pokemon Center Route 4",
822
+ "coordinates": [
823
+ 129,
824
+ 128
825
+ ],
826
+ "tileSize": [
827
+ 14,
828
+ 8
829
+ ]
830
+ },
831
+ {
832
+ "id": "69",
833
+ "name": "House Breakin V2",
834
+ "coordinates": [
835
+ 280,
836
+ 104
837
+ ],
838
+ "tileSize": [
839
+ 8,
840
+ 8
841
+ ]
842
+ },
843
+ {
844
+ "id": "70",
845
+ "name": "Saffron City Gate North",
846
+ "coordinates": [
847
+ 265,
848
+ 165
849
+ ],
850
+ "tileSize": [
851
+ 8,
852
+ 6
853
+ ]
854
+ },
855
+ {
856
+ "id": "71",
857
+ "name": "Underground Entrance North",
858
+ "coordinates": [
859
+ 274,
860
+ 163
861
+ ],
862
+ "tileSize": [
863
+ 8,
864
+ 8
865
+ ]
866
+ },
867
+ {
868
+ "id": "72",
869
+ "name": "Daycare",
870
+ "coordinates": [
871
+ 235,
872
+ 157
873
+ ],
874
+ "tileSize": [
875
+ 8,
876
+ 8
877
+ ]
878
+ },
879
+ {
880
+ "id": "73",
881
+ "name": "Underground Entrance",
882
+ "coordinates": [
883
+ 265,
884
+ 248
885
+ ],
886
+ "tileSize": [
887
+ 8,
888
+ 6
889
+ ]
890
+ },
891
+ {
892
+ "id": "74",
893
+ "name": "Underground Entrance South",
894
+ "coordinates": [
895
+ 265,
896
+ 255
897
+ ],
898
+ "tileSize": [
899
+ 8,
900
+ 8
901
+ ]
902
+ },
903
+ {
904
+ "id": "76",
905
+ "name": "Saffron City Gate",
906
+ "coordinates": [
907
+ 227,
908
+ 219
909
+ ],
910
+ "tileSize": [
911
+ 6,
912
+ 8
913
+ ]
914
+ },
915
+ {
916
+ "id": "77",
917
+ "name": "Underground Entrance",
918
+ "coordinates": [
919
+ 216,
920
+ 219
921
+ ],
922
+ "tileSize": [
923
+ 8,
924
+ 8
925
+ ]
926
+ },
927
+ {
928
+ "id": "78",
929
+ "name": "Underground Entrance V2",
930
+ "coordinates": [
931
+ 216,
932
+ 219
933
+ ],
934
+ "tileSize": [
935
+ 8,
936
+ 8
937
+ ]
938
+ },
939
+ {
940
+ "id": "79",
941
+ "name": "Underground Entrance V2",
942
+ "coordinates": [
943
+ 275,
944
+ 219
945
+ ],
946
+ "tileSize": [
947
+ 6,
948
+ 8
949
+ ]
950
+ },
951
+ {
952
+ "id": "80",
953
+ "name": "Underground Entrance V2",
954
+ "coordinates": [
955
+ 282,
956
+ 219
957
+ ],
958
+ "tileSize": [
959
+ 8,
960
+ 8
961
+ ]
962
+ },
963
+ {
964
+ "id": "81",
965
+ "name": "Pokemon Center Route 10",
966
+ "coordinates": [
967
+ 355,
968
+ 136
969
+ ],
970
+ "tileSize": [
971
+ 14,
972
+ 8
973
+ ]
974
+ },
975
+ {
976
+ "id": "82",
977
+ "name": "Rock Tunnel 1F",
978
+ "coordinates": [
979
+ 355,
980
+ 145
981
+ ],
982
+ "tileSize": [
983
+ 40,
984
+ 36
985
+ ]
986
+ },
987
+ {
988
+ "id": "83",
989
+ "name": "Power Plant",
990
+ "coordinates": [
991
+ 293,
992
+ 147
993
+ ],
994
+ "tileSize": [
995
+ 40,
996
+ 36
997
+ ]
998
+ },
999
+ {
1000
+ "id": "84",
1001
+ "name": "Gate 1F",
1002
+ "coordinates": [
1003
+ 325,
1004
+ 261
1005
+ ],
1006
+ "tileSize": [
1007
+ 8,
1008
+ 10
1009
+ ]
1010
+ },
1011
+ {
1012
+ "id": "85",
1013
+ "name": "Digletts Cave Entrance",
1014
+ "coordinates": [
1015
+ 275,
1016
+ 264
1017
+ ],
1018
+ "tileSize": [
1019
+ 8,
1020
+ 8
1021
+ ]
1022
+ },
1023
+ {
1024
+ "id": "86",
1025
+ "name": "Gate 2F",
1026
+ "coordinates": [
1027
+ 325,
1028
+ 252
1029
+ ],
1030
+ "tileSize": [
1031
+ 8,
1032
+ 8
1033
+ ]
1034
+ },
1035
+ {
1036
+ "id": "87",
1037
+ "name": "Gate 1F",
1038
+ "coordinates": [
1039
+ 355,
1040
+ 232
1041
+ ],
1042
+ "tileSize": [
1043
+ 10,
1044
+ 8
1045
+ ]
1046
+ },
1047
+ {
1048
+ "id": "88",
1049
+ "name": "Bills Lab",
1050
+ "coordinates": [
1051
+ 307,
1052
+ 76
1053
+ ],
1054
+ "tileSize": [
1055
+ 8,
1056
+ 8
1057
+ ]
1058
+ },
1059
+ {
1060
+ "id": "89",
1061
+ "name": "Pokemon Center Vermilion",
1062
+ "coordinates": [
1063
+ 219,
1064
+ 264
1065
+ ],
1066
+ "tileSize": [
1067
+ 14,
1068
+ 8
1069
+ ]
1070
+ },
1071
+ {
1072
+ "id": "90",
1073
+ "name": "Pokemon Fan Club",
1074
+ "coordinates": [
1075
+ 216,
1076
+ 273
1077
+ ],
1078
+ "tileSize": [
1079
+ 8,
1080
+ 8
1081
+ ]
1082
+ },
1083
+ {
1084
+ "id": "91",
1085
+ "name": "Pokemart Vermilion",
1086
+ "coordinates": [
1087
+ 225,
1088
+ 282
1089
+ ],
1090
+ "tileSize": [
1091
+ 8,
1092
+ 8
1093
+ ]
1094
+ },
1095
+ {
1096
+ "id": "92",
1097
+ "name": "Vermilion Gym",
1098
+ "coordinates": [
1099
+ 214,
1100
+ 282
1101
+ ],
1102
+ "tileSize": [
1103
+ 10,
1104
+ 18
1105
+ ]
1106
+ },
1107
+ {
1108
+ "id": "93",
1109
+ "name": "Trader House Pidgy Letter",
1110
+ "coordinates": [
1111
+ 225,
1112
+ 273
1113
+ ],
1114
+ "tileSize": [
1115
+ 8,
1116
+ 8
1117
+ ]
1118
+ },
1119
+ {
1120
+ "id": "94",
1121
+ "name": "Vermilion Harbor",
1122
+ "coordinates": [
1123
+ 239,
1124
+ 300
1125
+ ],
1126
+ "tileSize": [
1127
+ 28,
1128
+ 12
1129
+ ]
1130
+ },
1131
+ {
1132
+ "id": "95",
1133
+ "name": "SS Anne F1",
1134
+ "coordinates": [
1135
+ 298,
1136
+ 345
1137
+ ],
1138
+ "tileSize": [
1139
+ 40,
1140
+ 18
1141
+ ]
1142
+ },
1143
+ {
1144
+ "id": "96",
1145
+ "name": "SS Anne F2",
1146
+ "coordinates": [
1147
+ 298,
1148
+ 377
1149
+ ],
1150
+ "tileSize": [
1151
+ 40,
1152
+ 18
1153
+ ]
1154
+ },
1155
+ {
1156
+ "id": "97",
1157
+ "name": "SS Anne F3",
1158
+ "coordinates": [
1159
+ 279,
1160
+ 387
1161
+ ],
1162
+ "tileSize": [
1163
+ 20,
1164
+ 6
1165
+ ]
1166
+ },
1167
+ {
1168
+ "id": "98",
1169
+ "name": "SS Anne B1F",
1170
+ "coordinates": [
1171
+ 308,
1172
+ 362
1173
+ ],
1174
+ "tileSize": [
1175
+ 30,
1176
+ 8
1177
+ ]
1178
+ },
1179
+ {
1180
+ "id": "99",
1181
+ "name": "SS Anne Deck",
1182
+ "coordinates": [
1183
+ 265,
1184
+ 384
1185
+ ],
1186
+ "tileSize": [
1187
+ 20,
1188
+ 14
1189
+ ]
1190
+ },
1191
+ {
1192
+ "id": "100",
1193
+ "name": "SS Anne Kitchen",
1194
+ "coordinates": [
1195
+ 295,
1196
+ 363
1197
+ ],
1198
+ "tileSize": [
1199
+ 14,
1200
+ 16
1201
+ ]
1202
+ },
1203
+ {
1204
+ "id": "101",
1205
+ "name": "SS Anne Captains Office",
1206
+ "coordinates": [
1207
+ 334,
1208
+ 371
1209
+ ],
1210
+ "tileSize": [
1211
+ 6,
1212
+ 8
1213
+ ]
1214
+ },
1215
+ {
1216
+ "id": "102",
1217
+ "name": "SS Anne Cabins 1F",
1218
+ "coordinates": [
1219
+ 341,
1220
+ 345
1221
+ ],
1222
+ "tileSize": [
1223
+ 24,
1224
+ 16
1225
+ ]
1226
+ },
1227
+ {
1228
+ "id": "103",
1229
+ "name": "SS Anne Cabins 2F",
1230
+ "coordinates": [
1231
+ 341,
1232
+ 379
1233
+ ],
1234
+ "tileSize": [
1235
+ 24,
1236
+ 16
1237
+ ]
1238
+ },
1239
+ {
1240
+ "id": "104",
1241
+ "name": "SS Anne Cabins B1F",
1242
+ "coordinates": [
1243
+ 341,
1244
+ 362
1245
+ ],
1246
+ "tileSize": [
1247
+ 24,
1248
+ 16
1249
+ ]
1250
+ },
1251
+ {
1252
+ "id": "108",
1253
+ "name": "Victory Road Entrance",
1254
+ "coordinates": [
1255
+ 35,
1256
+ 116
1257
+ ],
1258
+ "tileSize": [
1259
+ 20,
1260
+ 18
1261
+ ]
1262
+ },
1263
+ {
1264
+ "id": "113",
1265
+ "name": "Lances Room",
1266
+ "coordinates": [
1267
+ 0,
1268
+ 16
1269
+ ],
1270
+ "tileSize": [
1271
+ 26,
1272
+ 26
1273
+ ]
1274
+ },
1275
+ {
1276
+ "id": "118",
1277
+ "name": "Hall of Fame",
1278
+ "coordinates": [
1279
+ 1,
1280
+ 0
1281
+ ],
1282
+ "tileSize": [
1283
+ 10,
1284
+ 8
1285
+ ]
1286
+ },
1287
+ {
1288
+ "id": "119",
1289
+ "name": "Underground Path Route 5 to Route 6",
1290
+ "coordinates": [
1291
+ 356,
1292
+ 241
1293
+ ],
1294
+ "tileSize": [
1295
+ 8,
1296
+ 48
1297
+ ]
1298
+ },
1299
+ {
1300
+ "id": "120",
1301
+ "name": "Champions Room",
1302
+ "coordinates": [
1303
+ 2,
1304
+ 8
1305
+ ],
1306
+ "tileSize": [
1307
+ 8,
1308
+ 8
1309
+ ]
1310
+ },
1311
+ {
1312
+ "id": "121",
1313
+ "name": "Undeground Path",
1314
+ "coordinates": [
1315
+ 355,
1316
+ 287
1317
+ ],
1318
+ "tileSize": [
1319
+ 50,
1320
+ 8
1321
+ ]
1322
+ },
1323
+ {
1324
+ "id": "122",
1325
+ "name": "Department Store F1",
1326
+ "coordinates": [
1327
+ 170,
1328
+ 183
1329
+ ],
1330
+ "tileSize": [
1331
+ 20,
1332
+ 8
1333
+ ]
1334
+ },
1335
+ {
1336
+ "id": "123",
1337
+ "name": "Department Store F2",
1338
+ "coordinates": [
1339
+ 170,
1340
+ 174
1341
+ ],
1342
+ "tileSize": [
1343
+ 20,
1344
+ 8
1345
+ ]
1346
+ },
1347
+ {
1348
+ "id": "124",
1349
+ "name": "Department Store F3",
1350
+ "coordinates": [
1351
+ 170,
1352
+ 165
1353
+ ],
1354
+ "tileSize": [
1355
+ 20,
1356
+ 8
1357
+ ]
1358
+ },
1359
+ {
1360
+ "id": "125",
1361
+ "name": "Department Store F4",
1362
+ "coordinates": [
1363
+ 170,
1364
+ 156
1365
+ ],
1366
+ "tileSize": [
1367
+ 20,
1368
+ 8
1369
+ ]
1370
+ },
1371
+ {
1372
+ "id": "126",
1373
+ "name": "Department Store Roof",
1374
+ "coordinates": [
1375
+ 149,
1376
+ 174
1377
+ ],
1378
+ "tileSize": [
1379
+ 20,
1380
+ 8
1381
+ ]
1382
+ },
1383
+ {
1384
+ "id": "127",
1385
+ "name": "Department Store Lift",
1386
+ "coordinates": [
1387
+ 159,
1388
+ 192
1389
+ ],
1390
+ "tileSize": [
1391
+ 4,
1392
+ 4
1393
+ ]
1394
+ },
1395
+ {
1396
+ "id": "128",
1397
+ "name": "Office Building F1",
1398
+ "coordinates": [
1399
+ 191,
1400
+ 179
1401
+ ],
1402
+ "tileSize": [
1403
+ 8,
1404
+ 12
1405
+ ]
1406
+ },
1407
+ {
1408
+ "id": "129",
1409
+ "name": "Office Building F2",
1410
+ "coordinates": [
1411
+ 191,
1412
+ 166
1413
+ ],
1414
+ "tileSize": [
1415
+ 8,
1416
+ 12
1417
+ ]
1418
+ },
1419
+ {
1420
+ "id": "130",
1421
+ "name": "Office Building F3",
1422
+ "coordinates": [
1423
+ 191,
1424
+ 153
1425
+ ],
1426
+ "tileSize": [
1427
+ 8,
1428
+ 12
1429
+ ]
1430
+ },
1431
+ {
1432
+ "id": "131",
1433
+ "name": "Office Building F1",
1434
+ "coordinates": [
1435
+ 200,
1436
+ 170
1437
+ ],
1438
+ "tileSize": [
1439
+ 8,
1440
+ 12
1441
+ ]
1442
+ },
1443
+ {
1444
+ "id": "132",
1445
+ "name": "Office Building Roof Room",
1446
+ "coordinates": [
1447
+ 200,
1448
+ 161
1449
+ ],
1450
+ "tileSize": [
1451
+ 8,
1452
+ 8
1453
+ ]
1454
+ },
1455
+ {
1456
+ "id": "133",
1457
+ "name": "Pokemon Center Celedon",
1458
+ "coordinates": [
1459
+ 200,
1460
+ 183
1461
+ ],
1462
+ "tileSize": [
1463
+ 14,
1464
+ 8
1465
+ ]
1466
+ },
1467
+ {
1468
+ "id": "134",
1469
+ "name": "Celadon Gym",
1470
+ "coordinates": [
1471
+ 153,
1472
+ 219
1473
+ ],
1474
+ "tileSize": [
1475
+ 10,
1476
+ 18
1477
+ ]
1478
+ },
1479
+ {
1480
+ "id": "135",
1481
+ "name": "Rocket Game Corner",
1482
+ "coordinates": [
1483
+ 164,
1484
+ 238
1485
+ ],
1486
+ "tileSize": [
1487
+ 20,
1488
+ 18
1489
+ ]
1490
+ },
1491
+ {
1492
+ "id": "136",
1493
+ "name": "Department Store F5",
1494
+ "coordinates": [
1495
+ 149,
1496
+ 183
1497
+ ],
1498
+ "tileSize": [
1499
+ 20,
1500
+ 8
1501
+ ]
1502
+ },
1503
+ {
1504
+ "id": "137",
1505
+ "name": "Prize Corner",
1506
+ "coordinates": [
1507
+ 169,
1508
+ 229
1509
+ ],
1510
+ "tileSize": [
1511
+ 10,
1512
+ 8
1513
+ ]
1514
+ },
1515
+ {
1516
+ "id": "138",
1517
+ "name": "Restaurant",
1518
+ "coordinates": [
1519
+ 180,
1520
+ 229
1521
+ ],
1522
+ "tileSize": [
1523
+ 10,
1524
+ 8
1525
+ ]
1526
+ },
1527
+ {
1528
+ "id": "139",
1529
+ "name": "Rocket House",
1530
+ "coordinates": [
1531
+ 191,
1532
+ 229
1533
+ ],
1534
+ "tileSize": [
1535
+ 8,
1536
+ 8
1537
+ ]
1538
+ },
1539
+ {
1540
+ "id": "140",
1541
+ "name": "Hotel",
1542
+ "coordinates": [
1543
+ 200,
1544
+ 229
1545
+ ],
1546
+ "tileSize": [
1547
+ 14,
1548
+ 8
1549
+ ]
1550
+ },
1551
+ {
1552
+ "id": "141",
1553
+ "name": "Pokemon Center Lavender",
1554
+ "coordinates": [
1555
+ 310,
1556
+ 191
1557
+ ],
1558
+ "tileSize": [
1559
+ 14,
1560
+ 8
1561
+ ]
1562
+ },
1563
+ {
1564
+ "id": "142",
1565
+ "name": "Pokemon Tower F1",
1566
+ "coordinates": [
1567
+ 387,
1568
+ 239
1569
+ ],
1570
+ "tileSize": [
1571
+ 20,
1572
+ 18
1573
+ ]
1574
+ },
1575
+ {
1576
+ "id": "143",
1577
+ "name": "Pokemon Tower F2",
1578
+ "coordinates": [
1579
+ 366,
1580
+ 239
1581
+ ],
1582
+ "tileSize": [
1583
+ 20,
1584
+ 18
1585
+ ]
1586
+ },
1587
+ {
1588
+ "id": "144",
1589
+ "name": "Pokemon Tower F3",
1590
+ "coordinates": [
1591
+ 387,
1592
+ 220
1593
+ ],
1594
+ "tileSize": [
1595
+ 20,
1596
+ 18
1597
+ ]
1598
+ },
1599
+ {
1600
+ "id": "145",
1601
+ "name": "Pokemon Tower F4",
1602
+ "coordinates": [
1603
+ 366,
1604
+ 220
1605
+ ],
1606
+ "tileSize": [
1607
+ 20,
1608
+ 18
1609
+ ]
1610
+ },
1611
+ {
1612
+ "id": "146",
1613
+ "name": "Pokemon Tower F5",
1614
+ "coordinates": [
1615
+ 387,
1616
+ 201
1617
+ ],
1618
+ "tileSize": [
1619
+ 20,
1620
+ 18
1621
+ ]
1622
+ },
1623
+ {
1624
+ "id": "147",
1625
+ "name": "Pokemon Tower F6",
1626
+ "coordinates": [
1627
+ 366,
1628
+ 201
1629
+ ],
1630
+ "tileSize": [
1631
+ 20,
1632
+ 18
1633
+ ]
1634
+ },
1635
+ {
1636
+ "id": "148",
1637
+ "name": "Pokemon Tower F7",
1638
+ "coordinates": [
1639
+ 366,
1640
+ 182
1641
+ ],
1642
+ "tileSize": [
1643
+ 20,
1644
+ 18
1645
+ ]
1646
+ },
1647
+ {
1648
+ "id": "149",
1649
+ "name": "Mr Fuji House",
1650
+ "coordinates": [
1651
+ 325,
1652
+ 191
1653
+ ],
1654
+ "tileSize": [
1655
+ 8,
1656
+ 8
1657
+ ]
1658
+ },
1659
+ {
1660
+ "id": "150",
1661
+ "name": "Pokemart Lavender",
1662
+ "coordinates": [
1663
+ 355,
1664
+ 210
1665
+ ],
1666
+ "tileSize": [
1667
+ 8,
1668
+ 8
1669
+ ]
1670
+ },
1671
+ {
1672
+ "id": "151",
1673
+ "name": "Cubone House",
1674
+ "coordinates": [
1675
+ 316,
1676
+ 219
1677
+ ],
1678
+ "tileSize": [
1679
+ 8,
1680
+ 8
1681
+ ]
1682
+ },
1683
+ {
1684
+ "id": "152",
1685
+ "name": "Pokemart Fuchsia",
1686
+ "coordinates": [
1687
+ 165,
1688
+ 353
1689
+ ],
1690
+ "tileSize": [
1691
+ 8,
1692
+ 8
1693
+ ]
1694
+ },
1695
+ {
1696
+ "id": "153",
1697
+ "name": "Bills Mom",
1698
+ "coordinates": [
1699
+ 165,
1700
+ 381
1701
+ ],
1702
+ "tileSize": [
1703
+ 8,
1704
+ 8
1705
+ ]
1706
+ },
1707
+ {
1708
+ "id": "154",
1709
+ "name": "Pokemon Center Fuchsia",
1710
+ "coordinates": [
1711
+ 165,
1712
+ 391
1713
+ ],
1714
+ "tileSize": [
1715
+ 14,
1716
+ 8
1717
+ ]
1718
+ },
1719
+ {
1720
+ "id": "155",
1721
+ "name": "Wardens House",
1722
+ "coordinates": [
1723
+ 205,
1724
+ 391
1725
+ ],
1726
+ "tileSize": [
1727
+ 10,
1728
+ 8
1729
+ ]
1730
+ },
1731
+ {
1732
+ "id": "156",
1733
+ "name": "Safari Gate",
1734
+ "coordinates": [
1735
+ 189,
1736
+ 348
1737
+ ],
1738
+ "tileSize": [
1739
+ 8,
1740
+ 6
1741
+ ]
1742
+ },
1743
+ {
1744
+ "id": "157",
1745
+ "name": "Fuchsia Gym",
1746
+ "coordinates": [
1747
+ 154,
1748
+ 381
1749
+ ],
1750
+ "tileSize": [
1751
+ 10,
1752
+ 18
1753
+ ]
1754
+ },
1755
+ {
1756
+ "id": "158",
1757
+ "name": "Meeting Room",
1758
+ "coordinates": [
1759
+ 215,
1760
+ 353
1761
+ ],
1762
+ "tileSize": [
1763
+ 14,
1764
+ 8
1765
+ ]
1766
+ },
1767
+ {
1768
+ "id": "159",
1769
+ "name": "Sea Foam Islands B1F",
1770
+ "coordinates": [
1771
+ 116,
1772
+ 388
1773
+ ],
1774
+ "tileSize": [
1775
+ 30,
1776
+ 18
1777
+ ]
1778
+ },
1779
+ {
1780
+ "id": "160",
1781
+ "name": "Sea Foam Islands B2F",
1782
+ "coordinates": [
1783
+ 85,
1784
+ 388
1785
+ ],
1786
+ "tileSize": [
1787
+ 30,
1788
+ 18
1789
+ ]
1790
+ },
1791
+ {
1792
+ "id": "161",
1793
+ "name": "Sea Foam Islands B3F",
1794
+ "coordinates": [
1795
+ 85,
1796
+ 369
1797
+ ],
1798
+ "tileSize": [
1799
+ 30,
1800
+ 18
1801
+ ]
1802
+ },
1803
+ {
1804
+ "id": "162",
1805
+ "name": "Sea Foam Islands B4F",
1806
+ "coordinates": [
1807
+ 85,
1808
+ 350
1809
+ ],
1810
+ "tileSize": [
1811
+ 30,
1812
+ 18
1813
+ ]
1814
+ },
1815
+ {
1816
+ "id": "163",
1817
+ "name": "Fishing Guru Vermilion",
1818
+ "coordinates": [
1819
+ 210,
1820
+ 264
1821
+ ],
1822
+ "tileSize": [
1823
+ 8,
1824
+ 8
1825
+ ]
1826
+ },
1827
+ {
1828
+ "id": "164",
1829
+ "name": "Fishing Guru Fuchsia",
1830
+ "coordinates": [
1831
+ 215,
1832
+ 381
1833
+ ],
1834
+ "tileSize": [
1835
+ 8,
1836
+ 8
1837
+ ]
1838
+ },
1839
+ {
1840
+ "id": "165",
1841
+ "name": "Pokemon Mansion F1",
1842
+ "coordinates": [
1843
+ 33,
1844
+ 389
1845
+ ],
1846
+ "tileSize": [
1847
+ 30,
1848
+ 28
1849
+ ]
1850
+ },
1851
+ {
1852
+ "id": "166",
1853
+ "name": "Cinnabar Gym",
1854
+ "coordinates": [
1855
+ 85,
1856
+ 407
1857
+ ],
1858
+ "tileSize": [
1859
+ 20,
1860
+ 18
1861
+ ]
1862
+ },
1863
+ {
1864
+ "id": "167",
1865
+ "name": "Pokemon Lab",
1866
+ "coordinates": [
1867
+ 45,
1868
+ 427
1869
+ ],
1870
+ "tileSize": [
1871
+ 18,
1872
+ 8
1873
+ ]
1874
+ },
1875
+ {
1876
+ "id": "168",
1877
+ "name": "Lab Room 1",
1878
+ "coordinates": [
1879
+ 37,
1880
+ 418
1881
+ ],
1882
+ "tileSize": [
1883
+ 8,
1884
+ 8
1885
+ ]
1886
+ },
1887
+ {
1888
+ "id": "169",
1889
+ "name": "Lab Room 2",
1890
+ "coordinates": [
1891
+ 46,
1892
+ 418
1893
+ ],
1894
+ "tileSize": [
1895
+ 8,
1896
+ 8
1897
+ ]
1898
+ },
1899
+ {
1900
+ "id": "170",
1901
+ "name": "Lab Room 3",
1902
+ "coordinates": [
1903
+ 55,
1904
+ 418
1905
+ ],
1906
+ "tileSize": [
1907
+ 8,
1908
+ 8
1909
+ ]
1910
+ },
1911
+ {
1912
+ "id": "171",
1913
+ "name": "Pokemon Center Cinnabar",
1914
+ "coordinates": [
1915
+ 40,
1916
+ 436
1917
+ ],
1918
+ "tileSize": [
1919
+ 14,
1920
+ 8
1921
+ ]
1922
+ },
1923
+ {
1924
+ "id": "172",
1925
+ "name": "Pokemart Cinnabar",
1926
+ "coordinates": [
1927
+ 55,
1928
+ 436
1929
+ ],
1930
+ "tileSize": [
1931
+ 8,
1932
+ 8
1933
+ ]
1934
+ },
1935
+ {
1936
+ "id": "173",
1937
+ "name": "Pokemart V2",
1938
+ "coordinates": [
1939
+ 55,
1940
+ 436
1941
+ ],
1942
+ "tileSize": [
1943
+ 8,
1944
+ 8
1945
+ ]
1946
+ },
1947
+ {
1948
+ "id": "174",
1949
+ "name": "Indigo Plateau Lobby",
1950
+ "coordinates": [
1951
+ 16,
1952
+ 72
1953
+ ],
1954
+ "tileSize": [
1955
+ 16,
1956
+ 12
1957
+ ]
1958
+ },
1959
+ {
1960
+ "id": "175",
1961
+ "name": "Coppy Cat F1",
1962
+ "coordinates": [
1963
+ 215,
1964
+ 191
1965
+ ],
1966
+ "tileSize": [
1967
+ 8,
1968
+ 8
1969
+ ]
1970
+ },
1971
+ {
1972
+ "id": "176",
1973
+ "name": "Coppy Cat F2",
1974
+ "coordinates": [
1975
+ 215,
1976
+ 182
1977
+ ],
1978
+ "tileSize": [
1979
+ 8,
1980
+ 8
1981
+ ]
1982
+ },
1983
+ {
1984
+ "id": "177",
1985
+ "name": "Fighting Dojo",
1986
+ "coordinates": [
1987
+ 233,
1988
+ 179
1989
+ ],
1990
+ "tileSize": [
1991
+ 10,
1992
+ 12
1993
+ ]
1994
+ },
1995
+ {
1996
+ "id": "178",
1997
+ "name": "Saffron Gym",
1998
+ "coordinates": [
1999
+ 265,
2000
+ 172
2001
+ ],
2002
+ "tileSize": [
2003
+ 20,
2004
+ 18
2005
+ ]
2006
+ },
2007
+ {
2008
+ "id": "179",
2009
+ "name": "Trainer House",
2010
+ "coordinates": [
2011
+ 224,
2012
+ 191
2013
+ ],
2014
+ "tileSize": [
2015
+ 8,
2016
+ 8
2017
+ ]
2018
+ },
2019
+ {
2020
+ "id": "180",
2021
+ "name": "Pokemart Saffron",
2022
+ "coordinates": [
2023
+ 275,
2024
+ 191
2025
+ ],
2026
+ "tileSize": [
2027
+ 8,
2028
+ 8
2029
+ ]
2030
+ },
2031
+ {
2032
+ "id": "181",
2033
+ "name": "Silph Co 1F",
2034
+ "coordinates": [
2035
+ 325,
2036
+ 109
2037
+ ],
2038
+ "tileSize": [
2039
+ 30,
2040
+ 18
2041
+ ]
2042
+ },
2043
+ {
2044
+ "id": "182",
2045
+ "name": "Pokemon Center Saffron",
2046
+ "coordinates": [
2047
+ 229,
2048
+ 229
2049
+ ],
2050
+ "tileSize": [
2051
+ 14,
2052
+ 8
2053
+ ]
2054
+ },
2055
+ {
2056
+ "id": "183",
2057
+ "name": "Mr Psychics",
2058
+ "coordinates": [
2059
+ 265,
2060
+ 229
2061
+ ],
2062
+ "tileSize": [
2063
+ 8,
2064
+ 8
2065
+ ]
2066
+ },
2067
+ {
2068
+ "id": "184",
2069
+ "name": "Gate House F1",
2070
+ "coordinates": [
2071
+ 230,
2072
+ 351
2073
+ ],
2074
+ "tileSize": [
2075
+ 8,
2076
+ 10
2077
+ ]
2078
+ },
2079
+ {
2080
+ "id": "185",
2081
+ "name": "Gate House F2",
2082
+ "coordinates": [
2083
+ 230,
2084
+ 342
2085
+ ],
2086
+ "tileSize": [
2087
+ 8,
2088
+ 8
2089
+ ]
2090
+ },
2091
+ {
2092
+ "id": "186",
2093
+ "name": "Cycling Gate F1",
2094
+ "coordinates": [
2095
+ 140,
2096
+ 185
2097
+ ],
2098
+ "tileSize": [
2099
+ 8,
2100
+ 14
2101
+ ]
2102
+ },
2103
+ {
2104
+ "id": "187",
2105
+ "name": "Cycling Gate F2",
2106
+ "coordinates": [
2107
+ 140,
2108
+ 176
2109
+ ],
2110
+ "tileSize": [
2111
+ 8,
2112
+ 8
2113
+ ]
2114
+ },
2115
+ {
2116
+ "id": "188",
2117
+ "name": "Secret House",
2118
+ "coordinates": [
2119
+ 128,
2120
+ 191
2121
+ ],
2122
+ "tileSize": [
2123
+ 8,
2124
+ 8
2125
+ ]
2126
+ },
2127
+ {
2128
+ "id": "189",
2129
+ "name": "Fishing Guru Route 12",
2130
+ "coordinates": [
2131
+ 325,
2132
+ 291
2133
+ ],
2134
+ "tileSize": [
2135
+ 8,
2136
+ 8
2137
+ ]
2138
+ },
2139
+ {
2140
+ "id": "190",
2141
+ "name": "Cycling Gate F1",
2142
+ "coordinates": [
2143
+ 156,
2144
+ 351
2145
+ ],
2146
+ "tileSize": [
2147
+ 8,
2148
+ 10
2149
+ ]
2150
+ },
2151
+ {
2152
+ "id": "191",
2153
+ "name": "Cycling Gate F2",
2154
+ "coordinates": [
2155
+ 156,
2156
+ 342
2157
+ ],
2158
+ "tileSize": [
2159
+ 8,
2160
+ 8
2161
+ ]
2162
+ },
2163
+ {
2164
+ "id": "192",
2165
+ "name": "Sea Foam Islands 1F",
2166
+ "coordinates": [
2167
+ 116,
2168
+ 407
2169
+ ],
2170
+ "tileSize": [
2171
+ 30,
2172
+ 18
2173
+ ]
2174
+ },
2175
+ {
2176
+ "id": "193",
2177
+ "name": "Badge Gate House",
2178
+ "coordinates": [
2179
+ 17,
2180
+ 246
2181
+ ],
2182
+ "tileSize": [
2183
+ 10,
2184
+ 8
2185
+ ]
2186
+ },
2187
+ {
2188
+ "id": "194",
2189
+ "name": "Victory Road F2",
2190
+ "coordinates": [
2191
+ 35,
2192
+ 97
2193
+ ],
2194
+ "tileSize": [
2195
+ 30,
2196
+ 18
2197
+ ]
2198
+ },
2199
+ {
2200
+ "id": "195",
2201
+ "name": "Gate 2F",
2202
+ "coordinates": [
2203
+ 355,
2204
+ 223
2205
+ ],
2206
+ "tileSize": [
2207
+ 8,
2208
+ 8
2209
+ ]
2210
+ },
2211
+ {
2212
+ "id": "196",
2213
+ "name": "Trainer House Farfetch'd Trade",
2214
+ "coordinates": [
2215
+ 225,
2216
+ 291
2217
+ ],
2218
+ "tileSize": [
2219
+ 8,
2220
+ 8
2221
+ ]
2222
+ },
2223
+ {
2224
+ "id": "197",
2225
+ "name": "DIgletts Cave",
2226
+ "coordinates": [
2227
+ 284,
2228
+ 235
2229
+ ],
2230
+ "tileSize": [
2231
+ 40,
2232
+ 36
2233
+ ]
2234
+ },
2235
+ {
2236
+ "id": "198",
2237
+ "name": "Victory Road F3",
2238
+ "coordinates": [
2239
+ 35,
2240
+ 78
2241
+ ],
2242
+ "tileSize": [
2243
+ 30,
2244
+ 18
2245
+ ]
2246
+ },
2247
+ {
2248
+ "id": "199",
2249
+ "name": "Rocket Hideout B1F",
2250
+ "coordinates": [
2251
+ 97,
2252
+ 117
2253
+ ],
2254
+ "tileSize": [
2255
+ 30,
2256
+ 28
2257
+ ]
2258
+ },
2259
+ {
2260
+ "id": "200",
2261
+ "name": "Rocket Hideout B2F",
2262
+ "coordinates": [
2263
+ 97,
2264
+ 88
2265
+ ],
2266
+ "tileSize": [
2267
+ 30,
2268
+ 28
2269
+ ]
2270
+ },
2271
+ {
2272
+ "id": "201",
2273
+ "name": "Rocket Hideout B3F",
2274
+ "coordinates": [
2275
+ 97,
2276
+ 59
2277
+ ],
2278
+ "tileSize": [
2279
+ 30,
2280
+ 28
2281
+ ]
2282
+ },
2283
+ {
2284
+ "id": "202",
2285
+ "name": "Rocket Hideout B4F",
2286
+ "coordinates": [
2287
+ 97,
2288
+ 34
2289
+ ],
2290
+ "tileSize": [
2291
+ 30,
2292
+ 24
2293
+ ]
2294
+ },
2295
+ {
2296
+ "id": "203",
2297
+ "name": "Rocket Hideout Lift",
2298
+ "coordinates": [
2299
+ 121,
2300
+ 137
2301
+ ],
2302
+ "tileSize": [
2303
+ 6,
2304
+ 8
2305
+ ]
2306
+ },
2307
+ {
2308
+ "id": "207",
2309
+ "name": "Silph Co 2F",
2310
+ "coordinates": [
2311
+ 325,
2312
+ 90
2313
+ ],
2314
+ "tileSize": [
2315
+ 30,
2316
+ 18
2317
+ ]
2318
+ },
2319
+ {
2320
+ "id": "208",
2321
+ "name": "Silph Co 3F",
2322
+ "coordinates": [
2323
+ 325,
2324
+ 71
2325
+ ],
2326
+ "tileSize": [
2327
+ 30,
2328
+ 18
2329
+ ]
2330
+ },
2331
+ {
2332
+ "id": "209",
2333
+ "name": "Silph Co 4F",
2334
+ "coordinates": [
2335
+ 325,
2336
+ 52
2337
+ ],
2338
+ "tileSize": [
2339
+ 30,
2340
+ 18
2341
+ ]
2342
+ },
2343
+ {
2344
+ "id": "210",
2345
+ "name": "Silph Co 5F",
2346
+ "coordinates": [
2347
+ 325,
2348
+ 33
2349
+ ],
2350
+ "tileSize": [
2351
+ 30,
2352
+ 18
2353
+ ]
2354
+ },
2355
+ {
2356
+ "id": "211",
2357
+ "name": "Silph Co 6F",
2358
+ "coordinates": [
2359
+ 325,
2360
+ 14
2361
+ ],
2362
+ "tileSize": [
2363
+ 26,
2364
+ 18
2365
+ ]
2366
+ },
2367
+ {
2368
+ "id": "212",
2369
+ "name": "Silph Co 7F",
2370
+ "coordinates": [
2371
+ 356,
2372
+ 109
2373
+ ],
2374
+ "tileSize": [
2375
+ 26,
2376
+ 18
2377
+ ]
2378
+ },
2379
+ {
2380
+ "id": "213",
2381
+ "name": "Silph Co 8F",
2382
+ "coordinates": [
2383
+ 356,
2384
+ 90
2385
+ ],
2386
+ "tileSize": [
2387
+ 26,
2388
+ 18
2389
+ ]
2390
+ },
2391
+ {
2392
+ "id": "214",
2393
+ "name": "Pokemon Mansion F2",
2394
+ "coordinates": [
2395
+ 33,
2396
+ 360
2397
+ ],
2398
+ "tileSize": [
2399
+ 30,
2400
+ 28
2401
+ ]
2402
+ },
2403
+ {
2404
+ "id": "215",
2405
+ "name": "Pokemon Mansion F3",
2406
+ "coordinates": [
2407
+ 33,
2408
+ 341
2409
+ ],
2410
+ "tileSize": [
2411
+ 30,
2412
+ 18
2413
+ ]
2414
+ },
2415
+ {
2416
+ "id": "216",
2417
+ "name": "Pokemon Mansion B1F",
2418
+ "coordinates": [
2419
+ 2,
2420
+ 389
2421
+ ],
2422
+ "tileSize": [
2423
+ 30,
2424
+ 28
2425
+ ]
2426
+ },
2427
+ {
2428
+ "id": "217",
2429
+ "name": "Safari East",
2430
+ "coordinates": [
2431
+ 208,
2432
+ 310
2433
+ ],
2434
+ "tileSize": [
2435
+ 30,
2436
+ 26
2437
+ ]
2438
+ },
2439
+ {
2440
+ "id": "218",
2441
+ "name": "Safari North",
2442
+ "coordinates": [
2443
+ 166,
2444
+ 274
2445
+ ],
2446
+ "tileSize": [
2447
+ 40,
2448
+ 36
2449
+ ]
2450
+ },
2451
+ {
2452
+ "id": "219",
2453
+ "name": "Safari West",
2454
+ "coordinates": [
2455
+ 148,
2456
+ 310
2457
+ ],
2458
+ "tileSize": [
2459
+ 30,
2460
+ 26
2461
+ ]
2462
+ },
2463
+ {
2464
+ "id": "220",
2465
+ "name": "Safari South",
2466
+ "coordinates": [
2467
+ 178,
2468
+ 322
2469
+ ],
2470
+ "tileSize": [
2471
+ 30,
2472
+ 26
2473
+ ]
2474
+ },
2475
+ {
2476
+ "id": "221",
2477
+ "name": "Rest House South",
2478
+ "coordinates": [
2479
+ 209,
2480
+ 337
2481
+ ],
2482
+ "tileSize": [
2483
+ 8,
2484
+ 8
2485
+ ]
2486
+ },
2487
+ {
2488
+ "id": "222",
2489
+ "name": "Secret House",
2490
+ "coordinates": [
2491
+ 148,
2492
+ 301
2493
+ ],
2494
+ "tileSize": [
2495
+ 8,
2496
+ 8
2497
+ ]
2498
+ },
2499
+ {
2500
+ "id": "223",
2501
+ "name": "Rest House",
2502
+ "coordinates": [
2503
+ 157,
2504
+ 301
2505
+ ],
2506
+ "tileSize": [
2507
+ 8,
2508
+ 8
2509
+ ]
2510
+ },
2511
+ {
2512
+ "id": "224",
2513
+ "name": "Rest House East",
2514
+ "coordinates": [
2515
+ 230,
2516
+ 301
2517
+ ],
2518
+ "tileSize": [
2519
+ 8,
2520
+ 8
2521
+ ]
2522
+ },
2523
+ {
2524
+ "id": "225",
2525
+ "name": "Rest House North",
2526
+ "coordinates": [
2527
+ 207,
2528
+ 273
2529
+ ],
2530
+ "tileSize": [
2531
+ 8,
2532
+ 8
2533
+ ]
2534
+ },
2535
+ {
2536
+ "id": "226",
2537
+ "name": "Cerulean Cave 2F",
2538
+ "coordinates": [
2539
+ 213,
2540
+ 81
2541
+ ],
2542
+ "tileSize": [
2543
+ 30,
2544
+ 18
2545
+ ]
2546
+ },
2547
+ {
2548
+ "id": "227",
2549
+ "name": "Cerulean Cave B1F",
2550
+ "coordinates": [
2551
+ 213,
2552
+ 62
2553
+ ],
2554
+ "tileSize": [
2555
+ 30,
2556
+ 18
2557
+ ]
2558
+ },
2559
+ {
2560
+ "id": "228",
2561
+ "name": "Cerulean Cave Entrance",
2562
+ "coordinates": [
2563
+ 213,
2564
+ 100
2565
+ ],
2566
+ "tileSize": [
2567
+ 30,
2568
+ 18
2569
+ ]
2570
+ },
2571
+ {
2572
+ "id": "229",
2573
+ "name": "Name Rater House",
2574
+ "coordinates": [
2575
+ 325,
2576
+ 219
2577
+ ],
2578
+ "tileSize": [
2579
+ 8,
2580
+ 8
2581
+ ]
2582
+ },
2583
+ {
2584
+ "id": "230",
2585
+ "name": "Badge Man House",
2586
+ "coordinates": [
2587
+ 216,
2588
+ 119
2589
+ ],
2590
+ "tileSize": [
2591
+ 8,
2592
+ 8
2593
+ ]
2594
+ },
2595
+ {
2596
+ "id": "232",
2597
+ "name": "Rock Tunnel 1F",
2598
+ "coordinates": [
2599
+ 396,
2600
+ 145
2601
+ ],
2602
+ "tileSize": [
2603
+ 40,
2604
+ 36
2605
+ ]
2606
+ },
2607
+ {
2608
+ "id": "233",
2609
+ "name": "Silph Co 9F",
2610
+ "coordinates": [
2611
+ 356,
2612
+ 71
2613
+ ],
2614
+ "tileSize": [
2615
+ 26,
2616
+ 18
2617
+ ]
2618
+ },
2619
+ {
2620
+ "id": "234",
2621
+ "name": "Silph Co 10F",
2622
+ "coordinates": [
2623
+ 356,
2624
+ 52
2625
+ ],
2626
+ "tileSize": [
2627
+ 16,
2628
+ 18
2629
+ ]
2630
+ },
2631
+ {
2632
+ "id": "235",
2633
+ "name": "Silph Co 11F",
2634
+ "coordinates": [
2635
+ 356,
2636
+ 32
2637
+ ],
2638
+ "tileSize": [
2639
+ 18,
2640
+ 18
2641
+ ]
2642
+ },
2643
+ {
2644
+ "id": "236",
2645
+ "name": "Silph Co Lift",
2646
+ "coordinates": [
2647
+ 355,
2648
+ 128
2649
+ ],
2650
+ "tileSize": [
2651
+ 4,
2652
+ 4
2653
+ ]
2654
+ },
2655
+ {
2656
+ "id": "239",
2657
+ "name": "Trade Center",
2658
+ "coordinates": [
2659
+ 85,
2660
+ 283
2661
+ ],
2662
+ "tileSize": [
2663
+ 10,
2664
+ 8
2665
+ ]
2666
+ },
2667
+ {
2668
+ "id": "240",
2669
+ "name": "Colosseum Club",
2670
+ "coordinates": [
2671
+ 96,
2672
+ 283
2673
+ ],
2674
+ "tileSize": [
2675
+ 10,
2676
+ 8
2677
+ ]
2678
+ },
2679
+ {
2680
+ "id": "245",
2681
+ "name": "Loreleis Room",
2682
+ "coordinates": [
2683
+ 20,
2684
+ 60
2685
+ ],
2686
+ "tileSize": [
2687
+ 10,
2688
+ 12
2689
+ ]
2690
+ },
2691
+ {
2692
+ "id": "246",
2693
+ "name": "Brunos Room",
2694
+ "coordinates": [
2695
+ 20,
2696
+ 48
2697
+ ],
2698
+ "tileSize": [
2699
+ 10,
2700
+ 12
2701
+ ]
2702
+ },
2703
+ {
2704
+ "id": "247",
2705
+ "name": "Agathas Room",
2706
+ "coordinates": [
2707
+ 20,
2708
+ 36
2709
+ ],
2710
+ "tileSize": [
2711
+ 10,
2712
+ 12
2713
+ ]
2714
+ }
2715
+ ]
2716
+ }
server/pokemonred_env_environment.py ADDED
@@ -0,0 +1,325 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Copyright (c) Meta Platforms, Inc. and affiliates.
2
+ # All rights reserved.
3
+ #
4
+ # This source code is licensed under the BSD-style license found in the
5
+ # LICENSE file in the root directory of this source tree.
6
+
7
+ """
8
+ Pokemon Red Environment Server Implementation.
9
+
10
+ This module wraps the PyBoy Game Boy emulator and exposes Pokemon Red
11
+ as an OpenEnv Environment for RL training.
12
+ """
13
+
14
+ from __future__ import annotations
15
+
16
+ import base64
17
+ import io
18
+ import uuid
19
+ from pathlib import Path
20
+ from typing import Any, Dict, List, Tuple
21
+
22
+ import numpy as np
23
+ from PIL import Image
24
+
25
+ try:
26
+ from pyboy import PyBoy
27
+ from pyboy.utils import WindowEvent
28
+ except ImportError as e:
29
+ raise ImportError(
30
+ "PyBoy is required for the Pokemon Red environment. "
31
+ "Install with: pip install pyboy"
32
+ ) from e
33
+
34
+ from openenv.core.env_server import Environment
35
+ from openenv.core.env_server.types import Action, Observation
36
+
37
+ from models import PokemonRedAction, PokemonRedObservation, PokemonRedState
38
+ from config import PokemonRedConfig
39
+ from .global_map import local_to_global, GLOBAL_MAP_SHAPE
40
+
41
+ # Memory addresses for Pokemon Red
42
+ EVENT_FLAGS_START = 0xD747
43
+ EVENT_FLAGS_END = 0xD87E
44
+ IS_IN_BATTLE_ADDR = 0xD057
45
+
46
+ # Party Pokemon HP addresses
47
+ HP_ADDRESSES = [0xD16C, 0xD198, 0xD1C4, 0xD1F0, 0xD21C, 0xD248]
48
+ MAX_HP_ADDRESSES = [0xD18D, 0xD1B9, 0xD1E5, 0xD211, 0xD23D, 0xD269]
49
+ LEVEL_ADDRESSES = [0xD18C, 0xD1B8, 0xD1E4, 0xD210, 0xD23C, 0xD268]
50
+
51
+
52
+ class PokemonRedEnvironment(Environment):
53
+ """
54
+ Pokemon Red Environment wrapper for OpenEnv.
55
+
56
+ This environment wraps Pokemon Red via PyBoy emulator and provides
57
+ a clean interface for RL training with rich observations and
58
+ configurable reward shaping.
59
+
60
+ Supported actions: 0=Down, 1=Left, 2=Right, 3=Up, 4=A, 5=B, 6=Start
61
+
62
+ Args:
63
+ config: PokemonRedConfig with environment settings.
64
+
65
+ Example:
66
+ >>> config = PokemonRedConfig(headless=True)
67
+ >>> env = PokemonRedEnvironment(config)
68
+ >>> obs = env.reset()
69
+ >>> obs = env.step(PokemonRedAction(action=4)) # Press A
70
+ """
71
+
72
+ # Enable concurrent WebSocket sessions
73
+ SUPPORTS_CONCURRENT_SESSIONS: bool = True
74
+
75
+ # Action mappings
76
+ VALID_ACTIONS = [
77
+ WindowEvent.PRESS_ARROW_DOWN,
78
+ WindowEvent.PRESS_ARROW_LEFT,
79
+ WindowEvent.PRESS_ARROW_RIGHT,
80
+ WindowEvent.PRESS_ARROW_UP,
81
+ WindowEvent.PRESS_BUTTON_A,
82
+ WindowEvent.PRESS_BUTTON_B,
83
+ WindowEvent.PRESS_BUTTON_START,
84
+ ]
85
+ RELEASE_ACTIONS = [
86
+ WindowEvent.RELEASE_ARROW_DOWN,
87
+ WindowEvent.RELEASE_ARROW_LEFT,
88
+ WindowEvent.RELEASE_ARROW_RIGHT,
89
+ WindowEvent.RELEASE_ARROW_UP,
90
+ WindowEvent.RELEASE_BUTTON_A,
91
+ WindowEvent.RELEASE_BUTTON_B,
92
+ WindowEvent.RELEASE_BUTTON_START,
93
+ ]
94
+ ACTION_NAMES = ["Down", "Left", "Right", "Up", "A", "B", "Start"]
95
+
96
+ def __init__(self, config: PokemonRedConfig):
97
+ """Initialize Pokemon Red environment."""
98
+ super().__init__()
99
+ self.config = config
100
+
101
+ # Initialize state
102
+ self._state = PokemonRedState(episode_id=str(uuid.uuid4()))
103
+
104
+ # Session path for saving states
105
+ self.session_path = Path(config.session_path)
106
+ self.session_path.mkdir(exist_ok=True, parents=True)
107
+
108
+ # Initialize PyBoy emulator
109
+ window_type = "null" if config.headless else "SDL2"
110
+ self.pyboy = PyBoy(
111
+ config.gb_path,
112
+ window=window_type,
113
+ sound_emulated=False, # Disable sound for headless operation
114
+ )
115
+ if not config.headless:
116
+ self.pyboy.set_emulation_speed(6)
117
+
118
+ # Tracking state
119
+ self.seen_coords: Dict[str, int] = {}
120
+ self.explore_map = np.zeros(GLOBAL_MAP_SHAPE, dtype=np.uint8)
121
+ self._prev_state_dict: Dict[str, Any] = {}
122
+
123
+ def reset(self) -> Observation:
124
+ """
125
+ Reset the environment and return initial observation.
126
+
127
+ Returns:
128
+ Initial PokemonRedObservation for the agent.
129
+ """
130
+ # Reset state tracking
131
+ self._state = PokemonRedState(episode_id=str(uuid.uuid4()))
132
+ self.seen_coords = {}
133
+ self.explore_map.fill(0)
134
+ self._prev_state_dict = {}
135
+
136
+ # Load initial save state
137
+ with open(self.config.init_state, "rb") as f:
138
+ self.pyboy.load_state(f)
139
+
140
+ # Tick once to render initial frame
141
+ self.pyboy.tick(1, True)
142
+
143
+ return self._make_observation(reward=0.0, done=False)
144
+
145
+ def step(self, action: Action) -> Observation:
146
+ """
147
+ Execute agent's action and return resulting observation.
148
+
149
+ Args:
150
+ action: PokemonRedAction containing the button to press.
151
+
152
+ Returns:
153
+ Observation after action execution.
154
+
155
+ Raises:
156
+ ValueError: If action is not a PokemonRedAction.
157
+ """
158
+ if not isinstance(action, PokemonRedAction):
159
+ raise ValueError(f"Expected PokemonRedAction, got {type(action)}")
160
+
161
+ # Validate action
162
+ action_idx = action.action
163
+ if action_idx < 0 or action_idx >= len(self.VALID_ACTIONS):
164
+ raise ValueError(f"Invalid action: {action_idx}. Valid range: [0, 6]")
165
+
166
+ # Execute action with press/release timing
167
+ press_duration = 8
168
+ self.pyboy.send_input(self.VALID_ACTIONS[action_idx])
169
+ self.pyboy.tick(press_duration, False)
170
+ self.pyboy.send_input(self.RELEASE_ACTIONS[action_idx])
171
+ self.pyboy.tick(self.config.action_freq - press_duration - 1, False)
172
+ self.pyboy.tick(1, True) # Render on final tick
173
+
174
+ # Update exploration tracking
175
+ self._update_exploration()
176
+
177
+ # Calculate reward
178
+ current_state = self._get_state_dict()
179
+ reward = self._calculate_reward(current_state, self._prev_state_dict)
180
+ self._prev_state_dict = current_state
181
+
182
+ # Update state
183
+ self._state.step_count += 1
184
+ self._state.total_reward += reward
185
+ self._state.badges_obtained = current_state["badge_count"]
186
+ self._state.max_level_sum = max(
187
+ self._state.max_level_sum, current_state["level_sum"]
188
+ )
189
+ self._state.events_triggered = current_state["event_count"]
190
+
191
+ # Check termination
192
+ done = self._state.step_count >= self.config.max_steps
193
+
194
+ return self._make_observation(reward=reward, done=done)
195
+
196
+ @property
197
+ def state(self) -> PokemonRedState:
198
+ """Get current environment state."""
199
+ return self._state
200
+
201
+ def _make_observation(self, reward: float, done: bool) -> PokemonRedObservation:
202
+ """Create observation from current game state."""
203
+ # Capture screen as base64 PNG
204
+ screen = self.pyboy.screen.ndarray[:, :, :3].astype(np.uint8)
205
+ img = Image.fromarray(screen)
206
+ buffer = io.BytesIO()
207
+ img.save(buffer, format="PNG")
208
+ screen_b64 = base64.b64encode(buffer.getvalue()).decode("utf-8")
209
+
210
+ # Read game state
211
+ x, y, map_id = self._get_position()
212
+ health = self._get_hp_fraction()
213
+ level_sum = self._get_level_sum()
214
+ badges = self._get_badges_list()
215
+ in_battle = self._is_in_battle()
216
+
217
+ return PokemonRedObservation(
218
+ screen_b64=screen_b64,
219
+ screen_shape=list(screen.shape),
220
+ health=health,
221
+ level_sum=level_sum,
222
+ badges=badges,
223
+ position=[x, y, map_id],
224
+ in_battle=in_battle,
225
+ seen_coords_count=len(self.seen_coords),
226
+ legal_actions=list(range(7)),
227
+ done=done,
228
+ reward=reward,
229
+ metadata={
230
+ "action_names": self.ACTION_NAMES,
231
+ "step_count": self._state.step_count,
232
+ "total_reward": self._state.total_reward,
233
+ },
234
+ )
235
+
236
+ def _get_position(self) -> Tuple[int, int, int]:
237
+ """Get player position (x, y, map_id)."""
238
+ return (
239
+ self.pyboy.memory[0xD362],
240
+ self.pyboy.memory[0xD361],
241
+ self.pyboy.memory[0xD35E],
242
+ )
243
+
244
+ def _update_exploration(self) -> None:
245
+ """Update exploration tracking with current position."""
246
+ x, y, map_id = self._get_position()
247
+ coord_key = f"{x}:{y}:{map_id}"
248
+ self.seen_coords[coord_key] = self.seen_coords.get(coord_key, 0) + 1
249
+
250
+ # Update global exploration map
251
+ gx, gy = local_to_global(y, x, map_id)
252
+ if 0 <= gx < GLOBAL_MAP_SHAPE[0] and 0 <= gy < GLOBAL_MAP_SHAPE[1]:
253
+ self.explore_map[gx, gy] = 255
254
+
255
+ def _get_hp_fraction(self) -> float:
256
+ """Get party HP as fraction [0, 1]."""
257
+ hp_sum = sum(self._read_hp(addr) for addr in HP_ADDRESSES)
258
+ max_hp_sum = sum(self._read_hp(addr) for addr in MAX_HP_ADDRESSES)
259
+ return hp_sum / max(max_hp_sum, 1)
260
+
261
+ def _read_hp(self, addr: int) -> int:
262
+ """Read 16-bit HP value from memory."""
263
+ return 256 * self.pyboy.memory[addr] + self.pyboy.memory[addr + 1]
264
+
265
+ def _get_level_sum(self) -> int:
266
+ """Get sum of party Pokemon levels."""
267
+ return sum(self.pyboy.memory[addr] for addr in LEVEL_ADDRESSES)
268
+
269
+ def _get_badges_list(self) -> List[int]:
270
+ """Get 8-element list of badge flags."""
271
+ badge_byte = self.pyboy.memory[0xD356]
272
+ return [int(b) for b in f"{badge_byte:08b}"][::-1]
273
+
274
+ def _is_in_battle(self) -> bool:
275
+ """Check if player is in battle."""
276
+ return self.pyboy.memory[IS_IN_BATTLE_ADDR] != 0
277
+
278
+ def _get_event_count(self) -> int:
279
+ """Count triggered event flags."""
280
+ count = 0
281
+ for addr in range(EVENT_FLAGS_START, EVENT_FLAGS_END):
282
+ count += self.pyboy.memory[addr].bit_count()
283
+ return count
284
+
285
+ def _get_state_dict(self) -> Dict[str, Any]:
286
+ """Get current game state as dictionary for reward calculation."""
287
+ return {
288
+ "seen_coords_count": len(self.seen_coords),
289
+ "badge_count": self.pyboy.memory[0xD356].bit_count(),
290
+ "level_sum": self._get_level_sum(),
291
+ "event_count": self._get_event_count(),
292
+ "hp_fraction": self._get_hp_fraction(),
293
+ }
294
+
295
+ def _calculate_reward(
296
+ self, current: Dict[str, Any], previous: Dict[str, Any]
297
+ ) -> float:
298
+ """
299
+ Calculate reward based on state changes.
300
+
301
+ Simple built-in reward shaping. For more complex reward functions,
302
+ see the rewards/ module for modular components.
303
+ """
304
+ if not previous:
305
+ return 0.0
306
+
307
+ reward = 0.0
308
+
309
+ # Exploration reward
310
+ new_coords = current["seen_coords_count"] - previous.get("seen_coords_count", 0)
311
+ reward += new_coords * 0.02
312
+
313
+ # Badge reward
314
+ new_badges = current["badge_count"] - previous.get("badge_count", 0)
315
+ reward += new_badges * 5.0
316
+
317
+ # Level up reward
318
+ level_diff = current["level_sum"] - previous.get("level_sum", 0)
319
+ reward += max(0, level_diff) * 1.0
320
+
321
+ # Event progress reward
322
+ event_diff = current["event_count"] - previous.get("event_count", 0)
323
+ reward += max(0, event_diff) * 0.1
324
+
325
+ return reward * self.config.reward_scale
server/pokered.sym ADDED
The diff for this file is too large to render. See raw diff
 
server/requirements.txt ADDED
@@ -0,0 +1,6 @@
 
 
 
 
 
 
 
1
+ openenv[core]>=0.2.0
2
+ fastapi>=0.115.0
3
+ uvicorn>=0.24.0
4
+
5
+
6
+
uv.lock ADDED
The diff for this file is too large to render. See raw diff
 
wrappers/__init__.py ADDED
@@ -0,0 +1,8 @@
 
 
 
 
 
 
 
 
 
1
+ # Copyright (c) Meta Platforms, Inc. and affiliates.
2
+ # All rights reserved.
3
+
4
+ """Wrappers for Pokemon Red OpenEnv environment."""
5
+
6
+ from .green_agent import GreenAgentTracker
7
+
8
+ __all__ = ["GreenAgentTracker"]
wrappers/green_agent.py ADDED
@@ -0,0 +1,190 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Copyright (c) Meta Platforms, Inc. and affiliates.
2
+ # All rights reserved.
3
+
4
+ """
5
+ Green Agent compute efficiency tracker for Pokemon Red OpenEnv.
6
+
7
+ This module implements compute efficiency tracking as required by
8
+ The OpenEnv Challenge evaluation criteria. It measures wall-clock time,
9
+ memory usage, and provides transparency metrics for sustainability analysis.
10
+ """
11
+
12
+ from __future__ import annotations
13
+
14
+ import os
15
+ import time
16
+ from dataclasses import dataclass, field
17
+ from typing import Any, Callable, Dict, Optional, TypeVar
18
+
19
+ try:
20
+ import psutil
21
+ HAS_PSUTIL = True
22
+ except ImportError:
23
+ HAS_PSUTIL = False
24
+
25
+ T = TypeVar("T")
26
+
27
+
28
+ @dataclass
29
+ class GreenMetrics:
30
+ """
31
+ Compute efficiency metrics for a single step or episode.
32
+
33
+ Attributes:
34
+ step_time_ms: Wall-clock time for last step in milliseconds.
35
+ avg_step_time_ms: Running average step time in milliseconds.
36
+ total_steps: Total steps executed.
37
+ total_time_s: Total wall-clock time in seconds.
38
+ peak_memory_mb: Peak memory usage in megabytes.
39
+ current_memory_mb: Current memory usage in megabytes.
40
+ cpu_percent: CPU utilization percentage (if available).
41
+ """
42
+ step_time_ms: float = 0.0
43
+ avg_step_time_ms: float = 0.0
44
+ total_steps: int = 0
45
+ total_time_s: float = 0.0
46
+ peak_memory_mb: float = 0.0
47
+ current_memory_mb: float = 0.0
48
+ cpu_percent: float = 0.0
49
+
50
+ def to_dict(self) -> Dict[str, Any]:
51
+ """Convert metrics to dictionary for JSON serialization."""
52
+ return {
53
+ "green_step_time_ms": round(self.step_time_ms, 3),
54
+ "green_avg_step_time_ms": round(self.avg_step_time_ms, 3),
55
+ "green_total_steps": self.total_steps,
56
+ "green_total_time_s": round(self.total_time_s, 3),
57
+ "green_peak_memory_mb": round(self.peak_memory_mb, 2),
58
+ "green_current_memory_mb": round(self.current_memory_mb, 2),
59
+ "green_cpu_percent": round(self.cpu_percent, 1),
60
+ }
61
+
62
+
63
+ class GreenAgentTracker:
64
+ """
65
+ Tracks compute efficiency metrics for RL environment steps.
66
+
67
+ Designed for the OpenEnv Challenge "Green Agent" evaluation criteria,
68
+ measuring the computational cost of environment interactions to
69
+ promote sustainable AI development.
70
+
71
+ Example:
72
+ >>> tracker = GreenAgentTracker()
73
+ >>>
74
+ >>> # Track a step
75
+ >>> result, metrics = tracker.track_step(lambda: env.step(action))
76
+ >>> print(f"Step took {metrics['green_step_time_ms']:.2f}ms")
77
+ >>>
78
+ >>> # Get summary
79
+ >>> summary = tracker.get_summary()
80
+ >>> print(f"Avg step: {summary['green_avg_step_time_ms']:.2f}ms")
81
+
82
+ Attributes:
83
+ enabled: Whether tracking is active.
84
+ metrics: Current aggregated metrics.
85
+ """
86
+
87
+ def __init__(self, enabled: bool = True):
88
+ """
89
+ Initialize Green Agent tracker.
90
+
91
+ Args:
92
+ enabled: Whether to enable tracking (default True).
93
+ Disable for benchmarking without overhead.
94
+ """
95
+ self.enabled = enabled
96
+ self._process: Optional[Any] = None
97
+ if HAS_PSUTIL:
98
+ self._process = psutil.Process(os.getpid())
99
+
100
+ self.reset()
101
+
102
+ def reset(self) -> None:
103
+ """Reset tracking metrics for new episode."""
104
+ self._total_steps = 0
105
+ self._total_time = 0.0
106
+ self._peak_memory = 0.0
107
+ self._last_step_time = 0.0
108
+
109
+ def track_step(self, step_fn: Callable[[], T]) -> tuple[T, Dict[str, Any]]:
110
+ """
111
+ Execute and track a step function.
112
+
113
+ Args:
114
+ step_fn: Callable that executes the environment step.
115
+
116
+ Returns:
117
+ Tuple of (step result, metrics dictionary).
118
+ """
119
+ if not self.enabled:
120
+ return step_fn(), {}
121
+
122
+ # Measure memory before
123
+ start_memory = self._get_memory_mb()
124
+
125
+ # Time the step
126
+ start_time = time.perf_counter()
127
+ result = step_fn()
128
+ elapsed = time.perf_counter() - start_time
129
+
130
+ # Update tracking
131
+ self._last_step_time = elapsed
132
+ self._total_time += elapsed
133
+ self._total_steps += 1
134
+
135
+ # Update peak memory
136
+ current_memory = self._get_memory_mb()
137
+ self._peak_memory = max(self._peak_memory, current_memory)
138
+
139
+ # Build metrics
140
+ metrics = self.get_metrics()
141
+ return result, metrics.to_dict()
142
+
143
+ def track_reset(self, reset_fn: Callable[[], T]) -> tuple[T, Dict[str, Any]]:
144
+ """
145
+ Execute and track a reset function.
146
+
147
+ Args:
148
+ reset_fn: Callable that executes the environment reset.
149
+
150
+ Returns:
151
+ Tuple of (reset result, metrics dictionary).
152
+ """
153
+ self.reset()
154
+ return self.track_step(reset_fn)
155
+
156
+ def get_metrics(self) -> GreenMetrics:
157
+ """Get current aggregated metrics."""
158
+ avg_step = self._total_time / max(self._total_steps, 1)
159
+
160
+ return GreenMetrics(
161
+ step_time_ms=self._last_step_time * 1000,
162
+ avg_step_time_ms=avg_step * 1000,
163
+ total_steps=self._total_steps,
164
+ total_time_s=self._total_time,
165
+ peak_memory_mb=self._peak_memory,
166
+ current_memory_mb=self._get_memory_mb(),
167
+ cpu_percent=self._get_cpu_percent(),
168
+ )
169
+
170
+ def get_summary(self) -> Dict[str, Any]:
171
+ """Get metrics summary as dictionary."""
172
+ return self.get_metrics().to_dict()
173
+
174
+ def _get_memory_mb(self) -> float:
175
+ """Get current process memory in MB."""
176
+ if self._process is not None:
177
+ try:
178
+ return self._process.memory_info().rss / (1024 * 1024)
179
+ except Exception:
180
+ pass
181
+ return 0.0
182
+
183
+ def _get_cpu_percent(self) -> float:
184
+ """Get current CPU utilization percentage."""
185
+ if self._process is not None:
186
+ try:
187
+ return self._process.cpu_percent()
188
+ except Exception:
189
+ pass
190
+ return 0.0