Merge pull request #79 from cawtds/time-based-encounters

Add Time based encounters
This commit is contained in:
cawtds 2025-05-01 16:59:30 +02:00 committed by GitHub
commit 9945f335f8
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
27 changed files with 5008 additions and 4136 deletions

View File

@ -175,8 +175,31 @@ MAPJSON := $(TOOLS_DIR)/mapjson/mapjson$(EXE)
JSONPROC := $(TOOLS_DIR)/jsonproc/jsonproc$(EXE)
TRAINERPROC := $(TOOLS_DIR)/trainerproc/trainerproc$(EXE)
PATCHELF := $(TOOLS_DIR)/patchelf/patchelf$(EXE)
ROMTEST ?= $(shell { command -v mgba-rom-test || command -v $(TOOLS_DIR)/mgba/mgba-rom-test$(EXE); } 2>/dev/null)
ROMTESTHYDRA := $(TOOLS_DIR)/mgba-rom-test-hydra/mgba-rom-test-hydra$(EXE)
ifeq ($(shell uname),Darwin)
ROMTEST ?= $(shell command -v mgba-rom-test-mac 2>/dev/null || echo $(TOOLS_DIR)/mgba/mgba-rom-test-mac)
ROMTESTHYDRA := $(shell command -v mgba-rom-test-hydra 2>/dev/null || echo $(TOOLS_DIR)/mgba-rom-test-hydra/mgba-rom-test-hydra)
else ifeq ($(shell uname),Linux)
ROMTEST ?= $(shell command -v mgba-rom-test 2>/dev/null || echo $(TOOLS_DIR)/mgba/mgba-rom-test)
ROMTESTHYDRA := $(shell command -v mgba-rom-test-hydra 2>/dev/null || echo $(TOOLS_DIR)/mgba-rom-test-hydra/mgba-rom-test-hydra)
else
ROMTEST ?= $(TOOLS_DIR)/mgba/mgba-rom-test$(EXE)
ROMTESTHYDRA := $(TOOLS_DIR)/mgba-rom-test-hydra/mgba-rom-test-hydra$(EXE)
endif
# Learnset helper is a Python script
LEARNSET_HELPERS_DIR := $(TOOLS_DIR)/learnset_helpers
LEARNSET_HELPERS_DATA_DIR := $(LEARNSET_HELPERS_DIR)/porymoves_files
LEARNSET_HELPERS_BUILD_DIR := $(LEARNSET_HELPERS_DIR)/build
ALL_LEARNABLES_JSON := $(LEARNSET_HELPERS_BUILD_DIR)/all_learnables.json
# wild_encounters.h is generated by a Python script
WILD_ENCOUNTERS_TOOL_DIR := $(TOOLS_DIR)/wild_encounters
AUTO_GEN_TARGETS += $(DATA_SRC_SUBDIR)/wild_encounters.h
$(DATA_SRC_SUBDIR)/wild_encounters.h: $(DATA_SRC_SUBDIR)/wild_encounters.json $(WILD_ENCOUNTERS_TOOL_DIR)/wild_encounters_to_header.py $(INCLUDE_DIRS)/config/overworld.h
python3 $(WILD_ENCOUNTERS_TOOL_DIR)/wild_encounters_to_header.py > $@
$(C_BUILDDIR)/wild_encounter.o: c_dep += $(DATA_SRC_SUBDIR)/wild_encounters.h
PERL := perl
SHA1 := $(shell { command -v sha1sum || command -v shasum; } 2>/dev/null) -c
@ -352,6 +375,7 @@ generated: $(AUTO_GEN_TARGETS)
clean-generated:
-rm -f $(AUTO_GEN_TARGETS)
-rm -f $(ALL_LEARNABLES_JSON)
COMPETITIVE_PARTY_SYNTAX := $(shell PATH="$(PATH)"; echo 'COMPETITIVE_PARTY_SYNTAX' | $(CPP) $(CPPFLAGS) -imacros include/gba/defines.h -imacros include/config/general.h | tail -n1)
ifeq ($(COMPETITIVE_PARTY_SYNTAX),1)
@ -441,11 +465,16 @@ $(OBJ_DIR)/sym_common.ld: sym_common.txt $(C_OBJS) $(wildcard common_syms/*.txt)
$(OBJ_DIR)/sym_ewram.ld: sym_ewram.txt
$(RAMSCRGEN) ewram_data $< ENGLISH > $@
MOVES_JSON_DIR := $(TOOLS_DIR)/learnset_helpers/porymoves_files
TEACHABLE_DEPS := $(shell find data/ -type f -name '*.inc') $(INCLUDE_DIRS)/constants/tms_hms.h $(C_SUBDIR)/pokemon.c $(wildcard $(MOVES_JSON_DIR)/*.json)
TEACHABLE_DEPS := $(ALL_LEARNABLES_JSON) $(shell find data/ -type f -name '*.inc') $(INCLUDE_DIRS)/constants/tms_hms.h $(INCLUDE_DIRS)/config/pokemon.h $(C_SUBDIR)/pokemon.c
$(LEARNSET_HELPERS_BUILD_DIR):
@mkdir -p $@
$(ALL_LEARNABLES_JSON): $(wildcard $(LEARNSET_HELPERS_DATA_DIR)/*.json) | $(LEARNSET_HELPERS_BUILD_DIR)
python3 $(LEARNSET_HELPERS_DIR)/make_learnables.py $(LEARNSET_HELPERS_DATA_DIR) $@
$(DATA_SRC_SUBDIR)/pokemon/teachable_learnsets.h: $(TEACHABLE_DEPS)
python3 $(TOOLS_DIR)/learnset_helpers/teachable.py
python3 $(LEARNSET_HELPERS_DIR)/make_teachables.py $<
# Linker script
LD_SCRIPT := ld_script_modern.ld

View File

@ -100,8 +100,11 @@ enum TimeOfDay {
TIME_DAY,
TIME_EVENING,
TIME_NIGHT,
TIMES_OF_DAY_COUNT,
};
#define TIME_OF_DAY_DEFAULT 0
enum Season {
SEASON_SPRING,
SEASON_SUMMER,

View File

@ -2,6 +2,16 @@
#define GUARD_WILD_ENCOUNTER_H
#include "global.h"
#include "rtc.h"
enum WildPokemonArea
{
WILD_AREA_LAND,
WILD_AREA_WATER,
WILD_AREA_ROCKS,
WILD_AREA_FISHING,
WILD_AREA_HIDDEN
};
#define LAND_WILD_COUNT 12
#define WATER_WILD_COUNT 5
@ -27,15 +37,25 @@ struct WildPokemonInfo
const struct WildPokemon *wildPokemon;
};
struct WildEncounterTypes
{
const struct WildPokemonInfo *landMonsInfo;
const struct WildPokemonInfo *waterMonsInfo;
const struct WildPokemonInfo *rockSmashMonsInfo;
const struct WildPokemonInfo *fishingMonsInfo;
const struct WildPokemonInfo *hiddenMonsInfo;
};
struct WildPokemonHeader
{
u8 mapGroup;
u8 mapNum;
const struct WildPokemonInfo *landMonsInfo;
const struct WildPokemonInfo *waterMonsInfo;
const struct WildPokemonInfo *rockSmashMonsInfo;
const struct WildPokemonInfo *hiddenMonsInfo;
const struct WildPokemonInfo *fishingMonsInfo;
#if OW_TIME_OF_DAY_ENCOUNTERS
const struct WildEncounterTypes encounterTypes[TIMES_OF_DAY_COUNT];
#else
const struct WildEncounterTypes encounterTypes[1];
#endif
};
extern const struct WildPokemonHeader gWildMonHeaders[];
@ -66,5 +86,6 @@ u8 ChooseWildMonIndex_Land(void);
u8 ChooseWildMonIndex_WaterRock(void);
u8 ChooseHiddenMonIndex(void);
bool32 MapHasNoEncounterData(void);
enum TimeOfDay GetTimeOfDayForEncounters(u32 headerId, enum WildPokemonArea area);
#endif // GUARD_WILD_ENCOUNTER_H

View File

@ -1,12 +1,6 @@
# JSON files are run through jsonproc, which is a tool that converts JSON data to an output file
# based on an Inja template. https://github.com/pantor/inja
AUTO_GEN_TARGETS += $(DATA_SRC_SUBDIR)/wild_encounters.h
$(DATA_SRC_SUBDIR)/wild_encounters.h: $(DATA_SRC_SUBDIR)/wild_encounters.json $(DATA_SRC_SUBDIR)/wild_encounters.json.txt
$(JSONPROC) $^ $@
$(C_BUILDDIR)/wild_encounter.o: c_dep += $(DATA_SRC_SUBDIR)/wild_encounters.h
AUTO_GEN_TARGETS += $(DATA_SRC_SUBDIR)/region_map/region_map_entries.h
$(DATA_SRC_SUBDIR)/region_map/region_map_entries.h: $(DATA_SRC_SUBDIR)/region_map/region_map_sections.json $(DATA_SRC_SUBDIR)/region_map/region_map_sections.json.txt
$(JSONPROC) $^ $@

File diff suppressed because it is too large Load Diff

View File

@ -97,11 +97,11 @@ const struct WildPokemonHeader {{ wild_encounter_group.label }}[] =
{
.mapGroup = {% if wild_encounter_group.for_maps %}MAP_GROUP({{ removePrefix(encounter.map, "MAP_") }}){% else %}0{% endif %},
.mapNum = {% if wild_encounter_group.for_maps %}MAP_NUM({{ removePrefix(encounter.map, "MAP_") }}){% else %}{{ loop.index1 }}{% endif %},
.landMonsInfo = {% if existsIn(encounter, "land_mons") %}&{{ encounter.base_label }}_LandMonsInfo{% else %}NULL{% endif %},
.waterMonsInfo = {% if existsIn(encounter, "water_mons") %}&{{ encounter.base_label }}_WaterMonsInfo{% else %}NULL{% endif %},
.rockSmashMonsInfo = {% if existsIn(encounter, "rock_smash_mons") %}&{{ encounter.base_label }}_RockSmashMonsInfo{% else %}NULL{% endif %},
.fishingMonsInfo = {% if existsIn(encounter, "fishing_mons") %}&{{ encounter.base_label }}_FishingMonsInfo{% else %}NULL{% endif %},
.hiddenMonsInfo = {% if existsIn(encounter, "hidden_mons") %}&{{ encounter.base_label }}_HiddenMonsInfo{% else %}NULL{% endif %},
.encounterTypes[timeOfDay].landMonsInfo = {% if existsIn(encounter, "land_mons") %}&{{ encounter.base_label }}_LandMonsInfo{% else %}NULL{% endif %},
.encounterTypes[timeOfDay].waterMonsInfo = {% if existsIn(encounter, "water_mons") %}&{{ encounter.base_label }}_WaterMonsInfo{% else %}NULL{% endif %},
.encounterTypes[timeOfDay].rockSmashMonsInfo = {% if existsIn(encounter, "rock_smash_mons") %}&{{ encounter.base_label }}_RockSmashMonsInfo{% else %}NULL{% endif %},
.encounterTypes[timeOfDay].fishingMonsInfo = {% if existsIn(encounter, "fishing_mons") %}&{{ encounter.base_label }}_FishingMonsInfo{% else %}NULL{% endif %},
.encounterTypes[timeOfDay].hiddenMonsInfo = {% if existsIn(encounter, "hidden_mons") %}&{{ encounter.base_label }}_HiddenMonsInfo{% else %}NULL{% endif %},
},
{% if contains(encounter.base_label, "FireRed") or contains(encounter.base_label, "LeafGreen") %}
#endif
@ -110,11 +110,11 @@ const struct WildPokemonHeader {{ wild_encounter_group.label }}[] =
{
.mapGroup = MAP_GROUP(UNDEFINED),
.mapNum = MAP_NUM(UNDEFINED),
.landMonsInfo = NULL,
.waterMonsInfo = NULL,
.rockSmashMonsInfo = NULL,
.fishingMonsInfo = NULL,
.hiddenMonsInfo = NULL,
.encounterTypes[timeOfDay].landMonsInfo = NULL,
.encounterTypes[timeOfDay].waterMonsInfo = NULL,
.encounterTypes[timeOfDay].rockSmashMonsInfo = NULL,
.encounterTypes[timeOfDay].fishingMonsInfo = NULL,
.encounterTypes[timeOfDay].hiddenMonsInfo = NULL,
},
};
## endfor

View File

@ -36,6 +36,7 @@
#include "pokemon_summary_screen.h"
#include "random.h"
#include "region_map.h"
#include "rtc.h"
#include "scanline_effect.h"
#include "script.h"
#include "script_pokemon_util.h"
@ -1516,9 +1517,7 @@ static u8 DexNavGeneratePotential(u8 searchLevel)
static u8 GetEncounterLevelFromMapData(u16 species, u8 environment)
{
u16 headerId = GetCurrentMapWildMonHeaderId();
const struct WildPokemonInfo *landMonsInfo = gWildMonHeaders[headerId].landMonsInfo;
const struct WildPokemonInfo *waterMonsInfo = gWildMonHeaders[headerId].waterMonsInfo;
const struct WildPokemonInfo *hiddenMonsInfo = gWildMonHeaders[headerId].hiddenMonsInfo;
enum TimeOfDay timeOfDay;
u8 min = 100;
u8 max = 0;
u8 i;
@ -1526,6 +1525,9 @@ static u8 GetEncounterLevelFromMapData(u16 species, u8 environment)
switch (environment)
{
case ENCOUNTER_TYPE_LAND: // grass
timeOfDay = GetTimeOfDayForEncounters(headerId, WILD_AREA_LAND);
const struct WildPokemonInfo *landMonsInfo = gWildMonHeaders[headerId].encounterTypes[timeOfDay].landMonsInfo;
if (landMonsInfo == NULL)
return MON_LEVEL_NONEXISTENT; //Hidden pokemon should only appear on walkable tiles or surf tiles
@ -1539,6 +1541,9 @@ static u8 GetEncounterLevelFromMapData(u16 species, u8 environment)
}
break;
case ENCOUNTER_TYPE_WATER: //water
timeOfDay = GetTimeOfDayForEncounters(headerId, WILD_AREA_WATER);
const struct WildPokemonInfo *waterMonsInfo = gWildMonHeaders[headerId].encounterTypes[timeOfDay].waterMonsInfo;
if (waterMonsInfo == NULL)
return MON_LEVEL_NONEXISTENT; //Hidden pokemon should only appear on walkable tiles or surf tiles
@ -1552,6 +1557,8 @@ static u8 GetEncounterLevelFromMapData(u16 species, u8 environment)
}
break;
case ENCOUNTER_TYPE_HIDDEN:
timeOfDay = GetTimeOfDayForEncounters(headerId, WILD_AREA_HIDDEN);
const struct WildPokemonInfo *hiddenMonsInfo = gWildMonHeaders[headerId].encounterTypes[timeOfDay].hiddenMonsInfo;
if (hiddenMonsInfo == NULL)
return MON_LEVEL_NONEXISTENT;
@ -1728,7 +1735,8 @@ static bool8 CapturedAllLandMons(u16 headerId)
{
u16 i, species;
int count = 0;
const struct WildPokemonInfo* landMonsInfo = gWildMonHeaders[headerId].landMonsInfo;
enum TimeOfDay timeOfDay = GetTimeOfDayForEncounters(headerId, WILD_AREA_LAND);
const struct WildPokemonInfo* landMonsInfo = gWildMonHeaders[headerId].encounterTypes[timeOfDay].landMonsInfo;
if (landMonsInfo != NULL)
{
@ -1761,7 +1769,8 @@ static bool8 CapturedAllWaterMons(u16 headerId)
u32 i;
u16 species;
u8 count = 0;
const struct WildPokemonInfo* waterMonsInfo = gWildMonHeaders[headerId].waterMonsInfo;
enum TimeOfDay timeOfDay = GetTimeOfDayForEncounters(headerId, WILD_AREA_WATER);
const struct WildPokemonInfo* waterMonsInfo = gWildMonHeaders[headerId].encounterTypes[timeOfDay].waterMonsInfo;
if (waterMonsInfo != NULL)
{
@ -1792,7 +1801,8 @@ static bool8 CapturedAllHiddenMons(u16 headerId)
u32 i;
u16 species;
u8 count = 0;
const struct WildPokemonInfo* hiddenMonsInfo = gWildMonHeaders[headerId].hiddenMonsInfo;
enum TimeOfDay timeOfDay = GetTimeOfDayForEncounters(headerId, WILD_AREA_HIDDEN);
const struct WildPokemonInfo* hiddenMonsInfo = gWildMonHeaders[headerId].encounterTypes[timeOfDay].hiddenMonsInfo;
if (hiddenMonsInfo != NULL)
{
@ -1937,9 +1947,14 @@ static void DexNavLoadEncounterData(void)
u16 species;
u32 i;
u16 headerId = GetCurrentMapWildMonHeaderId();
const struct WildPokemonInfo* landMonsInfo = gWildMonHeaders[headerId].landMonsInfo;
const struct WildPokemonInfo* waterMonsInfo = gWildMonHeaders[headerId].waterMonsInfo;
const struct WildPokemonInfo* hiddenMonsInfo = gWildMonHeaders[headerId].hiddenMonsInfo;
enum TimeOfDay timeOfDay;
timeOfDay = GetTimeOfDayForEncounters(headerId, WILD_AREA_LAND);
const struct WildPokemonInfo* landMonsInfo = gWildMonHeaders[headerId].encounterTypes[timeOfDay].landMonsInfo;
timeOfDay = GetTimeOfDayForEncounters(headerId, WILD_AREA_WATER);
const struct WildPokemonInfo* waterMonsInfo = gWildMonHeaders[headerId].encounterTypes[timeOfDay].waterMonsInfo;
timeOfDay = GetTimeOfDayForEncounters(headerId, WILD_AREA_HIDDEN);
const struct WildPokemonInfo* hiddenMonsInfo = gWildMonHeaders[headerId].encounterTypes[timeOfDay].hiddenMonsInfo;
// nop struct data
memset(sDexNavUiDataPtr->landSpecies, 0, sizeof(sDexNavUiDataPtr->landSpecies));
@ -2515,7 +2530,8 @@ bool8 TryFindHiddenPokemon(void)
u16 species;
u8 environment;
u8 taskId;
const struct WildPokemonInfo* hiddenMonsInfo = gWildMonHeaders[headerId].hiddenMonsInfo;
enum TimeOfDay timeOfDay = GetTimeOfDayForEncounters(headerId, WILD_AREA_HIDDEN);
const struct WildPokemonInfo* hiddenMonsInfo = gWildMonHeaders[headerId].encounterTypes[timeOfDay].hiddenMonsInfo;
bool8 isHiddenMon = FALSE;
// while you can still technically find hidden pokemon if there are not hidden-only pokemon on a map,
@ -2540,7 +2556,7 @@ bool8 TryFindHiddenPokemon(void)
}
else
{
species = gWildMonHeaders[headerId].landMonsInfo->wildPokemon[ChooseWildMonIndex_Land()].species;
species = gWildMonHeaders[headerId].encounterTypes[timeOfDay].landMonsInfo->wildPokemon[ChooseWildMonIndex_Land()].species;
environment = ENCOUNTER_TYPE_LAND;
}
break;
@ -2558,7 +2574,7 @@ bool8 TryFindHiddenPokemon(void)
}
else
{
species = gWildMonHeaders[headerId].waterMonsInfo->wildPokemon[ChooseWildMonIndex_WaterRock()].species;
species = gWildMonHeaders[headerId].encounterTypes[timeOfDay].waterMonsInfo->wildPokemon[ChooseWildMonIndex_WaterRock()].species;
environment = ENCOUNTER_TYPE_WATER;
}

View File

@ -113,9 +113,10 @@ void AdvanceScript(void)
u32 FakeRtc_GetSecondsRatio(void)
{
return (OW_ALTERED_TIME_RATIO == GEN_8_PLA) ? 60 :
(OW_ALTERED_TIME_RATIO == GEN_9) ? 20 :
1;
return (OW_ALTERED_TIME_RATIO == GEN_8_PLA) ? 60 :
(OW_ALTERED_TIME_RATIO == GEN_9) ? 20 :
(OW_ALTERED_TIME_RATIO == TIME_DEBUG) ? 1 :
1;
}
STATIC_ASSERT((OW_FLAG_PAUSE_TIME == 0 || OW_USE_FAKE_RTC == TRUE), FakeRtcMustBeTrueToPauseTime);

View File

@ -24,14 +24,6 @@
#define MAX_ENCOUNTER_RATE 1600
enum
{
WILD_AREA_LAND,
WILD_AREA_WATER,
WILD_AREA_ROCKS,
WILD_AREA_FISHING,
};
#define WILD_CHECK_REPEL 0x1
#define WILD_CHECK_KEEN_EYE 0x2
@ -289,6 +281,40 @@ u16 GetCurrentMapWildMonHeaderId(void)
return HEADER_NONE;
}
enum TimeOfDay GetTimeOfDayForEncounters(u32 headerId, enum WildPokemonArea area)
{
const struct WildPokemonInfo *wildMonInfo;
enum TimeOfDay timeOfDay = GetTimeOfDay();
if (!OW_TIME_OF_DAY_ENCOUNTERS)
return TIME_OF_DAY_DEFAULT;
switch (area)
{
default:
case WILD_AREA_LAND:
wildMonInfo = gWildMonHeaders[headerId].encounterTypes[timeOfDay].landMonsInfo;
break;
case WILD_AREA_WATER:
wildMonInfo = gWildMonHeaders[headerId].encounterTypes[timeOfDay].waterMonsInfo;
break;
case WILD_AREA_ROCKS:
wildMonInfo = gWildMonHeaders[headerId].encounterTypes[timeOfDay].rockSmashMonsInfo;
break;
case WILD_AREA_FISHING:
wildMonInfo = gWildMonHeaders[headerId].encounterTypes[timeOfDay].fishingMonsInfo;
break;
case WILD_AREA_HIDDEN:
wildMonInfo = gWildMonHeaders[headerId].encounterTypes[timeOfDay].hiddenMonsInfo;
break;
}
if (wildMonInfo == NULL && !OW_TIME_OF_DAY_DISABLE_FALLBACK)
return OW_TIME_OF_DAY_FALLBACK;
else
return timeOfDay;
}
static bool8 UnlockedTanobyOrAreNotInTanoby(void)
{
if (FlagGet(FLAG_SYS_UNLOCKED_TANOBY_RUINS))
@ -539,13 +565,14 @@ static bool8 DoGlobalWildEncounterDiceRoll(void)
bool8 TryStandardWildLandEncounter(u16 headerId, u32 currMetatileAttrs, u16 previousMetatileBehavior)
{
struct Roamer * roamer;
if (gWildMonHeaders[headerId].landMonsInfo == NULL)
enum TimeOfDay timeOfDay = GetTimeOfDayForEncounters(headerId, WILD_AREA_LAND);
if (gWildMonHeaders[headerId].encounterTypes[timeOfDay].landMonsInfo == NULL)
return FALSE;
if (previousMetatileBehavior != ExtractMetatileAttribute(currMetatileAttrs, METATILE_ATTRIBUTE_BEHAVIOR) && !DoGlobalWildEncounterDiceRoll())
return FALSE;
if (DoWildEncounterRateTest(gWildMonHeaders[headerId].landMonsInfo->encounterRate, FALSE) != TRUE)
if (DoWildEncounterRateTest(gWildMonHeaders[headerId].encounterTypes[timeOfDay].landMonsInfo->encounterRate, FALSE) != TRUE)
{
AddToWildEncounterRateBuff(gWildMonHeaders[headerId].landMonsInfo->encounterRate);
AddToWildEncounterRateBuff(gWildMonHeaders[headerId].encounterTypes[timeOfDay].landMonsInfo->encounterRate);
return FALSE;
}
if (TryStartRoamerEncounter() == TRUE)
@ -561,12 +588,12 @@ bool8 TryStandardWildLandEncounter(u16 headerId, u32 currMetatileAttrs, u16 prev
}
// try a regular wild land encounter
if (TryGenerateWildMon(gWildMonHeaders[headerId].landMonsInfo, WILD_AREA_LAND, WILD_CHECK_REPEL) == TRUE)
if (TryGenerateWildMon(gWildMonHeaders[headerId].encounterTypes[timeOfDay].landMonsInfo, WILD_AREA_LAND, WILD_CHECK_REPEL) == TRUE)
{
if (TryDoDoubleWildBattle())
{
struct Pokemon mon1 = gEnemyParty[0];
TryGenerateWildMon(gWildMonHeaders[headerId].landMonsInfo, WILD_AREA_LAND, WILD_CHECK_KEEN_EYE);
TryGenerateWildMon(gWildMonHeaders[headerId].encounterTypes[timeOfDay].landMonsInfo, WILD_AREA_LAND, WILD_CHECK_KEEN_EYE);
gEnemyParty[1] = mon1;
StartDoubleWildBattle();
}
@ -576,20 +603,21 @@ bool8 TryStandardWildLandEncounter(u16 headerId, u32 currMetatileAttrs, u16 prev
}
return TRUE;
}
AddToWildEncounterRateBuff(gWildMonHeaders[headerId].landMonsInfo->encounterRate);
AddToWildEncounterRateBuff(gWildMonHeaders[headerId].encounterTypes[timeOfDay].landMonsInfo->encounterRate);
return FALSE;
}
bool8 TryStandardWildSurfEncounter(u16 headerId, u32 currMetatileAttrs, u16 previousMetatileBehavior)
{
struct Roamer * roamer;
if (gWildMonHeaders[headerId].waterMonsInfo == NULL)
enum TimeOfDay timeOfDay = GetTimeOfDayForEncounters(headerId, WILD_AREA_WATER);
if (gWildMonHeaders[headerId].encounterTypes[timeOfDay].waterMonsInfo == NULL)
return FALSE;
if (previousMetatileBehavior != ExtractMetatileAttribute(currMetatileAttrs, METATILE_ATTRIBUTE_BEHAVIOR) && !DoGlobalWildEncounterDiceRoll())
return FALSE;
if (DoWildEncounterRateTest(gWildMonHeaders[headerId].waterMonsInfo->encounterRate, FALSE) != TRUE)
if (DoWildEncounterRateTest(gWildMonHeaders[headerId].encounterTypes[timeOfDay].waterMonsInfo->encounterRate, FALSE) != TRUE)
{
AddToWildEncounterRateBuff(gWildMonHeaders[headerId].waterMonsInfo->encounterRate);
AddToWildEncounterRateBuff(gWildMonHeaders[headerId].encounterTypes[timeOfDay].waterMonsInfo->encounterRate);
return FALSE;
}
@ -605,13 +633,13 @@ bool8 TryStandardWildSurfEncounter(u16 headerId, u32 currMetatileAttrs, u16 prev
return TRUE;
}
// try a regular surfing encounter
if (TryGenerateWildMon(gWildMonHeaders[headerId].waterMonsInfo, WILD_AREA_WATER, WILD_CHECK_REPEL) == TRUE)
if (TryGenerateWildMon(gWildMonHeaders[headerId].encounterTypes[timeOfDay].waterMonsInfo, WILD_AREA_WATER, WILD_CHECK_REPEL) == TRUE)
{
gIsSurfingEncounter = TRUE;
if (TryDoDoubleWildBattle())
{
struct Pokemon mon1 = gEnemyParty[0];
TryGenerateWildMon(gWildMonHeaders[headerId].waterMonsInfo, WILD_AREA_WATER, WILD_CHECK_KEEN_EYE);
TryGenerateWildMon(gWildMonHeaders[headerId].encounterTypes[timeOfDay].waterMonsInfo, WILD_AREA_WATER, WILD_CHECK_KEEN_EYE);
gEnemyParty[1] = mon1;
StartDoubleWildBattle();
}
@ -622,7 +650,7 @@ bool8 TryStandardWildSurfEncounter(u16 headerId, u32 currMetatileAttrs, u16 prev
return TRUE;
}
AddToWildEncounterRateBuff(gWildMonHeaders[headerId].waterMonsInfo->encounterRate);
AddToWildEncounterRateBuff(gWildMonHeaders[headerId].encounterTypes[timeOfDay].waterMonsInfo->encounterRate);
return FALSE;
}
@ -648,14 +676,15 @@ bool8 StandardWildEncounter(u32 currMetatileAttrs, u16 previousMetatileBehavior)
void RockSmashWildEncounter(void)
{
u16 headerIdx = GetCurrentMapWildMonHeaderId();
if (headerIdx == HEADER_NONE)
u16 headerId = GetCurrentMapWildMonHeaderId();
enum TimeOfDay timeOfDay = GetTimeOfDayForEncounters(headerId, WILD_AREA_ROCKS);
if (headerId == HEADER_NONE)
gSpecialVar_Result = FALSE;
else if (gWildMonHeaders[headerIdx].rockSmashMonsInfo == NULL)
else if (gWildMonHeaders[headerId].encounterTypes[timeOfDay].rockSmashMonsInfo == NULL)
gSpecialVar_Result = FALSE;
else if (DoWildEncounterRateTest(gWildMonHeaders[headerIdx].rockSmashMonsInfo->encounterRate, TRUE) != TRUE)
else if (DoWildEncounterRateTest(gWildMonHeaders[headerId].encounterTypes[timeOfDay].rockSmashMonsInfo->encounterRate, TRUE) != TRUE)
gSpecialVar_Result = FALSE;
else if (TryGenerateWildMon(gWildMonHeaders[headerIdx].rockSmashMonsInfo, WILD_AREA_ROCKS, WILD_CHECK_REPEL) == TRUE)
else if (TryGenerateWildMon(gWildMonHeaders[headerId].encounterTypes[timeOfDay].rockSmashMonsInfo, WILD_AREA_ROCKS, WILD_CHECK_REPEL) == TRUE)
{
StartWildBattle();
gSpecialVar_Result = TRUE;
@ -668,6 +697,7 @@ bool8 SweetScentWildEncounter(void)
{
s16 x, y;
u16 headerId;
enum TimeOfDay timeOfDay;
PlayerGetDestCoords(&x, &y);
headerId = GetCurrentMapWildMonHeaderId();
@ -682,11 +712,12 @@ bool8 SweetScentWildEncounter(void)
StartRoamerBattle();
return TRUE;
}
timeOfDay = GetTimeOfDayForEncounters(headerId, WILD_AREA_LAND);
if (gWildMonHeaders[headerId].landMonsInfo == NULL)
if (gWildMonHeaders[headerId].encounterTypes[timeOfDay].landMonsInfo == NULL)
return FALSE;
TryGenerateWildMon(gWildMonHeaders[headerId].landMonsInfo, WILD_AREA_LAND, 0);
TryGenerateWildMon(gWildMonHeaders[headerId].encounterTypes[timeOfDay].landMonsInfo, WILD_AREA_LAND, 0);
StartWildBattle();
return TRUE;
@ -699,10 +730,11 @@ bool8 SweetScentWildEncounter(void)
return TRUE;
}
if (gWildMonHeaders[headerId].waterMonsInfo == NULL)
timeOfDay = GetTimeOfDayForEncounters(headerId, WILD_AREA_WATER);
if (gWildMonHeaders[headerId].encounterTypes[timeOfDay].waterMonsInfo == NULL)
return FALSE;
TryGenerateWildMon(gWildMonHeaders[headerId].waterMonsInfo, WILD_AREA_WATER, 0);
TryGenerateWildMon(gWildMonHeaders[headerId].encounterTypes[timeOfDay].waterMonsInfo, WILD_AREA_WATER, 0);
StartWildBattle();
return TRUE;
}
@ -712,10 +744,12 @@ bool8 SweetScentWildEncounter(void)
bool8 DoesCurrentMapHaveFishingMons(void)
{
u16 headerIdx = GetCurrentMapWildMonHeaderId();
if (headerIdx == HEADER_NONE)
u16 headerId = GetCurrentMapWildMonHeaderId();
enum TimeOfDay timeOfDay = GetTimeOfDayForEncounters(headerId, WILD_AREA_FISHING);
if (headerId == HEADER_NONE)
return FALSE;
if (gWildMonHeaders[headerIdx].fishingMonsInfo == NULL)
if (gWildMonHeaders[headerId].encounterTypes[timeOfDay].fishingMonsInfo == NULL)
return FALSE;
return TRUE;
}
@ -738,15 +772,18 @@ static void UpdateChainFishingStreak()
void FishingWildEncounter(u8 rod)
{
u32 headerId = GetCurrentMapWildMonHeaderId();
enum TimeOfDay timeOfDay = GetTimeOfDayForEncounters(headerId, WILD_AREA_FISHING);
gIsFishingEncounter = TRUE;
GenerateFishingEncounter(gWildMonHeaders[GetCurrentMapWildMonHeaderId()].fishingMonsInfo, rod);
GenerateFishingEncounter(gWildMonHeaders[headerId].encounterTypes[timeOfDay].fishingMonsInfo, rod);
IncrementGameStat(GAME_STAT_FISHING_CAPTURES);
StartWildBattle();
}
u16 GetLocalWildMon(bool8 *isWaterMon)
{
u16 headerId;
u32 headerId;
enum TimeOfDay timeOfDay;
const struct WildPokemonInfo *landMonsInfo;
const struct WildPokemonInfo *waterMonsInfo;
@ -754,8 +791,11 @@ u16 GetLocalWildMon(bool8 *isWaterMon)
headerId = GetCurrentMapWildMonHeaderId();
if (headerId == HEADER_NONE)
return SPECIES_NONE;
landMonsInfo = gWildMonHeaders[headerId].landMonsInfo;
waterMonsInfo = gWildMonHeaders[headerId].waterMonsInfo;
timeOfDay = GetTimeOfDayForEncounters(headerId, WILD_AREA_LAND);
landMonsInfo = gWildMonHeaders[headerId].encounterTypes[timeOfDay].landMonsInfo;
timeOfDay = GetTimeOfDayForEncounters(headerId, WILD_AREA_WATER);
waterMonsInfo = gWildMonHeaders[headerId].encounterTypes[timeOfDay].waterMonsInfo;
// Neither
if (landMonsInfo == NULL && waterMonsInfo == NULL)
return SPECIES_NONE;
@ -783,10 +823,12 @@ u16 GetLocalWildMon(bool8 *isWaterMon)
u16 GetLocalWaterMon(void)
{
u16 headerId = GetCurrentMapWildMonHeaderId();
enum TimeOfDay timeOfDay;
if (headerId != HEADER_NONE)
{
const struct WildPokemonInfo * waterMonsInfo = gWildMonHeaders[headerId].waterMonsInfo;
timeOfDay = GetTimeOfDayForEncounters(headerId, WILD_AREA_WATER);
const struct WildPokemonInfo * waterMonsInfo = gWildMonHeaders[headerId].encounterTypes[timeOfDay].waterMonsInfo;
if (waterMonsInfo)
return waterMonsInfo->wildPokemon[ChooseWildMonIndex_WaterRock()].species;
@ -982,28 +1024,31 @@ static u16 WildEncounterRandom(void)
static u8 GetMapBaseEncounterCooldown(u8 encounterType)
{
u16 headerIdx = GetCurrentMapWildMonHeaderId();
if (headerIdx == HEADER_NONE)
u16 headerId = GetCurrentMapWildMonHeaderId();
enum TimeOfDay timeOfDay;
if (headerId == HEADER_NONE)
return 0xFF;
if (encounterType == TILE_ENCOUNTER_LAND)
{
if (gWildMonHeaders[headerIdx].landMonsInfo == NULL)
timeOfDay = GetTimeOfDayForEncounters(headerId, WILD_AREA_LAND);
if (gWildMonHeaders[headerId].encounterTypes[timeOfDay].landMonsInfo == NULL)
return 0xFF;
if (gWildMonHeaders[headerIdx].landMonsInfo->encounterRate >= 80)
if (gWildMonHeaders[headerId].encounterTypes[timeOfDay].landMonsInfo->encounterRate >= 80)
return 0;
if (gWildMonHeaders[headerIdx].landMonsInfo->encounterRate < 10)
if (gWildMonHeaders[headerId].encounterTypes[timeOfDay].landMonsInfo->encounterRate < 10)
return 8;
return 8 - (gWildMonHeaders[headerIdx].landMonsInfo->encounterRate / 10);
return 8 - (gWildMonHeaders[headerId].encounterTypes[timeOfDay].landMonsInfo->encounterRate / 10);
}
if (encounterType == TILE_ENCOUNTER_WATER)
{
if (gWildMonHeaders[headerIdx].waterMonsInfo == NULL)
timeOfDay = GetTimeOfDayForEncounters(headerId, WILD_AREA_WATER);
if (gWildMonHeaders[headerId].encounterTypes[timeOfDay].waterMonsInfo == NULL)
return 0xFF;
if (gWildMonHeaders[headerIdx].waterMonsInfo->encounterRate >= 80)
if (gWildMonHeaders[headerId].encounterTypes[timeOfDay].waterMonsInfo->encounterRate >= 80)
return 0;
if (gWildMonHeaders[headerIdx].waterMonsInfo->encounterRate < 10)
if (gWildMonHeaders[headerId].encounterTypes[timeOfDay].waterMonsInfo->encounterRate < 10)
return 8;
return 8 - (gWildMonHeaders[headerIdx].waterMonsInfo->encounterRate / 10);
return 8 - (gWildMonHeaders[headerId].encounterTypes[timeOfDay].waterMonsInfo->encounterRate / 10);
}
return 0xFF;
}

View File

@ -6,6 +6,7 @@
#include "overworld.h"
#include "pokedex.h"
#include "pokedex_area_markers.h"
#include "rtc.h"
#include "constants/region_map_sections.h"
#include "constants/maps.h"
@ -17,7 +18,7 @@ struct RoamerPair
static s32 GetRoamerIndex(u16 species);
static s32 GetRoamerPokedexAreaMarkers(u16 species, struct Subsprite * subsprites);
static bool32 IsSpeciesOnMap(const struct WildPokemonHeader * data, s32 species);
static bool32 IsSpeciesOnMap(const struct WildPokemonHeader * data, u32 headerId, s32 species);
static bool32 IsSpeciesInEncounterTable(const struct WildPokemonInfo * pokemon, s32 species, s32 count);
static u16 GetMapSecIdFromWildMonHeader(const struct WildPokemonHeader * header);
static bool32 FindDexAreaByMapSec(u16 mapSecId, const u16 (*lut)[2], s32 count, s32 * lutIdx_p, u16 * tableIdx_p);
@ -190,7 +191,7 @@ s32 GetSpeciesPokedexAreaMarkers(u16 species, struct Subsprite * subsprites)
if (alteringCaveNum != alteringCaveCount - 1)
continue;
}
if (IsSpeciesOnMap(&gWildMonHeaders[i], species))
if (IsSpeciesOnMap(&gWildMonHeaders[i], i, species))
{
// Search for all dex areas associated with this MAPSEC.
// In the vanilla game each MAPSEC only has at most one DEX_AREA.
@ -259,21 +260,22 @@ static s32 GetRoamerPokedexAreaMarkers(u16 species, struct Subsprite * subsprite
return 0;
}
static bool32 IsSpeciesOnMap(const struct WildPokemonHeader * data, s32 species)
static bool32 IsSpeciesOnMap(const struct WildPokemonHeader * data, u32 headerId, s32 species)
{
if (IsSpeciesInEncounterTable(data->landMonsInfo, species, LAND_WILD_COUNT))
enum TimeOfDay timeOfDay = GetTimeOfDayForEncounters(headerId, WILD_AREA_LAND);
if (IsSpeciesInEncounterTable(data->encounterTypes[timeOfDay].landMonsInfo, species, LAND_WILD_COUNT))
return TRUE;
if (IsSpeciesInEncounterTable(data->waterMonsInfo, species, WATER_WILD_COUNT))
if (IsSpeciesInEncounterTable(data->encounterTypes[timeOfDay].waterMonsInfo, species, WATER_WILD_COUNT))
return TRUE;
// When searching the fishing encounters, this incorrectly uses the size of the land encounters.
// As a result it's reading out of bounds of the fishing encounters tables.
#ifdef BUGFIX
if (IsSpeciesInEncounterTable(data->fishingMonsInfo, species, FISH_WILD_COUNT))
if (IsSpeciesInEncounterTable(data->encounterTypes[timeOfDay].fishingMonsInfo, species, FISH_WILD_COUNT))
#else
if (IsSpeciesInEncounterTable(data->fishingMonsInfo, species, LAND_WILD_COUNT))
if (IsSpeciesInEncounterTable(data->encounterTypes[timeOfDay].fishingMonsInfo, species, LAND_WILD_COUNT))
#endif
return TRUE;
if (IsSpeciesInEncounterTable(data->rockSmashMonsInfo, species, ROCK_WILD_COUNT))
if (IsSpeciesInEncounterTable(data->encounterTypes[timeOfDay].rockSmashMonsInfo, species, ROCK_WILD_COUNT))
return TRUE;
return FALSE;

View File

@ -45,13 +45,6 @@ int main(int argc, char *argv[])
return "//\n// DO NOT MODIFY THIS FILE! It is auto-generated from " + jsonfilepath +" and Inja template " + templateFilepath + "\n//\n";
});
env.add_callback("contains", 2, [](Arguments& args) {
string word = args.at(0)->get<string>();
string check = args.at(1)->get<string>();
return word.find(check) != std::string::npos;
});
env.add_callback("subtract", 2, [](Arguments& args) {
int minuend = args.at(0)->get<int>();
int subtrahend = args.at(1)->get<int>();

View File

@ -0,0 +1,62 @@
#!/usr/bin/env python3
"""
Usage: python3 make_learnables.py INPUTS_DIR OUTPUT_FILE
Build a primary store of learnable moves for each species based on input documents. This script
is meant to be run to generate a pre-processed store of data that should not change very much;
thus, it can safely be pre-computed in order to speed up incremental builds for end-users.
"""
from functools import reduce
import json
import pathlib
import sys
def from_single(fname: pathlib.Path) -> dict[str, set[str]]:
with open(fname, "r") as fp:
return {
species: set([level_up["Move"] for level_up in by_method["LevelMoves"]])
| set([move for move in by_method["TMMoves"]])
| set([move for move in by_method["EggMoves"]])
| set([move for move in by_method["TutorMoves"]])
for species, by_method in json.load(fp).items()
}
def from_batch(dir: pathlib.Path) -> dict[str, set[str]]:
return reduce(
lambda acc, single: {
species: acc.get(species, set()) | single.get(species, set())
for species in acc.keys() | single.keys()
},
map(from_single, dir.glob("*.json")),
{},
)
def main():
if len(sys.argv) < 3:
print("Missing required arguments", file=sys.stderr)
print(__doc__, file=sys.stderr)
quit(1)
INPUTS_DIR = pathlib.Path(sys.argv[1])
OUTPUT_FILE = pathlib.Path(sys.argv[2])
assert INPUTS_DIR.exists(), f"{INPUTS_DIR=} does not exist"
assert INPUTS_DIR.is_dir(), f"{INPUTS_DIR=} is not a directory"
assert OUTPUT_FILE.parent.exists(), f"parent of {OUTPUT_FILE=} does not exist"
batch = {
species: list(sorted(learnables))
for species, learnables in from_batch(INPUTS_DIR).items()
}
with open(OUTPUT_FILE, "w") as fp:
json.dump(batch, fp, indent=2)
if __name__ == "__main__":
main()

View File

@ -0,0 +1,233 @@
#!/usr/bin/env python3
"""
Usage: python3 make_teachable.py SOURCE_LEARNSETS_JSON
Build a C-header defining the set of teachable moves for each configured-on
species-family based on the learnable moves defined in SOURCE_LEARNSETS_JSON.
A move is "teachable" if it is:
1. Can be taught by some Move Tutor in the overworld, which is identified by
using the ChooseMonForMoveTutor special in a script and setting VAR_0x8005
to the offered MOVE constant. (e.g., MOVE_SWAGGER)
2. Assigned to some TM or HM in include/constants/tms_hms.h using the
FOREACH_TM macro.
3. Not a universal move, as defined by sUniversalMoves in src/pokemon.c.
For a given species, a move is considered teachable to that species if:
1. The species is not NONE -- which learns nothing -- nor MEW -- which
learns everything.
2. The species can learn the move via *any* method within any Expansion-
supported game.
"""
from itertools import chain
from textwrap import dedent
import glob
import json
import pathlib
import re
import sys
import typing
CONFIG_ENABLED_PAT = re.compile(r"#define P_LEARNSET_HELPER_TEACHABLE\s+(?P<cfg_val>[^ ]*)")
INCFILE_HAS_TUTOR_PAT = re.compile(r"special ChooseMonForMoveTutor")
INCFILE_MOVE_PAT = re.compile(r"setvar VAR_0x8005, (MOVE_.*)")
TMHM_MACRO_PAT = re.compile(r"F\((\w+)\)")
UNIVERSAL_MOVES_PAT = re.compile(r"static const u16 sUniversalMoves\[\]\s*=\s*{((.|\n)*?)\n};")
TEACHABLE_ARRAY_DECL_PAT = re.compile(r"(?P<decl>static const u16 s(?P<name>\w+)TeachableLearnset\[\]) = {[\s\S]*?};")
SNAKIFY_PAT = re.compile(r"(?!^)([A-Z]+)")
TUTOR_ARRAY_ENABLED_PAT = re.compile(r"#define\s+P_TUTOR_MOVES_ARRAY\s+(?P<cfg_val>[^ ]*)")
def enabled() -> bool:
"""
Check if the user has explicitly enabled this opt-in helper.
"""
with open("./include/config/pokemon.h", "r") as cfg_pokemon_fp:
cfg_pokemon = cfg_pokemon_fp.read()
cfg_defined = CONFIG_ENABLED_PAT.search(cfg_pokemon)
return cfg_defined is not None and cfg_defined.group("cfg_val") in ("TRUE", "1")
def extract_repo_tutors() -> typing.Generator[str, None, None]:
"""
Yield MOVE constants which are *likely* assigned to a move tutor. This isn't
foolproof, but it's suitable.
"""
for inc_fname in chain(glob.glob("./data/scripts/*.inc"), glob.glob("./data/maps/*/scripts.inc")):
with open(inc_fname, "r") as inc_fp:
incfile = inc_fp.read()
if not INCFILE_HAS_TUTOR_PAT.search(incfile):
continue
for move in INCFILE_MOVE_PAT.finditer(incfile):
yield move.group(1)
def extract_repo_tms() -> typing.Generator[str, None, None]:
"""
Yield MOVE constants assigned to a TM or HM in the user's repo.
"""
with open("./include/constants/tms_hms.h", "r") as tmshms_fp:
tmshms = tmshms_fp.read()
match_it = TMHM_MACRO_PAT.finditer(tmshms)
if not match_it:
return
for match in match_it:
yield f"MOVE_{match.group(1)}"
def extract_repo_universals() -> list[str]:
"""
Return a list of MOVE constants which are deemed to be universal and can
thus be learned by any species.
"""
with open("./src/pokemon.c", "r") as pokemon_fp:
if match := UNIVERSAL_MOVES_PAT.search(pokemon_fp.read()):
return list(filter(lambda s: s, map(lambda s: s.strip(), match.group(1).split(','))))
return list()
def prepare_output(all_learnables: dict[str, set[str]], repo_teachables: set[str], header: str) -> str:
"""
Build the file content for teachable_learnsets.h.
"""
with open("./src/data/pokemon/teachable_learnsets.h", "r") as teachables_fp:
old = teachables_fp.read()
cursor = 0
new = header + dedent("""
static const u16 sNoneTeachableLearnset[] = {
MOVE_UNAVAILABLE,
};
""")
joinpat = ",\n "
for species in TEACHABLE_ARRAY_DECL_PAT.finditer(old):
match_b, match_e = species.span()
species_upper = SNAKIFY_PAT.sub(r"_\1", species.group("name")).upper()
if species_upper == "NONE":
# NONE is hard-coded to be at the start of the file to keep this code simple.
cursor = match_e + 1
continue
if species_upper == "MEW":
new += old[cursor:match_e + 1] # copy the original content and skip.
cursor = match_e + 1
continue
repo_species_teachables = filter(lambda m: m in repo_teachables, all_learnables[species_upper])
new += old[cursor:match_b]
new += "\n".join([
f"{species.group('decl')} = {{",
f" {joinpat.join(chain(repo_species_teachables, ('MOVE_UNAVAILABLE',)))},",
"};\n",
])
cursor = match_e + 1
new += old[cursor:]
return new
def create_tutor_moves_array(tutors: list[str]) -> None:
"""
Generate gTutorMoves[] if P_TUTOR_MOVES_ARRAY is enabled.
"""
# Check if the config is enabled
with open("./include/config/pokemon.h", "r") as cfg_pokemon_fp:
cfg_pokemon = cfg_pokemon_fp.read()
cfg_defined = TUTOR_ARRAY_ENABLED_PAT.search(cfg_pokemon)
if not (cfg_defined and cfg_defined.group("cfg_val") in ("TRUE", "1")):
return
# If enabled, generate the tutor moves array
header = dedent("""\
// DO NOT MODIFY THIS FILE! It is auto-generated by tools/learnset_helpers/make_teachables.py
// Set the config P_TUTOR_MOVES_ARRAY in include/config/pokemon.h to TRUE to enable this array!
const u16 gTutorMoves[] = {
""")
lines = [f" {move}," for move in sorted(tutors)]
lines.append(" MOVE_UNAVAILABLE\n};\n")
with open("./src/data/tutor_moves.h", "w") as f:
f.write(header + "\n".join(lines))
def prepare_header(h_align: int, tmshms: list[str], tutors: list[str], universals: list[str]) -> str:
universals_title = "Near-universal moves found from sUniversalMoves:"
tmhm_title = "TM/HM moves found in \"include/constants/tms_hms.h\":"
tutor_title = "Tutor moves found from map scripts:"
h_align = max(h_align, len(universals_title), len(tmhm_title), len(tutor_title))
lines = [
"//",
"// DO NOT MODIFY THIS FILE! It is auto-generated by tools/learnset_helpers/make_teachables.py",
"//",
"",
f"// {'*' * h_align} //",
f"// {tmhm_title: >{h_align}} //",
]
lines.extend([f"// - {move: <{h_align - 2}} //" for move in tmshms])
lines.extend([
f"// {'*' * h_align} //",
f"// {tutor_title: <{h_align}} //",
])
lines.extend([f"// - {move: <{h_align - 2}} //" for move in sorted(tutors)])
lines.extend([
f"// {'*' * h_align} //",
f"// {universals_title: <{h_align}} //",
])
lines.extend([f"// - {move: <{h_align - 2}} //" for move in universals])
lines.extend([
f"// {'*' * h_align} //",
"",
])
return "\n".join(lines)
def main():
if not enabled():
quit()
if len(sys.argv) < 2:
print("Missing required arguments", file=sys.stderr)
print(__doc__, file=sys.stderr)
quit(1)
SOURCE_LEARNSETS_JSON = pathlib.Path(sys.argv[1])
assert SOURCE_LEARNSETS_JSON.exists(), f"{SOURCE_LEARNSETS_JSON=} does not exist"
assert SOURCE_LEARNSETS_JSON.is_file(), f"{SOURCE_LEARNSETS_JSON=} is not a file"
repo_universals = extract_repo_universals()
repo_tms = list(extract_repo_tms())
repo_tutors = list(extract_repo_tutors())
repo_teachables = set(filter(
lambda move: move not in set(repo_universals),
chain(repo_tms, repo_tutors)
))
create_tutor_moves_array(repo_tutors)
h_align = max(map(lambda move: len(move), chain(repo_universals, repo_teachables))) + 2
header = prepare_header(h_align, repo_tms, repo_tutors, repo_universals)
with open(SOURCE_LEARNSETS_JSON, "r") as source_fp:
all_learnables = json.load(source_fp)
content = prepare_output(all_learnables, repo_teachables, header)
with open("./src/data/pokemon/teachable_learnsets.h", "w") as teachables_fp:
teachables_fp.write(content)
if __name__ == "__main__":
main()

View File

@ -6536,7 +6536,7 @@
"MOVE_REVENGE",
"MOVE_REVERSAL",
"MOVE_SLEEP_TALK",
"MOVE_SMELLING_SALT"
"MOVE_SMELLING_SALTS"
],
"TutorMoves": [
"MOVE_COVET",
@ -6687,7 +6687,7 @@
"MOVE_REVENGE",
"MOVE_REVERSAL",
"MOVE_SLEEP_TALK",
"MOVE_SMELLING_SALT"
"MOVE_SMELLING_SALTS"
],
"TutorMoves": [
"MOVE_COVET",
@ -7754,7 +7754,7 @@
"MOVE_MEDITATE",
"MOVE_POWER_TRICK",
"MOVE_ROLLING_KICK",
"MOVE_SMELLING_SALT",
"MOVE_SMELLING_SALTS",
"MOVE_THUNDER_PUNCH",
"MOVE_TICKLE"
],
@ -7890,7 +7890,7 @@
"MOVE_MEDITATE",
"MOVE_POWER_TRICK",
"MOVE_ROLLING_KICK",
"MOVE_SMELLING_SALT",
"MOVE_SMELLING_SALTS",
"MOVE_THUNDER_PUNCH",
"MOVE_TICKLE"
],
@ -8033,7 +8033,7 @@
"MOVE_MEDITATE",
"MOVE_POWER_TRICK",
"MOVE_ROLLING_KICK",
"MOVE_SMELLING_SALT",
"MOVE_SMELLING_SALTS",
"MOVE_THUNDER_PUNCH",
"MOVE_TICKLE"
],
@ -13164,7 +13164,7 @@
"MOVE_MAGNITUDE",
"MOVE_MUDDY_WATER",
"MOVE_SLEEP_TALK",
"MOVE_SMELLING_SALT",
"MOVE_SMELLING_SALTS",
"MOVE_SNORE",
"MOVE_ZEN_HEADBUTT"
],
@ -25781,7 +25781,7 @@
"MOVE_METRONOME",
"MOVE_MIMIC",
"MOVE_PRESENT",
"MOVE_SMELLING_SALT",
"MOVE_SMELLING_SALTS",
"MOVE_SNORE",
"MOVE_THUNDER_FANG"
],
@ -25930,7 +25930,7 @@
"MOVE_METRONOME",
"MOVE_MIMIC",
"MOVE_PRESENT",
"MOVE_SMELLING_SALT",
"MOVE_SMELLING_SALTS",
"MOVE_SNORE",
"MOVE_THUNDER_FANG"
],
@ -31544,7 +31544,7 @@
"MOVE_LOW_KICK",
"MOVE_NIGHT_SLASH",
"MOVE_REVERSAL",
"MOVE_SMELLING_SALT"
"MOVE_SMELLING_SALTS"
],
"TutorMoves": [
"MOVE_BOUNCE",
@ -31677,7 +31677,7 @@
"MOVE_LOW_KICK",
"MOVE_NIGHT_SLASH",
"MOVE_REVERSAL",
"MOVE_SMELLING_SALT"
"MOVE_SMELLING_SALTS"
],
"TutorMoves": [
"MOVE_BOUNCE",
@ -31834,7 +31834,7 @@
"MOVE_LOW_KICK",
"MOVE_NIGHT_SLASH",
"MOVE_REVERSAL",
"MOVE_SMELLING_SALT"
"MOVE_SMELLING_SALTS"
],
"TutorMoves": [
"MOVE_BLAST_BURN",
@ -35812,7 +35812,7 @@
"MOVE_EXTRASENSORY",
"MOVE_FAKE_TEARS",
"MOVE_HAMMER_ARM",
"MOVE_SMELLING_SALT",
"MOVE_SMELLING_SALTS",
"MOVE_SMOKESCREEN",
"MOVE_SNORE",
"MOVE_TAKE_DOWN"
@ -35943,7 +35943,7 @@
"MOVE_EXTRASENSORY",
"MOVE_FAKE_TEARS",
"MOVE_HAMMER_ARM",
"MOVE_SMELLING_SALT",
"MOVE_SMELLING_SALTS",
"MOVE_SMOKESCREEN",
"MOVE_SNORE",
"MOVE_TAKE_DOWN"
@ -36099,7 +36099,7 @@
"MOVE_EXTRASENSORY",
"MOVE_FAKE_TEARS",
"MOVE_HAMMER_ARM",
"MOVE_SMELLING_SALT",
"MOVE_SMELLING_SALTS",
"MOVE_SMOKESCREEN",
"MOVE_SNORE",
"MOVE_TAKE_DOWN"
@ -36155,7 +36155,7 @@
},
{
"Level": 22,
"Move": "MOVE_SMELLING_SALT"
"Move": "MOVE_SMELLING_SALTS"
},
{
"Level": 25,
@ -36301,7 +36301,7 @@
},
{
"Level": 22,
"Move": "MOVE_SMELLING_SALT"
"Move": "MOVE_SMELLING_SALTS"
},
{
"Level": 27,
@ -37260,7 +37260,7 @@
"MOVE_HEAD_SMASH",
"MOVE_IRON_HEAD",
"MOVE_SCREECH",
"MOVE_SMELLING_SALT",
"MOVE_SMELLING_SALTS",
"MOVE_STEALTH_ROCK",
"MOVE_STOMP",
"MOVE_SUPERPOWER"
@ -37395,7 +37395,7 @@
"MOVE_HEAD_SMASH",
"MOVE_IRON_HEAD",
"MOVE_SCREECH",
"MOVE_SMELLING_SALT",
"MOVE_SMELLING_SALTS",
"MOVE_STEALTH_ROCK",
"MOVE_STOMP",
"MOVE_SUPERPOWER"
@ -37551,7 +37551,7 @@
"MOVE_HEAD_SMASH",
"MOVE_IRON_HEAD",
"MOVE_SCREECH",
"MOVE_SMELLING_SALT",
"MOVE_SMELLING_SALTS",
"MOVE_STEALTH_ROCK",
"MOVE_STOMP",
"MOVE_SUPERPOWER"
@ -40230,7 +40230,7 @@
"MOVE_PSYCHO_CUT",
"MOVE_RAPID_SPIN",
"MOVE_ROLE_PLAY",
"MOVE_SMELLING_SALT",
"MOVE_SMELLING_SALTS",
"MOVE_TRICK",
"MOVE_WATER_PULSE",
"MOVE_WISH"
@ -40775,7 +40775,7 @@
"MOVE_MAGICAL_LEAF",
"MOVE_NASTY_PLOT",
"MOVE_SEED_BOMB",
"MOVE_SMELLING_SALT",
"MOVE_SMELLING_SALTS",
"MOVE_SWITCHEROO",
"MOVE_TEETER_DANCE",
"MOVE_WORRY_SEED"
@ -40920,7 +40920,7 @@
"MOVE_MAGICAL_LEAF",
"MOVE_NASTY_PLOT",
"MOVE_SEED_BOMB",
"MOVE_SMELLING_SALT",
"MOVE_SMELLING_SALTS",
"MOVE_SWITCHEROO",
"MOVE_TEETER_DANCE",
"MOVE_WORRY_SEED"
@ -55166,7 +55166,7 @@
"MOVE_HEADBUTT",
"MOVE_ME_FIRST",
"MOVE_MEDITATE",
"MOVE_SMELLING_SALT",
"MOVE_SMELLING_SALTS",
"MOVE_VACUUM_WAVE",
"MOVE_WAKE_UP_SLAP"
],
@ -55321,7 +55321,7 @@
"MOVE_HEADBUTT",
"MOVE_ME_FIRST",
"MOVE_MEDITATE",
"MOVE_SMELLING_SALT",
"MOVE_SMELLING_SALTS",
"MOVE_VACUUM_WAVE",
"MOVE_WAKE_UP_SLAP"
],
@ -56469,7 +56469,7 @@
"MOVE_MAGNITUDE",
"MOVE_MUDDY_WATER",
"MOVE_SLEEP_TALK",
"MOVE_SMELLING_SALT",
"MOVE_SMELLING_SALTS",
"MOVE_SNORE",
"MOVE_ZEN_HEADBUTT"
],
@ -65266,7 +65266,7 @@
"MOVE_FORESIGHT",
"MOVE_MACH_PUNCH",
"MOVE_REVERSAL",
"MOVE_SMELLING_SALT",
"MOVE_SMELLING_SALTS",
"MOVE_WIDE_GUARD"
],
"TutorMoves": [
@ -65403,7 +65403,7 @@
"MOVE_FORESIGHT",
"MOVE_MACH_PUNCH",
"MOVE_REVERSAL",
"MOVE_SMELLING_SALT",
"MOVE_SMELLING_SALTS",
"MOVE_WIDE_GUARD"
],
"TutorMoves": [
@ -65544,7 +65544,7 @@
"MOVE_FORESIGHT",
"MOVE_MACH_PUNCH",
"MOVE_REVERSAL",
"MOVE_SMELLING_SALT",
"MOVE_SMELLING_SALTS",
"MOVE_WIDE_GUARD"
],
"TutorMoves": [
@ -76069,7 +76069,7 @@
"MOVE_KNOCK_OFF",
"MOVE_LOW_KICK",
"MOVE_ME_FIRST",
"MOVE_SMELLING_SALT",
"MOVE_SMELLING_SALTS",
"MOVE_VITAL_THROW"
],
"TutorMoves": [
@ -76215,7 +76215,7 @@
"MOVE_KNOCK_OFF",
"MOVE_LOW_KICK",
"MOVE_ME_FIRST",
"MOVE_SMELLING_SALT",
"MOVE_SMELLING_SALTS",
"MOVE_VITAL_THROW"
],
"TutorMoves": [

View File

@ -5876,7 +5876,7 @@
"MOVE_REVENGE",
"MOVE_REVERSAL",
"MOVE_SLEEP_TALK",
"MOVE_SMELLING_SALT"
"MOVE_SMELLING_SALTS"
],
"TutorMoves": []
},
@ -6010,7 +6010,7 @@
"MOVE_REVENGE",
"MOVE_REVERSAL",
"MOVE_SLEEP_TALK",
"MOVE_SMELLING_SALT"
"MOVE_SMELLING_SALTS"
],
"TutorMoves": []
},
@ -6954,7 +6954,7 @@
"MOVE_MEDITATE",
"MOVE_POWER_TRICK",
"MOVE_ROLLING_KICK",
"MOVE_SMELLING_SALT",
"MOVE_SMELLING_SALTS",
"MOVE_THUNDER_PUNCH",
"MOVE_TICKLE"
],
@ -7078,7 +7078,7 @@
"MOVE_MEDITATE",
"MOVE_POWER_TRICK",
"MOVE_ROLLING_KICK",
"MOVE_SMELLING_SALT",
"MOVE_SMELLING_SALTS",
"MOVE_THUNDER_PUNCH",
"MOVE_TICKLE"
],
@ -7209,7 +7209,7 @@
"MOVE_MEDITATE",
"MOVE_POWER_TRICK",
"MOVE_ROLLING_KICK",
"MOVE_SMELLING_SALT",
"MOVE_SMELLING_SALTS",
"MOVE_THUNDER_PUNCH",
"MOVE_TICKLE"
],
@ -11879,7 +11879,7 @@
"MOVE_MAGNITUDE",
"MOVE_MUDDY_WATER",
"MOVE_SLEEP_TALK",
"MOVE_SMELLING_SALT",
"MOVE_SMELLING_SALTS",
"MOVE_SNORE",
"MOVE_ZEN_HEADBUTT"
],
@ -23106,7 +23106,7 @@
"MOVE_METRONOME",
"MOVE_MIMIC",
"MOVE_PRESENT",
"MOVE_SMELLING_SALT",
"MOVE_SMELLING_SALTS",
"MOVE_SNORE",
"MOVE_THUNDER_FANG"
],
@ -23242,7 +23242,7 @@
"MOVE_METRONOME",
"MOVE_MIMIC",
"MOVE_PRESENT",
"MOVE_SMELLING_SALT",
"MOVE_SMELLING_SALTS",
"MOVE_SNORE",
"MOVE_THUNDER_FANG"
],
@ -28253,7 +28253,7 @@
"MOVE_LOW_KICK",
"MOVE_NIGHT_SLASH",
"MOVE_REVERSAL",
"MOVE_SMELLING_SALT"
"MOVE_SMELLING_SALTS"
],
"TutorMoves": [
"MOVE_FIRE_PLEDGE"
@ -28379,7 +28379,7 @@
"MOVE_LOW_KICK",
"MOVE_NIGHT_SLASH",
"MOVE_REVERSAL",
"MOVE_SMELLING_SALT"
"MOVE_SMELLING_SALTS"
],
"TutorMoves": [
"MOVE_FIRE_PLEDGE"
@ -28526,7 +28526,7 @@
"MOVE_LOW_KICK",
"MOVE_NIGHT_SLASH",
"MOVE_REVERSAL",
"MOVE_SMELLING_SALT"
"MOVE_SMELLING_SALTS"
],
"TutorMoves": [
"MOVE_BLAST_BURN",
@ -32107,7 +32107,7 @@
"MOVE_EXTRASENSORY",
"MOVE_FAKE_TEARS",
"MOVE_HAMMER_ARM",
"MOVE_SMELLING_SALT",
"MOVE_SMELLING_SALTS",
"MOVE_SMOKESCREEN",
"MOVE_SNORE",
"MOVE_TAKE_DOWN"
@ -32227,7 +32227,7 @@
"MOVE_EXTRASENSORY",
"MOVE_FAKE_TEARS",
"MOVE_HAMMER_ARM",
"MOVE_SMELLING_SALT",
"MOVE_SMELLING_SALTS",
"MOVE_SMOKESCREEN",
"MOVE_SNORE",
"MOVE_TAKE_DOWN"
@ -32371,7 +32371,7 @@
"MOVE_EXTRASENSORY",
"MOVE_FAKE_TEARS",
"MOVE_HAMMER_ARM",
"MOVE_SMELLING_SALT",
"MOVE_SMELLING_SALTS",
"MOVE_SMOKESCREEN",
"MOVE_SNORE",
"MOVE_TAKE_DOWN"
@ -32414,7 +32414,7 @@
},
{
"Level": 22,
"Move": "MOVE_SMELLING_SALT"
"Move": "MOVE_SMELLING_SALTS"
},
{
"Level": 25,
@ -32549,7 +32549,7 @@
},
{
"Level": 22,
"Move": "MOVE_SMELLING_SALT"
"Move": "MOVE_SMELLING_SALTS"
},
{
"Level": 27,
@ -33386,7 +33386,7 @@
"MOVE_HEAD_SMASH",
"MOVE_IRON_HEAD",
"MOVE_SCREECH",
"MOVE_SMELLING_SALT",
"MOVE_SMELLING_SALTS",
"MOVE_STEALTH_ROCK",
"MOVE_STOMP",
"MOVE_SUPERPOWER"
@ -33512,7 +33512,7 @@
"MOVE_HEAD_SMASH",
"MOVE_IRON_HEAD",
"MOVE_SCREECH",
"MOVE_SMELLING_SALT",
"MOVE_SMELLING_SALTS",
"MOVE_STEALTH_ROCK",
"MOVE_STOMP",
"MOVE_SUPERPOWER"
@ -33659,7 +33659,7 @@
"MOVE_HEAD_SMASH",
"MOVE_IRON_HEAD",
"MOVE_SCREECH",
"MOVE_SMELLING_SALT",
"MOVE_SMELLING_SALTS",
"MOVE_STEALTH_ROCK",
"MOVE_STOMP",
"MOVE_SUPERPOWER"
@ -36075,7 +36075,7 @@
"MOVE_PSYCHO_CUT",
"MOVE_RAPID_SPIN",
"MOVE_ROLE_PLAY",
"MOVE_SMELLING_SALT",
"MOVE_SMELLING_SALTS",
"MOVE_TRICK",
"MOVE_WATER_PULSE",
"MOVE_WISH"
@ -36505,7 +36505,7 @@
"MOVE_MAGICAL_LEAF",
"MOVE_NASTY_PLOT",
"MOVE_SEED_BOMB",
"MOVE_SMELLING_SALT",
"MOVE_SMELLING_SALTS",
"MOVE_SWITCHEROO",
"MOVE_TEETER_DANCE",
"MOVE_WORRY_SEED"
@ -36636,7 +36636,7 @@
"MOVE_MAGICAL_LEAF",
"MOVE_NASTY_PLOT",
"MOVE_SEED_BOMB",
"MOVE_SMELLING_SALT",
"MOVE_SMELLING_SALTS",
"MOVE_SWITCHEROO",
"MOVE_TEETER_DANCE",
"MOVE_WORRY_SEED"
@ -49431,7 +49431,7 @@
"MOVE_HEADBUTT",
"MOVE_ME_FIRST",
"MOVE_MEDITATE",
"MOVE_SMELLING_SALT",
"MOVE_SMELLING_SALTS",
"MOVE_VACUUM_WAVE",
"MOVE_WAKE_UP_SLAP"
],
@ -49567,7 +49567,7 @@
"MOVE_HEADBUTT",
"MOVE_ME_FIRST",
"MOVE_MEDITATE",
"MOVE_SMELLING_SALT",
"MOVE_SMELLING_SALTS",
"MOVE_VACUUM_WAVE",
"MOVE_WAKE_UP_SLAP"
],
@ -50591,7 +50591,7 @@
"MOVE_MAGNITUDE",
"MOVE_MUDDY_WATER",
"MOVE_SLEEP_TALK",
"MOVE_SMELLING_SALT",
"MOVE_SMELLING_SALTS",
"MOVE_SNORE",
"MOVE_ZEN_HEADBUTT"
],
@ -58423,7 +58423,7 @@
"MOVE_FORESIGHT",
"MOVE_MACH_PUNCH",
"MOVE_REVERSAL",
"MOVE_SMELLING_SALT",
"MOVE_SMELLING_SALTS",
"MOVE_WIDE_GUARD"
],
"TutorMoves": []
@ -58548,7 +58548,7 @@
"MOVE_FORESIGHT",
"MOVE_MACH_PUNCH",
"MOVE_REVERSAL",
"MOVE_SMELLING_SALT",
"MOVE_SMELLING_SALTS",
"MOVE_WIDE_GUARD"
],
"TutorMoves": []
@ -58677,7 +58677,7 @@
"MOVE_FORESIGHT",
"MOVE_MACH_PUNCH",
"MOVE_REVERSAL",
"MOVE_SMELLING_SALT",
"MOVE_SMELLING_SALTS",
"MOVE_WIDE_GUARD"
],
"TutorMoves": []
@ -68196,7 +68196,7 @@
"MOVE_KNOCK_OFF",
"MOVE_LOW_KICK",
"MOVE_ME_FIRST",
"MOVE_SMELLING_SALT",
"MOVE_SMELLING_SALTS",
"MOVE_VITAL_THROW"
],
"TutorMoves": []
@ -68332,7 +68332,7 @@
"MOVE_KNOCK_OFF",
"MOVE_LOW_KICK",
"MOVE_ME_FIRST",
"MOVE_SMELLING_SALT",
"MOVE_SMELLING_SALTS",
"MOVE_VITAL_THROW"
],
"TutorMoves": []

