From c8d3a6b4dfa7f10a8c7bce619e7ed5961d4f356e Mon Sep 17 00:00:00 2001 From: Hedara Date: Fri, 2 May 2025 16:03:55 +0200 Subject: [PATCH 01/11] Added missing include due to g++ changes --- tools/mapjson/json11.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/tools/mapjson/json11.cpp b/tools/mapjson/json11.cpp index 3ac5f392a0..fcacdbeb39 100644 --- a/tools/mapjson/json11.cpp +++ b/tools/mapjson/json11.cpp @@ -23,6 +23,7 @@ #include #include #include +#include namespace json11 { From 9259b7ee69b32b0582d6b24aff25c88721789502 Mon Sep 17 00:00:00 2001 From: Alex <93446519+AlexOn1ine@users.noreply.github.com> Date: Fri, 2 May 2025 20:14:27 +0200 Subject: [PATCH 02/11] Bugfixes batch (#6750) --- data/battle_scripts_1.s | 4 +- include/battle.h | 13 +++--- src/battle_script_commands.c | 26 +++++++---- src/battle_util.c | 36 ++++++++++----- test/battle/ability/beast_boost.c | 20 +++++++++ test/battle/ability/desolate_land.c | 18 ++++++++ test/battle/hold_effect/jaboca_berry.c | 15 +++++++ test/battle/hold_effect/life_orb.c | 17 +++++++ test/battle/hold_effect/restore_stats.c | 18 ++++++++ test/battle/hold_effect/rowap_berry.c | 15 +++++++ test/battle/move_effect/dragon_darts.c | 59 +++++++++++++++++++++++++ test/battle/move_effect/hit_escape.c | 16 +++++++ 12 files changed, 228 insertions(+), 29 deletions(-) diff --git a/data/battle_scripts_1.s b/data/battle_scripts_1.s index a00654d6c7..53ed13f9b6 100644 --- a/data/battle_scripts_1.s +++ b/data/battle_scripts_1.s @@ -8399,7 +8399,7 @@ BattleScript_BattlerAbilityStatRaiseOnSwitchIn:: BattleScript_ScriptingAbilityStatRaise:: copybyte gBattlerAbility, sBATTLER call BattleScript_AbilityPopUp - copybyte sSAVED_DMG, gBattlerAttacker + saveattacker copybyte gBattlerAttacker, sBATTLER statbuffchange MOVE_EFFECT_AFFECTS_USER | STAT_CHANGE_NOT_PROTECT_AFFECTED | MOVE_EFFECT_CERTAIN, NULL setgraphicalstatchangevalues @@ -8407,7 +8407,7 @@ BattleScript_ScriptingAbilityStatRaise:: waitanimation printstring STRINGID_ATTACKERABILITYSTATRAISE waitmessage B_WAIT_TIME_LONG - copybyte gBattlerAttacker, sSAVED_DMG + restoreattacker return BattleScript_WeakArmorActivates:: diff --git a/include/battle.h b/include/battle.h index 4620112194..49bd92cb1c 100644 --- a/include/battle.h +++ b/include/battle.h @@ -736,19 +736,19 @@ struct BattleStruct u8 debugBattler; u8 magnitudeBasePower; u8 presentBasePower; - u8 roostTypes[MAX_BATTLERS_COUNT][2]; + u8 roostTypes[MAX_BATTLERS_COUNT][NUM_BATTLE_SIDES]; u8 savedBattlerTarget[5]; u8 savedBattlerAttacker[5]; u8 savedTargetCount:4; u8 savedAttackerCount:4; bool8 ateBoost[MAX_BATTLERS_COUNT]; - u8 abilityPopUpSpriteIds[MAX_BATTLERS_COUNT][2]; // two per battler + u8 abilityPopUpSpriteIds[MAX_BATTLERS_COUNT][NUM_BATTLE_SIDES]; // two per battler struct ZMoveData zmove; struct DynamaxData dynamax; struct BattleGimmickData gimmick; const u8 *trainerSlideMsg; enum BattleIntroStates introState:8; - u8 ateBerry[2]; // array id determined by side, each party pokemon as bit + u8 ateBerry[NUM_BATTLE_SIDES]; // array id determined by side, each party pokemon as bit u8 stolenStats[NUM_BATTLE_STATS]; // hp byte is used for which stats to raise, other inform about by how many stages u8 lastMoveTarget[MAX_BATTLERS_COUNT]; // The last target on which each mon used a move, for the sake of Instruct u16 tracedAbility[MAX_BATTLERS_COUNT]; @@ -804,13 +804,14 @@ struct BattleStruct u32 stellarBoostFlags[NUM_BATTLE_SIDES]; // stored as a bitfield of flags for all types for each side u8 monCausingSleepClause[NUM_BATTLE_SIDES]; // Stores which pokemon on a given side is causing Sleep Clause to be active as the mon's index in the party u8 additionalEffectsCounter:4; // A counter for the additionalEffects applied by the current move in Cmd_setadditionaleffects + s16 savedcheekPouchDamage; // Cheek Pouch can happen in the middle of an attack execution so we need to store the current dmg u8 cheekPouchActivated:1; u8 padding2:3; u8 pursuitStoredSwitch; // Stored id for the Pursuit target's switch s32 battlerExpReward; u16 prevTurnSpecies[MAX_BATTLERS_COUNT]; // Stores species the AI has in play at start of turn - s32 moveDamage[MAX_BATTLERS_COUNT]; - s32 critChance[MAX_BATTLERS_COUNT]; + s16 moveDamage[MAX_BATTLERS_COUNT]; + s16 critChance[MAX_BATTLERS_COUNT]; u16 moveResultFlags[MAX_BATTLERS_COUNT]; u8 missStringId[MAX_BATTLERS_COUNT]; u8 noResultString[MAX_BATTLERS_COUNT]; @@ -821,10 +822,10 @@ struct BattleStruct u8 numSpreadTargets:2; u8 bypassMoldBreakerChecks:1; // for ABILITYEFFECT_IMMUNITY u8 noTargetPresent:1; - u8 usedEjectItem; u8 usedMicleBerry; struct MessageStatus slideMessageStatus; u8 trainerSlideSpriteIds[MAX_BATTLERS_COUNT]; + u8 storeBattlerSpriteId; u16 opponentMonCanTera:6; u16 opponentMonCanDynamax:6; u16 padding:4; diff --git a/src/battle_script_commands.c b/src/battle_script_commands.c index 3704eb1b01..c9db4dbc99 100644 --- a/src/battle_script_commands.c +++ b/src/battle_script_commands.c @@ -1677,6 +1677,7 @@ static void AccuracyCheck(bool32 recalcDragonDarts, const u8 *nextInstr, const u gBattleStruct->blunderPolicy = TRUE; // Only activates from missing through acc/evasion checks if (effect == EFFECT_DRAGON_DARTS + && !IsAffectedByFollowMe(gBattlerAttacker, GetBattlerSide(battlerDef), gCurrentMove) && !recalcDragonDarts // So we don't jump back and forth between targets && CanTargetPartner(gBattlerAttacker, battlerDef) && !TargetFullyImmuneToCurrMove(gBattlerAttacker, BATTLE_PARTNER(battlerDef))) @@ -6496,8 +6497,7 @@ static void Cmd_moveend(void) else if (moveRecoil > 0 && !(gBattleStruct->moveResultFlags[gBattlerTarget] & MOVE_RESULT_NO_EFFECT) && IsBattlerAlive(gBattlerAttacker) - && IsBattlerTurnDamaged(gBattlerTarget) - && gBattleScripting.savedDmg != 0) // Some checks may be redundant alongside this one + && IsBattlerTurnDamaged(gBattlerTarget)) { gBattleStruct->moveDamage[gBattlerAttacker] = max(1, gBattleScripting.savedDmg * max(1, moveRecoil) / 100); BattleScriptPushCursor(); @@ -7006,6 +7006,7 @@ static void Cmd_moveend(void) else { if (moveEffect == EFFECT_DRAGON_DARTS + && !IsAffectedByFollowMe(gBattlerAttacker, GetBattlerSide(gBattlerTarget), gCurrentMove) && !(gBattleStruct->moveResultFlags[BATTLE_PARTNER(gBattlerTarget)] & MOVE_RESULT_MISSED) // didn't miss the other target && CanTargetPartner(gBattlerAttacker, gBattlerTarget) && !TargetFullyImmuneToCurrMove(gBattlerAttacker, BATTLE_PARTNER(gBattlerTarget))) @@ -7157,6 +7158,10 @@ static void Cmd_moveend(void) if (!(ejectPackBattlers & 1u << battler)) continue; + // Hit escape moves activate before Eject Pack for user + if (moveEffect == EFFECT_HIT_ESCAPE && gBattlerAttacker == battler) + continue; + gBattleScripting.battler = battler; gLastUsedItem = gBattleMons[battler].item; @@ -9048,7 +9053,7 @@ static bool32 TryCheekPouch(u32 battler, u32 itemId) && !IsBattlerAtMaxHp(battler)) { gBattleStruct->cheekPouchActivated = TRUE; - gBattleScripting.savedDmg = gBattleStruct->moveDamage[battler]; + gBattleStruct->savedcheekPouchDamage = gBattleStruct->moveDamage[battler]; gBattleStruct->moveDamage[battler] = GetNonDynamaxMaxHP(battler) / 3; if (gBattleStruct->moveDamage[battler] == 0) gBattleStruct->moveDamage[battler] = 1; @@ -9066,7 +9071,7 @@ static void TryRestoreDamageAfterCheeckPouch(u32 battler) { if (gBattleStruct->cheekPouchActivated) { - gBattleStruct->moveDamage[battler] = gBattleScripting.savedDmg; + gBattleStruct->moveDamage[battler] = gBattleStruct->savedcheekPouchDamage; gBattleStruct->cheekPouchActivated = FALSE; } } @@ -10602,6 +10607,7 @@ static void Cmd_various(void) if ((battlerAbility == ABILITY_MOXIE || battlerAbility == ABILITY_CHILLING_NEIGH || battlerAbility == ABILITY_AS_ONE_ICE_RIDER) + && IsBattlerAlive(battler) && HasAttackerFaintedTarget() && !NoAliveMonsForEitherParty() && CompareStat(gBattlerAttacker, STAT_ATK, MAX_STAT_STAGE, CMP_LESS_THAN)) @@ -10625,6 +10631,7 @@ static void Cmd_various(void) if ((battlerAbility == ABILITY_GRIM_NEIGH || battlerAbility == ABILITY_AS_ONE_SHADOW_RIDER) + && IsBattlerAlive(battler) && HasAttackerFaintedTarget() && !NoAliveMonsForEitherParty() && CompareStat(gBattlerAttacker, STAT_SPATK, MAX_STAT_STAGE, CMP_LESS_THAN)) @@ -10663,7 +10670,8 @@ static void Cmd_various(void) VARIOUS_ARGS(); i = GetHighestStatId(battler); - if (GetBattlerAbility(battler) == ABILITY_BEAST_BOOST + if (IsBattlerAlive(battler) + && GetBattlerAbility(battler) == ABILITY_BEAST_BOOST && HasAttackerFaintedTarget() && !NoAliveMonsForEitherParty() && CompareStat(gBattlerAttacker, i, MAX_STAT_STAGE, CMP_LESS_THAN)) @@ -10701,6 +10709,7 @@ static void Cmd_various(void) { VARIOUS_ARGS(); if (GetMoveEffect(gCurrentMove) == EFFECT_FELL_STINGER + && IsBattlerAlive(gBattlerAttacker) && HasAttackerFaintedTarget() && !NoAliveMonsForEitherParty() && CompareStat(gBattlerAttacker, STAT_ATK, MAX_STAT_STAGE, CMP_LESS_THAN)) @@ -11122,7 +11131,7 @@ static void Cmd_various(void) if (cmd->case_ == 0) { // Save sprite IDs, because trainer slide in will overwrite gBattlerSpriteIds variable. - gBattleScripting.savedDmg = (gBattlerSpriteIds[battler] & 0xFF) | (gBattlerSpriteIds[BATTLE_PARTNER(battler)] << 8); + gBattleStruct->storeBattlerSpriteId = (gBattlerSpriteIds[battler] & 0xFF) | (gBattlerSpriteIds[BATTLE_PARTNER(battler)] << 8); } else if (cmd->case_ == 1) { @@ -11131,9 +11140,8 @@ static void Cmd_various(void) } else { - gBattlerSpriteIds[BATTLE_PARTNER(battler)] = gBattleScripting.savedDmg >> 8; - gBattlerSpriteIds[battler] = gBattleScripting.savedDmg & 0xFF; - gBattleScripting.savedDmg = 0; + gBattlerSpriteIds[BATTLE_PARTNER(battler)] = gBattleStruct->storeBattlerSpriteId >> 8; + gBattlerSpriteIds[battler] = gBattleStruct->storeBattlerSpriteId & 0xFF; if (IsBattlerAlive(battler)) { SetBattlerShadowSpriteCallback(battler, gBattleMons[battler].species); diff --git a/src/battle_util.c b/src/battle_util.c index 72d203609e..a9a976fb42 100644 --- a/src/battle_util.c +++ b/src/battle_util.c @@ -227,15 +227,28 @@ static bool32 ShouldTeraShellDistortTypeMatchups(u32 move, u32 battlerDef, u32 a return FALSE; } +static inline bool32 IsDragonDartsSecondHit(u32 effect) +{ + if (effect != EFFECT_DRAGON_DARTS) + return FALSE; + + if (gMultiHitCounter == 1) + return TRUE; + + return FALSE; +} + bool32 IsAffectedByFollowMe(u32 battlerAtk, u32 defSide, u32 move) { u32 ability = GetBattlerAbility(battlerAtk); u32 effect = GetMoveEffect(move); if (gSideTimers[defSide].followmeTimer == 0 - || !IsBattlerAlive(gSideTimers[defSide].followmeTarget) - || effect == EFFECT_SNIPE_SHOT || effect == EFFECT_SKY_DROP - || ability == ABILITY_PROPELLER_TAIL || ability == ABILITY_STALWART) + || (!IsBattlerAlive(gSideTimers[defSide].followmeTarget) && !IsDragonDartsSecondHit(effect)) + || effect == EFFECT_SNIPE_SHOT + || effect == EFFECT_SKY_DROP + || ability == ABILITY_PROPELLER_TAIL + || ability == ABILITY_STALWART) return FALSE; if (effect == EFFECT_PURSUIT && IsPursuitTargetSet()) @@ -3582,6 +3595,9 @@ static void CancellerWeatherPrimal(u32 *effect) } if (*effect == 1) { + gBattleScripting.moveEffect = 0; + gProtectStructs[gBattlerAttacker].chargingTurn = FALSE; + CancelMultiTurnMoves(gBattlerAttacker); gHitMarker |= HITMARKER_UNABLE_TO_USE_MOVE; BattleScriptPushCursor(); gBattlescriptCurrInstr = BattleScript_PrimalWeatherBlocksMove; @@ -3696,6 +3712,7 @@ static void CancellerMultihitMoves(u32 *effect) gMultiHitCounter = GetMoveStrikeCount(gCurrentMove); if (GetMoveEffect(gCurrentMove) == EFFECT_DRAGON_DARTS + && !IsAffectedByFollowMe(gBattlerAttacker, GetBattlerSide(gBattlerTarget), gCurrentMove) && CanTargetPartner(gBattlerAttacker, gBattlerTarget) && TargetFullyImmuneToCurrMove(gBattlerAttacker, gBattlerTarget)) gBattlerTarget = BATTLE_PARTNER(gBattlerTarget); @@ -7355,6 +7372,7 @@ u32 RestoreWhiteHerbStats(u32 battler) } if (effect != 0) { + gLastUsedItem = gBattleMons[battler].item; gBattleScripting.battler = battler; gPotentialItemEffectBattler = battler; } @@ -7679,10 +7697,7 @@ u32 ItemBattleEffects(enum ItemCaseId caseID, u32 battler, bool32 moveTurn) case HOLD_EFFECT_RESTORE_STATS: effect = RestoreWhiteHerbStats(battler); if (effect != 0) - { - gBattlerAttacker = battler; BattleScriptExecute(BattleScript_WhiteHerbEnd2); - } break; case HOLD_EFFECT_CONFUSE_SPICY: if (B_BERRIES_INSTANT >= GEN_4) @@ -7898,10 +7913,7 @@ u32 ItemBattleEffects(enum ItemCaseId caseID, u32 battler, bool32 moveTurn) case HOLD_EFFECT_RESTORE_STATS: effect = RestoreWhiteHerbStats(battler); if (effect != 0) - { - gBattlerAttacker = battler; BattleScriptExecute(BattleScript_WhiteHerbEnd2); - } break; case HOLD_EFFECT_BLACK_SLUDGE: if (IS_BATTLER_OF_TYPE(battler, TYPE_POISON)) @@ -8190,7 +8202,7 @@ u32 ItemBattleEffects(enum ItemCaseId caseID, u32 battler, bool32 moveTurn) break; case HOLD_EFFECT_LIFE_ORB: if (IsBattlerAlive(gBattlerAttacker) - && (IsBattlerTurnDamaged(gBattlerTarget) || gBattleStruct->moveDamage[gBattlerTarget]) // Needs the second check in case of Substitute + && (IsBattlerTurnDamaged(gBattlerTarget) || !(gBattleStruct->moveResultFlags[gBattlerTarget] & MOVE_RESULT_NO_EFFECT)) // Needs the second check in case of Substitute && !(TestIfSheerForceAffected(gBattlerAttacker, gCurrentMove)) && GetBattlerAbility(gBattlerAttacker) != ABILITY_MAGIC_GUARD && !gProtectStructs[gBattlerAttacker].confusionSelfDmg @@ -8311,7 +8323,7 @@ u32 ItemBattleEffects(enum ItemCaseId caseID, u32 battler, bool32 moveTurn) effect = TrySetEnigmaBerry(battler); break; case HOLD_EFFECT_JABOCA_BERRY: // consume and damage attacker if used physical move - if (IsBattlerAlive(battler) + if (IsBattlerAlive(gBattlerAttacker) && IsBattlerTurnDamaged(gBattlerTarget) && !DoesSubstituteBlockMove(gBattlerAttacker, battler, gCurrentMove) && IsBattleMovePhysical(gCurrentMove) @@ -8331,7 +8343,7 @@ u32 ItemBattleEffects(enum ItemCaseId caseID, u32 battler, bool32 moveTurn) } break; case HOLD_EFFECT_ROWAP_BERRY: // consume and damage attacker if used special move - if (IsBattlerAlive(battler) + if (IsBattlerAlive(gBattlerAttacker) && IsBattlerTurnDamaged(gBattlerTarget) && !DoesSubstituteBlockMove(gBattlerAttacker, battler, gCurrentMove) && IsBattleMoveSpecial(gCurrentMove) diff --git a/test/battle/ability/beast_boost.c b/test/battle/ability/beast_boost.c index 8ce0c55b9e..9b07c51f1d 100644 --- a/test/battle/ability/beast_boost.c +++ b/test/battle/ability/beast_boost.c @@ -36,3 +36,23 @@ SINGLE_BATTLE_TEST("Beast Boost boosts the most proficient stat when knocking ou } } } + +SINGLE_BATTLE_TEST("Beast Boost doesn't trigger if user is fainted") +{ + GIVEN { + ASSUME(GetMoveEffect(MOVE_DESTINY_BOND) == EFFECT_DESTINY_BOND); + ASSUME(GetMovePower(MOVE_SCRATCH) > 0); + PLAYER(SPECIES_WOBBUFFET) { HP(1); } + PLAYER(SPECIES_WYNAUT); + OPPONENT(SPECIES_KARTANA) { Ability(ABILITY_BEAST_BOOST); } + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(player, MOVE_DESTINY_BOND); MOVE(opponent, MOVE_SCRATCH); SEND_OUT(player, 1); SEND_OUT(opponent, 1); } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_DESTINY_BOND, player); + ANIMATION(ANIM_TYPE_MOVE, MOVE_SCRATCH, opponent); + NOT ABILITY_POPUP(opponent, ABILITY_BEAST_BOOST); + SEND_IN_MESSAGE("Wynaut"); + MESSAGE("2 sent out Wobbuffet!"); + } +} diff --git a/test/battle/ability/desolate_land.c b/test/battle/ability/desolate_land.c index 5bf1358503..e058b7b514 100644 --- a/test/battle/ability/desolate_land.c +++ b/test/battle/ability/desolate_land.c @@ -65,3 +65,21 @@ SINGLE_BATTLE_TEST("Desolate Land does not block a move if pokemon is asleep and MESSAGE("The opposing Wobbuffet is fast asleep."); } } + +SINGLE_BATTLE_TEST("Desolate Land will not create a softlock when move in semi invulnerable position is blocked") +{ + GIVEN { + PLAYER(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_GROUDON) { Item(ITEM_RED_ORB); } + } WHEN { + TURN { MOVE(player, MOVE_DIVE); } + TURN { SWITCH(opponent, 1); SKIP_TURN(player); } + TURN { MOVE(player, MOVE_CELEBRATE); } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_DIVE, player); + ABILITY_POPUP(opponent, ABILITY_DESOLATE_LAND); + NOT ANIMATION(ANIM_TYPE_MOVE, MOVE_DIVE, player); + ANIMATION(ANIM_TYPE_MOVE, MOVE_CELEBRATE, player); + } +} diff --git a/test/battle/hold_effect/jaboca_berry.c b/test/battle/hold_effect/jaboca_berry.c index 2eb10df77a..cdb5cbfacd 100644 --- a/test/battle/hold_effect/jaboca_berry.c +++ b/test/battle/hold_effect/jaboca_berry.c @@ -58,3 +58,18 @@ SINGLE_BATTLE_TEST("Jaboca Berry tirggers before Bug Bite can steal it") NOT MESSAGE("Wynaut stole and ate the opposing Wobbuffet's Jaboca Berry!"); } } + +SINGLE_BATTLE_TEST("Jaboca Berry is triggered even if berry user dies") +{ + GIVEN { + ASSUME(GetMoveCategory(MOVE_SWIFT) == DAMAGE_CATEGORY_SPECIAL); + PLAYER(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_WOBBUFFET) { HP(1); Item(ITEM_JABOCA_BERRY); } + } WHEN { + TURN { MOVE(player, MOVE_TACKLE); } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_TACKLE, player); + HP_BAR(player); + MESSAGE("Wobbuffet was hurt by the opposing Wobbuffet's Jaboca Berry!"); + } +} diff --git a/test/battle/hold_effect/life_orb.c b/test/battle/hold_effect/life_orb.c index e69de29bb2..61acd60660 100644 --- a/test/battle/hold_effect/life_orb.c +++ b/test/battle/hold_effect/life_orb.c @@ -0,0 +1,17 @@ +#include "global.h" +#include "test/battle.h" + +SINGLE_BATTLE_TEST("Life Orb activates if it hits a Substitute") +{ + GIVEN { + PLAYER(SPECIES_WOBBUFFET) { Item(ITEM_LIFE_ORB); } + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(opponent, MOVE_SUBSTITUTE); MOVE(player, MOVE_TACKLE); } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_SUBSTITUTE, opponent); + ANIMATION(ANIM_TYPE_MOVE, MOVE_TACKLE, player); + HP_BAR(player); + MESSAGE("Wobbuffet was hurt by the Life Orb!"); + } +} diff --git a/test/battle/hold_effect/restore_stats.c b/test/battle/hold_effect/restore_stats.c index e7f020910f..f0f7bc5908 100644 --- a/test/battle/hold_effect/restore_stats.c +++ b/test/battle/hold_effect/restore_stats.c @@ -217,3 +217,21 @@ SINGLE_BATTLE_TEST("White Herb has correct interactions with Intimidate triggere } } } + +DOUBLE_BATTLE_TEST("White Herb is correctly displayed") +{ + GIVEN { + PLAYER(SPECIES_WOBBUFFET); + PLAYER(SPECIES_WYNAUT) { Item(ITEM_WHITE_HERB); } + OPPONENT(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_WYNAUT); + } WHEN { + TURN { MOVE(playerRight, MOVE_SUPERPOWER, target: opponentRight); } + } SCENE { + ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_HELD_ITEM_EFFECT, playerRight); + MESSAGE("Wynaut returned its stats to normal using its White Herb!"); + } THEN { + EXPECT(playerLeft->item == ITEM_NONE); + EXPECT(playerLeft->statStages[STAT_DEF] = DEFAULT_STAT_STAGE); + } +} diff --git a/test/battle/hold_effect/rowap_berry.c b/test/battle/hold_effect/rowap_berry.c index 0604fefcb7..93ac49f608 100644 --- a/test/battle/hold_effect/rowap_berry.c +++ b/test/battle/hold_effect/rowap_berry.c @@ -57,3 +57,18 @@ SINGLE_BATTLE_TEST("Rowap Berry is not triggered by a physical move") } } } + +SINGLE_BATTLE_TEST("Rowap Berry is triggered even if berry user dies") +{ + GIVEN { + ASSUME(GetMoveCategory(MOVE_TACKLE) == DAMAGE_CATEGORY_PHYSICAL); + PLAYER(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_WOBBUFFET) { HP(1); Item(ITEM_ROWAP_BERRY); } + } WHEN { + TURN { MOVE(player, MOVE_SWIFT); } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_SWIFT, player); + HP_BAR(player); + MESSAGE("Wobbuffet was hurt by the opposing Wobbuffet's Rowap Berry!"); + } +} diff --git a/test/battle/move_effect/dragon_darts.c b/test/battle/move_effect/dragon_darts.c index 9e178f67c8..1d94968a09 100644 --- a/test/battle/move_effect/dragon_darts.c +++ b/test/battle/move_effect/dragon_darts.c @@ -76,6 +76,7 @@ DOUBLE_BATTLE_TEST("Dragon Darts strikes an opponent twice if the other one is F PARAMETRIZE { chosenTarget = opponentRight; finalTarget = opponentRight; speciesLeft = SPECIES_CLEFAIRY; speciesRight = SPECIES_WOBBUFFET; } PARAMETRIZE { chosenTarget = opponentLeft; finalTarget = opponentLeft; speciesLeft = SPECIES_WOBBUFFET; speciesRight = SPECIES_CLEFAIRY; } PARAMETRIZE { chosenTarget = opponentRight; finalTarget = opponentLeft; speciesLeft = SPECIES_WOBBUFFET; speciesRight = SPECIES_CLEFAIRY; } + GIVEN { ASSUME(gSpeciesInfo[SPECIES_CLEFAIRY].types[0] == TYPE_FAIRY || gSpeciesInfo[SPECIES_CLEFAIRY].types[1] == TYPE_FAIRY); PLAYER(SPECIES_WOBBUFFET); @@ -252,3 +253,61 @@ DOUBLE_BATTLE_TEST("Dragon Darts strikes right ally twice if one strike misses") MESSAGE("The Pokémon was hit 2 time(s)!"); } } + +DOUBLE_BATTLE_TEST("Dragon Darts strikes will be both redirected to Follow Me user") +{ + GIVEN { + ASSUME(gSpeciesInfo[SPECIES_CLEFAIRY].types[0] == TYPE_FAIRY || gSpeciesInfo[SPECIES_CLEFAIRY].types[1] == TYPE_FAIRY); + PLAYER(SPECIES_WOBBUFFET); + PLAYER(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(opponentRight, MOVE_FOLLOW_ME); MOVE(playerLeft, MOVE_DRAGON_DARTS, target: opponentLeft); } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_DRAGON_DARTS, playerLeft); + HP_BAR(opponentRight); + ANIMATION(ANIM_TYPE_MOVE, MOVE_DRAGON_DARTS, playerLeft); + HP_BAR(opponentRight); + MESSAGE("The Pokémon was hit 2 time(s)!"); + } +} + +DOUBLE_BATTLE_TEST("Dragon Darts fails to strike any target if under a fairy type follow me user") +{ + GIVEN { + ASSUME(gSpeciesInfo[SPECIES_CLEFAIRY].types[0] == TYPE_FAIRY || gSpeciesInfo[SPECIES_CLEFAIRY].types[1] == TYPE_FAIRY); + PLAYER(SPECIES_WOBBUFFET); + PLAYER(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_CLEFAIRY); + } WHEN { + TURN { MOVE(opponentRight, MOVE_FOLLOW_ME); MOVE(playerLeft, MOVE_DRAGON_DARTS, target: opponentLeft); } + } SCENE { + NONE_OF { + ANIMATION(ANIM_TYPE_MOVE, MOVE_DRAGON_DARTS, playerLeft); + ANIMATION(ANIM_TYPE_MOVE, MOVE_DRAGON_DARTS, playerLeft); + MESSAGE("The Pokémon was hit 2 time(s)!"); + } + } +} + +DOUBLE_BATTLE_TEST("Dragon Darts fails to strike the second target if first target fainted and follow me was active") +{ + GIVEN { + ASSUME(gSpeciesInfo[SPECIES_CLEFAIRY].types[0] == TYPE_FAIRY || gSpeciesInfo[SPECIES_CLEFAIRY].types[1] == TYPE_FAIRY); + PLAYER(SPECIES_WOBBUFFET); + PLAYER(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_WOBBUFFET) { HP(1); } + } WHEN { + TURN { MOVE(opponentRight, MOVE_FOLLOW_ME); MOVE(playerLeft, MOVE_DRAGON_DARTS, target: opponentLeft); } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_DRAGON_DARTS, playerLeft); + HP_BAR(opponentRight); + NONE_OF { + ANIMATION(ANIM_TYPE_MOVE, MOVE_DRAGON_DARTS, playerLeft); + MESSAGE("The Pokémon was hit 2 time(s)!"); + } + } +} diff --git a/test/battle/move_effect/hit_escape.c b/test/battle/move_effect/hit_escape.c index 83280f9f50..d0ef3d40f3 100644 --- a/test/battle/move_effect/hit_escape.c +++ b/test/battle/move_effect/hit_escape.c @@ -179,3 +179,19 @@ SINGLE_BATTLE_TEST("Hit Escape: Electric Seed boost is received by the right pok EXPECT_EQ(player->statStages[STAT_DEF], DEFAULT_STAT_STAGE + 1); } } + +SINGLE_BATTLE_TEST("Hit Escape: U-turn triggers before Eject Pack") +{ + GIVEN { + PLAYER(SPECIES_WOBBUFFET) { Item(ITEM_EJECT_PACK); }; + PLAYER(SPECIES_WYNAUT); + OPPONENT(SPECIES_GOODRA_HISUI) { Ability(ABILITY_GOOEY); }; + } WHEN { + TURN { MOVE(player, MOVE_U_TURN); SEND_OUT(player, 1); } + } SCENE { + NOT ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_HELD_ITEM_EFFECT, player); + ANIMATION(ANIM_TYPE_MOVE, MOVE_U_TURN, player); + HP_BAR(opponent); + SEND_IN_MESSAGE("Wynaut"); + } +} From fe2d7442af2004783358e2106a766d49f175cbce Mon Sep 17 00:00:00 2001 From: hedara90 <90hedara@gmail.com> Date: Sat, 3 May 2025 10:54:49 +0200 Subject: [PATCH 03/11] Remove old slide workaround (#6754) Co-authored-by: Hedara --- data/battle_scripts_2.s | 10 ++++------ include/battle.h | 1 - include/constants/battle.h | 6 ++++++ src/battle_script_commands.c | 11 ++--------- 4 files changed, 12 insertions(+), 16 deletions(-) diff --git a/data/battle_scripts_2.s b/data/battle_scripts_2.s index 572d076fab..27e3706e3f 100644 --- a/data/battle_scripts_2.s +++ b/data/battle_scripts_2.s @@ -265,13 +265,12 @@ BattleScript_ActionWallyThrow: end2 BattleScript_TrainerASlideMsgRet:: - handletrainerslidemsg BS_SCRIPTING, 0 trainerslidein BS_OPPONENT1 - handletrainerslidemsg BS_SCRIPTING, 1 + handletrainerslidemsg BS_SCRIPTING, PRINT_SLIDE_MESSAGE waitstate trainerslideout BS_OPPONENT1 waitstate - handletrainerslidemsg BS_SCRIPTING, 2 + handletrainerslidemsg BS_SCRIPTING, RESTORE_BATTLER_SLIDE_CONTROL return BattleScript_TrainerASlideMsgEnd2:: @@ -279,13 +278,12 @@ BattleScript_TrainerASlideMsgEnd2:: end2 BattleScript_TrainerBSlideMsgRet:: - handletrainerslidemsg BS_SCRIPTING, 0 trainerslidein BS_OPPONENT2 - handletrainerslidemsg BS_SCRIPTING, 1 + handletrainerslidemsg BS_SCRIPTING, PRINT_SLIDE_MESSAGE waitstate trainerslideout BS_OPPONENT2 waitstate - handletrainerslidemsg BS_SCRIPTING, 2 + handletrainerslidemsg BS_SCRIPTING, RESTORE_BATTLER_SLIDE_CONTROL return BattleScript_TrainerBSlideMsgEnd2:: diff --git a/include/battle.h b/include/battle.h index 49bd92cb1c..8874857efb 100644 --- a/include/battle.h +++ b/include/battle.h @@ -825,7 +825,6 @@ struct BattleStruct u8 usedMicleBerry; struct MessageStatus slideMessageStatus; u8 trainerSlideSpriteIds[MAX_BATTLERS_COUNT]; - u8 storeBattlerSpriteId; u16 opponentMonCanTera:6; u16 opponentMonCanDynamax:6; u16 padding:4; diff --git a/include/constants/battle.h b/include/constants/battle.h index 3bc59e8773..86226013d5 100644 --- a/include/constants/battle.h +++ b/include/constants/battle.h @@ -605,4 +605,10 @@ enum StartingStatus STARTING_STATUS_SWAMP_OPPONENT, }; +enum SlideMsgStates +{ + PRINT_SLIDE_MESSAGE, + RESTORE_BATTLER_SLIDE_CONTROL, +}; + #endif // GUARD_CONSTANTS_BATTLE_H diff --git a/src/battle_script_commands.c b/src/battle_script_commands.c index c9db4dbc99..03680aa5fc 100644 --- a/src/battle_script_commands.c +++ b/src/battle_script_commands.c @@ -11128,20 +11128,13 @@ static void Cmd_various(void) case VARIOUS_HANDLE_TRAINER_SLIDE_MSG: { VARIOUS_ARGS(u8 case_); - if (cmd->case_ == 0) - { - // Save sprite IDs, because trainer slide in will overwrite gBattlerSpriteIds variable. - gBattleStruct->storeBattlerSpriteId = (gBattlerSpriteIds[battler] & 0xFF) | (gBattlerSpriteIds[BATTLE_PARTNER(battler)] << 8); - } - else if (cmd->case_ == 1) + if (cmd->case_ == PRINT_SLIDE_MESSAGE) { BtlController_EmitPrintString(battler, BUFFER_A, STRINGID_TRAINERSLIDE); MarkBattlerForControllerExec(battler); } - else + else if (cmd->case_ == RESTORE_BATTLER_SLIDE_CONTROL) { - gBattlerSpriteIds[BATTLE_PARTNER(battler)] = gBattleStruct->storeBattlerSpriteId >> 8; - gBattlerSpriteIds[battler] = gBattleStruct->storeBattlerSpriteId & 0xFF; if (IsBattlerAlive(battler)) { SetBattlerShadowSpriteCallback(battler, gBattleMons[battler].species); From 904b399a8129d149fb3591bbcf57943a7f9441b7 Mon Sep 17 00:00:00 2001 From: PCG <75729017+PCG06@users.noreply.github.com> Date: Sun, 4 May 2025 15:13:57 +0530 Subject: [PATCH 04/11] Added Egg Moves for Basculin White Striped (#6769) --- src/data/pokemon/egg_moves.h | 7 +++++++ src/data/pokemon/species_info/gen_5_families.h | 1 + 2 files changed, 8 insertions(+) diff --git a/src/data/pokemon/egg_moves.h b/src/data/pokemon/egg_moves.h index 23c233de58..392d2a0549 100644 --- a/src/data/pokemon/egg_moves.h +++ b/src/data/pokemon/egg_moves.h @@ -4278,6 +4278,13 @@ static const u16 sBasculinEggMoveLearnset[] = { MOVE_HEAD_SMASH, MOVE_UNAVAILABLE, }; +#if P_HISUIAN_FORMS +static const u16 sBasculinWhiteStripedEggMoveLearnset[] = { + MOVE_ENDEAVOR, + MOVE_LAST_RESPECTS, + MOVE_UNAVAILABLE, +}; +#endif //P_HISUIAN_FORMS #endif //P_FAMILY_BASCULIN #if P_FAMILY_SANDILE diff --git a/src/data/pokemon/species_info/gen_5_families.h b/src/data/pokemon/species_info/gen_5_families.h index d55a7bf1d0..f1df023cec 100644 --- a/src/data/pokemon/species_info/gen_5_families.h +++ b/src/data/pokemon/species_info/gen_5_families.h @@ -4440,6 +4440,7 @@ const struct SpeciesInfo gSpeciesInfoGen5[] = ) .levelUpLearnset = sBasculinWhiteStripedLevelUpLearnset, .teachableLearnset = sBasculinWhiteStripedTeachableLearnset, + .eggMoveLearnset = sBasculinWhiteStripedEggMoveLearnset, .formSpeciesIdTable = sBasculinFormSpeciesIdTable, .evolutions = EVOLUTION({EVO_RECOIL_DAMAGE_MALE, 294, SPECIES_BASCULEGION_M}, {EVO_RECOIL_DAMAGE_FEMALE, 294, SPECIES_BASCULEGION_F}), From 110bc338d9cfb8af746d6d145ff2736f7b0dd3f0 Mon Sep 17 00:00:00 2001 From: ExMingYan <2264568487@qq.com> Date: Mon, 5 May 2025 01:58:05 +0800 Subject: [PATCH 05/11] =?UTF-8?q?makefile=E5=A2=9E=E5=8A=A0=E4=BD=BF?= =?UTF-8?q?=E7=94=A8readelf=E7=94=9F=E6=88=90no$gba=E4=BD=BF=E7=94=A8?= =?UTF-8?q?=E7=9A=84=E7=AC=A6=E5=8F=B7=E8=A1=A8=E5=91=BD=E4=BB=A4=EF=BC=9A?= =?UTF-8?q?make=20nosyms?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Makefile | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/Makefile b/Makefile index f2128cc25d..af7d69d919 100644 --- a/Makefile +++ b/Makefile @@ -50,6 +50,7 @@ endif PREFIX := arm-none-eabi- OBJCOPY := $(PREFIX)objcopy OBJDUMP := $(PREFIX)objdump +READELF := $(PREFIX)readelf AS := $(PREFIX)as LD := $(PREFIX)ld @@ -86,6 +87,7 @@ endif ELF := $(ROM:.gba=.elf) MAP := $(ROM:.gba=.map) SYM := $(ROM:.gba=.sym) +NOCASHSYM := $(ROM.gba=.sym) # Commonly used directories C_SUBDIR = src @@ -294,6 +296,8 @@ endif syms: $(SYM) +nosyms: $(NOCASHSYM) + clean: tidy clean-tools clean-check-tools clean-generated clean-assets @$(MAKE) clean -C libagbsyscall @@ -465,3 +469,7 @@ $(ROM): $(ELF) # Symbol file (`make syms`) $(SYM): $(ELF) $(OBJDUMP) -t $< | sort -u | grep -E "^0[2389]" | $(PERL) -p -e 's/^(\w{8}) (\w).{6} \S+\t(\w{8}) (\S+)$$/\1 \2 \3 \4/g' > $@ + +# Symbol file (`make nosyms) +$(NOCASHSYM): $(ELF) + $(READELF) -Ws $< | tail -n +4 | awk '$4 !~/(FILE|NOTYPE)/ && $8 !~/^(\$|\.)/ {print $2,$8}' | sort -k 1 | awk '!seen[$1]++' > $@ From 952501992fe4a6f70e49bc905aeabd0b4897e4f3 Mon Sep 17 00:00:00 2001 From: ExMingYan <2264568487@qq.com> Date: Mon, 5 May 2025 02:06:25 +0800 Subject: [PATCH 06/11] =?UTF-8?q?=E4=BF=AE=E6=AD=A3=E7=94=9F=E6=88=90no$gb?= =?UTF-8?q?a=E4=BD=BF=E7=94=A8=E7=9A=84=E7=AC=A6=E5=8F=B7=E8=A1=A8?= =?UTF-8?q?=E5=91=BD=E4=BB=A4=E4=B8=AD=E7=9A=84=E8=AF=AD=E6=B3=95=E9=94=99?= =?UTF-8?q?=E8=AF=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Makefile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Makefile b/Makefile index af7d69d919..aaa8e9db4a 100644 --- a/Makefile +++ b/Makefile @@ -87,7 +87,7 @@ endif ELF := $(ROM:.gba=.elf) MAP := $(ROM:.gba=.map) SYM := $(ROM:.gba=.sym) -NOCASHSYM := $(ROM.gba=.sym) +NOCASHSYM := $(ROM:.gba=.sym) # Commonly used directories C_SUBDIR = src @@ -472,4 +472,4 @@ $(SYM): $(ELF) # Symbol file (`make nosyms) $(NOCASHSYM): $(ELF) - $(READELF) -Ws $< | tail -n +4 | awk '$4 !~/(FILE|NOTYPE)/ && $8 !~/^(\$|\.)/ {print $2,$8}' | sort -k 1 | awk '!seen[$1]++' > $@ + $(READELF) -Ws $< | tail -n +4 | awk '$$4 !~/(FILE|NOTYPE)/ && $$8 !~/^(\$$|\.)/ {print $$2,$$8}' | sort -k 1 | awk '!seen[$$1]++' > $@ From 0a4efa9b4598cd0b500661e35ee2a91fea0c0460 Mon Sep 17 00:00:00 2001 From: ExMingYan <2264568487@qq.com> Date: Mon, 5 May 2025 02:44:56 +0800 Subject: [PATCH 07/11] =?UTF-8?q?WSL=5FZH.md=E5=8A=A0=E5=85=A5=E9=83=A8?= =?UTF-8?q?=E5=88=86=E9=94=99=E8=AF=AF=E8=A7=A3=E5=86=B3=E6=96=B9=E6=B3=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/install/windows/WSL_ZH.md | 36 ++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/docs/install/windows/WSL_ZH.md b/docs/install/windows/WSL_ZH.md index 991de2a25c..8fc5ede07b 100644 --- a/docs/install/windows/WSL_ZH.md +++ b/docs/install/windows/WSL_ZH.md @@ -113,4 +113,40 @@ mkdir decomps ```bash cd ~/decomps +``` + +## WSL更新或安装依赖时错误解决 + +更新WSL安装依赖项时如果出现以下错误提示 + +```console +E: Sub-process /usr/bin/dpkg returned an error code (1) +``` + +可先执行以下命令 + +```bash +sudo mv /var/lib/dpkg/info /var/lib/dpkg/info_old +sudo mkdir /var/lib/dpkg/info +``` + +等待命令执行完毕后再次运行更新WSL安装依赖项命令。更新或安装完毕后运行以下命令以恢复pkg信息 + +```bash +sudo mv /var/lib/dpkg/info_old/* /var/lib/dpkg/info/ +sudo rmdir /var/lib/dpkg/info_old +``` + +如果出现以下提示,并列出可移除的包名(以libllvm17t64为例) + +```console +The following package was automatically installed and is no longer required: + libllvm17t64 +``` + +可执行以下命令解决该提示 + +```bash +sudo apt autoremove +sudo apt install libllvm17t64 ``` \ No newline at end of file From 0742741dd3668dd2e38d8bb445b4f1cf23d75f81 Mon Sep 17 00:00:00 2001 From: spindrift64 <102487911+spindrift64@users.noreply.github.com> Date: Sun, 4 May 2025 22:26:12 +0200 Subject: [PATCH 08/11] Fix Life Orb inflicting self damage when using status moves (#6767) (#6773) --- src/battle_util.c | 1 + test/battle/hold_effect/life_orb.c | 16 ++++++++++++++++ 2 files changed, 17 insertions(+) diff --git a/src/battle_util.c b/src/battle_util.c index a9a976fb42..9bf82b0670 100644 --- a/src/battle_util.c +++ b/src/battle_util.c @@ -8202,6 +8202,7 @@ u32 ItemBattleEffects(enum ItemCaseId caseID, u32 battler, bool32 moveTurn) break; case HOLD_EFFECT_LIFE_ORB: if (IsBattlerAlive(gBattlerAttacker) + && !IsBattleMoveStatus(gCurrentMove) && (IsBattlerTurnDamaged(gBattlerTarget) || !(gBattleStruct->moveResultFlags[gBattlerTarget] & MOVE_RESULT_NO_EFFECT)) // Needs the second check in case of Substitute && !(TestIfSheerForceAffected(gBattlerAttacker, gCurrentMove)) && GetBattlerAbility(gBattlerAttacker) != ABILITY_MAGIC_GUARD diff --git a/test/battle/hold_effect/life_orb.c b/test/battle/hold_effect/life_orb.c index 61acd60660..f27ce29d03 100644 --- a/test/battle/hold_effect/life_orb.c +++ b/test/battle/hold_effect/life_orb.c @@ -15,3 +15,19 @@ SINGLE_BATTLE_TEST("Life Orb activates if it hits a Substitute") MESSAGE("Wobbuffet was hurt by the Life Orb!"); } } + +SINGLE_BATTLE_TEST("Life Orb does not activate if using a status move") +{ + GIVEN { + PLAYER(SPECIES_WOBBUFFET) { Item(ITEM_LIFE_ORB); } + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(player, MOVE_GROWL); } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_GROWL, player); + NONE_OF { + HP_BAR(player); + MESSAGE("Wobbuffet was hurt by the Life Orb!"); + } + } +} From cd2429f4e0469f33d856d5b4cbe7a5457e798f21 Mon Sep 17 00:00:00 2001 From: RoamerX <20692776+RoamerX@users.noreply.github.com> Date: Mon, 5 May 2025 14:44:01 +0800 Subject: [PATCH 09/11] =?UTF-8?q?NamingScreen=E6=8C=89=E9=92=AE=E9=AB=98?= =?UTF-8?q?=E5=85=89=E4=BF=AE=E5=A4=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 顺便汉化了遗漏的输入代码相关的一句英文 --- graphics/naming_screen/back_button.png | Bin 3694 -> 2054 bytes src/naming_screen.c | 2 +- 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/graphics/naming_screen/back_button.png b/graphics/naming_screen/back_button.png index 68e0acf8d6d58b4b59d3f9c064a26b375659c85d..460cb08ff775c9b9611246495ac2d544d4cac47d 100644 GIT binary patch literal 2054 zcmb_de{9rL9KQua03nJb%D_nJRHoAFYp=ato1Jj(#&*bUW4mN?&gkpwyIt8`TiR}S zgG3h)iCGpT8iLDWmT2NXhyzi?xgdYcKa4mdSyVI-%rgF10#Ra&8lA8A%VEZk5S#1u z_4V_<-_Q5^{e0hhwYjl=#j-Wad_LcbSVOdhJgdpQddVX4f4ZaT7xDnj+Y)s`d1L1xAeHB-g@T*e}3pRZ<9&Vr~LyOfH%bR$e(9Xm}^ zx)!F}#5jmswK%0W?6Ps|uEqq~)s1A0-t;6@lT(O+40a)v%cKoQ$%W~>U4@LjX_lt) z5Vt!_M?8mAd%T&dHEm2uevUx^07{bmFeC*yRo+PPfah2slOF?s5|ETYh$>z*ac65u zr6szh=#0FD>6GhQ3d?4*S${U*H|;K#BUxYp&+$;{uoCHL3Ato3SlZ=K0fssQRW(1%~f`BlOfL2-` zHBpaOS#Nzo<(i3zjeor&N#rGs7nmd`sZ1as1Q{4qB}NQzNaIx`1%qnIT9d7lMuX}3 zRy|f4u_$7sh5}NE5rd+@@S-3xG7RucNC@#s(k!ZkWKYd`fhY~SLrT|I?2lHwvp7oY zR9+JbM4r~eH1dj!Nj!yVeSv)3mgnO7Yzh;jHz|I>jbkR=EVOZ?i{$Q>;$m+^-hsV0 zr;d^umlS!8!76EcC<}mrDkP=kLP!>ZkW;Z#3VlBHvKV=VlS*Q|6Y9mZpcFK^Fxfd- z`p$#7JzW-9E*Q-G&iem?VZHsbpfL8o;>&-Vx3`i)=BLPp?G4LE1$ikSHrOC}vdK}h z@zg`!`FB1RjU=iM4xT%6d@r?p-=%f4{-NJqI=khY=ghH&m64~}waMvg4-c(BGk9?} z_S2!iE1sW}dn>7?(H}2cKlqNm)nBa)D?juf8|(bD?d`>%9N2#4+moZeAE>xE*;!A0y#LfI-f0`FYm6R!>V-Z302kn? AT>t<8 delta 3645 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 P0000 Date: Mon, 5 May 2025 15:33:45 +0800 Subject: [PATCH 10/11] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E4=B8=A4=E4=B8=AA?= =?UTF-8?q?=E8=B6=85=E9=93=BE=E6=8E=A5=E8=AF=AD=E6=B3=95=E9=94=99=E8=AF=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/README.md b/.github/README.md index ad763cf7d4..0f240e88a9 100644 --- a/.github/README.md +++ b/.github/README.md @@ -64,14 +64,14 @@ pokeemerald-expansion是基于pret的[pokeemerald](https://github.com/pret/pokee - 检查你的当前版本。 - 你可以在调试菜单的`Utilities -> Expansion Version`选项中检查。 - 如果该选项不可用,你可能拥有的是1.6.2或更早的版本。在那种情况下,请查看[更改日志](docs/CHANGELOG.md)以确定你的版本,基于你仓库中可用的功能。 -- ***重要提示***:如果你落后了几个版本,我们建议你一次更新一个小版本,而不是直接跳到最新的补丁版本(例如,1.5.3 -> 1.6.2 -> 1.7.4等等。查看在线文档网站](https://rh-hideout.github.io/pokeemerald-expansion/CHANGELOG.html)以查看每个步骤的最新版本。) +- ***重要提示***:如果你落后了几个版本,我们建议你一次更新一个小版本,而不是直接跳到最新的补丁版本(例如,1.5.3 -> 1.6.2 -> 1.7.4等等。[查看在线文档网站](https://rh-hideout.github.io/pokeemerald-expansion/CHANGELOG.html)以查看每个步骤的最新版本。) - 一旦你设置了远程仓库,请运行命令`git pull RHH expansion/X.Y.Z`,将X、Y和Z替换为你想要更新到的相应版本的数字(例如,要更新到1.11.1,请使用`git pull RHH expansion/1.11.1`)。 - ***重要提示***:如果你落后了几个版本,我们建议你一次更新一个小版本,而不是直接跳到最新的补丁版本(例如,1.5.3 -> 1.6.2 -> 1.7.4等等) - 另外,你可以更新到扩展的未发布版本。 - ***master(稳定版)***:它包含将在下一个补丁版本中发布的***bug修复***。要合并,请使用`git pull RHH master`。 - ***upcoming(不稳定版,可能存在bug)***:它包含将在下一个小版本中发布的***功能***。要合并,请使用`git pull RHH upcoming`。 -### 请考虑在你的项目中归功于整个贡献者名单](https://github.com/rh-hideout/pokeemerald-expansion/wiki/Credits),因为他们都为开发这个项目付出了辛勤的努力 :) +### 请考虑在你的项目中归功于整个[贡献者名单](https://github.com/rh-hideout/pokeemerald-expansion/wiki/Credits),因为他们都为开发这个项目付出了辛勤的努力 :) ## 谁在维护这个项目? @@ -246,4 +246,4 @@ pokeemerald-expansion是基于pret的[pokeemerald](https://github.com/pret/pokee - 《黑2/白2》及以后的驱虫喷雾系统,也支持《Let's Go!皮卡丘/伊布》中的香水。 - 第六世代及以后的努力值上限。 - 包含了pret的所有错误修复。 - - 修复了地图上的下雪天气效果。 \ No newline at end of file + - 修复了地图上的下雪天气效果。 From 5614d7b87fa5c4c9c36ffcf0a06a9eecba466c96 Mon Sep 17 00:00:00 2001 From: ExMingYan <2264568487@qq.com> Date: Mon, 5 May 2025 16:37:20 +0800 Subject: [PATCH 11/11] =?UTF-8?q?=E4=BF=AE=E6=94=B9py=E6=96=87=E4=BB=B6?= =?UTF-8?q?=E4=B8=AD=E8=B7=AF=E5=BE=84=E5=A4=84=E7=90=86=E7=9B=B8=E5=85=B3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- python_tools/test.py | 1 + python_tools/test_follow.py | 14 ++++++++++++-- python_tools/test_string_extract.py | 12 ++++++++++-- python_tools/translate_battle_message.py | 7 +++++-- python_tools/translate_debug.py | 5 +++-- python_tools/translate_decoration.py | 5 +++-- python_tools/translate_decoration2.py | 6 ++++-- python_tools/translate_items.py | 7 ++++--- python_tools/translate_pokemon.py | 8 ++++---- python_tools/translate_skills.py | 8 ++++---- python_tools/translate_string.py | 9 ++++----- 11 files changed, 54 insertions(+), 28 deletions(-) diff --git a/python_tools/test.py b/python_tools/test.py index db53d85da8..3da0158781 100644 --- a/python_tools/test.py +++ b/python_tools/test.py @@ -1,3 +1,4 @@ +#!/usr/bin/python python3 # 原始字符串 text = "全副武装的样子。\n即使是极巨化宝可梦的\n攻击也能轻易抵挡。" diff --git a/python_tools/test_follow.py b/python_tools/test_follow.py index a37a02974c..07b1f309bd 100644 --- a/python_tools/test_follow.py +++ b/python_tools/test_follow.py @@ -1,9 +1,19 @@ +#!/usr/bin/python python3 +import os import openpyxl import re +# 获取py文件所在文件夹绝对路径 +pydir = os.path.dirname(os.path.realpath(__file__)) + +#获取excel相对py文件路径 +excel_path = os.path.join(pydir, "src", "精灵跟随.xlsx") + +# 获取C文件所在文件夹相对py文件路径 +cdir = os.path.join(os.path.dirname(pydir), "src") + # 文件路径 -excel_path = r"c:\Users\Nox\Documents\GitHub\pokeemerald-expansion-Chinese\python_tools\src\精灵跟随.xlsx" -c_file_path = r"c:\Users\Nox\Documents\GitHub\pokeemerald-expansion-Chinese\src\follower_helper.c" +c_file_path = os.path.join(cdir, "follower_helper.c") # 读取 Excel 文件 wb = openpyxl.load_workbook(excel_path) diff --git a/python_tools/test_string_extract.py b/python_tools/test_string_extract.py index 1d26e42607..8ad841ac67 100644 --- a/python_tools/test_string_extract.py +++ b/python_tools/test_string_extract.py @@ -1,8 +1,16 @@ +#!/usr/bin/python python3 +import os import re +# 获取py文件所在文件夹绝对路径 +pydir = os.path.dirname(os.path.realpath(__file__)) + +# 获取C文件所在文件夹相对py文件路径 +cdir = os.path.join(os.path.dirname(pydir), "src") + # 文件路径 -input_file = r"c:\Users\Nox\Documents\GitHub\pokeemerald-expansion-Chinese\src\strings.c" -output_file = r"c:\Users\Nox\Documents\GitHub\pokeemerald-expansion-Chinese\extracted_strings.txt" +input_file = os.path.join(cdir, "strings.c") +output_file = os.path.join(os.path.dirname(pydir), "extracted_strings.txt") # 正则表达式匹配变量名和 _("...") 之间的内容 pattern = re.compile(r'const\s+u8\s+(\w+)\[\]\s*=\s*_\("([^"]*)"\)') diff --git a/python_tools/translate_battle_message.py b/python_tools/translate_battle_message.py index 9b895933ba..f41b913609 100644 --- a/python_tools/translate_battle_message.py +++ b/python_tools/translate_battle_message.py @@ -1,10 +1,13 @@ +#!/usr/bin/python python3 import re import os from openpyxl import load_workbook +pydir = os.path.dirname(os.path.abspath(__file__)) + # 文件路径 -c_file_path = os.path.dirname(os.path.abspath(__file__))+"/../src/battle_message.c" -xlsx_file_path = os.path.dirname(os.path.abspath(__file__))+"/src/战斗文本.xlsx" +c_file_path = os.path.join(os.path.dirname(pydir), "src", "battle_message.c") +xlsx_file_path = os.path.join(pydir, "src", "战斗文本.xlsx") # 读取 xlsx 文件并解析为字典 def load_translations(xlsx_file_path): diff --git a/python_tools/translate_debug.py b/python_tools/translate_debug.py index ac685988f8..8e7624d8d9 100644 --- a/python_tools/translate_debug.py +++ b/python_tools/translate_debug.py @@ -1,3 +1,4 @@ +#!/usr/bin/python python3 import re import openpyxl import os @@ -45,8 +46,8 @@ def replace_in_c_file(c_file, replacement_dict): # 主函数 def main(): current_folder = os.path.dirname(os.path.abspath(__file__)) - xlsx_file = current_folder+"/src/debug文本.xlsx" # Excel 文件路径 - c_file = current_folder+"/../src/battle_debug.c" # C 文件路径 + xlsx_file = os.path.join(current_folder, "src", "debug文本.xlsx") # Excel 文件路径 + c_file = os.path.join(os.path.dirname(current_folder), "src", "battle_debug.c") # C 文件路径 # 加载替换字典 replacement_dict = load_replacement_dict(xlsx_file) diff --git a/python_tools/translate_decoration.py b/python_tools/translate_decoration.py index 282f3ed249..1697847d53 100644 --- a/python_tools/translate_decoration.py +++ b/python_tools/translate_decoration.py @@ -1,11 +1,12 @@ +#!/usr/bin/python python3 import openpyxl import re import os # 文件路径 base_dir = os.path.dirname(os.path.abspath(__file__)) -h_file_path = os.path.join(base_dir, "../src/data/decoration/header.h") -xlsx_path = os.path.join(base_dir, "src/装饰物品.xlsx") +h_file_path = os.path.join(os.path.dirname(base_dir), "src", "data", "decoration", "header.h") +xlsx_path = os.path.join(base_dir, "src", "装饰物品.xlsx") # 加载Excel文件 wb = openpyxl.load_workbook(xlsx_path) diff --git a/python_tools/translate_decoration2.py b/python_tools/translate_decoration2.py index 2ea84296fc..906f1c91c6 100644 --- a/python_tools/translate_decoration2.py +++ b/python_tools/translate_decoration2.py @@ -1,10 +1,12 @@ +#!/usr/bin/python python3 import openpyxl import re import os # 文件路径 -h_file_path = os.path.dirname(os.path.abspath(__file__))+"/../src/data/decoration/description.h" -xlsx_path = os.path.dirname(os.path.abspath(__file__))+"/src/装饰物品.xlsx" +base_dir = os.path.dirname(os.path.abspath(__file__)) +h_file_path = os.path.join(os.path.dirname(base_dir), "src", "data", "decoration", "description.h") +xlsx_path = os.path.join(base_dir, "src", "装饰物品.xlsx") # 加载Excel文件 wb = openpyxl.load_workbook(xlsx_path) diff --git a/python_tools/translate_items.py b/python_tools/translate_items.py index 32d9f346c0..f7d59b2863 100644 --- a/python_tools/translate_items.py +++ b/python_tools/translate_items.py @@ -1,3 +1,4 @@ +#!/usr/bin/python python3 import os import re import pandas as pd @@ -60,13 +61,13 @@ def replace_item_info(content, df): return content def log(message): - with open(current_folder+"\log.txt", "a", encoding="utf-8") as log_file: + with open(os.path.join(current_folder, "log.txt"), "a", encoding="utf-8") as log_file: log_file.write(message + "\n") print(message) if __name__ == "__main__": - work_file = current_folder +"\..\src\data\items.h" - df = pd.read_excel(current_folder +r'\src\道具.xlsx') + work_file = os.path.join(os.path.dirname(current_folder), "src", "data", "items.h") + df = pd.read_excel(os.path.join(current_folder, "src", "道具.xlsx")) df.set_index('道具', inplace=True) diff --git a/python_tools/translate_pokemon.py b/python_tools/translate_pokemon.py index 58c98edbe0..f96ad05c85 100644 --- a/python_tools/translate_pokemon.py +++ b/python_tools/translate_pokemon.py @@ -1,3 +1,4 @@ +#!/usr/bin/python python3 import os import re import pandas as pd @@ -56,14 +57,13 @@ def replace_species_info(content, df): return content def log(message): - with open(current_folder+"\log.txt", "a", encoding="utf-8") as log_file: + with open(os.path.join(current_folder, "log.txt"), "a", encoding="utf-8") as log_file: log_file.write(message + "\n") print(message) if __name__ == "__main__": - - work_folder = current_folder +"\..\src\data\pokemon\species_info" - df = pd.read_excel(current_folder +r'\src\图鉴.xlsx') + work_folder = os.path.join(os.path.dirname(current_folder), "src", "data", "pokemon", "species_info") + df = pd.read_excel(os.path.join(current_folder, "src", "图鉴.xlsx")) df.set_index('name', inplace=True) for filename in os.listdir(work_folder): diff --git a/python_tools/translate_skills.py b/python_tools/translate_skills.py index 4e8a215fb5..a3b21ccf25 100644 --- a/python_tools/translate_skills.py +++ b/python_tools/translate_skills.py @@ -1,3 +1,4 @@ +#!/usr/bin/python python3 import os import re import pandas as pd @@ -60,14 +61,13 @@ def replace_move_info(content, df): return content def log(message): - with open(current_folder+"\log.txt", "a", encoding="utf-8") as log_file: + with open(os.path.join(current_folder, "log.txt"), "a", encoding="utf-8") as log_file: log_file.write(message + "\n") print(message) if __name__ == "__main__": - - work_file = current_folder +"\..\src\data\moves_info.h" - df = pd.read_excel(current_folder +r'\src\招式.xlsx') + work_file = os.path.join(os.path.dirname(current_folder), "src", "data", "moves_info.h") + df = pd.read_excel(os.path.join(current_folder, "src", "招式.xlsx")) df.set_index('招式', inplace=True) diff --git a/python_tools/translate_string.py b/python_tools/translate_string.py index 1783699a0a..5156ed61c3 100644 --- a/python_tools/translate_string.py +++ b/python_tools/translate_string.py @@ -1,4 +1,4 @@ - +#!/usr/bin/python python3 import os import re import pandas as pd @@ -44,13 +44,12 @@ def replace_move_info(content, df): return content def log(message): - with open(current_folder+"\log.txt", "a", encoding="utf-8") as log_file: + with open(os.path.join(current_folder, "log.txt"), "a", encoding="utf-8") as log_file: log_file.write(message + "\n") print(message) if __name__ == "__main__": - - work_file = current_folder +"\..\src\strings.c" - df = pd.read_excel(current_folder + r'\src\文本.xlsx') + work_file = os.path.join(os.path.dirname(current_folder), "src", "strings.c") + df = pd.read_excel(os.path.join(current_folder, "src", "文本.xlsx")) # 检查并清理重复的“变量名” df = df.drop_duplicates(subset='变量名', keep='first')