From 364945a85f6a643e25b021d1ae17f4787ae64e91 Mon Sep 17 00:00:00 2001
From: Rachel <lhearachel@proton.me>
Date: Sun, 10 Nov 2024 23:12:14 -0800
Subject: [PATCH] Refactor generation of encounter data files and packing of
 pl_enc_data.narc

---
 res/field/encounters/meson.build | 19 +++++----
 tools/json2bin/encounter.py      | 66 ++++++++++++++++++++++++++++++++
 tools/json2bin/encounters.py     | 63 ------------------------------
 tools/json2bin/meson.build       |  3 +-
 4 files changed, 79 insertions(+), 72 deletions(-)
 create mode 100644 tools/json2bin/encounter.py
 delete mode 100644 tools/json2bin/encounters.py

diff --git a/res/field/encounters/meson.build b/res/field/encounters/meson.build
index 03318dcba7..5dea283ec8 100644
--- a/res/field/encounters/meson.build
+++ b/res/field/encounters/meson.build
@@ -1,3 +1,9 @@
+enc_bin_gen = generator(
+    encounters_new_py,
+    arguments: [ '@INPUT@', '@OUTPUT@', ],
+    output: '@BASENAME@.bin'
+)
+
 pl_enc_data_srcs = files(
     '000.json',
     '001.json',
@@ -181,20 +187,17 @@ pl_enc_data_srcs = files(
     '179.json',
     '180.json',
     '181.json',
-    '182.json'
+    '182.json',
 )
 
 pl_enc_tbl_narc = custom_target('pl_enc_data.narc',
     output: 'pl_enc_data.narc',
-    input: pl_enc_data_srcs,
-    env: json2bin_env,
+    input: enc_bin_gen.process(pl_enc_data_srcs, env: json2bin_env),
     depends: [ py_consts_generators ],
     command: [
-        encounters_py,
-        '--knarc', knarc_exe,
-        '--source-dir', '@CURRENT_SOURCE_DIR@',
-        '--private-dir', '@PRIVATE_DIR@',
-        '--output-dir', '@OUTDIR@',
+        knarc_exe,
+        '-d', '@PRIVATE_DIR@',
+        '-p', '@OUTPUT@',
     ]
 )
 
diff --git a/tools/json2bin/encounter.py b/tools/json2bin/encounter.py
new file mode 100644
index 0000000000..704b5f2309
--- /dev/null
+++ b/tools/json2bin/encounter.py
@@ -0,0 +1,66 @@
+#!/usr/bin/env python3
+import itertools
+import json
+import pathlib
+import sys
+
+from consts import species
+
+
+def as_species(s: str) -> bytes:
+    return species.PokemonSpecies[s].value.to_bytes(4, 'little')
+
+def convert_land(encs: list) -> bytes:
+    return b''.join(itertools.chain.from_iterable([
+        (
+            int(encs[i]['level']).to_bytes(4, 'little'),
+            as_species(encs[i]['species']),
+        )
+        for i in range(12)
+    ]))
+
+def convert_water(encs: list) -> bytes:
+    return b''.join(itertools.chain.from_iterable([
+        (
+            int(encs[i]['level_max']).to_bytes(1, 'little'),
+            int(encs[i]['level_min']).to_bytes(1, 'little'),
+            (0).to_bytes(2, 'little'),
+            as_species(encs[i]['species']),
+        )
+        for i in range(5)
+    ]))
+
+
+input_path = pathlib.Path(sys.argv[1])
+output_path = pathlib.Path(sys.argv[2])
+
+data = {}
+with open(input_path, 'r', encoding='utf-8') as input_file:
+    data = json.load(input_file)
+
+packables = bytearray([])
+packables.extend(int(data['land_rate']).to_bytes(4, 'little'))
+packables.extend(convert_land(data['land_encounters']))
+
+for enc_type, i in itertools.product(['swarms', 'morning', 'night'], range(2)):
+    packables.extend(as_species(data[enc_type][i]))
+
+for i in range(4):
+    packables.extend(as_species(data['radar'][i]))
+
+for key in ['rate_form0', 'rate_form1', 'rate_form2', 'rate_form3', 'rate_form4', 'unown_table']:
+    packables.extend(int(data[key]).to_bytes(4, 'little'))
+
+for version, i in itertools.product(['ruby', 'sapphire', 'emerald', 'firered', 'leafgreen'], range(2)):
+    packables.extend(as_species(data[version][i]))
+
+packables.extend(data['surf_rate'].to_bytes(4, 'little'))
+packables.extend(convert_water(data['surf_encounters']))
+packables.extend((0).to_bytes(44, 'little'))
+
+for rod in ['old', 'good', 'super']:
+    packables.extend(data[f'{rod}_rod_rate'].to_bytes(4, 'little'))
+    packables.extend(convert_water(data[f'{rod}_rod_encounters']))
+
+with open(output_path, 'wb') as output_file:
+    output_file.write(packables)
diff --git a/tools/json2bin/encounters.py b/tools/json2bin/encounters.py
deleted file mode 100644
index a78b11531e..0000000000
--- a/tools/json2bin/encounters.py
+++ /dev/null
@@ -1,63 +0,0 @@
-#!/usr/bin/env python3
-import pathlib
-import json2bin as j2b
-
-from consts import species
-
-
-SCHEMA = j2b.Parser().register('land_rate', 4, j2b.parse_int)
-
-# Land encounters
-for i in range(12):
-    SCHEMA = SCHEMA \
-    .register(f'land_encounters.{i}.level', 1, j2b.parse_int) \
-    .pad(3) \
-    .register(f'land_encounters.{i}.species', 4, j2b.parse_const, species.PokemonSpecies)
-
-# Swarms, day-only, night-only
-for encounter_type in ['swarms', 'morning', 'night']:
-    for i in range(2):
-        SCHEMA = SCHEMA.register(f'{encounter_type}.{i}', 4, j2b.parse_const, species.PokemonSpecies)
-
-# Poké Radar
-for i in range(4):
-        SCHEMA = SCHEMA.register(f'radar.{i}', 4, j2b.parse_const, species.PokemonSpecies)
-
-# ???
-SCHEMA = SCHEMA \
-    .register('rate_form0', 4, j2b.parse_int)  \
-    .register('rate_form1', 4, j2b.parse_int)  \
-    .register('rate_form2', 4, j2b.parse_int)  \
-    .register('rate_form3', 4, j2b.parse_int)  \
-    .register('rate_form4', 4, j2b.parse_int)  \
-    .register('unown_table', 4, j2b.parse_int) \
-    
-# GBA slot
-for version in ['ruby', 'sapphire', 'emerald', 'firered', 'leafgreen']:
-    for i in range(2):
-        SCHEMA = SCHEMA.register(f'{version}.{i}', 4, j2b.parse_const, species.PokemonSpecies)
-
-# Surf & Rods
-for method in ['surf', 'old_rod', 'good_rod', 'super_rod']:
-    SCHEMA = SCHEMA.register(f'{method}_rate', 4, j2b.parse_int)
-    for i in range(5):
-        SCHEMA = SCHEMA \
-        .register(f'{method}_encounters.{i}.level_max', 1, j2b.parse_int) \
-        .register(f'{method}_encounters.{i}.level_min', 1, j2b.parse_int) \
-        .pad(2) \
-        .register(f'{method}_encounters.{i}.species', 4, j2b.parse_const, species.PokemonSpecies)
-    
-    if method == 'surf':
-         SCHEMA = SCHEMA.pad(44)
-
-def indexer(file_path: pathlib.Path) -> int:
-    return int(file_path.stem)
-
-args = j2b.ARGPARSER.parse_args()
-j2b.json2bin(args.source_dir,
-             SCHEMA,
-             args.private_dir,
-             args.output_dir,
-             index_func=indexer,
-             narc_name='pl_enc_data',
-             narc_packer=args.knarc)
\ No newline at end of file
diff --git a/tools/json2bin/meson.build b/tools/json2bin/meson.build
index 8888806b47..e113e394dc 100644
--- a/tools/json2bin/meson.build
+++ b/tools/json2bin/meson.build
@@ -1,7 +1,6 @@
 json2bin_env = environment()
 json2bin_env.set('PYTHONPATH', meson.project_build_root()) # access to constants geneated by constgen
 
-encounters_py = find_program('encounters.py', native: true)
 events_py = find_program('events.py', native: true)
 movedata_py = find_program('movedata.py', native: true)
 pokemon_personal_data_py = find_program('pokemon_personal_data.py', native: true)
@@ -9,3 +8,5 @@ pokemon_wotbl_data_py = find_program('pokemon_wotbl_data.py', native: true)
 trainer_data_py = find_program('trainer_data.py', native: true)
 evo_py = find_program('evo.py', native: true)
 pl_poke_data_py = find_program('pl_poke_data.py', native: true)
+
+encounters_new_py = find_program('encounter.py', native: true)