View File

@ -5745,7 +5745,7 @@
"MOVE_REVENGE",
"MOVE_REVERSAL",
"MOVE_ROCK_SLIDE",
"MOVE_SMELLING_SALT"
"MOVE_SMELLING_SALTS"
],
"TutorMoves": []
},
@ -5873,7 +5873,7 @@
"MOVE_REVENGE",
"MOVE_REVERSAL",
"MOVE_ROCK_SLIDE",
"MOVE_SMELLING_SALT"
"MOVE_SMELLING_SALTS"
],
"TutorMoves": []
},
@ -6789,7 +6789,7 @@
"MOVE_MEDITATE",
"MOVE_ROCK_SLIDE",
"MOVE_ROLLING_KICK",
"MOVE_SMELLING_SALT",
"MOVE_SMELLING_SALTS",
"MOVE_THUNDER_PUNCH"
],
"TutorMoves": []
@ -6902,7 +6902,7 @@
"MOVE_MEDITATE",
"MOVE_ROCK_SLIDE",
"MOVE_ROLLING_KICK",
"MOVE_SMELLING_SALT",
"MOVE_SMELLING_SALTS",
"MOVE_THUNDER_PUNCH"
],
"TutorMoves": []
@ -7018,7 +7018,7 @@
"MOVE_MEDITATE",
"MOVE_ROCK_SLIDE",
"MOVE_ROLLING_KICK",
"MOVE_SMELLING_SALT",
"MOVE_SMELLING_SALTS",
"MOVE_THUNDER_PUNCH"
],
"TutorMoves": []
@ -11489,7 +11489,7 @@
"MOVE_HAMMER_ARM",
"MOVE_MAGNITUDE",
"MOVE_SLEEP_TALK",
"MOVE_SMELLING_SALT",
"MOVE_SMELLING_SALTS",
"MOVE_SNORE",
"MOVE_SUBSTITUTE"
],
@ -22486,7 +22486,7 @@
"MOVE_METRONOME",
"MOVE_PRESENT",
"MOVE_REFLECT",
"MOVE_SMELLING_SALT",
"MOVE_SMELLING_SALTS",
"MOVE_SNORE",
"MOVE_THUNDER_FANG"
],
@ -22618,7 +22618,7 @@
"MOVE_METRONOME",
"MOVE_PRESENT",
"MOVE_REFLECT",
"MOVE_SMELLING_SALT",
"MOVE_SMELLING_SALTS",
"MOVE_SNORE",
"MOVE_THUNDER_FANG"
],
@ -27537,7 +27537,7 @@
"MOVE_NIGHT_SLASH",
"MOVE_REVERSAL",
"MOVE_ROCK_SLIDE",
"MOVE_SMELLING_SALT",
"MOVE_SMELLING_SALTS",
"MOVE_SWAGGER"
],
"TutorMoves": []
@ -27658,7 +27658,7 @@
"MOVE_NIGHT_SLASH",
"MOVE_REVERSAL",
"MOVE_ROCK_SLIDE",
"MOVE_SMELLING_SALT",
"MOVE_SMELLING_SALTS",
"MOVE_SWAGGER"
],
"TutorMoves": []
@ -27795,7 +27795,7 @@
"MOVE_NIGHT_SLASH",
"MOVE_REVERSAL",
"MOVE_ROCK_SLIDE",
"MOVE_SMELLING_SALT",
"MOVE_SMELLING_SALTS",
"MOVE_SWAGGER"
],
"TutorMoves": [
@ -31332,7 +31332,7 @@
"EggMoves": [
"MOVE_ENDEAVOR",
"MOVE_EXTRASENSORY",
"MOVE_SMELLING_SALT",
"MOVE_SMELLING_SALTS",
"MOVE_SMOKESCREEN",
"MOVE_SNORE",
"MOVE_SWAGGER",
@ -31446,7 +31446,7 @@
"EggMoves": [
"MOVE_ENDEAVOR",
"MOVE_EXTRASENSORY",
"MOVE_SMELLING_SALT",
"MOVE_SMELLING_SALTS",
"MOVE_SMOKESCREEN",
"MOVE_SNORE",
"MOVE_SWAGGER",
@ -31586,7 +31586,7 @@
"EggMoves": [
"MOVE_ENDEAVOR",
"MOVE_EXTRASENSORY",
"MOVE_SMELLING_SALT",
"MOVE_SMELLING_SALTS",
"MOVE_SMOKESCREEN",
"MOVE_SNORE",
"MOVE_SWAGGER",
@ -31630,7 +31630,7 @@
},
{
"Level": 22,
"Move": "MOVE_SMELLING_SALT"
"Move": "MOVE_SMELLING_SALTS"
},
{
"Level": 25,
@ -31758,7 +31758,7 @@
},
{
"Level": 22,
"Move": "MOVE_SMELLING_SALT"
"Move": "MOVE_SMELLING_SALTS"
},
{
"Level": 27,
@ -32577,7 +32577,7 @@
"MOVE_ENDEAVOR",
"MOVE_IRON_HEAD",
"MOVE_SCREECH",
"MOVE_SMELLING_SALT",
"MOVE_SMELLING_SALTS",
"MOVE_STOMP"
],
"TutorMoves": []
@ -32698,7 +32698,7 @@
"MOVE_ENDEAVOR",
"MOVE_IRON_HEAD",
"MOVE_SCREECH",
"MOVE_SMELLING_SALT",
"MOVE_SMELLING_SALTS",
"MOVE_STOMP"
],
"TutorMoves": []
@ -32842,7 +32842,7 @@
"MOVE_ENDEAVOR",
"MOVE_IRON_HEAD",
"MOVE_SCREECH",
"MOVE_SMELLING_SALT",
"MOVE_SMELLING_SALTS",
"MOVE_STOMP"
],
"TutorMoves": []
@ -35217,7 +35217,7 @@
"MOVE_PSYCHO_CUT",
"MOVE_ROCK_SLIDE",
"MOVE_ROLE_PLAY",
"MOVE_SMELLING_SALT",
"MOVE_SMELLING_SALTS",
"MOVE_TRICK",
"MOVE_WISH"
],
@ -35649,7 +35649,7 @@
"MOVE_LOW_KICK",
"MOVE_MAGICAL_LEAF",
"MOVE_SEED_BOMB",
"MOVE_SMELLING_SALT",
"MOVE_SMELLING_SALTS",
"MOVE_TEETER_DANCE"
],
"TutorMoves": []
@ -35782,7 +35782,7 @@
"MOVE_LOW_KICK",
"MOVE_MAGICAL_LEAF",
"MOVE_SEED_BOMB",
"MOVE_SMELLING_SALT",
"MOVE_SMELLING_SALTS",
"MOVE_TEETER_DANCE"
],
"TutorMoves": []
@ -48274,7 +48274,7 @@
"MOVE_HEADBUTT",
"MOVE_ME_FIRST",
"MOVE_MEDITATE",
"MOVE_SMELLING_SALT",
"MOVE_SMELLING_SALTS",
"MOVE_VACUUM_WAVE",
"MOVE_WAKE_UP_SLAP"
],
@ -48405,7 +48405,7 @@
"MOVE_HEADBUTT",
"MOVE_ME_FIRST",
"MOVE_MEDITATE",
"MOVE_SMELLING_SALT",
"MOVE_SMELLING_SALTS",
"MOVE_VACUUM_WAVE",
"MOVE_WAKE_UP_SLAP"
],
@ -49430,7 +49430,7 @@
"MOVE_HAMMER_ARM",
"MOVE_MAGNITUDE",
"MOVE_SLEEP_TALK",
"MOVE_SMELLING_SALT",
"MOVE_SMELLING_SALTS",
"MOVE_SNORE",
"MOVE_SUBSTITUTE"
],

View File

@ -4694,7 +4694,7 @@
"MOVE_REVENGE",
"MOVE_REVERSAL",
"MOVE_ROCK_SLIDE",
"MOVE_SMELLING_SALT"
"MOVE_SMELLING_SALTS"
],
"TutorMoves": [
"MOVE_BODY_SLAM",
@ -4807,7 +4807,7 @@
"MOVE_REVENGE",
"MOVE_REVERSAL",
"MOVE_ROCK_SLIDE",
"MOVE_SMELLING_SALT"
"MOVE_SMELLING_SALTS"
],
"TutorMoves": [
"MOVE_BODY_SLAM",
@ -5582,7 +5582,7 @@
"MOVE_MEDITATE",
"MOVE_ROCK_SLIDE",
"MOVE_ROLLING_KICK",
"MOVE_SMELLING_SALT"
"MOVE_SMELLING_SALTS"
],
"TutorMoves": [
"MOVE_BODY_SLAM",
@ -5685,7 +5685,7 @@
"MOVE_MEDITATE",
"MOVE_ROCK_SLIDE",
"MOVE_ROLLING_KICK",
"MOVE_SMELLING_SALT"
"MOVE_SMELLING_SALTS"
],
"TutorMoves": [
"MOVE_BODY_SLAM",
@ -5789,7 +5789,7 @@
"MOVE_MEDITATE",
"MOVE_ROCK_SLIDE",
"MOVE_ROLLING_KICK",
"MOVE_SMELLING_SALT"
"MOVE_SMELLING_SALTS"
],
"TutorMoves": [
"MOVE_BODY_SLAM",
@ -9379,7 +9379,7 @@
"MOVE_CURSE",
"MOVE_MAGNITUDE",
"MOVE_SLEEP_TALK",
"MOVE_SMELLING_SALT",
"MOVE_SMELLING_SALTS",
"MOVE_SNORE",
"MOVE_SUBSTITUTE"
],
@ -18107,7 +18107,7 @@
"MOVE_METRONOME",
"MOVE_PRESENT",
"MOVE_REFLECT",
"MOVE_SMELLING_SALT",
"MOVE_SMELLING_SALTS",
"MOVE_SNORE"
],
"TutorMoves": [
@ -18212,7 +18212,7 @@
"MOVE_METRONOME",
"MOVE_PRESENT",
"MOVE_REFLECT",
"MOVE_SMELLING_SALT",
"MOVE_SMELLING_SALTS",
"MOVE_SNORE"
],
"TutorMoves": [
@ -22086,7 +22086,7 @@
"MOVE_ENDURE",
"MOVE_REVERSAL",
"MOVE_ROCK_SLIDE",
"MOVE_SMELLING_SALT",
"MOVE_SMELLING_SALTS",
"MOVE_SWAGGER"
],
"TutorMoves": [
@ -22195,7 +22195,7 @@
"MOVE_ENDURE",
"MOVE_REVERSAL",
"MOVE_ROCK_SLIDE",
"MOVE_SMELLING_SALT",
"MOVE_SMELLING_SALTS",
"MOVE_SWAGGER"
],
"TutorMoves": [
@ -22315,7 +22315,7 @@
"MOVE_ENDURE",
"MOVE_REVERSAL",
"MOVE_ROCK_SLIDE",
"MOVE_SMELLING_SALT",
"MOVE_SMELLING_SALTS",
"MOVE_SWAGGER"
],
"TutorMoves": [
@ -25387,7 +25387,7 @@
],
"EggMoves": [
"MOVE_EXTRASENSORY",
"MOVE_SMELLING_SALT",
"MOVE_SMELLING_SALTS",
"MOVE_SNORE",
"MOVE_SWAGGER",
"MOVE_TAKE_DOWN"
@ -25495,7 +25495,7 @@
],
"EggMoves": [
"MOVE_EXTRASENSORY",
"MOVE_SMELLING_SALT",
"MOVE_SMELLING_SALTS",
"MOVE_SNORE",
"MOVE_SWAGGER",
"MOVE_TAKE_DOWN"
@ -25609,7 +25609,7 @@
],
"EggMoves": [
"MOVE_EXTRASENSORY",
"MOVE_SMELLING_SALT",
"MOVE_SMELLING_SALTS",
"MOVE_SNORE",
"MOVE_SWAGGER",
"MOVE_TAKE_DOWN"
@ -25662,7 +25662,7 @@
},
{
"Level": 31,
"Move": "MOVE_SMELLING_SALT"
"Move": "MOVE_SMELLING_SALTS"
},
{
"Level": 37,
@ -25772,7 +25772,7 @@
},
{
"Level": 33,
"Move": "MOVE_SMELLING_SALT"
"Move": "MOVE_SMELLING_SALTS"
},
{
"Level": 40,
@ -26446,7 +26446,7 @@
"EggMoves": [
"MOVE_BODY_SLAM",
"MOVE_ENDEAVOR",
"MOVE_SMELLING_SALT",
"MOVE_SMELLING_SALTS",
"MOVE_STOMP"
],
"TutorMoves": [
@ -26550,7 +26550,7 @@
"EggMoves": [
"MOVE_BODY_SLAM",
"MOVE_ENDEAVOR",
"MOVE_SMELLING_SALT",
"MOVE_SMELLING_SALTS",
"MOVE_STOMP"
],
"TutorMoves": [
@ -26667,7 +26667,7 @@
"EggMoves": [
"MOVE_BODY_SLAM",
"MOVE_ENDEAVOR",
"MOVE_SMELLING_SALT",
"MOVE_SMELLING_SALTS",
"MOVE_STOMP"
],
"TutorMoves": [
@ -28659,7 +28659,7 @@
"MOVE_DISABLE",
"MOVE_ENCORE",
"MOVE_ROCK_SLIDE",
"MOVE_SMELLING_SALT",
"MOVE_SMELLING_SALTS",
"MOVE_TRICK",
"MOVE_WISH"
],

View File

@ -6393,7 +6393,7 @@
"MOVE_REVENGE",
"MOVE_REVERSAL",
"MOVE_ROCK_SLIDE",
"MOVE_SMELLING_SALT"
"MOVE_SMELLING_SALTS"
],
"TutorMoves": [
"MOVE_ENDEAVOR",
@ -6539,7 +6539,7 @@
"MOVE_REVENGE",
"MOVE_REVERSAL",
"MOVE_ROCK_SLIDE",
"MOVE_SMELLING_SALT"
"MOVE_SMELLING_SALTS"
],
"TutorMoves": [
"MOVE_ENDEAVOR",
@ -7558,7 +7558,7 @@
"MOVE_POWER_TRICK",
"MOVE_ROCK_SLIDE",
"MOVE_ROLLING_KICK",
"MOVE_SMELLING_SALT",
"MOVE_SMELLING_SALTS",
"MOVE_THUNDER_PUNCH"
],
"TutorMoves": [
@ -7684,7 +7684,7 @@
"MOVE_POWER_TRICK",
"MOVE_ROCK_SLIDE",
"MOVE_ROLLING_KICK",
"MOVE_SMELLING_SALT",
"MOVE_SMELLING_SALTS",
"MOVE_THUNDER_PUNCH"
],
"TutorMoves": [
@ -7813,7 +7813,7 @@
"MOVE_POWER_TRICK",
"MOVE_ROCK_SLIDE",
"MOVE_ROLLING_KICK",
"MOVE_SMELLING_SALT",
"MOVE_SMELLING_SALTS",
"MOVE_THUNDER_PUNCH"
],
"TutorMoves": [
@ -12749,7 +12749,7 @@
"MOVE_MAGNITUDE",
"MOVE_MUDDY_WATER",
"MOVE_SLEEP_TALK",
"MOVE_SMELLING_SALT",
"MOVE_SMELLING_SALTS",
"MOVE_SNORE",
"MOVE_SUBSTITUTE"
],
@ -25059,7 +25059,7 @@
"MOVE_METRONOME",
"MOVE_PRESENT",
"MOVE_REFLECT",
"MOVE_SMELLING_SALT",
"MOVE_SMELLING_SALTS",
"MOVE_SNORE",
"MOVE_THUNDER_FANG"
],
@ -25203,7 +25203,7 @@
"MOVE_METRONOME",
"MOVE_PRESENT",
"MOVE_REFLECT",
"MOVE_SMELLING_SALT",
"MOVE_SMELLING_SALTS",
"MOVE_SNORE",
"MOVE_THUNDER_FANG"
],
@ -30728,7 +30728,7 @@
"MOVE_NIGHT_SLASH",
"MOVE_REVERSAL",
"MOVE_ROCK_SLIDE",
"MOVE_SMELLING_SALT",
"MOVE_SMELLING_SALTS",
"MOVE_SWAGGER"
],
"TutorMoves": [
@ -30859,7 +30859,7 @@
"MOVE_NIGHT_SLASH",
"MOVE_REVERSAL",
"MOVE_ROCK_SLIDE",
"MOVE_SMELLING_SALT",
"MOVE_SMELLING_SALTS",
"MOVE_SWAGGER"
],
"TutorMoves": [
@ -31011,7 +31011,7 @@
"MOVE_NIGHT_SLASH",
"MOVE_REVERSAL",
"MOVE_ROCK_SLIDE",
"MOVE_SMELLING_SALT",
"MOVE_SMELLING_SALTS",
"MOVE_SWAGGER"
],
"TutorMoves": [
@ -34988,7 +34988,7 @@
"MOVE_ENDEAVOR",
"MOVE_EXTRASENSORY",
"MOVE_HAMMER_ARM",
"MOVE_SMELLING_SALT",
"MOVE_SMELLING_SALTS",
"MOVE_SMOKESCREEN",
"MOVE_SNORE",
"MOVE_SWAGGER",
@ -35114,7 +35114,7 @@
"MOVE_ENDEAVOR",
"MOVE_EXTRASENSORY",
"MOVE_HAMMER_ARM",
"MOVE_SMELLING_SALT",
"MOVE_SMELLING_SALTS",
"MOVE_SMOKESCREEN",
"MOVE_SNORE",
"MOVE_SWAGGER",
@ -35268,7 +35268,7 @@
"MOVE_ENDEAVOR",
"MOVE_EXTRASENSORY",
"MOVE_HAMMER_ARM",
"MOVE_SMELLING_SALT",
"MOVE_SMELLING_SALTS",
"MOVE_SMOKESCREEN",
"MOVE_SNORE",
"MOVE_SWAGGER",
@ -35325,7 +35325,7 @@
},
{
"Level": 22,
"Move": "MOVE_SMELLING_SALT"
"Move": "MOVE_SMELLING_SALTS"
},
{
"Level": 25,
@ -35468,7 +35468,7 @@
},
{
"Level": 22,
"Move": "MOVE_SMELLING_SALT"
"Move": "MOVE_SMELLING_SALTS"
},
{
"Level": 27,
@ -36406,7 +36406,7 @@
"MOVE_HEAD_SMASH",
"MOVE_IRON_HEAD",
"MOVE_SCREECH",
"MOVE_SMELLING_SALT",
"MOVE_SMELLING_SALTS",
"MOVE_STOMP"
],
"TutorMoves": [
@ -36543,7 +36543,7 @@
"MOVE_HEAD_SMASH",
"MOVE_IRON_HEAD",
"MOVE_SCREECH",
"MOVE_SMELLING_SALT",
"MOVE_SMELLING_SALTS",
"MOVE_STOMP"
],
"TutorMoves": [
@ -36704,7 +36704,7 @@
"MOVE_HEAD_SMASH",
"MOVE_IRON_HEAD",
"MOVE_SCREECH",
"MOVE_SMELLING_SALT",
"MOVE_SMELLING_SALTS",
"MOVE_STOMP"
],
"TutorMoves": [
@ -39350,7 +39350,7 @@
"MOVE_PSYCHO_CUT",
"MOVE_ROCK_SLIDE",
"MOVE_ROLE_PLAY",
"MOVE_SMELLING_SALT",
"MOVE_SMELLING_SALTS",
"MOVE_TRICK",
"MOVE_WISH"
],
@ -39836,7 +39836,7 @@
"MOVE_MAGICAL_LEAF",
"MOVE_NASTY_PLOT",
"MOVE_SEED_BOMB",
"MOVE_SMELLING_SALT",
"MOVE_SMELLING_SALTS",
"MOVE_TEETER_DANCE"
],
"TutorMoves": [
@ -39983,7 +39983,7 @@
"MOVE_MAGICAL_LEAF",
"MOVE_NASTY_PLOT",
"MOVE_SEED_BOMB",
"MOVE_SMELLING_SALT",
"MOVE_SMELLING_SALTS",
"MOVE_TEETER_DANCE"
],
"TutorMoves": [
@ -54014,7 +54014,7 @@
"MOVE_HEADBUTT",
"MOVE_ME_FIRST",
"MOVE_MEDITATE",
"MOVE_SMELLING_SALT",
"MOVE_SMELLING_SALTS",
"MOVE_VACUUM_WAVE",
"MOVE_WAKE_UP_SLAP"
],
@ -54164,7 +54164,7 @@
"MOVE_HEADBUTT",
"MOVE_ME_FIRST",
"MOVE_MEDITATE",
"MOVE_SMELLING_SALT",
"MOVE_SMELLING_SALTS",
"MOVE_VACUUM_WAVE",
"MOVE_WAKE_UP_SLAP"
],
@ -55299,7 +55299,7 @@
"MOVE_MAGNITUDE",
"MOVE_MUDDY_WATER",
"MOVE_SLEEP_TALK",
"MOVE_SMELLING_SALT",
"MOVE_SMELLING_SALTS",
"MOVE_SNORE",
"MOVE_SUBSTITUTE"
],

View File

@ -6941,7 +6941,7 @@
"MOVE_REVENGE",
"MOVE_REVERSAL",
"MOVE_SLEEP_TALK",
"MOVE_SMELLING_SALT"
"MOVE_SMELLING_SALTS"
],
"TutorMoves": [
"MOVE_COVET",
@ -7101,7 +7101,7 @@
"MOVE_REVENGE",
"MOVE_REVERSAL",
"MOVE_SLEEP_TALK",
"MOVE_SMELLING_SALT"
"MOVE_SMELLING_SALTS"
],
"TutorMoves": [
"MOVE_COVET",
@ -8220,7 +8220,7 @@
"MOVE_POWER_TRICK",
"MOVE_QUICK_GUARD",
"MOVE_ROLLING_KICK",
"MOVE_SMELLING_SALT",
"MOVE_SMELLING_SALTS",
"MOVE_THUNDER_PUNCH",
"MOVE_TICKLE"
],
@ -8372,7 +8372,7 @@
"MOVE_POWER_TRICK",
"MOVE_QUICK_GUARD",
"MOVE_ROLLING_KICK",
"MOVE_SMELLING_SALT",
"MOVE_SMELLING_SALTS",
"MOVE_THUNDER_PUNCH",
"MOVE_TICKLE"
],
@ -8531,7 +8531,7 @@
"MOVE_POWER_TRICK",
"MOVE_QUICK_GUARD",
"MOVE_ROLLING_KICK",
"MOVE_SMELLING_SALT",
"MOVE_SMELLING_SALTS",
"MOVE_THUNDER_PUNCH",
"MOVE_TICKLE"
],
@ -13938,7 +13938,7 @@
"MOVE_MAGNITUDE",
"MOVE_MUDDY_WATER",
"MOVE_SLEEP_TALK",
"MOVE_SMELLING_SALT",
"MOVE_SMELLING_SALTS",
"MOVE_SNORE",
"MOVE_ZEN_HEADBUTT"
],
@ -27315,7 +27315,7 @@
"MOVE_METRONOME",
"MOVE_MIMIC",
"MOVE_PRESENT",
"MOVE_SMELLING_SALT",
"MOVE_SMELLING_SALTS",
"MOVE_SNORE",
"MOVE_THUNDER_FANG"
],
@ -27475,7 +27475,7 @@
"MOVE_METRONOME",
"MOVE_MIMIC",
"MOVE_PRESENT",
"MOVE_SMELLING_SALT",
"MOVE_SMELLING_SALTS",
"MOVE_SNORE",
"MOVE_THUNDER_FANG"
],
@ -33468,7 +33468,7 @@
"MOVE_LOW_KICK",
"MOVE_NIGHT_SLASH",
"MOVE_REVERSAL",
"MOVE_SMELLING_SALT"
"MOVE_SMELLING_SALTS"
],
"TutorMoves": [
"MOVE_BOUNCE",
@ -33608,7 +33608,7 @@
"MOVE_LOW_KICK",
"MOVE_NIGHT_SLASH",
"MOVE_REVERSAL",
"MOVE_SMELLING_SALT"
"MOVE_SMELLING_SALTS"
],
"TutorMoves": [
"MOVE_BOUNCE",
@ -33777,7 +33777,7 @@
"MOVE_LOW_KICK",
"MOVE_NIGHT_SLASH",
"MOVE_REVERSAL",
"MOVE_SMELLING_SALT"
"MOVE_SMELLING_SALTS"
],
"TutorMoves": [
"MOVE_BLAST_BURN",
@ -38135,7 +38135,7 @@
"MOVE_EXTRASENSORY",
"MOVE_FAKE_TEARS",
"MOVE_HAMMER_ARM",
"MOVE_SMELLING_SALT",
"MOVE_SMELLING_SALTS",
"MOVE_SMOKESCREEN",
"MOVE_SNORE",
"MOVE_TAKE_DOWN"
@ -38275,7 +38275,7 @@
"MOVE_EXTRASENSORY",
"MOVE_FAKE_TEARS",
"MOVE_HAMMER_ARM",
"MOVE_SMELLING_SALT",
"MOVE_SMELLING_SALTS",
"MOVE_SMOKESCREEN",
"MOVE_SNORE",
"MOVE_TAKE_DOWN"
@ -38448,7 +38448,7 @@
"MOVE_EXTRASENSORY",
"MOVE_FAKE_TEARS",
"MOVE_HAMMER_ARM",
"MOVE_SMELLING_SALT",
"MOVE_SMELLING_SALTS",
"MOVE_SMOKESCREEN",
"MOVE_SNORE",
"MOVE_TAKE_DOWN"
@ -38513,7 +38513,7 @@
},
{
"Level": 28,
"Move": "MOVE_SMELLING_SALT"
"Move": "MOVE_SMELLING_SALTS"
},
{
"Level": 31,
@ -38662,7 +38662,7 @@
},
{
"Level": 30,
"Move": "MOVE_SMELLING_SALT"
"Move": "MOVE_SMELLING_SALTS"
},
{
"Level": 34,
@ -39698,7 +39698,7 @@
"MOVE_IRON_HEAD",
"MOVE_REVERSAL",
"MOVE_SCREECH",
"MOVE_SMELLING_SALT",
"MOVE_SMELLING_SALTS",
"MOVE_STEALTH_ROCK",
"MOVE_STOMP",
"MOVE_SUPERPOWER"
@ -39846,7 +39846,7 @@
"MOVE_IRON_HEAD",
"MOVE_REVERSAL",
"MOVE_SCREECH",
"MOVE_SMELLING_SALT",
"MOVE_SMELLING_SALTS",
"MOVE_STEALTH_ROCK",
"MOVE_STOMP",
"MOVE_SUPERPOWER"
@ -40017,7 +40017,7 @@
"MOVE_IRON_HEAD",
"MOVE_REVERSAL",
"MOVE_SCREECH",
"MOVE_SMELLING_SALT",
"MOVE_SMELLING_SALTS",
"MOVE_STEALTH_ROCK",
"MOVE_STOMP",
"MOVE_SUPERPOWER"
@ -42918,7 +42918,7 @@
"MOVE_PSYCHO_SHIFT",
"MOVE_RAPID_SPIN",
"MOVE_ROLE_PLAY",
"MOVE_SMELLING_SALT",
"MOVE_SMELLING_SALTS",
"MOVE_TRICK",
"MOVE_WATER_PULSE",
"MOVE_WISH"
@ -43493,7 +43493,7 @@
"MOVE_NASTY_PLOT",
"MOVE_ROTOTILLER",
"MOVE_SEED_BOMB",
"MOVE_SMELLING_SALT",
"MOVE_SMELLING_SALTS",
"MOVE_SWITCHEROO",
"MOVE_TEETER_DANCE",
"MOVE_WORRY_SEED"
@ -43658,7 +43658,7 @@
"MOVE_NASTY_PLOT",
"MOVE_ROTOTILLER",
"MOVE_SEED_BOMB",
"MOVE_SMELLING_SALT",
"MOVE_SMELLING_SALTS",
"MOVE_SWITCHEROO",
"MOVE_TEETER_DANCE",
"MOVE_WORRY_SEED"
@ -58895,7 +58895,7 @@
"MOVE_ME_FIRST",
"MOVE_MEDITATE",
"MOVE_QUICK_GUARD",
"MOVE_SMELLING_SALT",
"MOVE_SMELLING_SALTS",
"MOVE_VACUUM_WAVE",
"MOVE_WAKE_UP_SLAP"
],
@ -59058,7 +59058,7 @@
"MOVE_ME_FIRST",
"MOVE_MEDITATE",
"MOVE_QUICK_GUARD",
"MOVE_SMELLING_SALT",
"MOVE_SMELLING_SALTS",
"MOVE_VACUUM_WAVE",
"MOVE_WAKE_UP_SLAP"
],
@ -60269,7 +60269,7 @@
"MOVE_MAGNITUDE",
"MOVE_MUDDY_WATER",
"MOVE_SLEEP_TALK",
"MOVE_SMELLING_SALT",
"MOVE_SMELLING_SALTS",
"MOVE_SNORE",
"MOVE_ZEN_HEADBUTT"
],
@ -69623,7 +69623,7 @@
"MOVE_FORESIGHT",
"MOVE_MACH_PUNCH",
"MOVE_REVERSAL",
"MOVE_SMELLING_SALT",
"MOVE_SMELLING_SALTS",
"MOVE_WIDE_GUARD"
],
"TutorMoves": [
@ -69763,7 +69763,7 @@
"MOVE_FORESIGHT",
"MOVE_MACH_PUNCH",
"MOVE_REVERSAL",
"MOVE_SMELLING_SALT",
"MOVE_SMELLING_SALTS",
"MOVE_WIDE_GUARD"
],
"TutorMoves": [
@ -69907,7 +69907,7 @@
"MOVE_FORESIGHT",
"MOVE_MACH_PUNCH",
"MOVE_REVERSAL",
"MOVE_SMELLING_SALT",
"MOVE_SMELLING_SALTS",
"MOVE_WIDE_GUARD"
],
"TutorMoves": [
@ -81039,7 +81039,7 @@
"MOVE_KNOCK_OFF",
"MOVE_LOW_KICK",
"MOVE_ME_FIRST",
"MOVE_SMELLING_SALT",
"MOVE_SMELLING_SALTS",
"MOVE_VITAL_THROW"
],
"TutorMoves": [
@ -81197,7 +81197,7 @@
"MOVE_KNOCK_OFF",
"MOVE_LOW_KICK",
"MOVE_ME_FIRST",
"MOVE_SMELLING_SALT",
"MOVE_SMELLING_SALTS",
"MOVE_VITAL_THROW"
],
"TutorMoves": [

View File

@ -6231,7 +6231,7 @@
"MOVE_REVENGE",
"MOVE_REVERSAL",
"MOVE_ROCK_SLIDE",
"MOVE_SMELLING_SALT"
"MOVE_SMELLING_SALTS"
],
"TutorMoves": [
"MOVE_ENDEAVOR",
@ -6373,7 +6373,7 @@
"MOVE_REVENGE",
"MOVE_REVERSAL",
"MOVE_ROCK_SLIDE",
"MOVE_SMELLING_SALT"
"MOVE_SMELLING_SALTS"
],
"TutorMoves": [
"MOVE_ENDEAVOR",
@ -7363,7 +7363,7 @@
"MOVE_MEDITATE",
"MOVE_ROCK_SLIDE",
"MOVE_ROLLING_KICK",
"MOVE_SMELLING_SALT",
"MOVE_SMELLING_SALTS",
"MOVE_THUNDER_PUNCH"
],
"TutorMoves": [
@ -7485,7 +7485,7 @@
"MOVE_MEDITATE",
"MOVE_ROCK_SLIDE",
"MOVE_ROLLING_KICK",
"MOVE_SMELLING_SALT",
"MOVE_SMELLING_SALTS",
"MOVE_THUNDER_PUNCH"
],
"TutorMoves": [
@ -7610,7 +7610,7 @@
"MOVE_MEDITATE",
"MOVE_ROCK_SLIDE",
"MOVE_ROLLING_KICK",
"MOVE_SMELLING_SALT",
"MOVE_SMELLING_SALTS",
"MOVE_THUNDER_PUNCH"
],
"TutorMoves": [
@ -12437,7 +12437,7 @@
"MOVE_HAMMER_ARM",
"MOVE_MAGNITUDE",
"MOVE_SLEEP_TALK",
"MOVE_SMELLING_SALT",
"MOVE_SMELLING_SALTS",
"MOVE_SNORE",
"MOVE_SUBSTITUTE"
],
@ -24447,7 +24447,7 @@
"MOVE_METRONOME",
"MOVE_PRESENT",
"MOVE_REFLECT",
"MOVE_SMELLING_SALT",
"MOVE_SMELLING_SALTS",
"MOVE_SNORE",
"MOVE_THUNDER_FANG"
],
@ -24587,7 +24587,7 @@
"MOVE_METRONOME",
"MOVE_PRESENT",
"MOVE_REFLECT",
"MOVE_SMELLING_SALT",
"MOVE_SMELLING_SALTS",
"MOVE_SNORE",
"MOVE_THUNDER_FANG"
],
@ -29978,7 +29978,7 @@
"MOVE_NIGHT_SLASH",
"MOVE_REVERSAL",
"MOVE_ROCK_SLIDE",
"MOVE_SMELLING_SALT",
"MOVE_SMELLING_SALTS",
"MOVE_SWAGGER"
],
"TutorMoves": [
@ -30107,7 +30107,7 @@
"MOVE_NIGHT_SLASH",
"MOVE_REVERSAL",
"MOVE_ROCK_SLIDE",
"MOVE_SMELLING_SALT",
"MOVE_SMELLING_SALTS",
"MOVE_SWAGGER"
],
"TutorMoves": [
@ -30256,7 +30256,7 @@
"MOVE_NIGHT_SLASH",
"MOVE_REVERSAL",
"MOVE_ROCK_SLIDE",
"MOVE_SMELLING_SALT",
"MOVE_SMELLING_SALTS",
"MOVE_SWAGGER"
],
"TutorMoves": [
@ -34139,7 +34139,7 @@
"EggMoves": [
"MOVE_ENDEAVOR",
"MOVE_EXTRASENSORY",
"MOVE_SMELLING_SALT",
"MOVE_SMELLING_SALTS",
"MOVE_SMOKESCREEN",
"MOVE_SNORE",
"MOVE_SWAGGER",
@ -34263,7 +34263,7 @@
"EggMoves": [
"MOVE_ENDEAVOR",
"MOVE_EXTRASENSORY",
"MOVE_SMELLING_SALT",
"MOVE_SMELLING_SALTS",
"MOVE_SMOKESCREEN",
"MOVE_SNORE",
"MOVE_SWAGGER",
@ -34413,7 +34413,7 @@
"EggMoves": [
"MOVE_ENDEAVOR",
"MOVE_EXTRASENSORY",
"MOVE_SMELLING_SALT",
"MOVE_SMELLING_SALTS",
"MOVE_SMOKESCREEN",
"MOVE_SNORE",
"MOVE_SWAGGER",
@ -34468,7 +34468,7 @@
},
{
"Level": 22,
"Move": "MOVE_SMELLING_SALT"
"Move": "MOVE_SMELLING_SALTS"
},
{
"Level": 25,
@ -34606,7 +34606,7 @@
},
{
"Level": 22,
"Move": "MOVE_SMELLING_SALT"
"Move": "MOVE_SMELLING_SALTS"
},
{
"Level": 27,
@ -35512,7 +35512,7 @@
"MOVE_ENDEAVOR",
"MOVE_IRON_HEAD",
"MOVE_SCREECH",
"MOVE_SMELLING_SALT",
"MOVE_SMELLING_SALTS",
"MOVE_STOMP"
],
"TutorMoves": [
@ -35647,7 +35647,7 @@
"MOVE_ENDEAVOR",
"MOVE_IRON_HEAD",
"MOVE_SCREECH",
"MOVE_SMELLING_SALT",
"MOVE_SMELLING_SALTS",
"MOVE_STOMP"
],
"TutorMoves": [
@ -35805,7 +35805,7 @@
"MOVE_ENDEAVOR",
"MOVE_IRON_HEAD",
"MOVE_SCREECH",
"MOVE_SMELLING_SALT",
"MOVE_SMELLING_SALTS",
"MOVE_STOMP"
],
"TutorMoves": [
@ -38387,7 +38387,7 @@
"MOVE_PSYCHO_CUT",
"MOVE_ROCK_SLIDE",
"MOVE_ROLE_PLAY",
"MOVE_SMELLING_SALT",
"MOVE_SMELLING_SALTS",
"MOVE_TRICK",
"MOVE_WISH"
],
@ -38859,7 +38859,7 @@
"MOVE_LOW_KICK",
"MOVE_MAGICAL_LEAF",
"MOVE_SEED_BOMB",
"MOVE_SMELLING_SALT",
"MOVE_SMELLING_SALTS",
"MOVE_TEETER_DANCE"
],
"TutorMoves": [
@ -39001,7 +39001,7 @@
"MOVE_LOW_KICK",
"MOVE_MAGICAL_LEAF",
"MOVE_SEED_BOMB",
"MOVE_SMELLING_SALT",
"MOVE_SMELLING_SALTS",
"MOVE_TEETER_DANCE"
],
"TutorMoves": [
@ -52668,7 +52668,7 @@
"MOVE_HEADBUTT",
"MOVE_ME_FIRST",
"MOVE_MEDITATE",
"MOVE_SMELLING_SALT",
"MOVE_SMELLING_SALTS",
"MOVE_VACUUM_WAVE",
"MOVE_WAKE_UP_SLAP"
],
@ -52813,7 +52813,7 @@
"MOVE_HEADBUTT",
"MOVE_ME_FIRST",
"MOVE_MEDITATE",
"MOVE_SMELLING_SALT",
"MOVE_SMELLING_SALTS",
"MOVE_VACUUM_WAVE",
"MOVE_WAKE_UP_SLAP"
],
@ -53921,7 +53921,7 @@
"MOVE_HAMMER_ARM",
"MOVE_MAGNITUDE",
"MOVE_SLEEP_TALK",
"MOVE_SMELLING_SALT",
"MOVE_SMELLING_SALTS",
"MOVE_SNORE",
"MOVE_SUBSTITUTE"
],

