From f0cf373bb684e232b7b4ea942c6154b5250dd77c Mon Sep 17 00:00:00 2001 From: Justin Marquez Date: Thu, 23 Jul 2026 18:49:50 -0500 Subject: [PATCH 01/22] feat: add models and serializers for new encounter_pokemon_details.csv file --- data/v2/build.py | 16 +++++++ data/v2/csv/encounter_pokemon_details.csv | 1 + .../migrations/0030_encounterpokemondetail.py | 42 +++++++++++++++++++ pokemon_v2/models.py | 16 +++++++ pokemon_v2/serializers.py | 27 ++++++++++++ pokemon_v2/tests.py | 22 ++++++++++ 6 files changed, 124 insertions(+) create mode 100644 data/v2/csv/encounter_pokemon_details.csv create mode 100644 pokemon_v2/migrations/0030_encounterpokemondetail.py diff --git a/data/v2/build.py b/data/v2/build.py index 93cb69711..2c105fb18 100644 --- a/data/v2/build.py +++ b/data/v2/build.py @@ -2425,6 +2425,22 @@ def csv_record_to_objects(info): csv_record_to_objects, ) + def csv_record_to_objects(info): + yield EncounterPokemonDetail( + encounter_id=int(info[0]), + min_perfect_ivs=int(info[1]) if info[1] != "" else None, + min_perfect_evs=int(info[2]) if info[2] != "" else None, + always_shiny=bool(int(info[3])), + never_shiny=bool(int(info[4])), + is_alpha=bool(int(info[5])), + ) + + build_generic( + (EncounterPokemonDetail,), + "encounter_pokemon_details.csv", + csv_record_to_objects, + ) + ############## # PAL PARK # diff --git a/data/v2/csv/encounter_pokemon_details.csv b/data/v2/csv/encounter_pokemon_details.csv new file mode 100644 index 000000000..85d0cfaea --- /dev/null +++ b/data/v2/csv/encounter_pokemon_details.csv @@ -0,0 +1 @@ +encounter_id,min_perfect_ivs,min_perfect_evs,always_shiny,never_shiny,is_alpha diff --git a/pokemon_v2/migrations/0030_encounterpokemondetail.py b/pokemon_v2/migrations/0030_encounterpokemondetail.py new file mode 100644 index 000000000..e49e895e6 --- /dev/null +++ b/pokemon_v2/migrations/0030_encounterpokemondetail.py @@ -0,0 +1,42 @@ +# Generated by Django 5.2.10 on 2026-07-23 21:10 + +import django.db.models.deletion +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ("pokemon_v2", "0029_pokemonformtrigger_pokemonformcondition"), + ] + + operations = [ + migrations.CreateModel( + name="EncounterPokemonDetail", + fields=[ + ( + "id", + models.AutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), + ("min_perfect_ivs", models.IntegerField(blank=True, null=True)), + ("min_perfect_evs", models.IntegerField(blank=True, null=True)), + ("always_shiny", models.BooleanField(default=False)), + ("never_shiny", models.BooleanField(default=False)), + ("is_alpha", models.BooleanField(default=False)), + ( + "encounter", + models.ForeignKey( + blank=True, + null=True, + on_delete=django.db.models.deletion.CASCADE, + to="pokemon_v2.encounter", + ), + ), + ], + ), + ] diff --git a/pokemon_v2/models.py b/pokemon_v2/models.py index e8311991c..e6c2fd51c 100644 --- a/pokemon_v2/models.py +++ b/pokemon_v2/models.py @@ -1182,6 +1182,22 @@ class EncounterConditionValueMap(models.Model): ) +class EncounterPokemonDetail(models.Model): + encounter = models.ForeignKey( + Encounter, blank=True, null=True, on_delete=models.CASCADE + ) + + min_perfect_ivs = models.IntegerField(blank=True, null=True) + + min_perfect_evs = models.IntegerField(blank=True, null=True) + + always_shiny = models.BooleanField(default=False) + + never_shiny = models.BooleanField(default=False) + + is_alpha = models.BooleanField(default=False) + + ################# # MOVE MODELS # ################# diff --git a/pokemon_v2/serializers.py b/pokemon_v2/serializers.py index cf0ac95c6..6a1251a76 100644 --- a/pokemon_v2/serializers.py +++ b/pokemon_v2/serializers.py @@ -911,11 +911,24 @@ class Meta: fields = ("id", "slot", "chance", "encounter_method", "version_group") +class EncounterPokemonDetailSerializer(serializers.ModelSerializer): + class Meta: + model = EncounterPokemonDetail + fields = ( + "min_perfect_ivs", + "min_perfect_evs", + "always_shiny", + "never_shiny", + "is_alpha", + ) + + class EncounterDetailSerializer(serializers.ModelSerializer): version = VersionSummarySerializer() location_area = LocationAreaSummarySerializer() pokemon = PokemonSummarySerializer() condition_values = serializers.SerializerMethodField("get_encounter_conditions") + pokemon_details = serializers.SerializerMethodField("get_encounter_pokemon_details") class Meta: model = Encounter @@ -927,6 +940,7 @@ class Meta: "pokemon", "location_area", "condition_values", + "pokemon_details", ) def get_encounter_conditions(self, obj): @@ -941,6 +955,19 @@ def get_encounter_conditions(self, obj): return values + def get_encounter_pokemon_details(self, obj): + encounter_pokemon_details = EncounterPokemonDetail.objects.filter(encounter=obj) + data = EncounterPokemonDetailSerializer( + encounter_pokemon_details, many=True, context=self.context + ).data + + pokemon_details = [] + for map in data: + detail = {key: val for key, val in map.items() if val} + pokemon_details.append(detail) + + return pokemon_details + class LocationAreaEncounterRateSerializer(serializers.ModelSerializer): encounter_method = EncounterMethodSummarySerializer() diff --git a/pokemon_v2/tests.py b/pokemon_v2/tests.py index 23c2ae95b..183540681 100644 --- a/pokemon_v2/tests.py +++ b/pokemon_v2/tests.py @@ -2018,6 +2018,28 @@ def setup_encounter_condition_value_map_data( return encounter_condition_value_map + @classmethod + def setup_encounter_pokemon_detail_data( + cls, + encounter, + min_perfect_ivs=None, + min_perfect_evs=None, + always_shiny=False, + never_shiny=False, + is_alpha=False, + ): + encounter_pokemon_detail = EncounterPokemonDetail.objects.create( + encounter=encounter, + min_perfect_ivs=min_perfect_ivs, + min_perfect_evs=min_perfect_evs, + always_shiny=always_shiny, + never_shiny=never_shiny, + is_alpha=is_alpha, + ) + encounter_pokemon_detail.save() + + return encounter_pokemon_detail + @classmethod def setup_encounter_slot_data(cls, encounter_method=None, slot=0, rarity=0): encounter_method = encounter_method or cls.setup_encounter_method_data( From a17927dcb6d7660e864f894dc0ca3645d3f83bea Mon Sep 17 00:00:00 2001 From: Justin Marquez Date: Thu, 23 Jul 2026 19:46:25 -0500 Subject: [PATCH 02/22] feat: remove min_perfect_evs field --- data/v2/build.py | 7 +++---- data/v2/csv/encounter_pokemon_details.csv | 2 +- pokemon_v2/models.py | 2 -- pokemon_v2/serializers.py | 1 - pokemon_v2/tests.py | 2 -- 5 files changed, 4 insertions(+), 10 deletions(-) diff --git a/data/v2/build.py b/data/v2/build.py index 2c105fb18..e3e7bca0d 100644 --- a/data/v2/build.py +++ b/data/v2/build.py @@ -2429,10 +2429,9 @@ def csv_record_to_objects(info): yield EncounterPokemonDetail( encounter_id=int(info[0]), min_perfect_ivs=int(info[1]) if info[1] != "" else None, - min_perfect_evs=int(info[2]) if info[2] != "" else None, - always_shiny=bool(int(info[3])), - never_shiny=bool(int(info[4])), - is_alpha=bool(int(info[5])), + always_shiny=bool(int(info[2])), + never_shiny=bool(int(info[3])), + is_alpha=bool(int(info[4])), ) build_generic( diff --git a/data/v2/csv/encounter_pokemon_details.csv b/data/v2/csv/encounter_pokemon_details.csv index 85d0cfaea..c88c53d1a 100644 --- a/data/v2/csv/encounter_pokemon_details.csv +++ b/data/v2/csv/encounter_pokemon_details.csv @@ -1 +1 @@ -encounter_id,min_perfect_ivs,min_perfect_evs,always_shiny,never_shiny,is_alpha +encounter_id,min_perfect_ivs,always_shiny,never_shiny,is_alpha diff --git a/pokemon_v2/models.py b/pokemon_v2/models.py index e6c2fd51c..2959a015a 100644 --- a/pokemon_v2/models.py +++ b/pokemon_v2/models.py @@ -1189,8 +1189,6 @@ class EncounterPokemonDetail(models.Model): min_perfect_ivs = models.IntegerField(blank=True, null=True) - min_perfect_evs = models.IntegerField(blank=True, null=True) - always_shiny = models.BooleanField(default=False) never_shiny = models.BooleanField(default=False) diff --git a/pokemon_v2/serializers.py b/pokemon_v2/serializers.py index 6a1251a76..2f0917662 100644 --- a/pokemon_v2/serializers.py +++ b/pokemon_v2/serializers.py @@ -916,7 +916,6 @@ class Meta: model = EncounterPokemonDetail fields = ( "min_perfect_ivs", - "min_perfect_evs", "always_shiny", "never_shiny", "is_alpha", diff --git a/pokemon_v2/tests.py b/pokemon_v2/tests.py index 183540681..34f841822 100644 --- a/pokemon_v2/tests.py +++ b/pokemon_v2/tests.py @@ -2023,7 +2023,6 @@ def setup_encounter_pokemon_detail_data( cls, encounter, min_perfect_ivs=None, - min_perfect_evs=None, always_shiny=False, never_shiny=False, is_alpha=False, @@ -2031,7 +2030,6 @@ def setup_encounter_pokemon_detail_data( encounter_pokemon_detail = EncounterPokemonDetail.objects.create( encounter=encounter, min_perfect_ivs=min_perfect_ivs, - min_perfect_evs=min_perfect_evs, always_shiny=always_shiny, never_shiny=never_shiny, is_alpha=is_alpha, From 7ccf092e07592215dd22312f3da53e242902c435 Mon Sep 17 00:00:00 2001 From: Justin Marquez Date: Thu, 23 Jul 2026 20:58:36 -0500 Subject: [PATCH 03/22] fix: remove xerneas encounter in Y and yveltal encounter in X --- data/v2/csv/encounters.csv | 2 -- 1 file changed, 2 deletions(-) diff --git a/data/v2/csv/encounters.csv b/data/v2/csv/encounters.csv index 1862dd738..442e46a24 100644 --- a/data/v2/csv/encounters.csv +++ b/data/v2/csv/encounters.csv @@ -61160,8 +61160,6 @@ id,version_id,location_area_id,encounter_slot_id,pokemon_id,min_level,max_level 66737,23,718,573,143,15,15 66738,24,718,573,143,15,15 66739,23,1176,573,716,50,50 -66740,24,1176,573,716,50,50 -66741,23,1176,573,717,50,50 66742,24,1176,573,717,50,50 66743,25,388,574,100,25,25 66744,26,388,574,100,25,25 From 5c5e741d29036c03f0da413129ae99a52a5a489f Mon Sep 17 00:00:00 2001 From: Justin Marquez Date: Thu, 23 Jul 2026 21:23:13 -0500 Subject: [PATCH 04/22] fix: remove duplicate tapu legendary encounters in SM and USUM --- data/v2/csv/encounters.csv | 16 ---------------- 1 file changed, 16 deletions(-) diff --git a/data/v2/csv/encounters.csv b/data/v2/csv/encounters.csv index 442e46a24..e4ec88b64 100644 --- a/data/v2/csv/encounters.csv +++ b/data/v2/csv/encounters.csv @@ -61193,14 +61193,6 @@ id,version_id,location_area_id,encounter_slot_id,pokemon_id,min_level,max_level 66772,26,1180,574,442,50,50 66773,25,1189,574,488,50,50 66774,26,1189,574,488,50,50 -66775,27,1126,869,785,60,60 -66776,28,1126,869,785,60,60 -66777,27,1128,869,786,60,60 -66778,28,1128,869,786,60,60 -66779,27,1125,869,787,60,60 -66780,28,1125,869,787,60,60 -66781,27,1127,869,788,60,60 -66782,28,1127,869,788,60,60 66783,27,1070,869,791,55,55 66784,28,1069,869,792,55,55 66785,27,1078,869,793,55,55 @@ -61226,14 +61218,6 @@ id,version_id,location_area_id,encounter_slot_id,pokemon_id,min_level,max_level 66805,29,1194,1133,92,19,19 66806,30,1194,1133,92,19,19 66807,30,1060,1133,769,30,30 -66808,29,1126,1133,785,60,60 -66809,30,1126,1133,785,60,60 -66810,29,1128,1133,786,60,60 -66811,30,1128,1133,786,60,60 -66812,29,1125,1133,787,60,60 -66813,30,1125,1133,787,60,60 -66814,29,1127,1133,788,60,60 -66815,30,1127,1133,788,60,60 66816,29,1098,1133,791,60,60 66817,30,1098,1133,792,60,60 66818,29,1141,1133,793,60,60 From 79b36523dd1c51329171f10e30b4203e71b5626c Mon Sep 17 00:00:00 2001 From: Justin Marquez Date: Thu, 23 Jul 2026 21:26:35 -0500 Subject: [PATCH 05/22] fix: remove duplicate solgaleo/lunala encounters in SM --- data/v2/csv/encounters.csv | 2 -- 1 file changed, 2 deletions(-) diff --git a/data/v2/csv/encounters.csv b/data/v2/csv/encounters.csv index e4ec88b64..9e718995b 100644 --- a/data/v2/csv/encounters.csv +++ b/data/v2/csv/encounters.csv @@ -61193,8 +61193,6 @@ id,version_id,location_area_id,encounter_slot_id,pokemon_id,min_level,max_level 66772,26,1180,574,442,50,50 66773,25,1189,574,488,50,50 66774,26,1189,574,488,50,50 -66783,27,1070,869,791,55,55 -66784,28,1069,869,792,55,55 66785,27,1078,869,793,55,55 66786,28,1078,869,793,55,55 66787,27,1156,869,793,55,55 From 77123e0fda55d45507dbf860eaabb69e9c3fa910 Mon Sep 17 00:00:00 2001 From: Justin Marquez Date: Thu, 23 Jul 2026 21:31:36 -0500 Subject: [PATCH 06/22] fix: remove additional static encounters for nihilego in SM --- data/v2/csv/encounters.csv | 4 ---- 1 file changed, 4 deletions(-) diff --git a/data/v2/csv/encounters.csv b/data/v2/csv/encounters.csv index 9e718995b..04b3277fc 100644 --- a/data/v2/csv/encounters.csv +++ b/data/v2/csv/encounters.csv @@ -61193,10 +61193,6 @@ id,version_id,location_area_id,encounter_slot_id,pokemon_id,min_level,max_level 66772,26,1180,574,442,50,50 66773,25,1189,574,488,50,50 66774,26,1189,574,488,50,50 -66785,27,1078,869,793,55,55 -66786,28,1078,869,793,55,55 -66787,27,1156,869,793,55,55 -66788,28,1156,869,793,55,55 66789,27,1102,869,794,65,65 66790,27,1102,869,794,65,65 66791,28,1193,869,795,60,60 From d85d7a978838740458814b7376e12780096fc6f3 Mon Sep 17 00:00:00 2001 From: Justin Marquez Date: Fri, 24 Jul 2026 08:23:19 -0500 Subject: [PATCH 07/22] fix: remove duplicate buzzwole encounters in SM --- data/v2/csv/encounters.csv | 2 -- 1 file changed, 2 deletions(-) diff --git a/data/v2/csv/encounters.csv b/data/v2/csv/encounters.csv index 04b3277fc..08fdd1091 100644 --- a/data/v2/csv/encounters.csv +++ b/data/v2/csv/encounters.csv @@ -61193,8 +61193,6 @@ id,version_id,location_area_id,encounter_slot_id,pokemon_id,min_level,max_level 66772,26,1180,574,442,50,50 66773,25,1189,574,488,50,50 66774,26,1189,574,488,50,50 -66789,27,1102,869,794,65,65 -66790,27,1102,869,794,65,65 66791,28,1193,869,795,60,60 66792,28,1193,869,795,60,60 66793,28,1193,869,795,60,60 From 8ca5f971629f4bfa0e8b5563dabedbadf989ff5f Mon Sep 17 00:00:00 2001 From: Justin Marquez Date: Fri, 24 Jul 2026 08:28:17 -0500 Subject: [PATCH 08/22] fix: remove duplicate xurkitree encounteres in SM --- data/v2/csv/encounters.csv | 4 ---- 1 file changed, 4 deletions(-) diff --git a/data/v2/csv/encounters.csv b/data/v2/csv/encounters.csv index 08fdd1091..f716eb577 100644 --- a/data/v2/csv/encounters.csv +++ b/data/v2/csv/encounters.csv @@ -61197,10 +61197,6 @@ id,version_id,location_area_id,encounter_slot_id,pokemon_id,min_level,max_level 66792,28,1193,869,795,60,60 66793,28,1193,869,795,60,60 66794,28,1193,869,795,60,60 -66795,27,1163,869,796,65,65 -66796,28,1163,869,796,65,65 -66797,27,1104,869,796,65,65 -66798,28,1104,869,796,65,65 66799,28,1081,869,797,65,65 66800,28,1101,869,797,65,65 66801,27,1164,869,798,60,60 From 528225982204d7b69a2d0ce440fba45aaa9fbd73 Mon Sep 17 00:00:00 2001 From: Justin Marquez Date: Fri, 24 Jul 2026 08:30:09 -0500 Subject: [PATCH 09/22] fix: remove duplicate celesteela and kartana encounters in SM --- data/v2/csv/encounters.csv | 2 -- 1 file changed, 2 deletions(-) diff --git a/data/v2/csv/encounters.csv b/data/v2/csv/encounters.csv index f716eb577..8d0fe0b89 100644 --- a/data/v2/csv/encounters.csv +++ b/data/v2/csv/encounters.csv @@ -61198,9 +61198,7 @@ id,version_id,location_area_id,encounter_slot_id,pokemon_id,min_level,max_level 66793,28,1193,869,795,60,60 66794,28,1193,869,795,60,60 66799,28,1081,869,797,65,65 -66800,28,1101,869,797,65,65 66801,27,1164,869,798,60,60 -66802,27,1101,869,798,60,60 66803,27,1123,869,799,70,70 66804,28,1123,869,799,70,70 66805,29,1194,1133,92,19,19 From cb96266b93f10947255a03750eb1e7e6a683701d Mon Sep 17 00:00:00 2001 From: Justin Marquez Date: Fri, 24 Jul 2026 08:31:33 -0500 Subject: [PATCH 10/22] fix: remove duplicate guzzlord encounters in SM --- data/v2/csv/encounters.csv | 2 -- 1 file changed, 2 deletions(-) diff --git a/data/v2/csv/encounters.csv b/data/v2/csv/encounters.csv index 8d0fe0b89..4e6d92442 100644 --- a/data/v2/csv/encounters.csv +++ b/data/v2/csv/encounters.csv @@ -61199,8 +61199,6 @@ id,version_id,location_area_id,encounter_slot_id,pokemon_id,min_level,max_level 66794,28,1193,869,795,60,60 66799,28,1081,869,797,65,65 66801,27,1164,869,798,60,60 -66803,27,1123,869,799,70,70 -66804,28,1123,869,799,70,70 66805,29,1194,1133,92,19,19 66806,30,1194,1133,92,19,19 66807,30,1060,1133,769,30,30 From d1fef3042caa426b505f8a5965014682a15d7e35 Mon Sep 17 00:00:00 2001 From: Justin Marquez Date: Fri, 24 Jul 2026 08:35:33 -0500 Subject: [PATCH 11/22] fix: remove duplicate encounters for solgaleo/lunala in USUM --- data/v2/csv/encounters.csv | 2 -- 1 file changed, 2 deletions(-) diff --git a/data/v2/csv/encounters.csv b/data/v2/csv/encounters.csv index 4e6d92442..73706df23 100644 --- a/data/v2/csv/encounters.csv +++ b/data/v2/csv/encounters.csv @@ -61202,8 +61202,6 @@ id,version_id,location_area_id,encounter_slot_id,pokemon_id,min_level,max_level 66805,29,1194,1133,92,19,19 66806,30,1194,1133,92,19,19 66807,30,1060,1133,769,30,30 -66816,29,1098,1133,791,60,60 -66817,30,1098,1133,792,60,60 66818,29,1141,1133,793,60,60 66819,30,1141,1133,793,60,60 66820,29,1144,1133,794,60,60 From 5fb029052049a4654d189ec9947b12c09e8b0fcc Mon Sep 17 00:00:00 2001 From: Justin Marquez Date: Fri, 24 Jul 2026 08:37:56 -0500 Subject: [PATCH 12/22] feat: add encounter pokemon details for always_shiny encounters --- data/v2/csv/encounter_pokemon_details.csv | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/data/v2/csv/encounter_pokemon_details.csv b/data/v2/csv/encounter_pokemon_details.csv index c88c53d1a..404a39129 100644 --- a/data/v2/csv/encounter_pokemon_details.csv +++ b/data/v2/csv/encounter_pokemon_details.csv @@ -1 +1,6 @@ encounter_id,min_perfect_ivs,always_shiny,never_shiny,is_alpha +62288,,1,0,0 +62289,,1,0,0 +62290,,1,0,0 +62291,,1,0,0 +62292,,1,0,0 From 7147403d4dcea0a3f2cb1ad784e596ff9847507c Mon Sep 17 00:00:00 2001 From: Justin Marquez Date: Fri, 24 Jul 2026 08:52:59 -0500 Subject: [PATCH 13/22] feat: add shiny-locked encounter pokemon details --- data/v2/csv/encounter_pokemon_details.csv | 140 ++++++++++++++++++++++ 1 file changed, 140 insertions(+) diff --git a/data/v2/csv/encounter_pokemon_details.csv b/data/v2/csv/encounter_pokemon_details.csv index 404a39129..f83f748d6 100644 --- a/data/v2/csv/encounter_pokemon_details.csv +++ b/data/v2/csv/encounter_pokemon_details.csv @@ -4,3 +4,143 @@ encounter_id,min_perfect_ivs,always_shiny,never_shiny,is_alpha 62290,,1,0,0 62291,,1,0,0 62292,,1,0,0 +63735,,0,1,0 +63736,,0,1,0 +64082,,0,1,0 +64086,,0,1,0 +64462,,0,1,0 +64463,,0,1,0 +64464,,0,1,0 +64465,,0,1,0 +64466,,0,1,0 +64467,,0,1,0 +64706,,0,1,0 +64707,,0,1,0 +64746,,0,1,0 +64763,,0,1,0 +64832,,0,1,0 +64944,,0,1,0 +64948,,0,1,0 +65073,,0,1,0 +65081,,0,1,0 +65960,,0,1,0 +65964,,0,1,0 +65979,,0,1,0 +65980,,0,1,0 +65981,,0,1,0 +65982,,0,1,0 +65983,,0,1,0 +65984,,0,1,0 +65985,,0,1,0 +65986,,0,1,0 +65987,,0,1,0 +65988,,0,1,0 +65989,,0,1,0 +65990,,0,1,0 +65991,,0,1,0 +65992,,0,1,0 +65993,,0,1,0 +65994,,0,1,0 +66210,,0,1,0 +66216,,0,1,0 +66558,,0,1,0 +66577,,0,1,0 +66585,,0,1,0 +66627,,0,1,0 +66628,,0,1,0 +66655,,0,1,0 +66656,,0,1,0 +66657,,0,1,0 +66658,,0,1,0 +66731,,0,1,0 +66732,,0,1,0 +66739,,0,1,0 +66742,,0,1,0 +66767,,0,1,0 +66768,,0,1,0 +66769,,0,1,0 +66770,,0,1,0 +66852,,0,1,0 +66853,,0,1,0 +66854,,0,1,0 +66855,,0,1,0 +66856,,0,1,0 +66857,,0,1,0 +66858,,0,1,0 +66859,,0,1,0 +66860,,0,1,0 +66861,,0,1,0 +66994,,0,1,0 +66995,,0,1,0 +70090,,0,1,0 +70091,,0,1,0 +75309,,0,1,0 +75310,,0,1,0 +75886,,0,1,0 +75887,,0,1,0 +75888,,0,1,0 +75889,,0,1,0 +75890,,0,1,0 +75891,,0,1,0 +75892,,0,1,0 +75893,,0,1,0 +75894,,0,1,0 +75895,,0,1,0 +75912,,0,1,0 +75913,,0,1,0 +75914,,0,1,0 +75915,,0,1,0 +75916,,0,1,0 +75917,,0,1,0 +75918,,0,1,0 +75919,,0,1,0 +75920,,0,1,0 +75921,,0,1,0 +75922,,0,1,0 +75923,,0,1,0 +75924,,0,1,0 +75925,,0,1,0 +75926,,0,1,0 +75927,,0,1,0 +75928,,0,1,0 +75929,,0,1,0 +75930,,0,1,0 +75931,,0,1,0 +75932,,0,1,0 +75933,,0,1,0 +75934,,0,1,0 +75935,,0,1,0 +75936,,0,1,0 +75937,,0,1,0 +75938,,0,1,0 +75939,,0,1,0 +75940,,0,1,0 +75941,,0,1,0 +75942,,0,1,0 +75943,,0,1,0 +75896,,0,1,0 +75897,,0,1,0 +75898,,0,1,0 +75899,,0,1,0 +75900,,0,1,0 +75901,,0,1,0 +75910,,0,1,0 +75911,,0,1,0 +75944,,0,1,0 +75945,,0,1,0 +75946,,0,1,0 +75947,,0,1,0 +97808,,0,1,0 +97809,,0,1,0 +97810,,0,1,0 +97811,,0,1,0 +97812,,0,1,0 +97813,,0,1,0 +99316,,0,1,0 +99317,,0,1,0 +99348,,0,1,0 +99349,,0,1,0 +99350,,0,1,0 +99351,,0,1,0 +99352,,0,1,0 +99353,,0,1,0 From a40de508ed3f228edcb3b87cead03fd23302fbe6 Mon Sep 17 00:00:00 2001 From: Justin Marquez Date: Fri, 24 Jul 2026 11:14:55 -0500 Subject: [PATCH 14/22] feat: update pokemon_details field to include all values, not just truth-like ones --- pokemon_v2/serializers.py | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/pokemon_v2/serializers.py b/pokemon_v2/serializers.py index 2f0917662..0e7774d80 100644 --- a/pokemon_v2/serializers.py +++ b/pokemon_v2/serializers.py @@ -960,10 +960,7 @@ def get_encounter_pokemon_details(self, obj): encounter_pokemon_details, many=True, context=self.context ).data - pokemon_details = [] - for map in data: - detail = {key: val for key, val in map.items() if val} - pokemon_details.append(detail) + pokemon_details = list(data) return pokemon_details From 6323fdfb7da8c3812aac3ec71305281564d3363f Mon Sep 17 00:00:00 2001 From: Justin Marquez Date: Fri, 24 Jul 2026 11:35:48 -0500 Subject: [PATCH 15/22] fix: correct nullability of berry fields from recent PR --- pokemon_v2/models.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/pokemon_v2/models.py b/pokemon_v2/models.py index 2959a015a..9ebfc50cb 100644 --- a/pokemon_v2/models.py +++ b/pokemon_v2/models.py @@ -964,21 +964,21 @@ class Berry(HasName, HasItem): on_delete=models.CASCADE, ) - natural_gift_power = models.IntegerField() + natural_gift_power = models.IntegerField(blank=True, null=True) natural_gift_type = models.ForeignKey( Type, blank=True, null=True, related_name="%(class)s", on_delete=models.CASCADE ) - size = models.IntegerField() + size = models.IntegerField(blank=True, null=True) - max_harvest = models.IntegerField() + max_harvest = models.IntegerField(blank=True, null=True) - growth_time = models.IntegerField() + growth_time = models.IntegerField(blank=True, null=True) - soil_dryness = models.IntegerField() + soil_dryness = models.IntegerField(blank=True, null=True) - smoothness = models.IntegerField() + smoothness = models.IntegerField(blank=True, null=True) # Berry Flavors are a bit of a hack because their relationship From d5dcb58a8283891dbc3fb023425e2c2a267eca97 Mon Sep 17 00:00:00 2001 From: Justin Marquez Date: Fri, 24 Jul 2026 11:36:07 -0500 Subject: [PATCH 16/22] feat: rename migration script --- ...ounterpokemondetail.py => 0031_encounterpokemondetail.py} | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) rename pokemon_v2/migrations/{0030_encounterpokemondetail.py => 0031_encounterpokemondetail.py} (85%) diff --git a/pokemon_v2/migrations/0030_encounterpokemondetail.py b/pokemon_v2/migrations/0031_encounterpokemondetail.py similarity index 85% rename from pokemon_v2/migrations/0030_encounterpokemondetail.py rename to pokemon_v2/migrations/0031_encounterpokemondetail.py index e49e895e6..3a519c095 100644 --- a/pokemon_v2/migrations/0030_encounterpokemondetail.py +++ b/pokemon_v2/migrations/0031_encounterpokemondetail.py @@ -1,4 +1,4 @@ -# Generated by Django 5.2.10 on 2026-07-23 21:10 +# Generated by Django 5.2.10 on 2026-07-24 16:35 import django.db.models.deletion from django.db import migrations, models @@ -7,7 +7,7 @@ class Migration(migrations.Migration): dependencies = [ - ("pokemon_v2", "0029_pokemonformtrigger_pokemonformcondition"), + ("pokemon_v2", "0030_alter_berry_growth_time_alter_berry_max_harvest_and_more"), ] operations = [ @@ -24,7 +24,6 @@ class Migration(migrations.Migration): ), ), ("min_perfect_ivs", models.IntegerField(blank=True, null=True)), - ("min_perfect_evs", models.IntegerField(blank=True, null=True)), ("always_shiny", models.BooleanField(default=False)), ("never_shiny", models.BooleanField(default=False)), ("is_alpha", models.BooleanField(default=False)), From 86b90a5b4403258726f3b5011e225689cc107199 Mon Sep 17 00:00:00 2001 From: Justin Marquez Date: Fri, 24 Jul 2026 11:59:31 -0500 Subject: [PATCH 17/22] feat: add pokemon_details to check_encounters.py script --- Resources/scripts/data/check_encounters.py | 23 ++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/Resources/scripts/data/check_encounters.py b/Resources/scripts/data/check_encounters.py index 2c707f31b..510ca052b 100755 --- a/Resources/scripts/data/check_encounters.py +++ b/Resources/scripts/data/check_encounters.py @@ -89,12 +89,15 @@ def main(): parser.error(f"output directory already exists: {args.outdir}") if args.first_encounter is None: print("WARNING: argument -e/--first-encounter not provided. a LOT of files will be written!") + if not os.path.isdir(CSVDIR): + parser.error(f"invalid directory {CSVDIR}") # Read encounter CSV files encounters = read_csv("encounters", after=args.first_encounter) encounter_condition_value_map = read_csv( "encounter_condition_value_map", after=args.first_encounter, non_unique=True ) + encounter_pokemon_details = read_csv("encounter_pokemon_details", after=args.first_encounter, non_unique=True) # Gather CSV information for other sources sources = { @@ -140,6 +143,19 @@ def expand_source(info: dict, maxdepth: int = 1): else: encounters[enc_id]["encounter_conditions"] = [sources["encounter_condition_value"][cond_id]] + # Link encounter pokemon details to relevant encounters + for entry in encounter_pokemon_details.values(): + enc_id = entry["encounter_id"] + if enc_id in encounters: + if "pokemon_details" in encounters[enc_id]: + encounters[enc_id]["pokemon_details"].append( + {key: val for key, val in entry.items() if key != "encounter_id"} + ) + else: + encounters[enc_id]["pokemon_details"] = { + key: val for key, val in entry.items() if key != "encounter_id" + } + # Group encounters by location area location_area_encounters = {} for enc in encounters.values(): @@ -230,6 +246,13 @@ def restructure_encounters(encounters: list, write_if_empty: bool = True) -> dic output["encounters"][-1]["encounter_conditions"] = [ cond["identifier"] for cond in enc["encounter_conditions"] ] + + # Add encounter pokemon details, if they exist + if "pokemon_details" in enc: + output["encounters"][-1]["pokemon_details"] = [ + {key: val for key, val in enc["pokemon_details"].items() if val} + ] + if args.sort_by_natdex: output["encounters"] = list( sorted( From 9c4d2564abbaf0e5d00241d7b43c18383e90e655 Mon Sep 17 00:00:00 2001 From: Justin Marquez Date: Fri, 24 Jul 2026 13:34:15 -0500 Subject: [PATCH 18/22] fix: remove unused setup classmethod for pokemon details --- pokemon_v2/tests.py | 20 -------------------- 1 file changed, 20 deletions(-) diff --git a/pokemon_v2/tests.py b/pokemon_v2/tests.py index 34f841822..23c2ae95b 100644 --- a/pokemon_v2/tests.py +++ b/pokemon_v2/tests.py @@ -2018,26 +2018,6 @@ def setup_encounter_condition_value_map_data( return encounter_condition_value_map - @classmethod - def setup_encounter_pokemon_detail_data( - cls, - encounter, - min_perfect_ivs=None, - always_shiny=False, - never_shiny=False, - is_alpha=False, - ): - encounter_pokemon_detail = EncounterPokemonDetail.objects.create( - encounter=encounter, - min_perfect_ivs=min_perfect_ivs, - always_shiny=always_shiny, - never_shiny=never_shiny, - is_alpha=is_alpha, - ) - encounter_pokemon_detail.save() - - return encounter_pokemon_detail - @classmethod def setup_encounter_slot_data(cls, encounter_method=None, slot=0, rarity=0): encounter_method = encounter_method or cls.setup_encounter_method_data( From 68e4f1889baaa29fbd19f01cba80a6f271e4db69 Mon Sep 17 00:00:00 2001 From: Justin Marquez Date: Fri, 24 Jul 2026 14:50:17 -0500 Subject: [PATCH 19/22] tests: add test to ensure only one entry per encounter_id is found for encounter_pokemon_details --- pokemon_v2/test_models.py | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/pokemon_v2/test_models.py b/pokemon_v2/test_models.py index e0a338221..63b299655 100644 --- a/pokemon_v2/test_models.py +++ b/pokemon_v2/test_models.py @@ -15,6 +15,25 @@ def fields_are_valid(self): self.assertEqual(smell.generation_id, 3) +class EncounterPokemonDetailTestCase(TestCase): + def test_unique_encounter_pokemon_details(self): + csv_dir = os.path.join(settings.BASE_DIR, "data", "v2", "csv") + with open(os.path.join(csv_dir, "encounter_pokemon_details.csv")) as infile: + reader = csv.DictReader(infile) + encounter_ids = [] + duplicate_ids = [] + for row in reader: + if row["encounter_id"] in encounter_ids: + duplicate_ids.append(row["encounter_id"]) + else: + encounter_ids.append(row["encounter_id"]) + + if duplicate_ids: + self.fail( + f"Duplicate encounter ID(s) found in encounter_pokemon_details.csv: {duplicate_ids}" + ) + + class CSVResourceNameValidationTestCase(TestCase): """ Test that all resource identifiers in CSV files follow ASCII slug format. From be0e273f7243a2c834b78e6151780322495ffeec Mon Sep 17 00:00:00 2001 From: Justin Marquez Date: Fri, 24 Jul 2026 15:11:27 -0500 Subject: [PATCH 20/22] feat: update structure of pokemon_details field --- pokemon_v2/serializers.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pokemon_v2/serializers.py b/pokemon_v2/serializers.py index 0e7774d80..49747750f 100644 --- a/pokemon_v2/serializers.py +++ b/pokemon_v2/serializers.py @@ -960,7 +960,7 @@ def get_encounter_pokemon_details(self, obj): encounter_pokemon_details, many=True, context=self.context ).data - pokemon_details = list(data) + pokemon_details = data[0] if len(data) else {} return pokemon_details From cda74c52ddcf8dd6e6acbf8c243fea48f472aa62 Mon Sep 17 00:00:00 2001 From: Justin Marquez Date: Fri, 24 Jul 2026 18:03:10 -0500 Subject: [PATCH 21/22] feat: change default value for pokemon_details field --- pokemon_v2/serializers.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pokemon_v2/serializers.py b/pokemon_v2/serializers.py index 49747750f..1c5d08b65 100644 --- a/pokemon_v2/serializers.py +++ b/pokemon_v2/serializers.py @@ -960,7 +960,7 @@ def get_encounter_pokemon_details(self, obj): encounter_pokemon_details, many=True, context=self.context ).data - pokemon_details = data[0] if len(data) else {} + pokemon_details = data[0] if len(data) else None return pokemon_details From 425590b23e0b3211a69b7b585f3c88fa1cfca25d Mon Sep 17 00:00:00 2001 From: Justin Marquez Date: Fri, 24 Jul 2026 21:37:19 -0500 Subject: [PATCH 22/22] fix: re-generate openapi.yml file after fix to berry schema updates --- openapi.yml | 6 ------ 1 file changed, 6 deletions(-) diff --git a/openapi.yml b/openapi.yml index 8f9187619..877de78e9 100644 --- a/openapi.yml +++ b/openapi.yml @@ -3317,16 +3317,10 @@ components: required: - firmness - flavors - - growth_time - id - item - - max_harvest - name - - natural_gift_power - natural_gift_type - - size - - smoothness - - soil_dryness BerryFirmnessDetail: type: object properties: