Merge branch 'upcoming' of github.com:rh-hideout/pokeemerald-expansion into twelves

This commit is contained in:
grintoul1 2026-02-10 20:42:39 +00:00
commit 23cbbf4b60
13 changed files with 178 additions and 75 deletions

View File

@ -469,8 +469,8 @@ $(TEST_BUILDDIR)/%.o: CFLAGS := -mthumb -mthumb-interwork -O2 -mabi=apcs-gnu -mt
# Dependency rules (for the *.c & *.s sources to .o files)
# Have to be explicit or else missing files won't be reported.
$(C_BUILDDIR)/pokemon.o: $(C_SUBDIR)/pokemon.c $(DATA_SRC_SUBDIR)/pokemon/teachable_learnsets.h
$(C_BUILDDIR)/move_relearner.o: $(C_SUBDIR)/move_relearner.c $(DATA_SRC_SUBDIR)/tutor_moves.h
$(C_BUILDDIR)/pokemon.o: $(C_SUBDIR)/pokemon.c $(DATA_SRC_SUBDIR)/pokemon/teachable_learnsets.h
# As a side effect, they're evaluated immediately instead of when the rule is invoked.
# It doesn't look like $(shell) can be deferred so there might not be a better way (Icedude_907: there is soon).
@ -546,7 +546,7 @@ $(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 > $@
TEACHABLE_DEPS := $(ALL_LEARNABLES_JSON) $(INCLUDE_DIRS)/constants/tms_hms.h $(INCLUDE_DIRS)/config/pokemon.h $(DATA_SRC_SUBDIR)/pokemon/special_movesets.json $(INCLUDE_DIRS)/config/pokedex_plus_hgss.h $(LEARNSET_HELPERS_DIR)/make_teachables.py
TEACHABLE_DEPS := $(ALL_LEARNABLES_JSON) $(INCLUDE_DIRS)/constants/tms_hms.h $(INCLUDE_DIRS)/config/pokemon.h $(DATA_SRC_SUBDIR)/pokemon/special_movesets.json $(INCLUDE_DIRS)/config/pokedex_plus_hgss.h $(LEARNSET_HELPERS_DIR)/make_teachables.py
$(LEARNSET_HELPERS_BUILD_DIR):
@mkdir -p $@
@ -563,8 +563,8 @@ $(ALL_TEACHING_TYPES_JSON): $(wildcard $(DATA_SRC_SUBDIR)/pokemon/species_info/*
$(DATA_SRC_SUBDIR)/pokemon/teachable_learnsets.h: $(TEACHABLE_DEPS) | $(ALL_TUTORS_JSON) $(ALL_TEACHING_TYPES_JSON)
python3 $(LEARNSET_HELPERS_DIR)/make_teachables.py $(LEARNSET_HELPERS_BUILD_DIR)
$(DATA_SRC_SUBDIR)/tutor_moves.h: | $(ALL_TUTORS_JSON)
python3 $(LEARNSET_HELPERS_DIR)/make_teachables.py $(LEARNSET_HELPERS_BUILD_DIR)
$(DATA_SRC_SUBDIR)/tutor_moves.h: $(DATA_SRC_SUBDIR)/pokemon/special_movesets.json | $(ALL_TUTORS_JSON)
python3 $(LEARNSET_HELPERS_DIR)/make_teachables.py --tutors $(LEARNSET_HELPERS_BUILD_DIR)
# Linker script
LD_SCRIPT := ld_script_modern.ld

View File

@ -120,8 +120,8 @@ enum MoveEndState
MOVEEND_WHITE_HERB,
MOVEEND_OPPORTUNIST,
MOVEEND_MIRROR_HERB,
MOVEEND_PICKPOCKET,
MOVEEND_THIRD_MOVE_BLOCK,
MOVEEND_PICKPOCKET,
MOVEEND_CLEAR_BITS,
MOVEEND_DANCER,
MOVEEND_PURSUIT_NEXT_ACTION,

View File

@ -1,8 +1,6 @@
#ifndef GUARD_CONSTANTS_EVENT_OBJECT_MOVEMENT_H
#define GUARD_CONSTANTS_EVENT_OBJECT_MOVEMENT_H
#define MOVEMENT_TYPE_WANDER_AROUND_SLOWER MOVEMENT_TYPE_WANDER_AROUND
#define MOVEMENT_TYPE_NONE 0x0
#define MOVEMENT_TYPE_LOOK_AROUND 0x1
@ -86,7 +84,8 @@
#define MOVEMENT_TYPE_WALK_SLOWLY_IN_PLACE_LEFT 0x4F
#define MOVEMENT_TYPE_WALK_SLOWLY_IN_PLACE_RIGHT 0x50
#define MOVEMENT_TYPE_FOLLOW_PLAYER 0x51
#define NUM_MOVEMENT_TYPES 0x52
#define MOVEMENT_TYPE_WANDER_AROUND_SLOWER 0x52
#define NUM_MOVEMENT_TYPES 0x53
#define MOVEMENT_ACTION_FACE_DOWN 0x0
#define MOVEMENT_ACTION_FACE_UP 0x1

View File

@ -270,6 +270,7 @@ void CopyObjectGraphicsInfoToSpriteTemplate(u16 graphicsId, void (*callback)(str
void MovementType_None(struct Sprite *sprite);
void MovementType_LookAround(struct Sprite *sprite);
void MovementType_WanderAround(struct Sprite *sprite);
void MovementType_WanderAroundSlower(struct Sprite *sprite);
void MovementType_WanderUpAndDown(struct Sprite *sprite);
void MovementType_WanderLeftAndRight(struct Sprite *sprite);
void MovementType_FaceDirection(struct Sprite *sprite);
@ -335,6 +336,7 @@ u8 MovementType_WanderAround_Step2(struct ObjectEvent *objectEvent, struct Sprit
u8 MovementType_Wander_Step3(struct ObjectEvent *objectEvent, struct Sprite *sprite);
u8 MovementType_WanderAround_Step4(struct ObjectEvent *objectEvent, struct Sprite *sprite);
u8 MovementType_WanderAround_Step5(struct ObjectEvent *objectEvent, struct Sprite *sprite);
u8 MovementType_WanderAround_Step5Slower(struct ObjectEvent *objectEvent, struct Sprite *sprite);
u8 MovementType_WanderAround_Step6(struct ObjectEvent *objectEvent, struct Sprite *sprite);
enum Direction GetVectorDirection(s16 dx, s16 dy, s16 absdx, s16 absdy);
enum Direction GetLimitedVectorDirection_SouthNorth(s16 dx, s16 dy, s16 absdx, s16 absdy);

View File

@ -3341,10 +3341,35 @@ static s32 AI_DoubleBattle(enum BattlerId battlerAtk, enum BattlerId battlerDef,
}
else
{
ADJUST_SCORE(IncreaseStatUpScore(battlerAtkPartner, BATTLE_OPPOSITE(battlerAtk), STAT_CHANGE_ATK));
ADJUST_SCORE(IncreaseStatUpScore(battlerAtkPartner, BATTLE_OPPOSITE(battlerAtk), STAT_CHANGE_DEF));
ADJUST_SCORE(IncreaseStatUpScore(battlerAtkPartner, BATTLE_OPPOSITE(battlerAtkPartner), STAT_CHANGE_ATK));
ADJUST_SCORE(IncreaseStatUpScore(battlerAtkPartner, BATTLE_OPPOSITE(battlerAtkPartner), STAT_CHANGE_DEF));
s32 statUpScore = 0;
s32 tempScore = 0;
enum BattlerId foe = LEFT_FOE(battlerAtk);
if (IsBattlerAlive(foe))
{
tempScore += IncreaseStatUpScore(battlerAtkPartner, foe, STAT_CHANGE_ATK);
tempScore += IncreaseStatUpScore(battlerAtkPartner, foe, STAT_CHANGE_DEF);
if (tempScore == 0)
break;
statUpScore += tempScore;
}
tempScore = 0;
foe = RIGHT_FOE(battlerAtk);
if (IsBattlerAlive(foe))
{
tempScore += IncreaseStatUpScore(battlerAtkPartner, foe, STAT_CHANGE_ATK);
tempScore += IncreaseStatUpScore(battlerAtkPartner, foe, STAT_CHANGE_DEF);
if (tempScore == 0)
break;
statUpScore += tempScore;
}
if (statUpScore > BEST_EFFECT)
ADJUST_SCORE(BEST_EFFECT);
else
ADJUST_SCORE(statUpScore);
}
break;
default:

View File

@ -474,7 +474,7 @@ static bool32 ShouldSwitchIfAllMovesBad(enum BattlerId battler)
ctx.holdEffectDef = gAiLogicData->holdEffects[ctx.battlerDef];
// Switch if no moves affect opponents
if (HasTwoOpponents(battler))
if (IsDoubleBattle())
{
enum BattlerId opposingPartner = BATTLE_PARTNER(opposingBattler);
for (u32 moveIndex = 0; moveIndex < MAX_MON_MOVES; moveIndex++)
@ -1007,7 +1007,7 @@ static bool32 CanUseSuperEffectiveMoveAgainstOpponents(enum BattlerId battler)
if (CanUseSuperEffectiveMoveAgainstOpponent(battler, opposingBattler))
return TRUE;
if (HasTwoOpponents(battler) && CanUseSuperEffectiveMoveAgainstOpponent(battler, BATTLE_PARTNER(BATTLE_OPPOSITE(battler))))
if (IsDoubleBattle() && CanUseSuperEffectiveMoveAgainstOpponent(battler, BATTLE_PARTNER(BATTLE_OPPOSITE(battler))))
return TRUE;
return FALSE;
@ -1168,7 +1168,7 @@ static bool32 ShouldSwitchIfBadChoiceLock(enum BattlerId battler)
u32 moveIndex = GetMoveIndex(battler, choicedMove);
if (HasTwoOpponents(battler))
if (IsDoubleBattle())
{
enum BattlerId opposingPartner = BATTLE_PARTNER(opposingBattler);
if (IsHoldEffectChoice(ctx.holdEffectAtk) && IsBattlerItemEnabled(battler))
@ -1368,7 +1368,7 @@ bool32 ShouldSwitchIfAllScoresBad(enum BattlerId battler)
for (u32 moveIndex = 0; moveIndex < MAX_MON_MOVES; moveIndex++)
{
if (HasTwoOpponents(battler))
if (IsDoubleBattle())
{
u32 score1 = gAiBattleData->finalScore[battler][opposingBattler][moveIndex];
u32 score2 = gAiBattleData->finalScore[battler][BATTLE_PARTNER(opposingBattler)][moveIndex];
@ -1407,7 +1407,7 @@ bool32 ShouldStayInToUseMove(enum BattlerId battler)
continue;
if (gAiBattleData->finalScore[battler][opposingBattler][moveIndex] > AI_GOOD_SCORE_THRESHOLD
|| (HasTwoOpponents(battler) && gAiBattleData->finalScore[battler][BATTLE_PARTNER(opposingBattler)][moveIndex] > AI_GOOD_SCORE_THRESHOLD))
|| (IsDoubleBattle() && gAiBattleData->finalScore[battler][BATTLE_PARTNER(opposingBattler)][moveIndex] > AI_GOOD_SCORE_THRESHOLD))
return TRUE;
}
}

View File

@ -3168,46 +3168,6 @@ static enum MoveEndResult MoveEndMirrorHerb(void)
return MOVEEND_RESULT_CONTINUE;
}
static enum MoveEndResult MoveEndPickpocket(void)
{
enum MoveEndResult result = MOVEEND_RESULT_CONTINUE;
if (IsBattlerAlive(gBattlerAttacker)
&& gBattleMons[gBattlerAttacker].item != ITEM_NONE
&& !GetBattlerPartyState(gBattlerAttacker)->isKnockedOff) // Gen3 edge case where the knocked of item was not removed
{
enum BattlerId battlers[MAX_BATTLERS_COUNT] = {0, 1, 2, 3};
SortBattlersBySpeed(battlers, FALSE); // Pickpocket activates for fastest mon without item
for (u32 i = 0; i < gBattlersCount; i++)
{
enum BattlerId battlerDef = battlers[i];
if (battlerDef != gBattlerAttacker
&& !IsBattlerUnaffectedByMove(battlerDef)
&& GetBattlerAbility(battlerDef) == ABILITY_PICKPOCKET
&& IsMoveMakingContact(gBattlerAttacker, battlerDef, GetBattlerAbility(gBattlerAttacker), GetBattlerHoldEffect(gBattlerAttacker), gCurrentMove)
&& IsBattlerTurnDamaged(battlerDef)
&& !DoesSubstituteBlockMove(gBattlerAttacker, battlerDef, gCurrentMove)
&& IsBattlerAlive(battlerDef)
&& gBattleMons[battlerDef].item == ITEM_NONE
&& CanStealItem(battlerDef, gBattlerAttacker, gBattleMons[gBattlerAttacker].item))
{
gBattlerTarget = gBattlerAbility = battlerDef;
// Battle scripting is super brittle so we shall do the item exchange now (if possible)
if (GetBattlerAbility(gBattlerAttacker) != ABILITY_STICKY_HOLD)
StealTargetItem(battlerDef, gBattlerAttacker); // Target takes attacker's item
gEffectBattler = gBattlerAttacker;
BattleScriptCall(BattleScript_Pickpocket); // Includes sticky hold check to print separate string
result = MOVEEND_RESULT_RUN_SCRIPT;
break; // Pickpocket activates on fastest mon, so exit loop.
}
}
}
gBattleScripting.moveendState++;
return result;
}
static enum MoveEndResult MoveEndThirdMoveBlock(void)
{
enum MoveEndResult result = MOVEEND_RESULT_CONTINUE;
@ -3262,6 +3222,46 @@ static enum MoveEndResult MoveEndThirdMoveBlock(void)
return result;
}
static enum MoveEndResult MoveEndPickpocket(void)
{
enum MoveEndResult result = MOVEEND_RESULT_CONTINUE;
if (IsBattlerAlive(gBattlerAttacker)
&& gBattleMons[gBattlerAttacker].item != ITEM_NONE
&& !GetBattlerPartyState(gBattlerAttacker)->isKnockedOff) // Gen3 edge case where the knocked of item was not removed
{
enum BattlerId battlers[MAX_BATTLERS_COUNT] = {0, 1, 2, 3};
SortBattlersBySpeed(battlers, FALSE); // Pickpocket activates for fastest mon without item
for (u32 i = 0; i < gBattlersCount; i++)
{
enum BattlerId battlerDef = battlers[i];
if (battlerDef != gBattlerAttacker
&& !IsBattlerUnaffectedByMove(battlerDef)
&& GetBattlerAbility(battlerDef) == ABILITY_PICKPOCKET
&& IsMoveMakingContact(gBattlerAttacker, battlerDef, GetBattlerAbility(gBattlerAttacker), GetBattlerHoldEffect(gBattlerAttacker), gCurrentMove)
&& IsBattlerTurnDamaged(battlerDef)
&& !DoesSubstituteBlockMove(gBattlerAttacker, battlerDef, gCurrentMove)
&& IsBattlerAlive(battlerDef)
&& gBattleMons[battlerDef].item == ITEM_NONE
&& CanStealItem(battlerDef, gBattlerAttacker, gBattleMons[gBattlerAttacker].item))
{
gBattlerTarget = gBattlerAbility = battlerDef;
// Battle scripting is super brittle so we shall do the item exchange now (if possible)
if (GetBattlerAbility(gBattlerAttacker) != ABILITY_STICKY_HOLD)
StealTargetItem(battlerDef, gBattlerAttacker); // Target takes attacker's item
gEffectBattler = gBattlerAttacker;
BattleScriptCall(BattleScript_Pickpocket); // Includes sticky hold check to print separate string
result = MOVEEND_RESULT_RUN_SCRIPT;
break; // Pickpocket activates on fastest mon, so exit loop.
}
}
}
gBattleScripting.moveendState++;
return result;
}
static bool32 ShouldSetStompingTantrumTimer(void)
{
u32 numNotAffectedTargets = 0;
@ -3471,8 +3471,8 @@ static enum MoveEndResult (*const sMoveEndHandlers[])(void) =
[MOVEEND_WHITE_HERB] = MoveEndWhiteHerb,
[MOVEEND_OPPORTUNIST] = MoveEndOpportunist,
[MOVEEND_MIRROR_HERB] = MoveEndMirrorHerb,
[MOVEEND_PICKPOCKET] = MoveEndPickpocket,
[MOVEEND_THIRD_MOVE_BLOCK] = MoveEndThirdMoveBlock,
[MOVEEND_PICKPOCKET] = MoveEndPickpocket,
[MOVEEND_CLEAR_BITS] = MoveEndClearBits,
[MOVEEND_DANCER] = MoveEndDancer,
[MOVEEND_PURSUIT_NEXT_ACTION] = MoveEndPursuitNextAction,

View File

@ -8,6 +8,16 @@ u8 (*const gMovementTypeFuncs_WanderAround[])(struct ObjectEvent *, struct Sprit
MovementType_WanderAround_Step6,
};
u8 (*const gMovementTypeFuncs_WanderAroundSlower[])(struct ObjectEvent *, struct Sprite *) = {
MovementType_WanderAround_Step0,
MovementType_WanderAround_Step1,
MovementType_WanderAround_Step2,
MovementType_Wander_Step3,
MovementType_WanderAround_Step4,
MovementType_WanderAround_Step5Slower,
MovementType_WanderAround_Step6,
};
const enum Direction gStandardDirections[] = {DIR_SOUTH, DIR_NORTH, DIR_WEST, DIR_EAST};
enum Direction (*const gGetVectorDirectionFuncs[])(s16, s16, s16, s16) = {

View File

@ -266,6 +266,7 @@ static void (*const sMovementTypeCallbacks[])(struct Sprite *) =
[MOVEMENT_TYPE_NONE] = MovementType_None,
[MOVEMENT_TYPE_LOOK_AROUND] = MovementType_LookAround,
[MOVEMENT_TYPE_WANDER_AROUND] = MovementType_WanderAround,
[MOVEMENT_TYPE_WANDER_AROUND_SLOWER] = MovementType_WanderAroundSlower,
[MOVEMENT_TYPE_WANDER_UP_AND_DOWN] = MovementType_WanderUpAndDown,
[MOVEMENT_TYPE_WANDER_DOWN_AND_UP] = MovementType_WanderUpAndDown,
[MOVEMENT_TYPE_WANDER_LEFT_AND_RIGHT] = MovementType_WanderLeftAndRight,
@ -3874,6 +3875,7 @@ u16 GetObjectPaletteTag(u8 palSlot)
movement_type_empty_callback(MovementType_None)
movement_type_def(MovementType_WanderAround, gMovementTypeFuncs_WanderAround)
movement_type_def(MovementType_WanderAroundSlower, gMovementTypeFuncs_WanderAroundSlower)
bool8 MovementType_WanderAround_Step0(struct ObjectEvent *objectEvent, struct Sprite *sprite)
{
@ -3938,6 +3940,14 @@ bool8 MovementType_WanderAround_Step5(struct ObjectEvent *objectEvent, struct Sp
return TRUE;
}
bool8 MovementType_WanderAround_Step5Slower(struct ObjectEvent *objectEvent, struct Sprite *sprite)
{
ObjectEventSetSingleMovement(objectEvent, sprite, GetWalkSlowMovementAction(objectEvent->movementDirection));
objectEvent->singleMovementActive = TRUE;
sprite->data[1] = 6;
return TRUE;
}
bool8 MovementType_WanderAround_Step6(struct ObjectEvent *objectEvent, struct Sprite *sprite)
{
if (ObjectEventExecSingleMovementAction(objectEvent, sprite))

View File

@ -348,10 +348,10 @@ static void BufferFanClubTrainerName(u8 whichLinkTrainer, u8 whichNPCTrainer)
break;
#endif
case 1:
StringCopy(gStringVar1, gText_LtSurge);
StringCopy(gStringVar1, sText_LtSurge);
break;
case 2:
StringCopy(gStringVar1, gText_Koga);
StringCopy(gStringVar1, sText_Koga);
break;
}
}

View File

@ -310,3 +310,20 @@ SINGLE_BATTLE_TEST("Pickpocket does not prevent King's Rock or Razor Fang flinch
EXPECT(player->item == ITEM_NONE);
}
}
SINGLE_BATTLE_TEST("Pickpocket activates after an Item was knocked off")
{
GIVEN {
ASSUME(GetMoveEffect(MOVE_KNOCK_OFF) == EFFECT_KNOCK_OFF);
PLAYER(SPECIES_WOBBUFFET) { Item(ITEM_POTION); }
OPPONENT(SPECIES_SNEASEL) { Item(ITEM_POTION); Ability(ABILITY_PICKPOCKET); }
} WHEN {
TURN { MOVE(player, MOVE_KNOCK_OFF); }
} SCENE {
ANIMATION(ANIM_TYPE_MOVE, MOVE_KNOCK_OFF, player);
ABILITY_POPUP(opponent, ABILITY_PICKPOCKET);
} THEN {
EXPECT(opponent->item == ITEM_POTION);
EXPECT(player->item == ITEM_NONE);
}
}

View File

@ -2175,3 +2175,25 @@ AI_SINGLE_BATTLE_TEST("AI_FLAG_RANDOMIZE_SWITCHIN: AI will consider all mons tha
TURN { MOVE(player, MOVE_WATER_GUN); EXPECT_MOVE(opponent, MOVE_U_TURN); EXPECT_SEND_OUT(opponent, 2); }
}
}
AI_MULTI_BATTLE_TEST("AI will not switch out if the opposite battler is absent and its moves can still affect the other opponent")
{
GIVEN {
AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT);
MULTI_PLAYER(SPECIES_WOBBUFFET) { HP(41); Speed(1); }
MULTI_PARTNER(SPECIES_DRAKLOAK) { HP(41); MaxHP(100); Speed(4); Item(ITEM_LIFE_ORB); Moves(MOVE_DRAGON_RAGE, MOVE_SHADOW_BALL); }
MULTI_PARTNER(SPECIES_DRAGAPULT) { Speed(4); Moves(MOVE_SHADOW_BALL); }
MULTI_OPPONENT_A(SPECIES_CYCLIZAR) { HP(41); MaxHP(100); Speed(3); Item(ITEM_LIFE_ORB); Moves(MOVE_BODY_SLAM, MOVE_DRAGON_RAGE); }
MULTI_OPPONENT_A(SPECIES_DRAMPA) { Speed(3); Moves(MOVE_BODY_SLAM); }
MULTI_OPPONENT_B(SPECIES_WYNAUT) { Speed(2); HP(41); }
} WHEN {
TURN {
EXPECT_MOVE(opponentLeft, MOVE_BODY_SLAM, target: playerLeft);
EXPECT_MOVE(playerRight, MOVE_SHADOW_BALL, target: opponentRight);
}
TURN {
EXPECT_MOVE(opponentLeft, MOVE_DRAGON_RAGE, target: playerRight);
EXPECT_MOVE(playerRight, MOVE_DRAGON_RAGE, target: opponentLeft);
}
}
}

View File

@ -169,26 +169,52 @@ def create_tutor_moves_array(tutors):
with open("./src/data/tutor_moves.h", "w") as f:
f.write(header + "\n".join(lines))
def make_move_tutors(build_dir, special_movesets):
SOURCE_TUTORS_JSON = build_dir / "all_tutors.json"
assert SOURCE_TUTORS_JSON.exists(), f"{SOURCE_TUTORS_JSON=} does not exist"
assert SOURCE_TUTORS_JSON.is_file(), f"{SOURCE_TUTORS_JSON=} is not a file"
with open(SOURCE_TUTORS_JSON, "r") as fp:
repo_tutors = json.load(fp)
repo_tutors = sorted(repo_tutors + special_movesets["extraTutors"])
create_tutor_moves_array(repo_tutors)
return repo_tutors
def main():
if not enabled():
quit()
if len(sys.argv) < 2:
print("Missing required arguments", file=sys.stderr)
tutor_mode = False
if len(sys.argv) < 2 or len(sys.argv) > 3:
print("Invalid number of arguments", file=sys.stderr)
print(__doc__, file=sys.stderr)
quit(1)
SOURCE_DIR = pathlib.Path(sys.argv[1])
if len(sys.argv) == 2:
SOURCE_DIR = pathlib.Path(sys.argv[1])
elif len(sys.argv) == 3:
if sys.argv[1] != "--tutors":
print("Unknown make_teachables mode", file=sys.stderr)
quit(1)
tutor_mode = True
SOURCE_DIR = pathlib.Path(sys.argv[2])
with open("src/data/pokemon/special_movesets.json", "r") as file:
special_movesets = json.load(file)
repo_tutors = make_move_tutors(SOURCE_DIR, special_movesets)
if tutor_mode:
quit(0)
SOURCE_LEARNSETS_JSON = pathlib.Path("./src/data/pokemon/all_learnables.json")
SOURCE_TUTORS_JSON = SOURCE_DIR / "all_tutors.json"
SOURCE_TEACHING_TYPES_JSON = SOURCE_DIR / "all_teaching_types.json"
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"
assert SOURCE_TUTORS_JSON.exists(), f"{SOURCE_TUTORS_JSON=} does not exist"
assert SOURCE_TUTORS_JSON.is_file(), f"{SOURCE_TUTORS_JSON=} is not a file"
assert SOURCE_TEACHING_TYPES_JSON.exists(), f"{SOURCE_TEACHING_TYPES_JSON=} does not exist"
assert SOURCE_TEACHING_TYPES_JSON.is_file(), f"{SOURCE_TEACHING_TYPES_JSON=} is not a file"
@ -201,14 +227,6 @@ def main():
if cfg_defined is None or cfg_defined.group("cfg_val") in ("FALSE", "0"):
repo_tms = sorted(repo_tms)
with open(SOURCE_TUTORS_JSON, "r") as fp:
repo_tutors = json.load(fp)
with open("src/data/pokemon/special_movesets.json", "r") as file:
special_movesets = json.load(file)
repo_tutors = sorted(repo_tutors + special_movesets["extraTutors"])
create_tutor_moves_array(repo_tutors)
h_align = max(map(lambda move: len(move), chain(special_movesets["universalMoves"], repo_tms, repo_tutors))) + 2
header = prepare_header(h_align, repo_tms, repo_tutors, special_movesets["universalMoves"])