View File

@ -5046,7 +5046,7 @@
"MOVE_REVENGE",
"MOVE_REVERSAL",
"MOVE_ROCK_SLIDE",
"MOVE_SMELLING_SALT"
"MOVE_SMELLING_SALTS"
],
"TutorMoves": [
"MOVE_BODY_SLAM",
@ -5167,7 +5167,7 @@
"MOVE_REVENGE",
"MOVE_REVERSAL",
"MOVE_ROCK_SLIDE",
"MOVE_SMELLING_SALT"
"MOVE_SMELLING_SALTS"
],
"TutorMoves": [
"MOVE_BODY_SLAM",
@ -6014,7 +6014,7 @@
"MOVE_MEDITATE",
"MOVE_ROCK_SLIDE",
"MOVE_ROLLING_KICK",
"MOVE_SMELLING_SALT"
"MOVE_SMELLING_SALTS"
],
"TutorMoves": [
"MOVE_BODY_SLAM",
@ -6126,7 +6126,7 @@
"MOVE_MEDITATE",
"MOVE_ROCK_SLIDE",
"MOVE_ROLLING_KICK",
"MOVE_SMELLING_SALT"
"MOVE_SMELLING_SALTS"
],
"TutorMoves": [
"MOVE_BODY_SLAM",
@ -6239,7 +6239,7 @@
"MOVE_MEDITATE",
"MOVE_ROCK_SLIDE",
"MOVE_ROLLING_KICK",
"MOVE_SMELLING_SALT"
"MOVE_SMELLING_SALTS"
],
"TutorMoves": [
"MOVE_BODY_SLAM",
@ -10019,7 +10019,7 @@
"MOVE_CURSE",
"MOVE_MAGNITUDE",
"MOVE_SLEEP_TALK",
"MOVE_SMELLING_SALT",
"MOVE_SMELLING_SALTS",
"MOVE_SNORE",
"MOVE_SUBSTITUTE"
],
@ -19386,7 +19386,7 @@
"MOVE_METRONOME",
"MOVE_PRESENT",
"MOVE_REFLECT",
"MOVE_SMELLING_SALT",
"MOVE_SMELLING_SALTS",
"MOVE_SNORE"
],
"TutorMoves": [
@ -19501,7 +19501,7 @@
"MOVE_METRONOME",
"MOVE_PRESENT",
"MOVE_REFLECT",
"MOVE_SMELLING_SALT",
"MOVE_SMELLING_SALTS",
"MOVE_SNORE"
],
"TutorMoves": [
@ -23705,7 +23705,7 @@
"MOVE_ENDURE",
"MOVE_REVERSAL",
"MOVE_ROCK_SLIDE",
"MOVE_SMELLING_SALT",
"MOVE_SMELLING_SALTS",
"MOVE_SWAGGER"
],
"TutorMoves": [
@ -23820,7 +23820,7 @@
"MOVE_ENDURE",
"MOVE_REVERSAL",
"MOVE_ROCK_SLIDE",
"MOVE_SMELLING_SALT",
"MOVE_SMELLING_SALTS",
"MOVE_SWAGGER"
],
"TutorMoves": [
@ -23950,7 +23950,7 @@
"MOVE_ENDURE",
"MOVE_REVERSAL",
"MOVE_ROCK_SLIDE",
"MOVE_SMELLING_SALT",
"MOVE_SMELLING_SALTS",
"MOVE_SWAGGER"
],
"TutorMoves": [
@ -27284,7 +27284,7 @@
],
"EggMoves": [
"MOVE_EXTRASENSORY",
"MOVE_SMELLING_SALT",
"MOVE_SMELLING_SALTS",
"MOVE_SNORE",
"MOVE_SWAGGER",
"MOVE_TAKE_DOWN"
@ -27405,7 +27405,7 @@
],
"EggMoves": [
"MOVE_EXTRASENSORY",
"MOVE_SMELLING_SALT",
"MOVE_SMELLING_SALTS",
"MOVE_SNORE",
"MOVE_SWAGGER",
"MOVE_TAKE_DOWN"
@ -27532,7 +27532,7 @@
],
"EggMoves": [
"MOVE_EXTRASENSORY",
"MOVE_SMELLING_SALT",
"MOVE_SMELLING_SALTS",
"MOVE_SNORE",
"MOVE_SWAGGER",
"MOVE_TAKE_DOWN"
@ -27598,7 +27598,7 @@
},
{
"Level": 31,
"Move": "MOVE_SMELLING_SALT"
"Move": "MOVE_SMELLING_SALTS"
},
{
"Level": 37,
@ -27717,7 +27717,7 @@
},
{
"Level": 33,
"Move": "MOVE_SMELLING_SALT"
"Move": "MOVE_SMELLING_SALTS"
},
{
"Level": 40,
@ -28461,7 +28461,7 @@
"EggMoves": [
"MOVE_BODY_SLAM",
"MOVE_ENDEAVOR",
"MOVE_SMELLING_SALT",
"MOVE_SMELLING_SALTS",
"MOVE_STOMP"
],
"TutorMoves": [
@ -28573,7 +28573,7 @@
"EggMoves": [
"MOVE_BODY_SLAM",
"MOVE_ENDEAVOR",
"MOVE_SMELLING_SALT",
"MOVE_SMELLING_SALTS",
"MOVE_STOMP"
],
"TutorMoves": [
@ -28698,7 +28698,7 @@
"EggMoves": [
"MOVE_BODY_SLAM",
"MOVE_ENDEAVOR",
"MOVE_SMELLING_SALT",
"MOVE_SMELLING_SALTS",
"MOVE_STOMP"
],
"TutorMoves": [
@ -30867,7 +30867,7 @@
"MOVE_DISABLE",
"MOVE_ENCORE",
"MOVE_ROCK_SLIDE",
"MOVE_SMELLING_SALT",
"MOVE_SMELLING_SALTS",
"MOVE_TRICK",
"MOVE_WISH"
],

View File

@ -6229,7 +6229,7 @@
"MOVE_REVENGE",
"MOVE_REVERSAL",
"MOVE_SLEEP_TALK",
"MOVE_SMELLING_SALT"
"MOVE_SMELLING_SALTS"
],
"TutorMoves": []
},
@ -6382,7 +6382,7 @@
"MOVE_REVENGE",
"MOVE_REVERSAL",
"MOVE_SLEEP_TALK",
"MOVE_SMELLING_SALT"
"MOVE_SMELLING_SALTS"
],
"TutorMoves": []
},
@ -7355,7 +7355,7 @@
"MOVE_POWER_TRICK",
"MOVE_QUICK_GUARD",
"MOVE_ROLLING_KICK",
"MOVE_SMELLING_SALT",
"MOVE_SMELLING_SALTS",
"MOVE_THUNDER_PUNCH",
"MOVE_TICKLE"
],
@ -7489,7 +7489,7 @@
"MOVE_POWER_TRICK",
"MOVE_QUICK_GUARD",
"MOVE_ROLLING_KICK",
"MOVE_SMELLING_SALT",
"MOVE_SMELLING_SALTS",
"MOVE_THUNDER_PUNCH",
"MOVE_TICKLE"
],
@ -7638,7 +7638,7 @@
"MOVE_POWER_TRICK",
"MOVE_QUICK_GUARD",
"MOVE_ROLLING_KICK",
"MOVE_SMELLING_SALT",
"MOVE_SMELLING_SALTS",
"MOVE_THUNDER_PUNCH",
"MOVE_TICKLE"
],
@ -12606,7 +12606,7 @@
"MOVE_MAGNITUDE",
"MOVE_MUDDY_WATER",
"MOVE_SLEEP_TALK",
"MOVE_SMELLING_SALT",
"MOVE_SMELLING_SALTS",
"MOVE_SNORE",
"MOVE_ZEN_HEADBUTT"
],
@ -24581,7 +24581,7 @@
"MOVE_METRONOME",
"MOVE_MIMIC",
"MOVE_PRESENT",
"MOVE_SMELLING_SALT",
"MOVE_SMELLING_SALTS",
"MOVE_SNORE",
"MOVE_THUNDER_FANG"
],
@ -24720,7 +24720,7 @@
"MOVE_METRONOME",
"MOVE_MIMIC",
"MOVE_PRESENT",
"MOVE_SMELLING_SALT",
"MOVE_SMELLING_SALTS",
"MOVE_SNORE",
"MOVE_THUNDER_FANG"
],
@ -30061,7 +30061,7 @@
"MOVE_LOW_KICK",
"MOVE_NIGHT_SLASH",
"MOVE_REVERSAL",
"MOVE_SMELLING_SALT"
"MOVE_SMELLING_SALTS"
],
"TutorMoves": [
"MOVE_FIRE_PLEDGE"
@ -30192,7 +30192,7 @@
"MOVE_LOW_KICK",
"MOVE_NIGHT_SLASH",
"MOVE_REVERSAL",
"MOVE_SMELLING_SALT"
"MOVE_SMELLING_SALTS"
],
"TutorMoves": [
"MOVE_FIRE_PLEDGE"
@ -30349,7 +30349,7 @@
"MOVE_LOW_KICK",
"MOVE_NIGHT_SLASH",
"MOVE_REVERSAL",
"MOVE_SMELLING_SALT"
"MOVE_SMELLING_SALTS"
],
"TutorMoves": [
"MOVE_BLAST_BURN",
@ -34270,7 +34270,7 @@
"MOVE_EXTRASENSORY",
"MOVE_FAKE_TEARS",
"MOVE_HAMMER_ARM",
"MOVE_SMELLING_SALT",
"MOVE_SMELLING_SALTS",
"MOVE_SMOKESCREEN",
"MOVE_SNORE",
"MOVE_TAKE_DOWN"
@ -34397,7 +34397,7 @@
"MOVE_EXTRASENSORY",
"MOVE_FAKE_TEARS",
"MOVE_HAMMER_ARM",
"MOVE_SMELLING_SALT",
"MOVE_SMELLING_SALTS",
"MOVE_SMOKESCREEN",
"MOVE_SNORE",
"MOVE_TAKE_DOWN"
@ -34558,7 +34558,7 @@
"MOVE_EXTRASENSORY",
"MOVE_FAKE_TEARS",
"MOVE_HAMMER_ARM",
"MOVE_SMELLING_SALT",
"MOVE_SMELLING_SALTS",
"MOVE_SMOKESCREEN",
"MOVE_SNORE",
"MOVE_TAKE_DOWN"
@ -34609,7 +34609,7 @@
},
{
"Level": 28,
"Move": "MOVE_SMELLING_SALT"
"Move": "MOVE_SMELLING_SALTS"
},
{
"Level": 31,
@ -34742,7 +34742,7 @@
},
{
"Level": 30,
"Move": "MOVE_SMELLING_SALT"
"Move": "MOVE_SMELLING_SALTS"
},
{
"Level": 34,
@ -35641,7 +35641,7 @@
"MOVE_IRON_HEAD",
"MOVE_REVERSAL",
"MOVE_SCREECH",
"MOVE_SMELLING_SALT",
"MOVE_SMELLING_SALTS",
"MOVE_STEALTH_ROCK",
"MOVE_STOMP",
"MOVE_SUPERPOWER"
@ -35769,7 +35769,7 @@
"MOVE_IRON_HEAD",
"MOVE_REVERSAL",
"MOVE_SCREECH",
"MOVE_SMELLING_SALT",
"MOVE_SMELLING_SALTS",
"MOVE_STEALTH_ROCK",
"MOVE_STOMP",
"MOVE_SUPERPOWER"
@ -35920,7 +35920,7 @@
"MOVE_IRON_HEAD",
"MOVE_REVERSAL",
"MOVE_SCREECH",
"MOVE_SMELLING_SALT",
"MOVE_SMELLING_SALTS",
"MOVE_STEALTH_ROCK",
"MOVE_STOMP",
"MOVE_SUPERPOWER"
@ -38534,7 +38534,7 @@
"MOVE_PSYCHO_SHIFT",
"MOVE_RAPID_SPIN",
"MOVE_ROLE_PLAY",
"MOVE_SMELLING_SALT",
"MOVE_SMELLING_SALTS",
"MOVE_SPOTLIGHT",
"MOVE_TRICK",
"MOVE_WATER_PULSE",
@ -39048,7 +39048,7 @@
"MOVE_NASTY_PLOT",
"MOVE_ROTOTILLER",
"MOVE_SEED_BOMB",
"MOVE_SMELLING_SALT",
"MOVE_SMELLING_SALTS",
"MOVE_SWITCHEROO",
"MOVE_TEETER_DANCE",
"MOVE_WORRY_SEED"
@ -39198,7 +39198,7 @@
"MOVE_NASTY_PLOT",
"MOVE_ROTOTILLER",
"MOVE_SEED_BOMB",
"MOVE_SMELLING_SALT",
"MOVE_SMELLING_SALTS",
"MOVE_SWITCHEROO",
"MOVE_TEETER_DANCE",
"MOVE_WORRY_SEED"
@ -52913,7 +52913,7 @@
"MOVE_ME_FIRST",
"MOVE_MEDITATE",
"MOVE_QUICK_GUARD",
"MOVE_SMELLING_SALT",
"MOVE_SMELLING_SALTS",
"MOVE_VACUUM_WAVE",
"MOVE_WAKE_UP_SLAP"
],
@ -53052,7 +53052,7 @@
"MOVE_ME_FIRST",
"MOVE_MEDITATE",
"MOVE_QUICK_GUARD",
"MOVE_SMELLING_SALT",
"MOVE_SMELLING_SALTS",
"MOVE_VACUUM_WAVE",
"MOVE_WAKE_UP_SLAP"
],
@ -54137,7 +54137,7 @@
"MOVE_MAGNITUDE",
"MOVE_MUDDY_WATER",
"MOVE_SLEEP_TALK",
"MOVE_SMELLING_SALT",
"MOVE_SMELLING_SALTS",
"MOVE_SNORE",
"MOVE_ZEN_HEADBUTT"
],
@ -62422,7 +62422,7 @@
"MOVE_FORESIGHT",
"MOVE_MACH_PUNCH",
"MOVE_REVERSAL",
"MOVE_SMELLING_SALT",
"MOVE_SMELLING_SALTS",
"MOVE_WIDE_GUARD"
],
"TutorMoves": []
@ -62546,7 +62546,7 @@
"MOVE_FORESIGHT",
"MOVE_MACH_PUNCH",
"MOVE_REVERSAL",
"MOVE_SMELLING_SALT",
"MOVE_SMELLING_SALTS",
"MOVE_WIDE_GUARD"
],
"TutorMoves": []
@ -62674,7 +62674,7 @@
"MOVE_FORESIGHT",
"MOVE_MACH_PUNCH",
"MOVE_REVERSAL",
"MOVE_SMELLING_SALT",
"MOVE_SMELLING_SALTS",
"MOVE_WIDE_GUARD"
],
"TutorMoves": []
@ -72602,7 +72602,7 @@
"MOVE_KNOCK_OFF",
"MOVE_LOW_KICK",
"MOVE_ME_FIRST",
"MOVE_SMELLING_SALT",
"MOVE_SMELLING_SALTS",
"MOVE_VITAL_THROW"
],
"TutorMoves": []
@ -72745,7 +72745,7 @@
"MOVE_KNOCK_OFF",
"MOVE_LOW_KICK",
"MOVE_ME_FIRST",
"MOVE_SMELLING_SALT",
"MOVE_SMELLING_SALTS",
"MOVE_VITAL_THROW"
],
"TutorMoves": []

View File

@ -60044,7 +60044,7 @@
},
{
"Level": 52,
"Move": "MOVE_FOREST\u2019S_CURSE"
"Move": "MOVE_FORESTS_CURSE"
}
],
"PreEvoMoves": [],
@ -60166,7 +60166,7 @@
},
{
"Level": 52,
"Move": "MOVE_FOREST\u2019S_CURSE"
"Move": "MOVE_FORESTS_CURSE"
}
],
"PreEvoMoves": [],

View File

@ -6867,7 +6867,7 @@
"MOVE_REVENGE",
"MOVE_REVERSAL",
"MOVE_SLEEP_TALK",
"MOVE_SMELLING_SALT"
"MOVE_SMELLING_SALTS"
],
"TutorMoves": [
"MOVE_COVET",
@ -7039,7 +7039,7 @@
"MOVE_REVENGE",
"MOVE_REVERSAL",
"MOVE_SLEEP_TALK",
"MOVE_SMELLING_SALT"
"MOVE_SMELLING_SALTS"
],
"TutorMoves": [
"MOVE_COVET",
@ -8149,7 +8149,7 @@
"MOVE_POWER_TRICK",
"MOVE_QUICK_GUARD",
"MOVE_ROLLING_KICK",
"MOVE_SMELLING_SALT",
"MOVE_SMELLING_SALTS",
"MOVE_THUNDER_PUNCH",
"MOVE_TICKLE"
],
@ -8295,7 +8295,7 @@
"MOVE_POWER_TRICK",
"MOVE_QUICK_GUARD",
"MOVE_ROLLING_KICK",
"MOVE_SMELLING_SALT",
"MOVE_SMELLING_SALTS",
"MOVE_THUNDER_PUNCH",
"MOVE_TICKLE"
],
@ -8457,7 +8457,7 @@
"MOVE_POWER_TRICK",
"MOVE_QUICK_GUARD",
"MOVE_ROLLING_KICK",
"MOVE_SMELLING_SALT",
"MOVE_SMELLING_SALTS",
"MOVE_THUNDER_PUNCH",
"MOVE_TICKLE"
],
@ -13908,7 +13908,7 @@
"MOVE_MAGNITUDE",
"MOVE_MUDDY_WATER",
"MOVE_SLEEP_TALK",
"MOVE_SMELLING_SALT",
"MOVE_SMELLING_SALTS",
"MOVE_SNORE",
"MOVE_THRASH",
"MOVE_ZEN_HEADBUTT"
@ -27257,7 +27257,7 @@
"MOVE_METRONOME",
"MOVE_MIMIC",
"MOVE_PRESENT",
"MOVE_SMELLING_SALT",
"MOVE_SMELLING_SALTS",
"MOVE_SNORE",
"MOVE_THUNDER_FANG"
],
@ -27411,7 +27411,7 @@
"MOVE_METRONOME",
"MOVE_MIMIC",
"MOVE_PRESENT",
"MOVE_SMELLING_SALT",
"MOVE_SMELLING_SALTS",
"MOVE_SNORE",
"MOVE_THUNDER_FANG"
],
@ -33325,7 +33325,7 @@
"MOVE_LOW_KICK",
"MOVE_NIGHT_SLASH",
"MOVE_REVERSAL",
"MOVE_SMELLING_SALT"
"MOVE_SMELLING_SALTS"
],
"TutorMoves": [
"MOVE_BOUNCE",
@ -33463,7 +33463,7 @@
"MOVE_LOW_KICK",
"MOVE_NIGHT_SLASH",
"MOVE_REVERSAL",
"MOVE_SMELLING_SALT"
"MOVE_SMELLING_SALTS"
],
"TutorMoves": [
"MOVE_BOUNCE",
@ -33631,7 +33631,7 @@
"MOVE_LOW_KICK",
"MOVE_NIGHT_SLASH",
"MOVE_REVERSAL",
"MOVE_SMELLING_SALT"
"MOVE_SMELLING_SALTS"
],
"TutorMoves": [
"MOVE_BLAST_BURN",
@ -37975,7 +37975,7 @@
"MOVE_EXTRASENSORY",
"MOVE_FAKE_TEARS",
"MOVE_HAMMER_ARM",
"MOVE_SMELLING_SALT",
"MOVE_SMELLING_SALTS",
"MOVE_SMOKESCREEN",
"MOVE_SNORE",
"MOVE_TAKE_DOWN",
@ -38115,7 +38115,7 @@
"MOVE_EXTRASENSORY",
"MOVE_FAKE_TEARS",
"MOVE_HAMMER_ARM",
"MOVE_SMELLING_SALT",
"MOVE_SMELLING_SALTS",
"MOVE_SMOKESCREEN",
"MOVE_SNORE",
"MOVE_TAKE_DOWN",
@ -38291,7 +38291,7 @@
"MOVE_EXTRASENSORY",
"MOVE_FAKE_TEARS",
"MOVE_HAMMER_ARM",
"MOVE_SMELLING_SALT",
"MOVE_SMELLING_SALTS",
"MOVE_SMOKESCREEN",
"MOVE_SNORE",
"MOVE_TAKE_DOWN",
@ -38358,7 +38358,7 @@
},
{
"Level": 28,
"Move": "MOVE_SMELLING_SALT"
"Move": "MOVE_SMELLING_SALTS"
},
{
"Level": 31,
@ -38502,7 +38502,7 @@
},
{
"Level": 30,
"Move": "MOVE_SMELLING_SALT"
"Move": "MOVE_SMELLING_SALTS"
},
{
"Level": 34,
@ -39511,7 +39511,7 @@
"MOVE_IRON_HEAD",
"MOVE_REVERSAL",
"MOVE_SCREECH",
"MOVE_SMELLING_SALT",
"MOVE_SMELLING_SALTS",
"MOVE_STEALTH_ROCK",
"MOVE_STOMP",
"MOVE_SUPERPOWER"
@ -39653,7 +39653,7 @@
"MOVE_IRON_HEAD",
"MOVE_REVERSAL",
"MOVE_SCREECH",
"MOVE_SMELLING_SALT",
"MOVE_SMELLING_SALTS",
"MOVE_STEALTH_ROCK",
"MOVE_STOMP",
"MOVE_SUPERPOWER"
@ -39819,7 +39819,7 @@
"MOVE_IRON_HEAD",
"MOVE_REVERSAL",
"MOVE_SCREECH",
"MOVE_SMELLING_SALT",
"MOVE_SMELLING_SALTS",
"MOVE_STEALTH_ROCK",
"MOVE_STOMP",
"MOVE_SUPERPOWER"
@ -42709,7 +42709,7 @@
"MOVE_PSYCHO_SHIFT",
"MOVE_RAPID_SPIN",
"MOVE_ROLE_PLAY",
"MOVE_SMELLING_SALT",
"MOVE_SMELLING_SALTS",
"MOVE_SPOTLIGHT",
"MOVE_TRICK",
"MOVE_WATER_PULSE",
@ -43284,7 +43284,7 @@
"MOVE_POWER_UP_PUNCH",
"MOVE_ROTOTILLER",
"MOVE_SEED_BOMB",
"MOVE_SMELLING_SALT",
"MOVE_SMELLING_SALTS",
"MOVE_SWITCHEROO",
"MOVE_TEETER_DANCE",
"MOVE_WORRY_SEED"
@ -43448,7 +43448,7 @@
"MOVE_POWER_UP_PUNCH",
"MOVE_ROTOTILLER",
"MOVE_SEED_BOMB",
"MOVE_SMELLING_SALT",
"MOVE_SMELLING_SALTS",
"MOVE_SWITCHEROO",
"MOVE_TEETER_DANCE",
"MOVE_WORRY_SEED"
@ -58660,7 +58660,7 @@
"MOVE_ME_FIRST",
"MOVE_MEDITATE",
"MOVE_QUICK_GUARD",
"MOVE_SMELLING_SALT",
"MOVE_SMELLING_SALTS",
"MOVE_VACUUM_WAVE",
"MOVE_WAKE_UP_SLAP"
],
@ -58817,7 +58817,7 @@
"MOVE_ME_FIRST",
"MOVE_MEDITATE",
"MOVE_QUICK_GUARD",
"MOVE_SMELLING_SALT",
"MOVE_SMELLING_SALTS",
"MOVE_VACUUM_WAVE",
"MOVE_WAKE_UP_SLAP"
],
@ -60013,7 +60013,7 @@
"MOVE_MAGNITUDE",
"MOVE_MUDDY_WATER",
"MOVE_SLEEP_TALK",
"MOVE_SMELLING_SALT",
"MOVE_SMELLING_SALTS",
"MOVE_SNORE",
"MOVE_THRASH",
"MOVE_ZEN_HEADBUTT"
@ -69340,7 +69340,7 @@
"MOVE_MACH_PUNCH",
"MOVE_POWER_UP_PUNCH",
"MOVE_REVERSAL",
"MOVE_SMELLING_SALT",
"MOVE_SMELLING_SALTS",
"MOVE_WIDE_GUARD"
],
"TutorMoves": [
@ -69477,7 +69477,7 @@
"MOVE_MACH_PUNCH",
"MOVE_POWER_UP_PUNCH",
"MOVE_REVERSAL",
"MOVE_SMELLING_SALT",
"MOVE_SMELLING_SALTS",
"MOVE_WIDE_GUARD"
],
"TutorMoves": [
@ -69618,7 +69618,7 @@
"MOVE_MACH_PUNCH",
"MOVE_POWER_UP_PUNCH",
"MOVE_REVERSAL",
"MOVE_SMELLING_SALT",
"MOVE_SMELLING_SALTS",
"MOVE_WIDE_GUARD"
],
"TutorMoves": [
@ -80651,7 +80651,7 @@
"MOVE_KNOCK_OFF",
"MOVE_LOW_KICK",
"MOVE_ME_FIRST",
"MOVE_SMELLING_SALT",
"MOVE_SMELLING_SALTS",
"MOVE_VITAL_THROW"
],
"TutorMoves": [
@ -80805,7 +80805,7 @@
"MOVE_KNOCK_OFF",
"MOVE_LOW_KICK",
"MOVE_ME_FIRST",
"MOVE_SMELLING_SALT",
"MOVE_SMELLING_SALTS",
"MOVE_VITAL_THROW"
],
"TutorMoves": [

View File

@ -6251,7 +6251,7 @@
"MOVE_REVENGE",
"MOVE_REVERSAL",
"MOVE_SLEEP_TALK",
"MOVE_SMELLING_SALT"
"MOVE_SMELLING_SALTS"
],
"TutorMoves": []
},
@ -6392,7 +6392,7 @@
"MOVE_REVENGE",
"MOVE_REVERSAL",
"MOVE_SLEEP_TALK",
"MOVE_SMELLING_SALT"
"MOVE_SMELLING_SALTS"
],
"TutorMoves": []
},
@ -7365,7 +7365,7 @@
"MOVE_POWER_TRICK",
"MOVE_QUICK_GUARD",
"MOVE_ROLLING_KICK",
"MOVE_SMELLING_SALT",
"MOVE_SMELLING_SALTS",
"MOVE_THUNDER_PUNCH",
"MOVE_TICKLE"
],
@ -7492,7 +7492,7 @@
"MOVE_POWER_TRICK",
"MOVE_QUICK_GUARD",
"MOVE_ROLLING_KICK",
"MOVE_SMELLING_SALT",
"MOVE_SMELLING_SALTS",
"MOVE_THUNDER_PUNCH",
"MOVE_TICKLE"
],
@ -7626,7 +7626,7 @@
"MOVE_POWER_TRICK",
"MOVE_QUICK_GUARD",
"MOVE_ROLLING_KICK",
"MOVE_SMELLING_SALT",
"MOVE_SMELLING_SALTS",
"MOVE_THUNDER_PUNCH",
"MOVE_TICKLE"
],
@ -12530,7 +12530,7 @@
"MOVE_MAGNITUDE",
"MOVE_MUDDY_WATER",
"MOVE_SLEEP_TALK",
"MOVE_SMELLING_SALT",
"MOVE_SMELLING_SALTS",
"MOVE_SNORE",
"MOVE_ZEN_HEADBUTT"
],
@ -24501,7 +24501,7 @@
"MOVE_METRONOME",
"MOVE_MIMIC",
"MOVE_PRESENT",
"MOVE_SMELLING_SALT",
"MOVE_SMELLING_SALTS",
"MOVE_SNORE",
"MOVE_THUNDER_FANG"
],
@ -24645,7 +24645,7 @@
"MOVE_METRONOME",
"MOVE_MIMIC",
"MOVE_PRESENT",
"MOVE_SMELLING_SALT",
"MOVE_SMELLING_SALTS",
"MOVE_SNORE",
"MOVE_THUNDER_FANG"
],
@ -30010,7 +30010,7 @@
"MOVE_LOW_KICK",
"MOVE_NIGHT_SLASH",
"MOVE_REVERSAL",
"MOVE_SMELLING_SALT"
"MOVE_SMELLING_SALTS"
],
"TutorMoves": [
"MOVE_FIRE_PLEDGE"
@ -30138,7 +30138,7 @@
"MOVE_LOW_KICK",
"MOVE_NIGHT_SLASH",
"MOVE_REVERSAL",
"MOVE_SMELLING_SALT"
"MOVE_SMELLING_SALTS"
],
"TutorMoves": [
"MOVE_FIRE_PLEDGE"
@ -30291,7 +30291,7 @@
"MOVE_LOW_KICK",
"MOVE_NIGHT_SLASH",
"MOVE_REVERSAL",
"MOVE_SMELLING_SALT"
"MOVE_SMELLING_SALTS"
],
"TutorMoves": [
"MOVE_BLAST_BURN",
@ -34074,7 +34074,7 @@
"MOVE_EXTRASENSORY",
"MOVE_FAKE_TEARS",
"MOVE_HAMMER_ARM",
"MOVE_SMELLING_SALT",
"MOVE_SMELLING_SALTS",
"MOVE_SMOKESCREEN",
"MOVE_SNORE",
"MOVE_TAKE_DOWN"
@ -34197,7 +34197,7 @@
"MOVE_EXTRASENSORY",
"MOVE_FAKE_TEARS",
"MOVE_HAMMER_ARM",
"MOVE_SMELLING_SALT",
"MOVE_SMELLING_SALTS",
"MOVE_SMOKESCREEN",
"MOVE_SNORE",
"MOVE_TAKE_DOWN"
@ -34352,7 +34352,7 @@
"MOVE_EXTRASENSORY",
"MOVE_FAKE_TEARS",
"MOVE_HAMMER_ARM",
"MOVE_SMELLING_SALT",
"MOVE_SMELLING_SALTS",
"MOVE_SMOKESCREEN",
"MOVE_SNORE",
"MOVE_TAKE_DOWN"
@ -34395,7 +34395,7 @@
},
{
"Level": 22,
"Move": "MOVE_SMELLING_SALT"
"Move": "MOVE_SMELLING_SALTS"
},
{
"Level": 25,
@ -34532,7 +34532,7 @@
},
{
"Level": 22,
"Move": "MOVE_SMELLING_SALT"
"Move": "MOVE_SMELLING_SALTS"
},
{
"Level": 27,
@ -35457,7 +35457,7 @@
"MOVE_IRON_HEAD",
"MOVE_REVERSAL",
"MOVE_SCREECH",
"MOVE_SMELLING_SALT",
"MOVE_SMELLING_SALTS",
"MOVE_STEALTH_ROCK",
"MOVE_STOMP",
"MOVE_SUPERPOWER"
@ -35582,7 +35582,7 @@
"MOVE_IRON_HEAD",
"MOVE_REVERSAL",
"MOVE_SCREECH",
"MOVE_SMELLING_SALT",
"MOVE_SMELLING_SALTS",
"MOVE_STEALTH_ROCK",
"MOVE_STOMP",
"MOVE_SUPERPOWER"
@ -35730,7 +35730,7 @@
"MOVE_IRON_HEAD",
"MOVE_REVERSAL",
"MOVE_SCREECH",
"MOVE_SMELLING_SALT",
"MOVE_SMELLING_SALTS",
"MOVE_STEALTH_ROCK",
"MOVE_STOMP",
"MOVE_SUPERPOWER"
@ -38335,7 +38335,7 @@
"MOVE_PSYCHO_SHIFT",
"MOVE_RAPID_SPIN",
"MOVE_ROLE_PLAY",
"MOVE_SMELLING_SALT",
"MOVE_SMELLING_SALTS",
"MOVE_TRICK",
"MOVE_WATER_PULSE",
"MOVE_WISH"
@ -38856,7 +38856,7 @@
"MOVE_NASTY_PLOT",
"MOVE_ROTOTILLER",
"MOVE_SEED_BOMB",
"MOVE_SMELLING_SALT",
"MOVE_SMELLING_SALTS",
"MOVE_SWITCHEROO",
"MOVE_TEETER_DANCE",
"MOVE_WORRY_SEED"
@ -38999,7 +38999,7 @@
"MOVE_NASTY_PLOT",
"MOVE_ROTOTILLER",
"MOVE_SEED_BOMB",
"MOVE_SMELLING_SALT",
"MOVE_SMELLING_SALTS",
"MOVE_SWITCHEROO",
"MOVE_TEETER_DANCE",
"MOVE_WORRY_SEED"
@ -52626,7 +52626,7 @@
"MOVE_ME_FIRST",
"MOVE_MEDITATE",
"MOVE_QUICK_GUARD",
"MOVE_SMELLING_SALT",
"MOVE_SMELLING_SALTS",
"MOVE_VACUUM_WAVE",
"MOVE_WAKE_UP_SLAP"
],
@ -52770,7 +52770,7 @@
"MOVE_ME_FIRST",
"MOVE_MEDITATE",
"MOVE_QUICK_GUARD",
"MOVE_SMELLING_SALT",
"MOVE_SMELLING_SALTS",
"MOVE_VACUUM_WAVE",
"MOVE_WAKE_UP_SLAP"
],
@ -53863,7 +53863,7 @@
"MOVE_MAGNITUDE",
"MOVE_MUDDY_WATER",
"MOVE_SLEEP_TALK",
"MOVE_SMELLING_SALT",
"MOVE_SMELLING_SALTS",
"MOVE_SNORE",
"MOVE_ZEN_HEADBUTT"
],
@ -62168,7 +62168,7 @@
"MOVE_FORESIGHT",
"MOVE_MACH_PUNCH",
"MOVE_REVERSAL",
"MOVE_SMELLING_SALT",
"MOVE_SMELLING_SALTS",
"MOVE_WIDE_GUARD"
],
"TutorMoves": []
@ -62295,7 +62295,7 @@
"MOVE_FORESIGHT",
"MOVE_MACH_PUNCH",
"MOVE_REVERSAL",
"MOVE_SMELLING_SALT",
"MOVE_SMELLING_SALTS",
"MOVE_WIDE_GUARD"
],
"TutorMoves": []
@ -62426,7 +62426,7 @@
"MOVE_FORESIGHT",
"MOVE_MACH_PUNCH",
"MOVE_REVERSAL",
"MOVE_SMELLING_SALT",
"MOVE_SMELLING_SALTS",
"MOVE_WIDE_GUARD"
],
"TutorMoves": []
@ -72468,7 +72468,7 @@
"MOVE_KNOCK_OFF",
"MOVE_LOW_KICK",
"MOVE_ME_FIRST",
"MOVE_SMELLING_SALT",
"MOVE_SMELLING_SALTS",
"MOVE_VITAL_THROW"
],
"TutorMoves": []
@ -72615,7 +72615,7 @@
"MOVE_KNOCK_OFF",
"MOVE_LOW_KICK",
"MOVE_ME_FIRST",
"MOVE_SMELLING_SALT",
"MOVE_SMELLING_SALTS",
"MOVE_VITAL_THROW"
],
"TutorMoves": []

View File

@ -1,214 +0,0 @@
import glob
import re
import json
import os
# before all else, abort if the config is off
with open("./include/config/pokemon.h", "r") as file:
learnset_config = re.findall(r"#define P_LEARNSET_HELPER_TEACHABLE *([^ ]*)", file.read())
if len(learnset_config) != 1:
quit()
if learnset_config[0] != "TRUE":
quit()
def parse_mon_name(name):
return re.sub(r'(?!^)([A-Z]+)', r'_\1', name).upper()
tm_moves = []
tutor_moves = []
# scan incs
incs_to_check = glob.glob('./data/scripts/*.inc') # all .incs in the script folder
incs_to_check += glob.glob('./data/maps/*/scripts.inc') # all map scripts
if len(incs_to_check) == 0: # disabled if no jsons present
quit()
for file in incs_to_check:
with open(file, 'r') as f2:
raw = f2.read()
if 'special ChooseMonForMoveTutor' in raw:
for x in re.findall(r'setvar VAR_0x8005, (MOVE_.*)', raw):
if not x in tutor_moves:
tutor_moves.append(x)
# scan TMs and HMs
with open("./include/constants/tms_hms.h", 'r') as file:
for x in re.findall(r'F\((.*)\)', file.read()):
if not 'MOVE_' + x in tm_moves:
tm_moves.append('MOVE_' + x)
# look up universal moves to exclude them
universal_moves = []
with open("./src/pokemon.c", "r") as file:
for x in re.findall(r"static const u16 sUniversalMoves\[\] =(.|\n)*?{((.|\n)*?)};", file.read())[0]:
x = x.replace("\n", "")
for y in x.split(","):
y = y.strip()
if y == "":
continue
universal_moves.append(y)
# get compatibility from jsons
def construct_compatibility_dict(force_custom_check):
dict_out = {}
for pth in glob.glob('./tools/learnset_helpers/porymoves_files/*.json'):
f = open(pth, 'r')
data = json.load(f)
for mon in data.keys():
if not mon in dict_out:
dict_out[mon] = []
for move in data[mon]['LevelMoves']:
if not move['Move'] in dict_out[mon]:
dict_out[mon].append(move['Move'])
#for move in data[mon]['PreEvoMoves']:
# if not move in dict_out[mon]:
# dict_out[mon].append(move)
for move in data[mon]['TMMoves']:
if not move in dict_out[mon]:
dict_out[mon].append(move)
for move in data[mon]['EggMoves']:
if not move in dict_out[mon]:
dict_out[mon].append(move)
for move in data[mon]['TutorMoves']:
if not move in dict_out[mon]:
dict_out[mon].append(move)
# if the file was not previously generated, check if there is custom data there that needs to be preserved
with open("./src/data/pokemon/teachable_learnsets.h", 'r') as file:
raw = file.read()
if not "// DO NOT MODIFY THIS FILE!" in raw and force_custom_check == True:
custom_teachable_compatibilities = {}
for entry in re.findall(r"static const u16 s(.*)TeachableLearnset\[\] = {\n((.|\n)*?)\n};", raw):
monname = parse_mon_name(entry[0])
if monname == "NONE":
continue
compatibility = entry[1].split("\n")
if not monname in custom_teachable_compatibilities:
custom_teachable_compatibilities[monname] = []
if not monname in dict_out:
# this mon is unknown, so all data needs to be preserved
for move in compatibility:
move = move.replace(",", "").strip()
if move == "" or move == "MOVE_UNAVAILABLE":
continue
custom_teachable_compatibilities[monname].append(move)
else:
# this mon is known, so check if the moves in the old teachable_learnsets.h are not in the jsons
for move in compatibility:
move = move.replace(",", "").strip()
if move == "" or move == "MOVE_UNAVAILABLE":
continue
if not move in dict_out[monname]:
custom_teachable_compatibilities[monname].append(move)
# actually store the data in custom.json
if os.path.exists("./tools/learnset_helpers/porymoves_files/custom.json"):
f2 = open("./tools/learnset_helpers/porymoves_files/custom.json", "r")
custom_json = json.load(f2)
f2.close()
else:
custom_json = {}
for x in custom_teachable_compatibilities:
if len(custom_teachable_compatibilities[x]) == 0:
continue
if not x in custom_json:
custom_json[x] = {"LevelMoves": [], "PreEvoMoves": [], "TMMoves": [], "EggMoves": [], "TutorMoves": []}
for move in custom_teachable_compatibilities[x]:
custom_json[x]["TutorMoves"].append(move)
f2 = open("./tools/learnset_helpers/porymoves_files/custom.json", "w")
f2.write(json.dumps(custom_json, indent=2))
f2.close()
print("FIRST RUN: Updated custom.json with teachable_learnsets.h's data")
# rerun the process
dict_out = construct_compatibility_dict(False)
return dict_out
compatibility_dict = construct_compatibility_dict(True)
# actually prepare the file
with open("./src/data/pokemon/teachable_learnsets.h", 'r') as file:
out = file.read()
list_of_mons = re.findall(r'static const u16 s(.*)TeachableLearnset', out)
for mon in list_of_mons:
mon_parsed = parse_mon_name(mon)
tm_learnset = []
tutor_learnset = []
if mon_parsed == "NONE" or mon_parsed == "MEW":
continue
if not mon_parsed in compatibility_dict:
print("Unable to find %s in json" % mon)
continue
for move in tm_moves:
if move in universal_moves:
continue
if move in tm_learnset:
continue
if move in compatibility_dict[mon_parsed]:
tm_learnset.append(move)
continue
for move in tutor_moves:
if move in universal_moves:
continue
if move in tutor_learnset:
continue
if move in compatibility_dict[mon_parsed]:
tutor_learnset.append(move)
continue
tm_learnset.sort()
tutor_learnset.sort()
tm_learnset += tutor_learnset
repl = "static const u16 s%sTeachableLearnset[] = {\n " % mon
if len(tm_learnset) > 0:
repl += ",\n ".join(tm_learnset) + ",\n "
repl += "MOVE_UNAVAILABLE,\n};"
newout = re.sub(r'static const u16 s%sTeachableLearnset\[\] = {[\s\S]*?};' % mon, repl, out)
if newout != out:
out = newout
print("Updated %s" % mon)
# add/update header
header = "//\n// DO NOT MODIFY THIS FILE! It is auto-generated from tools/learnset_helpers/teachable.py\n//\n\n"
longest_move_name = 0
for move in tm_moves + tutor_moves:
if len(move) > longest_move_name:
longest_move_name = len(move)
longest_move_name += 2 # + 2 for a hyphen and a space
universal_title = "Near-universal moves found in sUniversalMoves:"
tmhm_title = "TM/HM moves found in \"include/constants/tms_hms.h\":"
tutor_title = "Tutor moves found in map scripts:"
if longest_move_name < len(universal_title):
longest_move_name = len(universal_title)
if longest_move_name < len(tmhm_title):
longest_move_name = len(tmhm_title)
if longest_move_name < len(tutor_title):
longest_move_name = len(tutor_title)
def header_print(str):
global header
header += "// " + str + " " * (longest_move_name - len(str)) + " //\n"
header += "// " + longest_move_name * "*" + " //\n"
header_print(tmhm_title)
for move in tm_moves:
header_print("- " + move)
header += "// " + longest_move_name * "*" + " //\n"
header_print(tutor_title)
tutor_moves.sort() # alphabetically sort tutor moves for easier referencing
for move in tutor_moves:
header_print("- " + move)
header += "// " + longest_move_name * "*" + " //\n"
header_print(universal_title)
universal_moves.sort() # alphabetically sort near-universal moves for easier referencing
for move in universal_moves:
header_print("- " + move)
header += "// " + longest_move_name * "*" + " //\n\n"
if not "// DO NOT MODIFY THIS FILE!" in out:
out = header + out
else:
out = re.sub(r"\/\/\n\/\/ DO NOT MODIFY THIS FILE!(.|\n)*\* \/\/\n\n", header, out)
with open("./src/data/pokemon/teachable_learnsets.h", 'w') as file:
file.write(out)

View File

@ -0,0 +1,687 @@
import json
import re
import os
IS_ENABLED = False
# C string vars
define = "#define"
ENCOUNTER_CHANCE = "ENCOUNTER_CHANCE"
SLOT = "SLOT"
TOTAL = "TOTAL"
NULL = "NULL"
UNDEFINED = "UNDEFINED"
MAP_UNDEFINED = "MAP_UNDEFINED"
# encounter group header types, filled out programmatically
MON_HEADERS = []
# mon encounter group types
fieldData = []
fieldInfoStrings = []
fieldStrings = []
# time of day encounter data
TIME_DEFAULT = ""
TIME_DEFAULT_LABEL = "TIME_OF_DAY_DEFAULT"
TIME_DEFAULT_INDEX = 0
TIMES_OF_DAY_COUNT = TIME_DEFAULT_INDEX + 1
# struct building blocks
baseStruct = "const struct WildPokemon"
structLabel = ""
structMonType = ""
structTime = ""
structMap = ""
structInfo = "Info"
structHeader = "Header"
structArrayAssign = "[] ="
baseStructLabel = ""
baseStructContent = []
infoStructString = ""
infoStructRate = 0
infoStructContent = []
headerStructLabel = ""
headerStructContent = {}
headerStructTable = {}
headerIndex = 0
# map header data variables
hLabel = ""
hForMaps = True
headersArray = [headerIndex]
# debug output control
mainSwitch = True
printWarningAndInclude = mainSwitch
printEncounterHeaders = mainSwitch
printEncounterRateMacros = mainSwitch
printEncounterStructsInfoString = mainSwitch
printEncounterStructs = mainSwitch
class TimeOfDay():
def __init__(self):
self.vals = []
self.lvals = []
self.fvals = []
self.count = 0
def __len__(self):
return self.count
# for debugging purposes
def __str__(self):
return str([self.vals, self.lvals, self.fvals, self.count])
def add(self, val):
self.vals.append(val)
self.lvals.append(val.lower())
self.fvals.append(GetTimeLabelFromString(val).capitalize())
self.count += 1
def indexOf(self, val):
tempArr = [self.vals, self.lvals, self.fvals]
for tvals in tempArr:
i = 0
for time in tvals:
if val in time:
return i
i += 1
# return -1 here so it returns a consistent type and can be checked against < 0
return -1
def ImportWildEncounterFile():
# make sure we're in the right directory before anything else
if not os.path.exists("Makefile"):
print("Please run this script from the project's root folder.")
quit()
global MON_HEADERS
global TIME_OF_DAY
TIME_OF_DAY = SetupUserTimeEnum(TimeOfDay())
global IS_ENABLED
global TIMES_OF_DAY_COUNT
if IsConfigEnabled():
IS_ENABLED = True
TIMES_OF_DAY_COUNT = len(TIME_OF_DAY)
global fieldInfoStrings
global fieldStrings
global structLabel
global structMonType
global structTime
global structMap
global baseStructLabel
global baseStructContent
global infoStructString
global infoStructRate
global headerStructLabel
global headerStructContent
global hLabel
global headersArray
global encounterTotalCount
global encounterCount
global headerIndex
global fieldData
global tabStr
tabStr = " "
wFile = open("src/data/wild_encounters.json")
wData = json.load(wFile)
encounterTotalCount = []
encounterCount = []
groupCount = 0
while groupCount < len(wData["wild_encounter_groups"]):
encounterTotalCount.append(0)
encounterCount.append(0)
groupCount += 1
for data in wData["wild_encounter_groups"]:
wEncounters = wData["wild_encounter_groups"][headerIndex]["encounters"]
headerSuffix = structHeader + "s"
if data["label"]:
hLabel = wData["wild_encounter_groups"][headerIndex]["label"]
if headerSuffix in hLabel:
hLabel = hLabel[:len(hLabel) - len(headerSuffix)]
MON_HEADERS.append(hLabel)
if data["for_maps"]:
hForMaps = wData["wild_encounter_groups"][headerIndex]["for_maps"]
# for the encounter rate macros, so we don't worry about hidden mons here
if headerIndex == 0:
wFields = wData["wild_encounter_groups"][headerIndex]["fields"]
fieldCounter = 0
for field in wFields:
fieldData.append({})
fieldData[fieldCounter]["name"] = field["type"]
fieldData[fieldCounter]["pascalName"] = GetPascalCase(field["type"])
fieldData[fieldCounter]["snakeName"] = GetSnakeCase(field["type"])
fieldData[fieldCounter]["encounter_rates"] = field["encounter_rates"]
if "groups" in field:
fieldData[fieldCounter]["groups"] = field["groups"]
if fieldCounter == len(wFields) - 1:
fieldData.append({})
fieldData[fieldCounter + 1]["name"] = "hidden_mons"
fieldData[fieldCounter + 1]["pascalName"] = GetPascalCase("hidden_mons")
fieldData[fieldCounter + 1]["snakeName"] = GetSnakeCase("hidden_mons")
fieldCounter += 1
if printWarningAndInclude:
PrintGeneratedWarningText()
print('#include "rtc.h"')
print("\n")
PrintEncounterRateMacros()
for encounter in wEncounters:
if "map" in encounter:
structMap = encounter["map"]
else:
structMap = encounter["base_label"]
structLabel = encounter["base_label"]
if encounterTotalCount[headerIndex] != len(wEncounters):
encounterTotalCount[headerIndex] = len(wEncounters)
encounterCount[headerIndex] += 1
headersArray = []
structTime = TIME_DEFAULT_INDEX
if IS_ENABLED:
timeCounter = 0
while timeCounter < TIMES_OF_DAY_COUNT:
tempfTime = f"_{TIME_OF_DAY.fvals[timeCounter]}"
tempTime = TIME_OF_DAY.vals[timeCounter]
if tempfTime in structLabel or tempTime in structLabel:
structTime = timeCounter
timeCounter += 1
fieldCounter = 0
fieldInfoStrings = []
while fieldCounter < len(fieldData):
fieldInfoStrings.append("")
fieldStrings.append("")
fieldCounter += 1
fieldCounter = 0
while fieldCounter < len(fieldData):
for areaTable in encounter:
if fieldData[fieldCounter]["name"] in areaTable:
structMonType = fieldData[fieldCounter]["pascalName"]
if f"_{TIME_OF_DAY.fvals[structTime]}" in structLabel:
fieldInfoStrings[fieldCounter] = f"{structLabel}_{structMonType}{structInfo}"
fieldStrings[fieldCounter] = f"{structLabel}_{structMonType}"
else:
fieldInfoStrings[fieldCounter] = f"{structLabel}_{TIME_OF_DAY.fvals[structTime]}_{structMonType}{structInfo}"
fieldStrings[fieldCounter] = f"{structLabel}_{TIME_OF_DAY.fvals[structTime]}_{structMonType}"
else:
structMonType = ""
continue
baseStructContent = []
for group in encounter[areaTable]:
if "mons" in group:
for mon in encounter[areaTable][group]:
baseStructContent.append(list(mon.values()))
if "encounter_rate" in group:
infoStructRate = encounter[areaTable][group]
baseStructLabel = f"{baseStruct} {fieldStrings[fieldCounter]}{structArrayAssign}"
if printEncounterStructs:
print()
print(baseStructLabel)
print("{")
PrintStructContent(baseStructContent)
print("};")
if printEncounterStructsInfoString:
infoStructString = f"{baseStruct}{structInfo} {fieldInfoStrings[fieldCounter]} = {{ {infoStructRate}, {fieldStrings[fieldCounter]} }};"
print(infoStructString)
fieldCounter += 1
AssembleMonHeaderContent()
headerIndex += 1
PrintWildMonHeadersContent()
def PrintStructContent(contentList):
for monList in contentList:
print(f"{tabStr}{{ {monList[0]}, {monList[1]}, {monList[2]} }},")
return
def GetStructLabelWithoutTime(label):
labelLength = len(label)
timeLength = 0
if not IS_ENABLED:
return label
timeCounter = 0
while timeCounter < TIMES_OF_DAY_COUNT:
tempTime = TIME_OF_DAY.fvals[timeCounter]
if tempTime in label:
timeLength = len(tempTime)
return label[:(labelLength - (timeLength + 1))]
timeCounter += 1
return label
def GetStructTimeWithoutLabel(label):
if not IS_ENABLED:
return TIME_DEFAULT_INDEX
timeCounter = 0
while timeCounter < TIMES_OF_DAY_COUNT:
tempTime = f"_{TIME_OF_DAY.fvals[timeCounter]}"
if tempTime in label:
return timeCounter
timeCounter += 1
return TIME_DEFAULT_INDEX
def AssembleMonHeaderContent():
SetupMonInfoVars()
tempHeaderLabel = GetWildMonHeadersLabel()
tempHeaderTimeIndex = GetStructTimeWithoutLabel(structLabel)
structLabelNoTime = GetStructLabelWithoutTime(structLabel)
if tempHeaderLabel not in headerStructTable:
headerStructTable[tempHeaderLabel] = {}
headerStructTable[tempHeaderLabel]["groupNum"] = headerIndex
if structLabelNoTime not in headerStructTable[tempHeaderLabel]:
headerStructTable[tempHeaderLabel][structLabelNoTime] = {}
headerStructTable[tempHeaderLabel][structLabelNoTime]["headerType"] = GetWildMonHeadersLabel()
headerStructTable[tempHeaderLabel][structLabelNoTime]["mapGroup"] = structMap
headerStructTable[tempHeaderLabel][structLabelNoTime]["mapNum"] = structMap
headerStructTable[tempHeaderLabel][structLabelNoTime]["encounterTotalCount"] = encounterTotalCount[headerIndex]
headerStructTable[tempHeaderLabel][structLabelNoTime]["encounter_types"] = []
timeCounter = 0
while timeCounter < TIMES_OF_DAY_COUNT:
headerStructTable[tempHeaderLabel][structLabelNoTime]["encounter_types"].append([])
timeCounter += 1
fieldCounter = 0
while fieldCounter < len(fieldData):
headerStructTable[tempHeaderLabel][structLabelNoTime]["encounter_types"][tempHeaderTimeIndex].append(fieldInfoStrings[fieldCounter])
fieldCounter += 1
def SetupMonInfoVars():
i = 0
while i < len(fieldData):
fieldData[i]["infoStringBase"] = "." + fieldData[i]["snakeName"] + structInfo
if CheckEmpty(fieldInfoStrings[i]):
fieldInfoStrings[i] = NULL
else:
fieldInfoStrings[i] = "&" + fieldInfoStrings[i]
i += 1
def PrintWildMonHeadersContent():
groupCount = 0
for group in headerStructTable:
labelCount = 0
for label in headerStructTable[group]:
if label != "groupNum":
if labelCount == 0:
PrintEncounterHeaders("\n")
PrintEncounterHeaders(headerStructTable[group][label]["headerType"])
PrintEncounterHeaders(tabStr + "{")
for stat in headerStructTable[group][label]:
mapData = headerStructTable[group][label][stat]
if stat == "mapGroup":
PrintEncounterHeaders(f"{TabStr(2)}.mapGroup = {GetMapGroupEnum(mapData)},")
elif stat == "mapNum":
PrintEncounterHeaders(f"{TabStr(2)}.mapNum = {GetMapGroupEnum(mapData, labelCount + 1)},")
if type(headerStructTable[group][label][stat]) == list:
PrintEncounterHeaders(f"{TabStr(2)}.encounterTypes =")
PrintEncounterHeaders(TabStr(2) + "{")
timeCounter = 0
while timeCounter < TIMES_OF_DAY_COUNT:
monInfo = headerStructTable[group][label][stat][timeCounter]
PrintEncounterHeaders(f"{TabStr(3)}[{TIME_OF_DAY.vals[timeCounter]}] = ")
infoIndex = 0
while infoIndex < len(fieldData):
if infoIndex == 0:
PrintEncounterHeaders(TabStr(3) + "{")
if len(monInfo) == 0:
PrintEncounterHeaders(f"{TabStr(4)}{GetIMonInfoStringFromIndex(infoIndex)} = NULL,")
else:
PrintEncounterHeaders(f"{TabStr(4)}{GetIMonInfoStringFromIndex(infoIndex)} = {monInfo[infoIndex]},")
if infoIndex == len(fieldData) - 1:
PrintEncounterHeaders(TabStr(3) + "},")
infoIndex += 1
timeCounter += 1
PrintEncounterHeaders(TabStr(2) + "},")
PrintEncounterHeaders(tabStr + "},")
if labelCount + 1 == headerStructTable[group][label]["encounterTotalCount"]:
PrintEncounterHeaders(tabStr + "{")
PrintEncounterHeaders(f"{TabStr(2)}.mapGroup = {GetMapGroupEnum(MAP_UNDEFINED)},")
PrintEncounterHeaders(f"{TabStr(2)}.mapNum = {GetMapGroupEnum(MAP_UNDEFINED, labelCount + 1)},")
nullCount = 0
while nullCount < TIMES_OF_DAY_COUNT:
if nullCount == 0:
PrintEncounterHeaders(f"{TabStr(2)}.encounterTypes =")
PrintEncounterHeaders(TabStr(2)+ "{")
PrintEncounterHeaders(f"{TabStr(3)}[{TIME_OF_DAY.vals[nullCount]}] = ")
nullIndex = 0
while nullIndex <= len(fieldData) - 1:
if nullIndex == 0:
PrintEncounterHeaders(TabStr(3) + "{")
PrintEncounterHeaders(f"{TabStr(4)}{GetIMonInfoStringFromIndex(nullIndex)} = NULL,")
if nullIndex == len(fieldData) - 1:
PrintEncounterHeaders(TabStr(3) + "},")
nullIndex += 1
nullCount += 1
PrintEncounterHeaders(TabStr(2) + "},")
PrintEncounterHeaders(tabStr + "},")
labelCount += 1
groupCount += 1
PrintEncounterHeaders("};")
def GetWildMonHeadersLabel():
return f"{baseStruct}{structHeader} {MON_HEADERS[headerIndex]}{structHeader}s{structArrayAssign}" + "\n{"
def PrintEncounterHeaders(content):
if printEncounterHeaders:
print(content)
def PrintEncounterRateMacros():
if not printEncounterRateMacros:
return
fieldCounter = 0
# len(fieldData) - 1 here so we skip hidden_mons
while fieldCounter < len(fieldData) - 1:
tempName = fieldData[fieldCounter]["name"].upper()
if "groups" not in fieldData[fieldCounter]:
rateCount = 0
for percent in fieldData[fieldCounter]["encounter_rates"]:
if rateCount == 0:
print(f"{define} {ENCOUNTER_CHANCE}_{tempName}_{SLOT}_{rateCount} {percent}")
else:
print(
f"{define} {ENCOUNTER_CHANCE}_{tempName}_{SLOT}_{rateCount} {ENCOUNTER_CHANCE}_{tempName}_{SLOT}_{rateCount - 1} + {percent}"
)
if rateCount + 1 == len(fieldData[fieldCounter]["encounter_rates"]):
print(
f"{define} {ENCOUNTER_CHANCE}_{tempName}_{TOTAL} ({ENCOUNTER_CHANCE}_{tempName}_{SLOT}_{rateCount})"
)
rateCount += 1
else:
rates = fieldData[fieldCounter]["encounter_rates"]
groups = fieldData[fieldCounter]["groups"]
for method in groups:
method_indices = groups[method]
if not method_indices:
continue
for i, methodPercentIndex in enumerate(method_indices):
if methodPercentIndex < 0 or methodPercentIndex >= len(rates):
print(f"#error Invalid fishing encounter rate index {methodPercentIndex} for {method.upper()}")
continue
rate_value = rates[methodPercentIndex]
if i == 0:
print(f"{define} {ENCOUNTER_CHANCE}_{tempName}_{method.upper()}_{SLOT}_{methodPercentIndex} {rate_value}")
else:
previous_method_index = method_indices[i - 1]
print(f"{define} {ENCOUNTER_CHANCE}_{tempName}_{method.upper()}_{SLOT}_{methodPercentIndex} {ENCOUNTER_CHANCE}_{tempName}_{method.upper()}_{SLOT}_{previous_method_index} + {rate_value}")
if i == len(method_indices) - 1:
print(f"{define} {ENCOUNTER_CHANCE}_{tempName}_{method.upper()}_{TOTAL} ({ENCOUNTER_CHANCE}_{tempName}_{method.upper()}_{SLOT}_{methodPercentIndex})")
fieldCounter += 1
print()
def GetTimeLabelFromString(string):
time = "TIME"
time_ = "TIME_"
if string == "TIMES_OF_DAY_COUNT":
return string
if time_ in string.upper():
return string[len(time_):len(string)]
elif time in string.upper():
return string[len(time):len(string)]
return string
def GetIMonInfoStringFromIndex(index):
return fieldData[index]["infoStringBase"]
def GetMapGroupEnum(string, index = 0):
if "MAP_" in string and index == 0:
return "MAP_GROUP(" + string[4:len(string)] + ")"
elif "MAP_" in string and index != 0:
return "MAP_NUM(" + string[4:len(string)] + ")"
return index
"""
get copied lhea :^ )
- next three functions copied almost verbatim from @lhearachel's python scripts in tools/learnset_helpers
"""
def PrintGeneratedWarningText():
print("//")
print("// DO NOT MODIFY THIS FILE! It is auto-generated by tools/wild_encounters/wild_encounters_to_header.py")
print("//")
print("\n")
def IsConfigEnabled():
CONFIG_ENABLED_PAT = re.compile(r"#define OW_TIME_OF_DAY_ENCOUNTERS\s+(?P<cfg_val>[^ ]*)")
with open("./include/config/overworld.h", "r") as overworld_config_file:
config_overworld = overworld_config_file.read()
config_setting = CONFIG_ENABLED_PAT.search(config_overworld)
return config_setting is not None and config_setting.group("cfg_val") in ("TRUE", "1")
def GetTimeEnum():
DEFAULT_TIME_PAT = re.compile(r"enum\s+TimeOfDay\s*\{(?P<rtc_val>[\s*\w+,\=\d*]+)\s*\}\s*\;")
with open("./include/rtc.h", "r") as rtc_include_file:
include_rtc = rtc_include_file.read()
include_enum = DEFAULT_TIME_PAT.search(include_rtc)
return include_enum.group("rtc_val")
def CheckEmpty(string):
return string == "" or string.isspace() or string == "\n"
def SetupUserTimeEnum(timeOfDay):
enum_string = GetTimeEnum()
enum_string = enum_string.split(",")
# check for extra element from trailing comma
if CheckEmpty(enum_string[-1]):
enum_string.pop(-1)
# we don't need the `TIMES_OF_DAY_COUNT` value, so - 1 from the value of len(enum_string)
strCount = 0
while strCount < len(enum_string) - 1:
tempStr = enum_string[strCount].strip("\n ")
"""
we need to ignore any value assignments, as the times will need to correspond
with the elements in the array.
"""
if "=" in tempStr:
tempStr = tempStr[0:tempStr.index("=")]
tempStr = tempStr.strip(" ")
#double check we didn't catch any empty values
if not CheckEmpty(enum_string[strCount]):
timeOfDay.add(tempStr)
strCount += 1
return timeOfDay
def TabStr(amount):
return tabStr * amount
def GetPascalCase(string):
stringArray = string.split("_")
pascalString = ""
for string in stringArray:
pascalString += string.capitalize()
return pascalString
def GetSnakeCase(string):
stringArray = string.split("_")
snakeString = ""
i = 0
for string in stringArray:
if i == 0:
snakeString += string
else:
snakeString += string.capitalize()
i += 1
return snakeString
def main():
pass
if __name__ == "__main__":
ImportWildEncounterFile()
"""
!!!! EXAMPLE OUTPUT !!!!
- when OW_TIME_OF DAY_ENCOUNTERS is FALSE in configoverworld.h
#define ENCOUNTER_CHANCE_LAND_MONS_SLOT_0 20
#define ENCOUNTER_CHANCE_LAND_MONS_SLOT_1 ENCOUNTER_CHANCE_LAND_MONS_SLOT_0 + 20
#define ENCOUNTER_CHANCE_LAND_MONS_SLOT_2 ENCOUNTER_CHANCE_LAND_MONS_SLOT_1 + 10
#define ENCOUNTER_CHANCE_LAND_MONS_SLOT_3 ENCOUNTER_CHANCE_LAND_MONS_SLOT_2 + 10
#define ENCOUNTER_CHANCE_LAND_MONS_SLOT_4 ENCOUNTER_CHANCE_LAND_MONS_SLOT_3 + 10
#define ENCOUNTER_CHANCE_LAND_MONS_SLOT_5 ENCOUNTER_CHANCE_LAND_MONS_SLOT_4 + 10
#define ENCOUNTER_CHANCE_LAND_MONS_SLOT_6 ENCOUNTER_CHANCE_LAND_MONS_SLOT_5 + 5
#define ENCOUNTER_CHANCE_LAND_MONS_SLOT_7 ENCOUNTER_CHANCE_LAND_MONS_SLOT_6 + 5
#define ENCOUNTER_CHANCE_LAND_MONS_SLOT_8 ENCOUNTER_CHANCE_LAND_MONS_SLOT_7 + 4
#define ENCOUNTER_CHANCE_LAND_MONS_SLOT_9 ENCOUNTER_CHANCE_LAND_MONS_SLOT_8 + 4
#define ENCOUNTER_CHANCE_LAND_MONS_SLOT_10 ENCOUNTER_CHANCE_LAND_MONS_SLOT_9 + 1
#define ENCOUNTER_CHANCE_LAND_MONS_SLOT_11 ENCOUNTER_CHANCE_LAND_MONS_SLOT_10 + 1
#define ENCOUNTER_CHANCE_LAND_MONS_TOTAL (ENCOUNTER_CHANCE_LAND_MONS_SLOT_11)
#define ENCOUNTER_CHANCE_WATER_MONS_SLOT_0 60
#define ENCOUNTER_CHANCE_WATER_MONS_SLOT_1 ENCOUNTER_CHANCE_WATER_MONS_SLOT_0 + 30
#define ENCOUNTER_CHANCE_WATER_MONS_SLOT_2 ENCOUNTER_CHANCE_WATER_MONS_SLOT_1 + 5
#define ENCOUNTER_CHANCE_WATER_MONS_SLOT_3 ENCOUNTER_CHANCE_WATER_MONS_SLOT_2 + 4
#define ENCOUNTER_CHANCE_WATER_MONS_SLOT_4 ENCOUNTER_CHANCE_WATER_MONS_SLOT_3 + 1
#define ENCOUNTER_CHANCE_WATER_MONS_TOTAL (ENCOUNTER_CHANCE_WATER_MONS_SLOT_4)
#define ENCOUNTER_CHANCE_ROCK_SMASH_MONS_SLOT_0 60
#define ENCOUNTER_CHANCE_ROCK_SMASH_MONS_SLOT_1 ENCOUNTER_CHANCE_ROCK_SMASH_MONS_SLOT_0 + 30
#define ENCOUNTER_CHANCE_ROCK_SMASH_MONS_SLOT_2 ENCOUNTER_CHANCE_ROCK_SMASH_MONS_SLOT_1 + 5
#define ENCOUNTER_CHANCE_ROCK_SMASH_MONS_SLOT_3 ENCOUNTER_CHANCE_ROCK_SMASH_MONS_SLOT_2 + 4
#define ENCOUNTER_CHANCE_ROCK_SMASH_MONS_SLOT_4 ENCOUNTER_CHANCE_ROCK_SMASH_MONS_SLOT_3 + 1
#define ENCOUNTER_CHANCE_ROCK_SMASH_MONS_TOTAL (ENCOUNTER_CHANCE_ROCK_SMASH_MONS_SLOT_4)
#define ENCOUNTER_CHANCE_FISHING_MONS_GOOD_ROD_SLOT_2 60
#define ENCOUNTER_CHANCE_FISHING_MONS_GOOD_ROD_SLOT_3 ENCOUNTER_CHANCE_FISHING_MONS_GOOD_ROD_SLOT_2 + 20
#define ENCOUNTER_CHANCE_FISHING_MONS_GOOD_ROD_SLOT_4 ENCOUNTER_CHANCE_FISHING_MONS_GOOD_ROD_SLOT_3 + 20
#define ENCOUNTER_CHANCE_FISHING_MONS_GOOD_ROD_TOTAL (ENCOUNTER_CHANCE_FISHING_MONS_GOOD_ROD_SLOT_4)
#define ENCOUNTER_CHANCE_FISHING_MONS_OLD_ROD_SLOT_0 70
#define ENCOUNTER_CHANCE_FISHING_MONS_OLD_ROD_SLOT_1 ENCOUNTER_CHANCE_FISHING_MONS_OLD_ROD_SLOT_0 + 30
#define ENCOUNTER_CHANCE_FISHING_MONS_OLD_ROD_TOTAL (ENCOUNTER_CHANCE_FISHING_MONS_OLD_ROD_SLOT_1)
#define ENCOUNTER_CHANCE_FISHING_MONS_SUPER_ROD_SLOT_5 40
#define ENCOUNTER_CHANCE_FISHING_MONS_SUPER_ROD_SLOT_6 ENCOUNTER_CHANCE_FISHING_MONS_SUPER_ROD_SLOT_5 + 40
#define ENCOUNTER_CHANCE_FISHING_MONS_SUPER_ROD_SLOT_7 ENCOUNTER_CHANCE_FISHING_MONS_SUPER_ROD_SLOT_6 + 15
#define ENCOUNTER_CHANCE_FISHING_MONS_SUPER_ROD_SLOT_8 ENCOUNTER_CHANCE_FISHING_MONS_SUPER_ROD_SLOT_7 + 4
#define ENCOUNTER_CHANCE_FISHING_MONS_SUPER_ROD_SLOT_9 ENCOUNTER_CHANCE_FISHING_MONS_SUPER_ROD_SLOT_8 + 1
#define ENCOUNTER_CHANCE_FISHING_MONS_SUPER_ROD_TOTAL (ENCOUNTER_CHANCE_FISHING_MONS_SUPER_ROD_SLOT_9)
const struct WildPokemon gRoute101_LandMons_Day[] =
{
{ 2, 2, SPECIES_WURMPLE },
{ 2, 2, SPECIES_POOCHYENA },
{ 2, 2, SPECIES_WURMPLE },
{ 3, 3, SPECIES_WURMPLE },
{ 3, 3, SPECIES_POOCHYENA },
{ 3, 3, SPECIES_POOCHYENA },
{ 3, 3, SPECIES_WURMPLE },
{ 3, 3, SPECIES_POOCHYENA },
{ 2, 2, SPECIES_ZIGZAGOON },
{ 2, 2, SPECIES_ZIGZAGOON },
{ 3, 3, SPECIES_ZIGZAGOON },
{ 3, 3, SPECIES_ZIGZAGOON },
};
const struct WildPokemonInfo gRoute101_Day_LandMonsInfo= { 20, gRoute101_Day_LandMons };
const struct WildPokemonHeader gWildMonHeaders[] =
{
{
.mapGroup = MAP(ROUTE101),
.mapNum = MAP_NUM(ROUTE101),
.encounterTypes =
[OW_TIME_OF_DAY_DEFAULT] =
{
.encounterTypes[timeOfDay].landMonsInfo = &gRoute101_LandMonsInfo,
.encounterTypes[timeOfDay].waterMonsInfo = NULL,
.encounterTypes[timeOfDay].rockSmashMonsInfo = NULL,
.encounterTypes[timeOfDay].fishingMonsInfo = NULL,
.encounterTypes[timeOfDay].hiddenMonsInfo = NULL,
}
},
}
"""