mirror of
https://github.com/pret/pokefirered.git
synced 2026-05-20 11:58:04 -05:00
Merge pull request #6 from cawtds/update-trainers-and-ai
Updated Trainers, AI and fixed 1v2 double battles
This commit is contained in:
commit
bb77330a35
File diff suppressed because it is too large
Load Diff
|
|
@ -14,9 +14,6 @@ PewterCity_Gym_Text_BrockIntro::
|
|||
.string "Fine, then!\n"
|
||||
.string "Show me your best!{PLAY_BGM}{MUS_ENCOUNTER_GYM_LEADER}$"
|
||||
|
||||
@ NOTE: This defeat text actually causes a buffer overflow. It's too long for the gDisplayedStringBattle
|
||||
@ buffer that it's put into, and it stomps all over the gBattleTextBuffs after, as well as the otherwise
|
||||
@ unused array after that, sFlickerArray. Perhaps that's the reason why said array exists.
|
||||
PewterCity_Gym_Text_BrockDefeat::
|
||||
.string "I took you for granted, and so\n"
|
||||
.string "I lost.\p"
|
||||
|
|
|
|||
|
|
@ -102,6 +102,7 @@ ViridianCity_Mart_Items::
|
|||
.2byte ITEM_MEGA_RING
|
||||
.2byte ITEM_CHARIZARDITE_X
|
||||
.2byte ITEM_CHARIZARDITE_Y
|
||||
.2byte ITEM_SILPH_SCOPE
|
||||
.2byte ITEM_NONE
|
||||
release
|
||||
end
|
||||
|
|
|
|||
304
include/battle.h
304
include/battle.h
|
|
@ -317,29 +317,75 @@ struct WishFutureKnock
|
|||
|
||||
extern struct WishFutureKnock gWishFutureKnock;
|
||||
|
||||
struct AI_SavedBattleMon
|
||||
{
|
||||
u16 ability;
|
||||
u16 moves[MAX_MON_MOVES];
|
||||
u16 heldItem;
|
||||
u16 species;
|
||||
u8 types[3];
|
||||
};
|
||||
|
||||
struct AiPartyMon
|
||||
{
|
||||
u16 species;
|
||||
u16 item;
|
||||
u16 heldEffect;
|
||||
u16 ability;
|
||||
u16 gender;
|
||||
u16 level;
|
||||
u16 moves[MAX_MON_MOVES];
|
||||
u32 status;
|
||||
bool8 isFainted;
|
||||
bool8 wasSentInBattle;
|
||||
u8 switchInCount; // Counts how many times this Pokemon has been sent out or switched into in a battle.
|
||||
};
|
||||
|
||||
struct AIPartyData // Opposing battlers - party mons.
|
||||
{
|
||||
struct AiPartyMon mons[NUM_BATTLE_SIDES][PARTY_SIZE]; // 2 parties(player, opponent). Used to save information on opposing party.
|
||||
u8 count[NUM_BATTLE_SIDES];
|
||||
};
|
||||
|
||||
struct SwitchinCandidate
|
||||
{
|
||||
struct BattlePokemon battleMon;
|
||||
bool8 hypotheticalStatus;
|
||||
};
|
||||
|
||||
// Ai Data used when deciding which move to use, computed only once before each turn's start.
|
||||
struct AiLogicData
|
||||
{
|
||||
u16 abilities[MAX_BATTLERS_COUNT];
|
||||
u16 items[MAX_BATTLERS_COUNT];
|
||||
u16 holdEffects[MAX_BATTLERS_COUNT];
|
||||
u8 holdEffectParams[MAX_BATTLERS_COUNT];
|
||||
u16 predictedMoves[MAX_BATTLERS_COUNT];
|
||||
u8 hpPercents[MAX_BATTLERS_COUNT];
|
||||
u16 partnerMove;
|
||||
u16 speedStats[MAX_BATTLERS_COUNT]; // Speed stats for all battles, calculated only once, same way as damages
|
||||
s32 simulatedDmg[MAX_BATTLERS_COUNT][MAX_BATTLERS_COUNT][MAX_MON_MOVES]; // attacker, target, moveIndex
|
||||
u8 effectiveness[MAX_BATTLERS_COUNT][MAX_BATTLERS_COUNT][MAX_MON_MOVES]; // attacker, target, moveIndex
|
||||
u8 moveAccuracy[MAX_BATTLERS_COUNT][MAX_BATTLERS_COUNT][MAX_MON_MOVES]; // attacker, target, moveIndex
|
||||
u8 moveLimitations[MAX_BATTLERS_COUNT];
|
||||
bool8 shouldSwitchMon; // Because all available moves have no/little effect. Each bit per battler.
|
||||
u8 monToSwitchId[MAX_BATTLERS_COUNT]; // ID of the mon to switch.
|
||||
bool8 weatherHasEffect; // The same as WEATHER_HAS_EFFECT. Stored here, so it's called only once.
|
||||
u8 mostSuitableMonId[MAX_BATTLERS_COUNT]; // Stores result of GetMostSuitableMonToSwitchInto, which decides which generic mon the AI would switch into if they decide to switch. This can be overruled by specific mons found in ShouldSwitch; the final resulting mon is stored in AI_monToSwitchIntoId.
|
||||
struct SwitchinCandidate switchinCandidate; // Struct used for deciding which mon to switch to in battle_ai_switch_items.c
|
||||
};
|
||||
|
||||
struct AI_ThinkingStruct
|
||||
{
|
||||
u8 aiState;
|
||||
u8 movesetIndex;
|
||||
u16 moveConsidered;
|
||||
s8 score[4];
|
||||
s32 score[MAX_MON_MOVES];
|
||||
u32 funcResult;
|
||||
u32 aiFlags;
|
||||
u32 aiFlags[MAX_BATTLERS_COUNT];
|
||||
u8 aiAction;
|
||||
u8 aiLogicId;
|
||||
u8 filler12[6];
|
||||
u8 simulatedRNG[4];
|
||||
};
|
||||
|
||||
extern u8 gBattlerTarget;
|
||||
extern u8 gAbsentBattlerFlags;
|
||||
|
||||
extern struct BattlePokemon gBattleMons[MAX_BATTLERS_COUNT];
|
||||
|
||||
struct UsedMoves
|
||||
{
|
||||
u16 moves[MAX_BATTLERS_COUNT];
|
||||
u16 unknown[MAX_BATTLERS_COUNT];
|
||||
struct AI_SavedBattleMon saved[MAX_BATTLERS_COUNT];
|
||||
};
|
||||
|
||||
#define AI_MOVE_HISTORY_COUNT 3
|
||||
|
|
@ -392,6 +438,11 @@ struct BattleResources
|
|||
|
||||
extern struct BattleResources *gBattleResources;
|
||||
|
||||
#define AI_THINKING_STRUCT ((struct AI_ThinkingStruct *)(gBattleResources->ai))
|
||||
#define AI_DATA ((struct AiLogicData *)(gBattleResources->aiData))
|
||||
#define AI_PARTY ((struct AIPartyData *)(gBattleResources->aiParty))
|
||||
#define BATTLE_HISTORY ((struct BattleHistory *)(gBattleResources->battleHistory))
|
||||
|
||||
struct BattleResults
|
||||
{
|
||||
u8 playerFaintCounter; // 0x0
|
||||
|
|
@ -502,165 +553,163 @@ struct BattleStruct
|
|||
{
|
||||
u8 turnEffectsTracker;
|
||||
u8 turnEffectsBattlerId;
|
||||
u8 filler2; // unused
|
||||
u8 turnCountersTracker;
|
||||
u16 wrappedMove[MAX_BATTLERS_COUNT];
|
||||
u8 moveTarget[MAX_BATTLERS_COUNT];
|
||||
u16 moveTarget[MAX_BATTLERS_COUNT];
|
||||
u32 expShareExpValue;
|
||||
u32 expValue;
|
||||
u8 expGettersOrder[PARTY_SIZE]; // First battlers which were sent out, then via exp-share
|
||||
u8 expGetterMonId;
|
||||
u8 field_11; // unused
|
||||
u8 expOrderId:3;
|
||||
u8 expGetterBattlerId:2;
|
||||
u8 teamGotExpMsgPrinted:1; // The 'Rest of your team got msg' has been printed.
|
||||
u8 givenExpMons; // Bits for enemy party's pokemon that gave exp to player's party.
|
||||
u8 expSentInMons; // As bits for player party mons - not including exp share mons.
|
||||
u8 wildVictorySong;
|
||||
u8 dynamicMoveType;
|
||||
u8 wrappedBy[MAX_BATTLERS_COUNT];
|
||||
u8 focusPunchBattlerId;
|
||||
u8 focusPunchBattlers; // as bits
|
||||
u8 battlerPreventingSwitchout;
|
||||
u8 moneyMultiplier;
|
||||
u8 moneyMultiplier:6;
|
||||
u8 moneyMultiplierItem:1;
|
||||
u8 moneyMultiplierMove:1;
|
||||
u8 savedTurnActionNumber;
|
||||
u8 switchInAbilitiesCounter;
|
||||
u8 faintedActionsState;
|
||||
u8 faintedActionsBattlerId;
|
||||
// balign 2
|
||||
u32 expValue;
|
||||
u8 scriptPartyIdx; // for printing the nickname
|
||||
u8 sentInPokes;
|
||||
bool8 selectionScriptFinished[MAX_BATTLERS_COUNT];
|
||||
u8 battlerPartyIndexes[MAX_BATTLERS_COUNT];
|
||||
u8 monToSwitchIntoId[MAX_BATTLERS_COUNT];
|
||||
u8 battlerPartyOrders[MAX_BATTLERS_COUNT][3];
|
||||
u8 battlerPartyOrders[MAX_BATTLERS_COUNT][PARTY_SIZE / 2];
|
||||
u8 runTries;
|
||||
u8 caughtMonNick[POKEMON_NAME_LENGTH + 1];
|
||||
u8 field_78; // unused
|
||||
u8 safariRockThrowCounter; // safariGoNearCounter in pokeemerald
|
||||
u8 safariBaitThrowCounter; // safariPkblThrowCounter in pokeemerald
|
||||
u8 safariEscapeFactor;
|
||||
u8 safariCatchFactor;
|
||||
u8 linkBattleVsSpriteId_V;
|
||||
u8 linkBattleVsSpriteId_S;
|
||||
u8 linkBattleVsSpriteId_V; // The letter "V"
|
||||
u8 linkBattleVsSpriteId_S; // The letter "S"
|
||||
u8 formToChangeInto;
|
||||
u8 chosenMovePositions[MAX_BATTLERS_COUNT];
|
||||
u8 stateIdAfterSelScript[MAX_BATTLERS_COUNT];
|
||||
u8 field_88; // unused
|
||||
u8 field_89; // unused
|
||||
u8 field_8A; // unused
|
||||
u8 playerPartyIdx;
|
||||
u8 field_8C; // unused
|
||||
u8 field_8D; // unused
|
||||
u8 prevSelectedPartySlot;
|
||||
u8 stringMoveType;
|
||||
u8 expGetterBattlerId;
|
||||
u8 field_90; // unused
|
||||
u8 absentBattlerFlags;
|
||||
u8 AI_monToSwitchIntoId[2];
|
||||
u8 simulatedInputState[4]; // used by Oak/Old Man/Pokedude controllers
|
||||
u8 lastTakenMove[MAX_BATTLERS_COUNT * 2 * 2]; // ask gamefreak why they declared it that way
|
||||
u16 hpOnSwitchout[2];
|
||||
u8 field_93; // related to choosing pokemon?
|
||||
u8 simulatedInputState[4]; // used by Oak/Old Man/Pokedude controllers, Wally States/Frames in pokeemerald
|
||||
u16 lastTakenMove[MAX_BATTLERS_COUNT]; // Last move that a battler was hit with.
|
||||
u16 hpOnSwitchout[NUM_BATTLE_SIDES];
|
||||
u32 savedBattleTypeFlags;
|
||||
u16 abilityPreventingSwitchout;
|
||||
u8 hpScale;
|
||||
u16 savedBattleTypeFlags;
|
||||
void (*savedCallback)(void);
|
||||
u16 synchronizeMoveEffect;
|
||||
u8 multiplayerId;
|
||||
u8 overworldWeatherDone;
|
||||
u8 atkCancellerTracker;
|
||||
bool8 anyMonHasTransformed;
|
||||
void (*savedCallback)(void);
|
||||
u16 usedHeldItems[PARTY_SIZE][NUM_BATTLE_SIDES]; // For each party member and side. For harvest, recycle
|
||||
u8 chosenItem[MAX_BATTLERS_COUNT]; // why is this an u8?
|
||||
u8 AI_itemType[2];
|
||||
u8 AI_itemFlags[2];
|
||||
u16 chosenItem[MAX_BATTLERS_COUNT];
|
||||
u16 choicedMove[MAX_BATTLERS_COUNT];
|
||||
u16 changedItems[MAX_BATTLERS_COUNT];
|
||||
u8 intimidateBattler;
|
||||
u8 switchInItemsCounter;
|
||||
u8 field_DA; // battle tower related
|
||||
u8 turnSideTracker;
|
||||
u8 fillerDC[0xDF-0xDC];
|
||||
u8 givenExpMons;
|
||||
u8 lastTakenMoveFrom[MAX_BATTLERS_COUNT][MAX_BATTLERS_COUNT];
|
||||
u8 wishPerishSongState;
|
||||
u8 wishPerishSongBattlerId;
|
||||
u8 lastAttackerToFaintOpponent;
|
||||
// align 4
|
||||
u16 lastTakenMoveFrom[MAX_BATTLERS_COUNT][MAX_BATTLERS_COUNT]; // a 2-D array [target][attacker]
|
||||
union {
|
||||
struct LinkBattlerHeader linkBattlerHeader;
|
||||
struct MultiPartnerMenuPokemon multiBattleMons[3];
|
||||
} multiBuffer;
|
||||
u8 itemPartyIndex[MAX_BATTLERS_COUNT];
|
||||
u8 itemMoveIndex[MAX_BATTLERS_COUNT];
|
||||
u8 padding_1E4[0x14];
|
||||
// pokeemerald
|
||||
u8 isSkyBattle:1;
|
||||
u8 wishPerishSongState;
|
||||
u8 wishPerishSongBattlerId;
|
||||
u8 overworldWeatherDone:1;
|
||||
u8 startingStatusDone:1;
|
||||
u8 isAtkCancelerForCalledMove:1; // Certain cases in atk canceler should only be checked once, when the original move is called, however others need to be checked the twice.
|
||||
u8 swapDamageCategory:1; // Photon Geyser, Shell Side Arm, Light That Burns the Sky
|
||||
u8 beatUpSlot:3;
|
||||
u8 pledgeMove:1;
|
||||
u8 terrainDone:1;
|
||||
u8 startingStatus; // status to apply at battle start. defined in constants/battle.h
|
||||
u8 startingStatusTimer;
|
||||
u8 atkCancellerTracker;
|
||||
u8 AI_monToSwitchIntoId[MAX_BATTLERS_COUNT];
|
||||
u8 alreadyStatusedMoveAttempt; // As bits for battlers; For example when using Thunder Wave on an already paralyzed Pokémon.
|
||||
u8 magnitudeBasePower;
|
||||
u8 presentBasePower;
|
||||
u8 sameMoveTurns[MAX_BATTLERS_COUNT]; // For Metronome, number of times the same moves has been SUCCESFULLY used.
|
||||
u8 lastMoveFailed; // as bits for each battler, for the sake of Stomping Tantrum
|
||||
bool8 ateBoost[MAX_BATTLERS_COUNT];
|
||||
u8 timesGotHit[NUM_BATTLE_SIDES][PARTY_SIZE];
|
||||
u8 supremeOverlordCounter[MAX_BATTLERS_COUNT];
|
||||
struct Illusion illusion[MAX_BATTLERS_COUNT];
|
||||
u8 trainerSlideFirstSTABMoveMsgState:2;
|
||||
u8 blunderPolicy:1; // should blunder policy activate
|
||||
u8 skyDropTargets[MAX_BATTLERS_COUNT]; // For Sky Drop, to account for if multiple Pokemon use Sky Drop in a double battle.
|
||||
u8 bonusCritStages[MAX_BATTLERS_COUNT]; // G-Max Chi Strike boosts crit stages of allies.
|
||||
u8 enduredDamage;
|
||||
u16 changedSpecies[NUM_BATTLE_SIDES][PARTY_SIZE]; // For forms when multiple mons can change into the same pokemon.
|
||||
u8 trainerSlideFirstCriticalHitMsgState:2;
|
||||
u8 trainerSlideFirstSuperEffectiveHitMsgState:2;
|
||||
u8 additionalEffectsCounter:4; // A counter for the additionalEffects applied by the current move in Cmd_setadditionaleffects
|
||||
u8 targetsDone[MAX_BATTLERS_COUNT]; // Each battler as a bit.
|
||||
u16 moveEffect2; // For Knock Off
|
||||
u8 stolenStats[NUM_BATTLE_STATS]; // hp byte is used for which stats to raise, other inform about by how many stages
|
||||
u8 stickySyrupdBy[MAX_BATTLERS_COUNT];
|
||||
u8 moneyMultiplierMove:1;
|
||||
struct LostItem itemLost[PARTY_SIZE]; // Player's team that had items consumed or stolen (two bytes per party member)
|
||||
u8 roostTypes[MAX_BATTLERS_COUNT][2];
|
||||
u8 savedBattlerTarget;
|
||||
u8 ateBerry[2]; // array id determined by side, each party pokemon as bit
|
||||
u16 overwrittenAbilities[MAX_BATTLERS_COUNT]; // abilities overwritten during battle (keep separate from battle history in case of switching)
|
||||
bool8 ateBoost[MAX_BATTLERS_COUNT];
|
||||
u8 activeAbilityPopUps; // as bits for each battler
|
||||
u8 abilityPopUpSpriteIds[MAX_BATTLERS_COUNT][2]; // two per battler
|
||||
bool8 throwingPokeBall;
|
||||
struct MegaEvolutionData mega;
|
||||
struct UltraBurstData burst;
|
||||
struct ZMoveData zmove;
|
||||
struct DynamaxData dynamax;
|
||||
u8 appearedInBattle; // Bitfield to track which Pokemon appeared in battle. Used for Burmy's form change
|
||||
bool8 allowedToChangeFormInWeather[PARTY_SIZE][NUM_BATTLE_SIDES]; // For each party member and side, used by Ice Face.
|
||||
u8 startingStatus; // status to apply at battle start. defined in constants/battle.h
|
||||
u8 startingStatusTimer;
|
||||
u8 transformZeroToHero[NUM_BATTLE_SIDES];
|
||||
u8 supersweetSyrup[NUM_BATTLE_SIDES];
|
||||
u8 intrepidSwordBoost[NUM_BATTLE_SIDES];
|
||||
u8 dauntlessShieldBoost[NUM_BATTLE_SIDES];
|
||||
const u8 *trainerSlideMsg;
|
||||
bool8 trainerSlideLowHpMsgDone;
|
||||
u8 introState;
|
||||
u8 ateBerry[2]; // 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 lastMoveFailed; // as bits for each battler, for the sake of Stomping Tantrum
|
||||
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];
|
||||
u16 hpBefore[MAX_BATTLERS_COUNT]; // Hp of battlers before using a move. For Berserk and Anger Shell.
|
||||
u8 friskedBattler; // Frisk needs to identify 2 battlers in double battles.
|
||||
bool8 friskedAbility; // If identifies two mons, show the ability pop-up only once.
|
||||
bool8 spriteIgnore0Hp;
|
||||
u8 moneyMultiplierItem:1;
|
||||
u8 expGettersOrder[PARTY_SIZE]; // First battlers which were sent out, then via exp-share
|
||||
u32 expShareExpValue;
|
||||
u8 expOrderId:3;
|
||||
u8 expSentInMons; // As bits for player party mons - not including exp share mons.
|
||||
u8 teamGotExpMsgPrinted:1; // The 'Rest of your team got msg' has been printed.
|
||||
u8 roostTypes[MAX_BATTLERS_COUNT][2];
|
||||
u8 lastMoveTarget[MAX_BATTLERS_COUNT]; // The last target on which each mon used a move, for the sake of Instruct
|
||||
u8 attackerBeforeBounce:2;
|
||||
bool8 hitSwitchTargetFailed:1;
|
||||
u8 storedHealingWish:4; // Each battler as a bit.
|
||||
u8 storedLunarDance:4; // Each battler as a bit.
|
||||
u8 forcedSwitch:4; // For each battler
|
||||
u8 alreadyStatusedMoveAttempt; // As bits for battlers; For example when using Thunder Wave on an already paralyzed Pokémon.
|
||||
u8 soulheartBattlerId;
|
||||
const u8 *trainerSlideMsg;
|
||||
u8 battleBondTransformed[NUM_BATTLE_SIDES]; // Bitfield for each party.
|
||||
u8 quickClawBattlerId;
|
||||
bool8 effectsBeforeUsingMoveDone:1; // Mega Evo and Focus Punch/Shell Trap effects.
|
||||
u8 focusPunchBattlers; // as bits
|
||||
u8 quickClawRandom[MAX_BATTLERS_COUNT];
|
||||
u8 quickDrawRandom[MAX_BATTLERS_COUNT];
|
||||
bool8 throwingPokeBall;
|
||||
struct Illusion illusion[MAX_BATTLERS_COUNT];
|
||||
s32 aiFinalScore[MAX_BATTLERS_COUNT][MAX_BATTLERS_COUNT][MAX_MON_MOVES]; // AI, target, moves to make debugging easier
|
||||
u8 aiMoveOrAction[MAX_BATTLERS_COUNT];
|
||||
u8 aiChosenTarget[MAX_BATTLERS_COUNT];
|
||||
// pokeemerald unknown use
|
||||
u8 field_93; // related to choosing pokemon? probably related to recording
|
||||
u8 soulheartBattlerId;
|
||||
u8 friskedBattler; // Frisk needs to identify 2 battlers in double battles.
|
||||
bool8 friskedAbility; // If identifies two mons, show the ability pop-up only once.
|
||||
u8 sameMoveTurns[MAX_BATTLERS_COUNT]; // For Metronome, number of times the same moves has been SUCCESFULLY used.
|
||||
u16 moveEffect2; // For Knock Off
|
||||
u16 changedSpecies[NUM_BATTLE_SIDES][PARTY_SIZE]; // For forms when multiple mons can change into the same pokemon.
|
||||
u8 quickClawBattlerId;
|
||||
struct LostItem itemLost[PARTY_SIZE]; // Player's team that had items consumed or stolen (two bytes per party member)
|
||||
u8 forcedSwitch:4; // For each battler
|
||||
u8 additionalEffectsCounter:4; // A counter for the additionalEffects applied by the current move in Cmd_setadditionaleffects
|
||||
u8 blunderPolicy:1; // should blunder policy activate
|
||||
u8 swapDamageCategory:1; // Photon Geyser, Shell Side Arm, Light That Burns the Sky
|
||||
u8 bouncedMoveIsUsed:1;
|
||||
u8 ballSpriteIds[2]; // item gfx, window gfx
|
||||
u8 appearedInBattle; // Bitfield to track which Pokemon appeared in battle. Used for Burmy's form change
|
||||
u8 skyDropTargets[MAX_BATTLERS_COUNT]; // For Sky Drop, to account for if multiple Pokemon use Sky Drop in a double battle.
|
||||
// When using a move which hits multiple opponents which is then bounced by a target, we need to make sure, the move hits both opponents, the one with bounce, and the one without.
|
||||
u8 attackerBeforeBounce:2;
|
||||
u8 beatUpSlot:3;
|
||||
bool8 hitSwitchTargetFailed:1;
|
||||
bool8 effectsBeforeUsingMoveDone:1; // Mega Evo and Focus Punch/Shell Trap effects.
|
||||
u8 targetsDone[MAX_BATTLERS_COUNT]; // Each battler as a bit.
|
||||
u16 overwrittenAbilities[MAX_BATTLERS_COUNT]; // abilities overwritten during battle (keep separate from battle history in case of switching)
|
||||
bool8 allowedToChangeFormInWeather[PARTY_SIZE][NUM_BATTLE_SIDES]; // For each party member and side, used by Ice Face.
|
||||
u8 battleBondTransformed[NUM_BATTLE_SIDES]; // Bitfield for each party.
|
||||
u8 storedHealingWish:4; // Each battler as a bit.
|
||||
u8 storedLunarDance:4; // Each battler as a bit.
|
||||
u8 bonusCritStages[MAX_BATTLERS_COUNT]; // G-Max Chi Strike boosts crit stages of allies.
|
||||
u8 itemPartyIndex[MAX_BATTLERS_COUNT];
|
||||
u8 itemMoveIndex[MAX_BATTLERS_COUNT];
|
||||
u8 trainerSlideFirstCriticalHitMsgState:2;
|
||||
u8 trainerSlideFirstSuperEffectiveHitMsgState:2;
|
||||
u8 trainerSlideFirstSTABMoveMsgState:2;
|
||||
u8 trainerSlidePlayerMonUnaffectedMsgState:2;
|
||||
u8 trainerSlideHalfHpMsgDone:1;
|
||||
u8 trainerSlideMegaEvolutionMsgDone:1;
|
||||
u8 trainerSlideZMoveMsgDone:1;
|
||||
u8 trainerSlideBeforeFirstTurnMsgDone:1;
|
||||
u8 trainerSlideDynamaxMsgDone:1;
|
||||
u8 pledgeMove:1;
|
||||
u8 isSkyBattle:1;
|
||||
u32 aiDelayTimer; // Counts number of frames AI takes to choose an action.
|
||||
u32 aiDelayFrames; // Number of frames it took to choose an action.
|
||||
u8 timesGotHit[NUM_BATTLE_SIDES][PARTY_SIZE];
|
||||
u8 enduredDamage;
|
||||
u8 transformZeroToHero[NUM_BATTLE_SIDES];
|
||||
u8 stickySyrupdBy[MAX_BATTLERS_COUNT];
|
||||
u8 intrepidSwordBoost[NUM_BATTLE_SIDES];
|
||||
u8 dauntlessShieldBoost[NUM_BATTLE_SIDES];
|
||||
u8 supersweetSyrup[NUM_BATTLE_SIDES];
|
||||
u8 supremeOverlordCounter[MAX_BATTLERS_COUNT];
|
||||
u8 quickClawRandom[MAX_BATTLERS_COUNT];
|
||||
u8 quickDrawRandom[MAX_BATTLERS_COUNT];
|
||||
// pokefirered
|
||||
u8 field_DA; // battle tower related
|
||||
u8 lastAttackerToFaintOpponent;
|
||||
};
|
||||
|
||||
extern struct BattleStruct *gBattleStruct;
|
||||
|
|
@ -824,6 +873,9 @@ struct BattleHealthboxInfo
|
|||
u8 triedShinyMonAnim : 1; // x80
|
||||
u8 finishedShinyMonAnim : 1; // x1
|
||||
u8 opponentDrawPartyStatusSummaryDelay : 5; // x2
|
||||
u8 bgmRestored:1;
|
||||
u8 waitForCry:1;
|
||||
u8 healthboxSlideInStarted:1;
|
||||
u8 healthboxBounceSpriteId;
|
||||
u8 battlerBounceSpriteId;
|
||||
u8 animationState;
|
||||
|
|
@ -865,7 +917,7 @@ extern u8 *gLinkBattleRecvBuffer;
|
|||
struct MonSpritesGfx
|
||||
{
|
||||
void *firstDecompressed; // ptr to the decompressed sprite of the first pokemon
|
||||
void *sprites[MAX_BATTLERS_COUNT];
|
||||
u8 *sprites[MAX_BATTLERS_COUNT];
|
||||
struct SpriteTemplate templates[MAX_BATTLERS_COUNT];
|
||||
struct SpriteFrameImage images[MAX_BATTLERS_COUNT][4];
|
||||
u8 field_F4[0x80 - (4 * MAX_BATTLERS_COUNT)]; // unused, original - spritesGfx
|
||||
|
|
@ -929,10 +981,7 @@ extern bool8 gTransformedShininess[MAX_BATTLERS_COUNT];
|
|||
extern u8 gBattlerPositions[MAX_BATTLERS_COUNT];
|
||||
extern u8 gHealthboxSpriteIds[MAX_BATTLERS_COUNT];
|
||||
extern u8 gBattleOutcome;
|
||||
extern u8 gBattleMonForms[MAX_BATTLERS_COUNT];
|
||||
extern u32 gBattleControllerExecFlags;
|
||||
// extern u8 gBattleBufferA[MAX_BATTLERS_COUNT][0x200];
|
||||
// extern u8 gBattleBufferB[MAX_BATTLERS_COUNT][0x200];
|
||||
extern u8 gActionSelectionCursor[MAX_BATTLERS_COUNT];
|
||||
extern void (*gPreBattleCallback1)(void);
|
||||
extern bool8 gDoingBattleAnim;
|
||||
|
|
@ -942,6 +991,7 @@ extern u8 *gBattleAnimBgTilemapBuffer;
|
|||
extern void (*gBattleMainFunc)(void);
|
||||
extern u8 gMoveSelectionCursor[MAX_BATTLERS_COUNT];
|
||||
extern u8 gBattlerAttacker;
|
||||
extern u8 gBattlerTarget;
|
||||
extern u8 gEffectBattler;
|
||||
extern u8 gMultiHitCounter;
|
||||
extern struct BattleScripting gBattleScripting;
|
||||
|
|
@ -999,6 +1049,8 @@ extern u8 gLastUsedBall;
|
|||
extern u16 gLastThrownBall;
|
||||
extern u16 gBallToDisplay;
|
||||
extern struct QueuedStatBoost gQueuedStatBoosts[MAX_BATTLERS_COUNT];
|
||||
extern struct BattlePokemon gBattleMons[MAX_BATTLERS_COUNT];
|
||||
extern u8 gAbsentBattlerFlags;
|
||||
|
||||
static inline u32 GetBattlerPosition(u32 battler)
|
||||
{
|
||||
|
|
|
|||
96
include/battle_ai_main.h
Normal file
96
include/battle_ai_main.h
Normal file
|
|
@ -0,0 +1,96 @@
|
|||
#ifndef GUARD_BATTLE_AI_MAIN_H
|
||||
#define GUARD_BATTLE_AI_MAIN_H
|
||||
|
||||
#define UNKNOWN_NO_OF_HITS UINT32_MAX
|
||||
|
||||
// return vals for BattleAI_ChooseMoveOrAction
|
||||
// 0 - 3 are move idx
|
||||
#define AI_CHOICE_FLEE 4
|
||||
#define AI_CHOICE_WATCH 5
|
||||
#define AI_CHOICE_SWITCH 7
|
||||
|
||||
// for AI_WhoStrikesFirst
|
||||
#define AI_IS_FASTER 1
|
||||
#define AI_IS_SLOWER -1
|
||||
|
||||
// for stat increasing / decreasing scores
|
||||
#define STAT_CHANGE_ATK 0
|
||||
#define STAT_CHANGE_DEF 1
|
||||
#define STAT_CHANGE_SPEED 2
|
||||
#define STAT_CHANGE_SPATK 3
|
||||
#define STAT_CHANGE_SPDEF 4
|
||||
|
||||
#define STAT_CHANGE_ATK_2 5
|
||||
#define STAT_CHANGE_DEF_2 6
|
||||
#define STAT_CHANGE_SPEED_2 7
|
||||
#define STAT_CHANGE_SPATK_2 8
|
||||
#define STAT_CHANGE_SPDEF_2 9
|
||||
|
||||
#define STAT_CHANGE_ACC 10
|
||||
#define STAT_CHANGE_EVASION 11
|
||||
|
||||
#define BEST_DAMAGE_MOVE 1 // Move with the most amount of hits with the best accuracy/effect
|
||||
#define POWERFUL_STATUS_MOVE 10 // Moves with this score will be chosen over a move that faints target
|
||||
|
||||
// Temporary scores that are added together to determine a final score at the at of AI_CalcMoveScore
|
||||
#define WEAK_EFFECT 1
|
||||
#define DECENT_EFFECT 2
|
||||
#define GOOD_EFFECT 4
|
||||
#define BEST_EFFECT 6
|
||||
|
||||
// AI_CalcMoveScore final score
|
||||
#define NOT_GOOD_ENOUGH 0 // Not worth using over a damaging move
|
||||
#define GOOD_MOVE_EFFECTS 2 // Worth using over a damaging move
|
||||
#define PREFERRED_MOVE_EFFECTS 3 // Worth using over a damagin move and is better then DECENT_EFFECT
|
||||
#define BEST_MOVE_EFFECTS 4 // Best possible move effects. E.g. stat boosting moves that boost multiply moves
|
||||
|
||||
// AI_TryToFaint
|
||||
#define FAST_KILL 6 // AI is faster and faints target
|
||||
#define SLOW_KILL 4 // AI is slower and faints target
|
||||
#define LAST_CHANCE 2 // AI faints to target. It should try and do damage with a priority move
|
||||
|
||||
|
||||
// Logs for debugging AI tests.
|
||||
#define SET_SCORE(battler, movesetIndex, val) \
|
||||
do \
|
||||
{ \
|
||||
AI_THINKING_STRUCT->score[movesetIndex] = val; \
|
||||
} while (0) \
|
||||
|
||||
#define ADJUST_SCORE(val) \
|
||||
do \
|
||||
{ \
|
||||
score += val; \
|
||||
} while (0) \
|
||||
|
||||
#define ADJUST_SCORE_PTR(val) \
|
||||
do \
|
||||
{ \
|
||||
(*score) += val; \
|
||||
} while (0) \
|
||||
|
||||
#define RETURN_SCORE_PLUS(val) \
|
||||
{ \
|
||||
ADJUST_SCORE(val); \
|
||||
return score; \
|
||||
}
|
||||
|
||||
#define RETURN_SCORE_MINUS(val) \
|
||||
{ \
|
||||
ADJUST_SCORE(-val); \
|
||||
return score; \
|
||||
}
|
||||
|
||||
u32 ComputeBattleAiScores(u32 battler);
|
||||
void BattleAI_SetupItems(void);
|
||||
void BattleAI_SetupFlags(void);
|
||||
void BattleAI_SetupAIData(u8 defaultScoreMoves, u32 battler);
|
||||
u32 BattleAI_ChooseMoveOrAction(void);
|
||||
void Ai_InitPartyStruct(void);
|
||||
void Ai_UpdateSwitchInData(u32 battler);
|
||||
void Ai_UpdateFaintData(u32 battler);
|
||||
void SetAiLogicDataForTurn(struct AiLogicData *aiData);
|
||||
|
||||
extern u8 sBattler_AI;
|
||||
|
||||
#endif // GUARD_BATTLE_AI_MAIN_H
|
||||
|
|
@ -1,22 +0,0 @@
|
|||
#ifndef GUARD_BATTLE_AI_SCRIPT_COMMANDS_H
|
||||
#define GUARD_BATTLE_AI_SCRIPT_COMMANDS_H
|
||||
|
||||
#include "global.h"
|
||||
|
||||
// return values for BattleAI_ChooseMoveOrAction
|
||||
// 0 - 3 are move idx
|
||||
#define AI_CHOICE_FLEE 4
|
||||
#define AI_CHOICE_WATCH 5
|
||||
#define AI_CHOICE_SWITCH 7
|
||||
|
||||
void BattleAI_HandleItemUseBeforeAISetup(void);
|
||||
void BattleAI_SetupAIData(u32 battler);
|
||||
u8 BattleAI_ChooseMoveOrAction(void);
|
||||
void ClearBankMoveHistory(u8 bank);
|
||||
void RecordAbilityBattle(u32 bank, u32 abilityId);
|
||||
void ClearBankAbilityHistory(u8 bank);
|
||||
void RecordItemEffectBattle(u32 bank, u32 itemEffect);
|
||||
void ClearBankItemEffectHistory(u8 bank);
|
||||
u8 BattleAI_ChooseMoveOrAction(void);
|
||||
|
||||
#endif // GUARD_BATTLE_AI_SCRIPT_COMMANDS_H
|
||||
|
|
@ -1,27 +1,9 @@
|
|||
#ifndef GUARD_BATTLE_AI_SWITCH_ITEMS_H
|
||||
#define GUARD_BATTLE_AI_SWITCH_ITEMS_H
|
||||
|
||||
#include "global.h"
|
||||
|
||||
enum {
|
||||
AI_ITEM_FULL_RESTORE = 1,
|
||||
AI_ITEM_HEAL_HP,
|
||||
AI_ITEM_CURE_CONDITION,
|
||||
AI_ITEM_X_STAT,
|
||||
AI_ITEM_GUARD_SPECS,
|
||||
AI_ITEM_NOT_RECOGNIZABLE
|
||||
};
|
||||
|
||||
enum {
|
||||
AI_HEAL_CONFUSION,
|
||||
AI_HEAL_PARALYSIS,
|
||||
AI_HEAL_FREEZE,
|
||||
AI_HEAL_BURN,
|
||||
AI_HEAL_POISON,
|
||||
AI_HEAL_SLEEP,
|
||||
};
|
||||
|
||||
void GetAIPartyIndexes(u32 battlerId, s32 *firstId, s32 *lastId);
|
||||
void AI_TrySwitchOrUseItem(u32 battler);
|
||||
u8 GetMostSuitableMonToSwitchInto(u32 battler);
|
||||
u8 GetMostSuitableMonToSwitchInto(u32 battler, bool32 switchAfterMonKOd);
|
||||
bool32 ShouldSwitch(u32 battler, bool32 emitResult);
|
||||
|
||||
#endif // GUARD_BATTLE_AI_SWITCH_ITEMS_H
|
||||
|
|
|
|||
196
include/battle_ai_util.h
Normal file
196
include/battle_ai_util.h
Normal file
|
|
@ -0,0 +1,196 @@
|
|||
#ifndef GUARD_BATTLE_AI_UTIL_H
|
||||
#define GUARD_BATTLE_AI_UTIL_H
|
||||
|
||||
#define FOE(battler) ((BATTLE_OPPOSITE(battler)) & BIT_SIDE)
|
||||
|
||||
#define AI_STRIKES_FIRST(battlerAi, battlerDef, move)((AI_WhoStrikesFirst(battlerAi, battlerDef, move) == AI_IS_FASTER))
|
||||
|
||||
bool32 AI_RandLessThan(u32 val);
|
||||
bool32 IsAiVsAiBattle(void);
|
||||
bool32 BattlerHasAi(u32 battlerId);
|
||||
bool32 IsAiBattlerAware(u32 battlerId);
|
||||
void ClearBattlerMoveHistory(u32 battlerId);
|
||||
void RecordLastUsedMoveBy(u32 battlerId, u32 move);
|
||||
void RecordAllMoves(u32 battler);
|
||||
void RecordKnownMove(u32 battlerId, u32 move);
|
||||
void RecordAbilityBattle(u32 battlerId, u32 abilityId);
|
||||
void ClearBattlerAbilityHistory(u32 battlerId);
|
||||
void RecordItemEffectBattle(u32 battlerId, u32 itemEffect);
|
||||
void ClearBattlerItemEffectHistory(u32 battlerId);
|
||||
void SaveBattlerData(u32 battlerId);
|
||||
void SetBattlerData(u32 battlerId);
|
||||
void RestoreBattlerData(u32 battlerId);
|
||||
u32 GetAIChosenMove(u32 battlerId);
|
||||
u32 GetTotalBaseStat(u32 species);
|
||||
bool32 IsTruantMonVulnerable(u32 battlerAI, u32 opposingBattler);
|
||||
bool32 AtMaxHp(u32 battler);
|
||||
u32 GetHealthPercentage(u32 battler);
|
||||
bool32 IsBattlerTrapped(u32 battler, bool32 switching);
|
||||
s32 AI_WhoStrikesFirst(u32 battlerAI, u32 battler2, u32 moveConsidered);
|
||||
bool32 CanTargetFaintAi(u32 battlerDef, u32 battlerAtk);
|
||||
u32 NoOfHitsForTargetToFaintAI(u32 battlerDef, u32 battlerAtk);
|
||||
u32 GetBestDmgMoveFromBattler(u32 battlerAtk, u32 battlerDef);
|
||||
bool32 CanTargetMoveFaintAi(u32 move, u32 battlerDef, u32 battlerAtk, u32 nHits);
|
||||
bool32 CanTargetFaintAiWithMod(u32 battlerDef, u32 battlerAtk, s32 hpMod, s32 dmgMod);
|
||||
s32 AI_DecideKnownAbilityForTurn(u32 battlerId);
|
||||
u32 AI_DecideHoldEffectForTurn(u32 battlerId);
|
||||
bool32 DoesBattlerIgnoreAbilityChecks(u32 atkAbility, u32 move);
|
||||
u32 AI_GetWeather(struct AiLogicData *aiData);
|
||||
bool32 CanAIFaintTarget(u32 battlerAtk, u32 battlerDef, u32 numHits);
|
||||
bool32 CanIndexMoveFaintTarget(u32 battlerAtk, u32 battlerDef, u32 index, u32 numHits);
|
||||
bool32 AI_IsTerrainAffected(u32 battlerId, u32 flags);
|
||||
bool32 AI_IsBattlerGrounded(u32 battlerId);
|
||||
bool32 HasDamagingMove(u32 battlerId);
|
||||
bool32 HasDamagingMoveOfType(u32 battlerId, u32 type);
|
||||
u32 GetBattlerSecondaryDamage(u32 battlerId);
|
||||
bool32 BattlerWillFaintFromWeather(u32 battler, u32 ability);
|
||||
bool32 BattlerWillFaintFromSecondaryDamage(u32 battler, u32 ability);
|
||||
bool32 ShouldTryOHKO(u32 battlerAtk, u32 battlerDef, u32 atkAbility, u32 defAbility, u32 move);
|
||||
bool32 ShouldUseRecoilMove(u32 battlerAtk, u32 battlerDef, u32 recoilDmg, u32 moveIndex);
|
||||
u32 GetBattlerSideSpeedAverage(u32 battler);
|
||||
bool32 ShouldAbsorb(u32 battlerAtk, u32 battlerDef, u32 move, s32 damage);
|
||||
bool32 ShouldRecover(u32 battlerAtk, u32 battlerDef, u32 move, u32 healPercent);
|
||||
bool32 ShouldSetScreen(u32 battlerAtk, u32 battlerDef, u32 moveEffect);
|
||||
bool32 ShouldPivot(u32 battlerAtk, u32 battlerDef, u32 defAbility, u32 move, u32 moveIndex);
|
||||
bool32 IsRecycleEncouragedItem(u32 item);
|
||||
bool32 ShouldRestoreHpBerry(u32 battlerAtk, u32 item);
|
||||
bool32 IsStatBoostingBerry(u32 item);
|
||||
bool32 CanKnockOffItem(u32 battler, u32 item);
|
||||
bool32 IsAbilityOfRating(u32 ability, s8 rating);
|
||||
bool32 AI_IsAbilityOnSide(u32 battlerId, u32 ability);
|
||||
bool32 AI_MoveMakesContact(u32 ability, u32 holdEffect, u32 move);
|
||||
u32 AI_GetBattlerMoveTargetType(u32 battlerId, u32 move);
|
||||
bool32 ShouldUseZMove(u32 battlerAtk, u32 battlerDef, u32 chosenMove);
|
||||
|
||||
// stat stage checks
|
||||
bool32 AnyStatIsRaised(u32 battlerId);
|
||||
bool32 ShouldLowerStat(u32 battler, u32 battlerAbility, u32 stat);
|
||||
bool32 BattlerStatCanRise(u32 battler, u32 battlerAbility, u32 stat);
|
||||
bool32 AreBattlersStatsMaxed(u32 battler);
|
||||
bool32 BattlerHasAnyStatRaised(u32 battlerId);
|
||||
u32 CountPositiveStatStages(u32 battlerId);
|
||||
u32 CountNegativeStatStages(u32 battlerId);
|
||||
bool32 ShouldLowerAttack(u32 battlerAtk, u32 battlerDef, u32 defAbility);
|
||||
bool32 ShouldLowerDefense(u32 battlerAtk, u32 battlerDef, u32 defAbility);
|
||||
bool32 ShouldLowerSpeed(u32 battlerAtk, u32 battlerDef, u32 defAbility);
|
||||
bool32 ShouldLowerSpAtk(u32 battlerAtk, u32 battlerDef, u32 defAbility);
|
||||
bool32 ShouldLowerSpDef(u32 battlerAtk, u32 battlerDef, u32 defAbility);
|
||||
bool32 ShouldLowerAccuracy(u32 battlerAtk, u32 battlerDef, u32 defAbility);
|
||||
bool32 ShouldLowerEvasion(u32 battlerAtk, u32 battlerDef, u32 defAbility);
|
||||
|
||||
// move checks
|
||||
bool32 IsAffectedByPowder(u32 battler, u32 ability, u32 holdEffect);
|
||||
bool32 MovesWithCategoryUnusable(u32 attacker, u32 target, u32 category);
|
||||
s32 AI_WhichMoveBetter(u32 move1, u32 move2, u32 battlerAtk, u32 battlerDef, s32 noOfHitsToKo);
|
||||
s32 AI_CalcDamageSaveBattlers(u32 move, u32 battlerAtk, u32 battlerDef, u8 *typeEffectiveness, bool32 considerZPower);
|
||||
s32 AI_CalcDamage(u32 move, u32 battlerAtk, u32 battlerDef, u8 *typeEffectiveness, bool32 considerZPower, u32 weather);
|
||||
bool32 AI_IsDamagedByRecoil(u32 battler);
|
||||
u32 GetNoOfHitsToKO(u32 dmg, s32 hp);
|
||||
u32 GetNoOfHitsToKOBattlerDmg(u32 dmg, u32 battlerDef);
|
||||
u32 GetNoOfHitsToKOBattler(u32 battlerAtk, u32 battlerDef, u32 moveIndex);
|
||||
u32 GetCurrDamageHpPercent(u32 battlerAtk, u32 battlerDef);
|
||||
uq4_12_t AI_GetTypeEffectiveness(u32 move, u32 battlerAtk, u32 battlerDef);
|
||||
u32 AI_GetMoveEffectiveness(u32 move, u32 battlerAtk, u32 battlerDef);
|
||||
u16 *GetMovesArray(u32 battler);
|
||||
bool32 IsConfusionMoveEffect(u32 moveEffect);
|
||||
bool32 HasMove(u32 battlerId, u32 move);
|
||||
bool32 HasOnlyMovesWithCategory(u32 battlerId, u32 category, bool32 onlyOffensive);
|
||||
bool32 HasMoveWithCategory(u32 battler, u32 category);
|
||||
bool32 HasMoveWithType(u32 battler, u32 type);
|
||||
bool32 HasMoveEffect(u32 battlerId, u32 moveEffect);
|
||||
bool32 HasMoveEffectANDArg(u32 battlerId, u32 effect, u32 argument);
|
||||
bool32 HasMoveWithAdditionalEffect(u32 battlerId, u32 moveEffect);
|
||||
bool32 HasMoveWithCriticalHitChance(u32 battlerId);
|
||||
bool32 HasMoveWithMoveEffectExcept(u32 battlerId, u32 moveEffect, u32 exception);
|
||||
bool32 HasMoveWithLowAccuracy(u32 battlerAtk, u32 battlerDef, u32 accCheck, bool32 ignoreStatus, u32 atkAbility, u32 defAbility, u32 atkHoldEffect, u32 defHoldEffect);
|
||||
bool32 IsAromaVeilProtectedMove(u32 move);
|
||||
bool32 IsNonVolatileStatusMoveEffect(u32 moveEffect);
|
||||
bool32 IsStatLoweringMoveEffect(u32 moveEffect);
|
||||
bool32 IsMoveRedirectionPrevented(u32 move, u32 atkAbility);
|
||||
bool32 IsMoveEncouragedToHit(u32 battlerAtk, u32 battlerDef, u32 move);
|
||||
bool32 IsHazardMoveEffect(u32 moveEffect);
|
||||
bool32 IsTwoTurnNotSemiInvulnerableMove(u32 battlerAtk, u32 move);
|
||||
void ProtectChecks(u32 battlerAtk, u32 battlerDef, u32 move, u32 predictedMove, s32 *score);
|
||||
bool32 ShouldSetSandstorm(u32 battler, u32 ability, u32 holdEffect);
|
||||
bool32 ShouldSetHail(u32 battler, u32 ability, u32 holdEffect);
|
||||
bool32 ShouldSetSnow(u32 battler, u32 ability, u32 holdEffect);
|
||||
bool32 ShouldSetRain(u32 battlerAtk, u32 ability, u32 holdEffect);
|
||||
bool32 ShouldSetSun(u32 battlerAtk, u32 atkAbility, u32 holdEffect);
|
||||
bool32 HasSleepMoveWithLowAccuracy(u32 battlerAtk, u32 battlerDef);
|
||||
bool32 IsHealingMove(u32 move);
|
||||
bool32 HasHealingEffect(u32 battler);
|
||||
bool32 IsTrappingMove(u32 move);
|
||||
bool32 HasTrappingMoveEffect(u32 battler);
|
||||
bool32 ShouldFakeOut(u32 battlerAtk, u32 battlerDef, u32 move);
|
||||
bool32 HasThawingMove(u32 battler);
|
||||
bool32 IsStatRaisingEffect(u32 effect);
|
||||
bool32 IsStatLoweringEffect(u32 effect);
|
||||
bool32 IsAttackBoostMoveEffect(u32 effect);
|
||||
bool32 IsUngroundingEffect(u32 effect);
|
||||
bool32 IsSemiInvulnerable(u32 battlerDef, u32 move);
|
||||
bool32 HasSubstituteIgnoringMove(u32 battler);
|
||||
bool32 HasHighCritRatioMove(u32 battler);
|
||||
bool32 HasMagicCoatAffectedMove(u32 battler);
|
||||
bool32 HasSnatchAffectedMove(u32 battler);
|
||||
|
||||
// status checks
|
||||
bool32 AI_CanBeBurned(u32 battler, u32 ability);
|
||||
bool32 AI_CanGetFrostbite(u32 battler, u32 ability);
|
||||
bool32 AI_CanBeConfused(u32 battlerAtk, u32 battlerDef, u32 move, u32 ability);
|
||||
bool32 AI_CanSleep(u32 battler, u32 ability);
|
||||
bool32 IsBattlerIncapacitated(u32 battler, u32 ability);
|
||||
bool32 AI_CanPutToSleep(u32 battlerAtk, u32 battlerDef, u32 defAbility, u32 move, u32 partnerMove);
|
||||
bool32 ShouldPoisonSelf(u32 battler, u32 ability);
|
||||
bool32 AI_CanPoison(u32 battlerAtk, u32 battlerDef, u32 defAbility, u32 move, u32 partnerMove);
|
||||
bool32 AI_CanParalyze(u32 battlerAtk, u32 battlerDef, u32 defAbility, u32 move, u32 partnerMove);
|
||||
bool32 AI_CanConfuse(u32 battlerAtk, u32 battlerDef, u32 defAbility, u32 battlerAtkPartner, u32 move, u32 partnerMove);
|
||||
bool32 ShouldBurnSelf(u32 battler, u32 ability);
|
||||
bool32 AI_CanBurn(u32 battlerAtk, u32 battlerDef, u32 defAbility, u32 battlerAtkPartner, u32 move, u32 partnerMove);
|
||||
bool32 AI_CanGiveFrostbite(u32 battlerAtk, u32 battlerDef, u32 defAbility, u32 battlerAtkPartner, u32 move, u32 partnerMove);
|
||||
bool32 AI_CanBeInfatuated(u32 battlerAtk, u32 battlerDef, u32 defAbility);
|
||||
bool32 AnyPartyMemberStatused(u32 battlerId, bool32 checkSoundproof);
|
||||
u32 ShouldTryToFlinch(u32 battlerAtk, u32 battlerDef, u32 atkAbility, u32 defAbility, u32 move);
|
||||
bool32 ShouldTrap(u32 battlerAtk, u32 battlerDef, u32 move);
|
||||
bool32 IsWakeupTurn(u32 battler);
|
||||
bool32 AI_IsBattlerAsleepOrComatose(u32 battlerId);
|
||||
|
||||
// partner logic
|
||||
#define IS_TARGETING_PARTNER(battlerAtk, battlerDef)((battlerAtk) == (battlerDef ^ BIT_FLANK))
|
||||
u32 GetAllyChosenMove(u32 battlerId);
|
||||
bool32 IsValidDoubleBattle(u32 battlerAtk);
|
||||
bool32 IsTargetingPartner(u32 battlerAtk, u32 battlerDef);
|
||||
bool32 DoesPartnerHaveSameMoveEffect(u32 battlerAtkPartner, u32 battlerDef, u32 move, u32 partnerMove);
|
||||
bool32 PartnerHasSameMoveEffectWithoutTarget(u32 battlerAtkPartner, u32 move, u32 partnerMove);
|
||||
bool32 PartnerMoveEffectIsStatusSameTarget(u32 battlerAtkPartner, u32 battlerDef, u32 partnerMove);
|
||||
bool32 IsMoveEffectWeather(u32 move);
|
||||
bool32 PartnerMoveEffectIsTerrain(u32 battlerAtkPartner, u32 partnerMove);
|
||||
bool32 PartnerMoveIs(u32 battlerAtkPartner, u32 partnerMove, u32 moveCheck);
|
||||
bool32 PartnerMoveIsSameAsAttacker(u32 battlerAtkPartner, u32 battlerDef, u32 move, u32 partnerMove);
|
||||
bool32 PartnerMoveIsSameNoTarget(u32 battlerAtkPartner, u32 move, u32 partnerMove);
|
||||
bool32 ShouldUseWishAromatherapy(u32 battlerAtk, u32 battlerDef, u32 move);
|
||||
|
||||
// party logic
|
||||
struct BattlePokemon *AllocSaveBattleMons(void);
|
||||
void FreeRestoreBattleMons(struct BattlePokemon *savedBattleMons);
|
||||
s32 CountUsablePartyMons(u32 battlerId);
|
||||
bool32 IsPartyFullyHealedExceptBattler(u32 battler);
|
||||
bool32 PartyHasMoveCategory(u32 battlerId, u32 category);
|
||||
bool32 SideHasMoveCategory(u32 battlerId, u32 category);
|
||||
|
||||
// score increases
|
||||
void IncreaseStatUpScore(u32 battlerAtk, u32 battlerDef, u32 statId, s32 *score);
|
||||
void IncreasePoisonScore(u32 battlerAtk, u32 battlerDef, u32 move, s32 *score);
|
||||
void IncreaseBurnScore(u32 battlerAtk, u32 battlerDef, u32 move, s32 *score);
|
||||
void IncreaseParalyzeScore(u32 battlerAtk, u32 battlerDef, u32 move, s32 *score);
|
||||
void IncreaseSleepScore(u32 battlerAtk, u32 battlerDef, u32 move, s32 *score);
|
||||
void IncreaseConfusionScore(u32 battlerAtk, u32 battlerDef, u32 move, s32 *score);
|
||||
void IncreaseFrostbiteScore(u32 battlerAtk, u32 battlerDef, u32 move, s32 *score);
|
||||
|
||||
s32 AI_CalcPartyMonDamage(u32 move, u32 battlerAtk, u32 battlerDef, struct BattlePokemon switchinCandidate, bool8 isPartyMonAttacker);
|
||||
s32 AI_CheckMoveEffects(u32 battlerAtk, u32 battlerDef, u32 move, s32 score, struct AiLogicData *aiData, u32 predictedMove, bool32 isDoubleBattle);
|
||||
s32 AI_TryToClearStats(u32 battlerAtk, u32 battlerDef, bool32 isDoubleBattle);
|
||||
bool32 AI_ShouldCopyStatChanges(u32 battlerAtk, u32 battlerDef);
|
||||
bool32 AI_ShouldSetUpHazards(u32 battlerAtk, u32 battlerDef, struct AiLogicData *aiData);
|
||||
void IncreaseTidyUpScore(u32 battlerAtk, u32 battlerDef, u32 move, s32 *score);
|
||||
|
||||
#endif //GUARD_BATTLE_AI_UTIL_H
|
||||
|
|
@ -54,7 +54,6 @@ extern const u8 gStatusConditionString_IceJpn[8];
|
|||
extern const u8 gStatusConditionString_ConfusionJpn[8];
|
||||
extern const u8 gStatusConditionString_LoveJpn[8];
|
||||
extern const u8 *const gStatusConditionStringsTable[7][2];
|
||||
extern const struct TrainerMoney gTrainerMoneyTable[];
|
||||
|
||||
void CB2_InitBattle(void);
|
||||
void BattleMainCB2(void);
|
||||
|
|
@ -86,7 +85,6 @@ void SwitchPartyOrder(u32 battlerId);
|
|||
void SwapTurnOrder(u8 id1, u8 id2);
|
||||
void RunBattleScriptCommands_PopCallbacksStack(void);
|
||||
void RunBattleScriptCommands(void);
|
||||
bool8 TryRunFromBattle(u8 battler);
|
||||
s8 GetMovePriority(u32 battlerId, u16 move);
|
||||
s8 GetChosenMovePriority(u32 battlerId);
|
||||
u32 GetBattlerTotalSpeedStatArgs(u32 battler, u32 ability, u32 holdEffect);
|
||||
|
|
|
|||
|
|
@ -233,10 +233,10 @@ extern struct BattleMsgData *gBattleMsgDataPtr;
|
|||
|
||||
#define TEXT_BUFF_ARRAY_COUNT 16
|
||||
|
||||
extern u8 gDisplayedStringBattle[300];
|
||||
extern u8 gDisplayedStringBattle[550];
|
||||
extern u8 gBattleTextBuff1[TEXT_BUFF_ARRAY_COUNT];
|
||||
extern u8 gBattleTextBuff2[TEXT_BUFF_ARRAY_COUNT];
|
||||
extern u8 gBattleTextBuff3[TEXT_BUFF_ARRAY_COUNT];
|
||||
extern u8 gBattleTextBuff3[TEXT_BUFF_ARRAY_COUNT + 13];
|
||||
|
||||
extern const u8 *const gBattleStringsTable[];
|
||||
extern const u8 *const gStatNamesTable[];
|
||||
|
|
|
|||
|
|
@ -22,9 +22,6 @@ struct PickupItem
|
|||
u8 percentage[10];
|
||||
};
|
||||
|
||||
void AI_CalcDmg(u8 attacker, u8 defender);
|
||||
u8 TypeCalc(u16 move, u8 attacker, u8 defender);
|
||||
u8 AI_TypeCalc(u16 move, u16 targetSpecies, u16 targetAbility);
|
||||
u8 GetBattlerTurnOrderNum(u8 battlerId);
|
||||
void SetMoveEffect(bool32 primary, u32 certain);
|
||||
bool32 IsMonGettingExpSentOut(void);
|
||||
|
|
@ -53,6 +50,11 @@ bool32 CanBattlerSwitch(u32 battlerId);
|
|||
u8 GetFirstFaintedPartyIndex(u8 battlerId);
|
||||
u16 GetNaturePowerMove(void);
|
||||
bool32 CanCamouflage(u8 battlerId);
|
||||
bool32 IsTelekinesisBannedSpecies(u16 species);
|
||||
bool32 CanUseLastResort(u8 battlerId);
|
||||
bool32 ProteanTryChangeType(u32 battler, u32 ability, u32 move, u32 moveType);
|
||||
s32 CalcCritChanceStageArgs(u32 battlerAtk, u32 battlerDef, u32 move, bool32 recordAbility, u32 abilityAtk, u32 abilityDef, u32 holdEffectAtk);
|
||||
s32 GetCritHitChance(s32 critChanceIndex);
|
||||
|
||||
extern void (* const gBattleScriptingCommandsTable[])(void);
|
||||
extern const struct StatFractions gAccuracyStageRatios[];
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@
|
|||
extern u16 gPartnerTrainerId;
|
||||
|
||||
void StartWildBattle(void);
|
||||
void StartDoubleWildBattle(void);
|
||||
void StartRoamerBattle(void);
|
||||
void StartOldManTutorialBattle(void);
|
||||
void StartScriptedWildBattle(void);
|
||||
|
|
|
|||
|
|
@ -120,7 +120,23 @@ enum
|
|||
extern const struct TypePower gNaturalGiftTable[];
|
||||
extern const uq4_12_t gTypeEffectivenessTable[NUMBER_OF_MON_TYPES][NUMBER_OF_MON_TYPES];
|
||||
|
||||
void HandleAction_UseMove(void);
|
||||
void HandleAction_Switch(void);
|
||||
void HandleAction_UseItem(void);
|
||||
bool8 TryRunFromBattle(u8 battler);
|
||||
void HandleAction_Run(void);
|
||||
void HandleAction_WatchesCarefully(void);
|
||||
void HandleAction_SafariZoneBallThrow(void);
|
||||
void HandleAction_ThrowBait(void);
|
||||
void HandleAction_ThrowRock(void);
|
||||
void HandleAction_SafariZoneRun(void);
|
||||
void HandleAction_OldManBallThrow(void);
|
||||
void HandleAction_TryFinish(void);
|
||||
void HandleAction_NothingIsFainted(void);
|
||||
void HandleAction_ActionFinished(void);
|
||||
|
||||
u8 GetBattlerForBattleScript(u8 caseId);
|
||||
bool32 IsBattlerMarkedForControllerExec(u32 battler);
|
||||
void MarkBattlerForControllerExec(u8 battlerId);
|
||||
void MarkBattlerReceivedLinkData(u8 battlerId);
|
||||
const u8* CancelMultiTurnMoves(u32 battler);
|
||||
|
|
@ -148,9 +164,8 @@ void BattleScriptPushCursorAndCallback(const u8 *BS_ptr);
|
|||
u8 ItemBattleEffects(u8 caseID, u32 battler, bool32 moveTurn);
|
||||
void ClearVariousBattlerFlags(u32 battler);
|
||||
void HandleAction_RunBattleScript(void);
|
||||
u8 GetMoveTarget(u16 move, u8 setTarget);
|
||||
u32 GetMoveTarget(u16 move, u8 setTarget);
|
||||
u8 IsMonDisobedient(void);
|
||||
void SwitchPartyOrderInGameMulti(u8 battler, u8 arg1);
|
||||
// new
|
||||
bool32 IsAffectedByFollowMe(u32 battlerAtk, u32 defSide, u32 move);
|
||||
bool32 IsNeutralizingGasOnField(void);
|
||||
|
|
@ -178,6 +193,7 @@ bool32 IsBattlerProtected(u32 battler, u32 move);
|
|||
bool32 IsMoveMakingContact(u32 move, u32 battlerAtk);
|
||||
bool32 IsHealBlockPreventingMove(u32 battler, u32 move);
|
||||
s32 CalculateMoveDamage(u32 move, u32 battlerAtk, u32 battlerDef, u32 moveType, s32 fixedBasePower, bool32 isCrit, bool32 randomFactor, bool32 updateFlags);
|
||||
bool32 MoveHasAdditionalEffectWithChance(u32 move, u32 moveEffect, u32 chance);
|
||||
bool32 MoveHasAdditionalEffectSelfArg(u32 move, u32 moveEffect, u32 argument);
|
||||
u32 GetMoveSlot(u16 *moves, u32 move);
|
||||
u32 GetBattlerWeight(u32 battler);
|
||||
|
|
@ -191,6 +207,7 @@ bool32 AreBattlersOfOppositeGender(u32 battler1, u32 battler2);
|
|||
bool32 AreBattlersOfSameGender(u32 battler1, u32 battler2);
|
||||
u32 GetBattlerHoldEffectParam(u32 battler);
|
||||
uq4_12_t CalcTypeEffectivenessMultiplier(u32 move, u32 moveType, u32 battlerAtk, u32 battlerDef, u32 defAbility, bool32 recordAbilities);
|
||||
uq4_12_t CalcPartyMonTypeEffectivenessMultiplier(u16 move, u16 speciesDef, u16 abilityDef);
|
||||
bool32 MoveHasAdditionalEffectSelf(u32 move, u32 moveEffect);
|
||||
uq4_12_t GetTypeModifier(u32 atkType, u32 defType);
|
||||
u8 GetBattlerType(u32 battler, u8 typeIndex);
|
||||
|
|
@ -245,18 +262,11 @@ void TryClearRageAndFuryCutter(void);
|
|||
bool32 CanMegaEvolve(u32 battler);
|
||||
bool32 CanUltraBurst(u32 battler);
|
||||
bool32 CanTargetBattler(u32 battlerAtk, u32 battlerDef, u16 move);
|
||||
|
||||
// battle_ai_util.h
|
||||
bool32 IsHealingMove(u32 move);
|
||||
void RecordKnownMove(u32 battlerId, u32 move);
|
||||
s32 CountUsablePartyMons(u32 battlerId);
|
||||
bool32 IsAiVsAiBattle(void);
|
||||
void RecordLastUsedMoveBy(u32 battlerId, u32 move);
|
||||
bool32 BattlerHasAi(u32 battlerId);
|
||||
void ClearBattlerItemEffectHistory(u32 battlerId);
|
||||
bool32 IsAffectedByPowder(u32 battler, u32 ability, u32 holdEffect);
|
||||
void RecordAllMoves(u32 battler);
|
||||
|
||||
// end battle_ai_util.h
|
||||
u32 SetRandomTarget(u32 battler);
|
||||
bool32 MoveEffectIsGuaranteed(u32 battler, u32 battlerAbility, const struct AdditionalEffect *additionalEffect);
|
||||
u32 CalcRolloutBasePower(u32 battlerAtk, u32 basePower, u32 rolloutTimer);
|
||||
u32 CalcFuryCutterBasePower(u32 basePower, u32 furyCutterCounter);
|
||||
s32 CalculateMoveDamageVars(u32 move, u32 battlerAtk, u32 battlerDef, u32 moveType, s32 fixedBasePower, uq4_12_t typeEffectivenessModifier,
|
||||
u32 weather, bool32 isCrit, u32 holdEffectAtk, u32 holdEffectDef, u32 abilityAtk, u32 abilityDef);
|
||||
|
||||
#endif // GUARD_BATTLE_UTIL_H
|
||||
|
|
|
|||
|
|
@ -6,5 +6,6 @@
|
|||
void AllocateBattleResources(void);
|
||||
void FreeBattleResources(void);
|
||||
void AdjustFriendshipOnBattleFaint(u8 bank);
|
||||
void SwitchPartyOrderInGameMulti(u8 battler, u8 arg1);
|
||||
|
||||
#endif // GUARD_BATTLE_UTIL_H
|
||||
|
|
|
|||
|
|
@ -75,6 +75,7 @@
|
|||
#define IS_BATTLE_TYPE_GHOST_WITH_SCOPE(flags) ((flags) & BATTLE_TYPE_GHOST && (flags) & BATTLE_TYPE_GHOST_UNVEILED)
|
||||
#define WILD_DOUBLE_BATTLE ((gBattleTypeFlags & BATTLE_TYPE_DOUBLE && !(gBattleTypeFlags & (BATTLE_TYPE_LINK | BATTLE_TYPE_TRAINER))))
|
||||
#define BATTLE_TWO_VS_ONE_OPPONENT ((gBattleTypeFlags & BATTLE_TYPE_INGAME_PARTNER && gTrainerBattleOpponent_B == 0xFFFF))
|
||||
#define BATTLE_TYPE_HAS_AI (BATTLE_TYPE_TRAINER | BATTLE_TYPE_FIRST_BATTLE | BATTLE_TYPE_SAFARI | BATTLE_TYPE_ROAMER | BATTLE_TYPE_INGAME_PARTNER)
|
||||
|
||||
#define RIVAL_BATTLE_HEAL_AFTER 1
|
||||
#define RIVAL_BATTLE_TUTORIAL 3
|
||||
|
|
@ -211,11 +212,6 @@
|
|||
#define HITMARKER_FAINTED(battler) (gBitTable[battler] << 28)
|
||||
#define HITMARKER_FAINTED2(battler) ((1 << 28) << battler)
|
||||
#define HITMARKER_STRING_PRINTED (1 << 29)
|
||||
// TODO: old hitmarkers for compatability, remove with new battle system
|
||||
#define HITMARKER_SKIP_DMG_TRACK (1 << 30)
|
||||
#define HITMARKER_IGNORE_ON_AIR (1 << 31)
|
||||
#define HITMARKER_IGNORE_UNDERGROUND (1 << 0)
|
||||
#define HITMARKER_IGNORE_UNDERWATER (1 << 1)
|
||||
|
||||
|
||||
// Per-side statuses that affect an entire party
|
||||
|
|
@ -226,7 +222,6 @@
|
|||
#define SIDE_STATUS_SAFEGUARD (1 << 5)
|
||||
#define SIDE_STATUS_FUTUREATTACK (1 << 6)
|
||||
#define SIDE_STATUS_MIST (1 << 8)
|
||||
#define SIDE_STATUS_SPIKES_DAMAGED (1 << 9) // TODO: remove with new battle system
|
||||
// (1 << 9) previously was SIDE_STATUS_SPIKES_DAMAGED
|
||||
#define SIDE_STATUS_TAILWIND (1 << 10)
|
||||
#define SIDE_STATUS_AURORA_VEIL (1 << 11)
|
||||
|
|
|
|||
|
|
@ -15,38 +15,45 @@
|
|||
#define AI_TYPE_MOVE 4
|
||||
|
||||
// type effectiveness
|
||||
#define AI_EFFECTIVENESS_x4 160
|
||||
#define AI_EFFECTIVENESS_x2 80
|
||||
#define AI_EFFECTIVENESS_x1 40
|
||||
#define AI_EFFECTIVENESS_x0_5 20
|
||||
#define AI_EFFECTIVENESS_x0_25 10
|
||||
#define AI_EFFECTIVENESS_x8 7
|
||||
#define AI_EFFECTIVENESS_x4 6
|
||||
#define AI_EFFECTIVENESS_x2 5
|
||||
#define AI_EFFECTIVENESS_x1 4
|
||||
#define AI_EFFECTIVENESS_x0_5 3
|
||||
#define AI_EFFECTIVENESS_x0_25 2
|
||||
#define AI_EFFECTIVENESS_x0_125 1
|
||||
#define AI_EFFECTIVENESS_x0 0
|
||||
|
||||
// ai weather
|
||||
#define AI_WEATHER_SUN 0
|
||||
#define AI_WEATHER_RAIN 1
|
||||
#define AI_WEATHER_SANDSTORM 2
|
||||
#define AI_WEATHER_HAIL 3
|
||||
// AI Flags. Most run specific functions to update score, new flags are used for internal logic in other scripts
|
||||
#define AI_FLAG_CHECK_BAD_MOVE (1 << 0)
|
||||
#define AI_FLAG_TRY_TO_FAINT (1 << 1)
|
||||
#define AI_FLAG_CHECK_VIABILITY (1 << 2)
|
||||
#define AI_FLAG_SETUP_FIRST_TURN (1 << 3)
|
||||
#define AI_FLAG_RISKY (1 << 4)
|
||||
#define AI_FLAG_PREFER_STRONGEST_MOVE (1 << 5)
|
||||
#define AI_FLAG_PREFER_BATON_PASS (1 << 6)
|
||||
#define AI_FLAG_DOUBLE_BATTLE (1 << 7) // removed, split between AI_FLAG_CHECK_BAD_MOVE & AI_FLAG_CHECK_GOOD_MOVE
|
||||
#define AI_FLAG_HP_AWARE (1 << 8)
|
||||
#define AI_FLAG_POWERFUL_STATUS (1 << 9) // AI prefers moves that set up field effects or side statuses, even if the user can faint the target
|
||||
// New, Trainer Handicap Flags
|
||||
#define AI_FLAG_NEGATE_UNAWARE (1 << 10) // AI is NOT aware of negating effects like wonder room, mold breaker, etc
|
||||
#define AI_FLAG_WILL_SUICIDE (1 << 11) // AI will use explosion / self destruct / final gambit / etc
|
||||
// New, Trainer Strategy Flags
|
||||
#define AI_FLAG_HELP_PARTNER (1 << 12) // AI can try to help partner. If not set, will tend not to target partner
|
||||
#define AI_FLAG_PREFER_STATUS_MOVES (1 << 13) // AI gets a score bonus for status moves. Should be combined with AI_FLAG_CHECK_BAD_MOVE to prevent using only status moves
|
||||
#define AI_FLAG_STALL (1 << 14) // AI stalls battle and prefers secondary damage/trapping/etc. TODO not finished
|
||||
#define AI_FLAG_SMART_SWITCHING (1 << 15) // AI includes a lot more switching checks. Automatically includes AI_FLAG_SMART_MON_CHOICES.
|
||||
#define AI_FLAG_ACE_POKEMON (1 << 16) // AI has an Ace Pokemon. The last Pokemon in the party will not be used until it's the last one remaining.
|
||||
#define AI_FLAG_OMNISCIENT (1 << 17) // AI has full knowledge of player moves, abilities, hold items
|
||||
#define AI_FLAG_SMART_MON_CHOICES (1 << 18) // AI will make smarter decisions when choosing which mon to send out mid-battle and after a KO, which are separate decisions. Automatically included by AI_FLAG_SMART_SWITCHING.
|
||||
|
||||
// get_how_powerful_move_is
|
||||
#define MOVE_POWER_DISCOURAGED 0
|
||||
#define MOVE_NOT_MOST_POWERFUL 1
|
||||
#define MOVE_MOST_POWERFUL 2
|
||||
#define AI_FLAG_COUNT 19
|
||||
|
||||
// script's table id to bit
|
||||
#define AI_SCRIPT_CHECK_BAD_MOVE (1 << 0)
|
||||
#define AI_SCRIPT_CHECK_VIABILITY (1 << 1)
|
||||
#define AI_SCRIPT_TRY_TO_FAINT (1 << 2)
|
||||
#define AI_SCRIPT_SETUP_FIRST_TURN (1 << 3)
|
||||
#define AI_SCRIPT_RISKY (1 << 4)
|
||||
#define AI_SCRIPT_PREFER_STRONGEST_MOVE (1 << 5)
|
||||
#define AI_SCRIPT_PREFER_BATON_PASS (1 << 6)
|
||||
#define AI_SCRIPT_DOUBLE_BATTLE (1 << 7)
|
||||
#define AI_SCRIPT_HP_AWARE (1 << 8)
|
||||
#define AI_SCRIPT_UNKNOWN (1 << 9)
|
||||
// 10 - 28 are not used
|
||||
#define AI_SCRIPT_ROAMING (1 << 29)
|
||||
#define AI_SCRIPT_SAFARI (1 << 30)
|
||||
#define AI_SCRIPT_FIRST_BATTLE (1 << 31)
|
||||
// 'other' ai logic flags
|
||||
#define AI_FLAG_ROAMING (1 << 29)
|
||||
#define AI_FLAG_SAFARI (1 << 30)
|
||||
#define AI_FLAG_FIRST_BATTLE (1 << 31)
|
||||
|
||||
#define AI_SCORE_DEFAULT 100 // Default score for all AI moves.
|
||||
|
||||
#endif // GUARD_CONSTANTS_BATTLE_AI_H
|
||||
|
|
|
|||
|
|
@ -71,6 +71,7 @@
|
|||
#define ITEM_NAME_LENGTH 14
|
||||
#define ITEM_NAME_PLURAL_LENGTH ITEM_NAME_LENGTH + 2 // 2 is used for the instance where a word's suffix becomes y->ies
|
||||
#define POKEMON_NAME_LENGTH 10
|
||||
#define POKEMON_NAME_BUFFER_SIZE max(20, POKEMON_NAME_LENGTH + 1) // Frequently used buffer size. Larger than necessary
|
||||
#define PLAYER_NAME_LENGTH 7
|
||||
#define MAIL_WORDS_COUNT 9
|
||||
#define EASY_CHAT_BATTLE_WORDS_COUNT 6
|
||||
|
|
@ -82,6 +83,7 @@
|
|||
#define WONDER_NEWS_BODY_TEXT_LINES 10
|
||||
#define TYPE_NAME_LENGTH 6
|
||||
#define ABILITY_NAME_LENGTH ((B_EXPANDED_ABILITY_NAMES == TRUE) ? 16 : 12)
|
||||
#define TRAINER_NAME_LENGTH 10
|
||||
|
||||
#define MAX_STAMP_CARD_STAMPS 7
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,8 @@
|
|||
#ifndef GUARD_CONSTANTS_OPPONENTS_H
|
||||
#define GUARD_CONSTANTS_OPPONENTS_H
|
||||
|
||||
#include "constants/battle_partner.h"
|
||||
|
||||
#define TRAINER_NONE 0
|
||||
// Dummy trainers for all the RS trainer classes
|
||||
#define TRAINER_AQUA_LEADER 1
|
||||
|
|
@ -752,7 +754,7 @@
|
|||
// only space for 25 additional trainers before trainer flag space overflows.
|
||||
// MAX_TRAINERS_COUNT can be increased but will take up additional saveblock space
|
||||
|
||||
#define NUM_TRAINERS 744
|
||||
#define TRAINERS_COUNT 744
|
||||
#define MAX_TRAINERS_COUNT 769
|
||||
#define TRAINER_PARTNER(partner) (MAX_TRAINERS_COUNT + partner)
|
||||
|
||||
|
|
|
|||
|
|
@ -288,6 +288,8 @@
|
|||
#define TRAINER_CLASS_LADY 105
|
||||
#define TRAINER_CLASS_PAINTER 106
|
||||
|
||||
#define TRAINER_CLASS_COUNT 107
|
||||
|
||||
#define FACILITY_CLASS_AQUA_LEADER_ARCHIE 0
|
||||
#define FACILITY_CLASS_AQUA_GRUNT_M 1
|
||||
#define FACILITY_CLASS_AQUA_GRUNT_F 2
|
||||
|
|
@ -441,6 +443,10 @@
|
|||
|
||||
#define F_TRAINER_FEMALE (1 << 7)
|
||||
|
||||
// Trainer party defines
|
||||
#define TRAINER_MON_MALE 1
|
||||
#define TRAINER_MON_FEMALE 2
|
||||
|
||||
// All trainer parties specify the IV, level, and species for each Pokémon in the
|
||||
// party. Some trainer parties also specify held items and custom moves for each
|
||||
// Pokémon.
|
||||
|
|
|
|||
178
include/data.h
178
include/data.h
|
|
@ -18,6 +18,8 @@ struct MonCoords
|
|||
#define MON_COORDS_SIZE(width, height)(DIV_ROUND_UP(width, 8) << 4 | DIV_ROUND_UP(height, 8))
|
||||
#define GET_MON_COORDS_WIDTH(size)((size >> 4) * 8)
|
||||
#define GET_MON_COORDS_HEIGHT(size)((size & 0xF) * 8)
|
||||
#define TRAINER_PARTY_IVS(hp, atk, def, speed, spatk, spdef) (hp | (atk << 5) | (def << 10) | (speed << 15) | (spatk << 20) | (spdef << 25))
|
||||
#define TRAINER_PARTY_EVS(hp, atk, def, speed, spatk, spdef) ((const u8[6]){hp,atk,def,spatk,spdef,speed})
|
||||
|
||||
|
||||
#define MAX_TRAINER_ITEMS 4
|
||||
|
|
@ -28,76 +30,51 @@ enum {
|
|||
BATTLER_AFFINE_RETURN,
|
||||
};
|
||||
|
||||
struct TrainerMonNoItemDefaultMoves
|
||||
struct TrainerMon
|
||||
{
|
||||
u16 iv;
|
||||
u8 lvl;
|
||||
u16 species;
|
||||
};
|
||||
|
||||
struct TrainerMonItemDefaultMoves
|
||||
{
|
||||
u16 iv;
|
||||
u8 lvl;
|
||||
const u8 *nickname;
|
||||
const u8 *ev;
|
||||
u32 iv;
|
||||
u16 moves[4];
|
||||
u16 species;
|
||||
u16 heldItem;
|
||||
};
|
||||
|
||||
struct TrainerMonNoItemCustomMoves
|
||||
{
|
||||
u16 iv;
|
||||
u16 ability;
|
||||
u8 lvl;
|
||||
u16 species;
|
||||
u16 moves[MAX_MON_MOVES];
|
||||
u8 ball;
|
||||
u8 friendship;
|
||||
u8 nature:5;
|
||||
bool8 gender:2;
|
||||
bool8 isShiny:1;
|
||||
u8 dynamaxLevel:4;
|
||||
bool8 gigantamaxFactor:1;
|
||||
bool8 shouldDynamax:1;
|
||||
bool8 shouldTerastal:1;
|
||||
};
|
||||
|
||||
struct TrainerMonItemCustomMoves
|
||||
{
|
||||
u16 iv;
|
||||
u8 lvl;
|
||||
u16 species;
|
||||
u16 heldItem;
|
||||
u16 moves[MAX_MON_MOVES];
|
||||
};
|
||||
|
||||
#define NO_ITEM_DEFAULT_MOVES(party) { .NoItemDefaultMoves = party }, .partySize = ARRAY_COUNT(party), .partyFlags = 0
|
||||
#define NO_ITEM_CUSTOM_MOVES(party) { .NoItemCustomMoves = party }, .partySize = ARRAY_COUNT(party), .partyFlags = F_TRAINER_PARTY_CUSTOM_MOVESET
|
||||
#define ITEM_DEFAULT_MOVES(party) { .ItemDefaultMoves = party }, .partySize = ARRAY_COUNT(party), .partyFlags = F_TRAINER_PARTY_HELD_ITEM
|
||||
#define ITEM_CUSTOM_MOVES(party) { .ItemCustomMoves = party }, .partySize = ARRAY_COUNT(party), .partyFlags = F_TRAINER_PARTY_CUSTOM_MOVESET | F_TRAINER_PARTY_HELD_ITEM
|
||||
|
||||
union TrainerMonPtr
|
||||
{
|
||||
const struct TrainerMonNoItemDefaultMoves *NoItemDefaultMoves;
|
||||
const struct TrainerMonNoItemCustomMoves *NoItemCustomMoves;
|
||||
const struct TrainerMonItemDefaultMoves *ItemDefaultMoves;
|
||||
const struct TrainerMonItemCustomMoves *ItemCustomMoves;
|
||||
};
|
||||
#define TRAINER_PARTY(partyArray) partyArray, .partySize = ARRAY_COUNT(partyArray)
|
||||
|
||||
struct Trainer
|
||||
{
|
||||
/*0x00*/ u8 partyFlags;
|
||||
/*0x01*/ u8 trainerClass;
|
||||
/*0x02*/ u8 encounterMusic_gender; // last bit is gender
|
||||
/*0x03*/ u8 trainerPic;
|
||||
/*0x04*/ u8 trainerName[12];
|
||||
/*0x10*/ u16 items[MAX_TRAINER_ITEMS];
|
||||
/*0x18*/ bool8 doubleBattle;
|
||||
/*0x1C*/ u32 aiFlags;
|
||||
/*0x00*/ u32 aiFlags;
|
||||
/*0x04*/ const struct TrainerMon *party;
|
||||
/*0x08*/ u16 items[MAX_TRAINER_ITEMS];
|
||||
/*0x10*/ u8 trainerClass;
|
||||
/*0x11*/ u8 encounterMusic_gender; // last bit is gender
|
||||
/*0x12*/ u8 trainerPic;
|
||||
/*0x13*/ u8 trainerName[TRAINER_NAME_LENGTH + 1];
|
||||
/*0x1E*/ bool8 doubleBattle:1;
|
||||
bool8 mugshotEnabled:1;
|
||||
u8 startingStatus:6; // this trainer starts a battle with a given status. see include/constants/battle.h for values
|
||||
/*0x1F*/ u8 mugshotColor;
|
||||
/*0x20*/ u8 partySize;
|
||||
/*0x24*/ const union TrainerMonPtr party;
|
||||
};
|
||||
|
||||
// extern const u8 gSpeciesNames[][POKEMON_NAME_LENGTH + 1];
|
||||
// extern const u8 gMoveNames[][MOVE_NAME_LENGTH + 1];
|
||||
|
||||
extern const u8 gTrainerClassNames[][13];
|
||||
|
||||
static inline u16 SanitizeTrainerId(u16 trainerId)
|
||||
struct TrainerClass
|
||||
{
|
||||
if (trainerId >= NUM_TRAINERS)
|
||||
return TRAINER_NONE;
|
||||
return trainerId;
|
||||
}
|
||||
u8 name[13];
|
||||
u8 money;
|
||||
u16 ball;
|
||||
};
|
||||
|
||||
struct TypeInfo
|
||||
{
|
||||
|
|
@ -116,12 +93,6 @@ struct TypeInfo
|
|||
//u16 arceusForm;
|
||||
};
|
||||
|
||||
// extern const struct MonCoords gMonFrontPicCoords[];
|
||||
// extern const struct CompressedSpriteSheet gMonFrontPicTable[];
|
||||
// extern const struct MonCoords gMonBackPicCoords[];
|
||||
// extern const struct CompressedSpriteSheet gMonBackPicTable[];
|
||||
// extern const struct CompressedSpritePalette gMonPaletteTable[];
|
||||
// extern const struct CompressedSpritePalette gMonShinyPaletteTable[];
|
||||
extern const union AnimCmd *const *const gTrainerFrontAnimsPtrTable[];
|
||||
extern const struct MonCoords gTrainerFrontPicCoords[];
|
||||
extern const struct CompressedSpriteSheet gTrainerFrontPicTable[];
|
||||
|
|
@ -155,16 +126,85 @@ extern const struct SpriteFrameImage gTrainerBackPicTable_RSMay[];
|
|||
extern const union AnimCmd sAnim_GeneralFrame0[];
|
||||
|
||||
extern const struct Trainer gTrainers[];
|
||||
extern const struct Trainer gBattlePartners[];
|
||||
|
||||
extern const struct TrainerClass gTrainerClasses[TRAINER_CLASS_COUNT];
|
||||
|
||||
|
||||
static inline u16 SanitizeTrainerId(u16 trainerId)
|
||||
{
|
||||
if (trainerId >= TRAINERS_COUNT)
|
||||
return TRAINER_NONE;
|
||||
return trainerId;
|
||||
}
|
||||
|
||||
static inline const struct Trainer *GetTrainerStructFromId(u16 trainerId)
|
||||
{
|
||||
return &gTrainers[SanitizeTrainerId(trainerId)];
|
||||
}
|
||||
|
||||
static inline const u8 GetTrainerClassFromId(u16 trainerId)
|
||||
{
|
||||
return gTrainers[SanitizeTrainerId(trainerId)].trainerClass;
|
||||
}
|
||||
|
||||
static inline const u8 *GetTrainerClassNameFromId(u16 trainerId)
|
||||
{
|
||||
if (trainerId > TRAINER_PARTNER(PARTNER_NONE))
|
||||
return gTrainerClasses[gBattlePartners[trainerId - TRAINER_PARTNER(PARTNER_NONE)].trainerClass].name;
|
||||
return gTrainerClasses[GetTrainerClassFromId(trainerId)].name;
|
||||
}
|
||||
|
||||
static inline const u8 *GetTrainerNameFromId(u16 trainerId)
|
||||
{
|
||||
// if (trainerId > TRAINER_PARTNER(PARTNER_NONE))
|
||||
// return gBattlePartners[trainerId - TRAINER_PARTNER(PARTNER_NONE)].trainerName;
|
||||
if (trainerId > TRAINER_PARTNER(PARTNER_NONE))
|
||||
return gBattlePartners[trainerId - TRAINER_PARTNER(PARTNER_NONE)].trainerName;
|
||||
return gTrainers[SanitizeTrainerId(trainerId)].trainerName;
|
||||
}
|
||||
// static inline const struct TrainerMon *GetTrainerPartyFromId(u16 trainerId)
|
||||
// {
|
||||
// return gTrainers[SanitizeTrainerId(trainerId)].party;
|
||||
// }
|
||||
|
||||
static inline const u8 GetTrainerPicFromId(u16 trainerId)
|
||||
{
|
||||
return gTrainers[SanitizeTrainerId(trainerId)].trainerPic;
|
||||
}
|
||||
|
||||
static inline const u8 GetTrainerStartingStatusFromId(u16 trainerId)
|
||||
{
|
||||
return gTrainers[SanitizeTrainerId(trainerId)].startingStatus;
|
||||
}
|
||||
|
||||
static inline const bool32 IsTrainerDoubleBattle(u16 trainerId)
|
||||
{
|
||||
return gTrainers[SanitizeTrainerId(trainerId)].doubleBattle;
|
||||
}
|
||||
|
||||
static inline const u8 GetTrainerPartySizeFromId(u16 trainerId)
|
||||
{
|
||||
return gTrainers[SanitizeTrainerId(trainerId)].partySize;
|
||||
}
|
||||
|
||||
static inline const bool32 DoesTrainerHaveMugshot(u16 trainerId)
|
||||
{
|
||||
return gTrainers[SanitizeTrainerId(trainerId)].mugshotEnabled;
|
||||
}
|
||||
|
||||
static inline const u8 GetTrainerMugshotColorFromId(u16 trainerId)
|
||||
{
|
||||
return gTrainers[SanitizeTrainerId(trainerId)].mugshotColor;
|
||||
}
|
||||
|
||||
static inline const u16 *GetTrainerItemsFromId(u16 trainerId)
|
||||
{
|
||||
return gTrainers[SanitizeTrainerId(trainerId)].items;
|
||||
}
|
||||
|
||||
static inline const struct TrainerMon *GetTrainerPartyFromId(u16 trainerId)
|
||||
{
|
||||
return gTrainers[SanitizeTrainerId(trainerId)].party;
|
||||
}
|
||||
|
||||
static inline const bool32 GetTrainerAIFlagsFromId(u16 trainerId)
|
||||
{
|
||||
return gTrainers[SanitizeTrainerId(trainerId)].aiFlags;
|
||||
}
|
||||
|
||||
#endif // GUARD_DATA_H
|
||||
|
|
|
|||
|
|
@ -745,11 +745,13 @@ const struct FormChange *GetSpeciesFormChanges(u16 species);
|
|||
u8 CalculatePPWithBonus(u16 move, u8 ppBonuses, u8 moveIndex);
|
||||
void RemoveMonPPBonus(struct Pokemon *mon, u8 moveIndex);
|
||||
void RemoveBattleMonPPBonus(struct BattlePokemon *mon, u8 moveIndex);
|
||||
void PokemonToBattleMon(struct Pokemon *src, struct BattlePokemon *dst);
|
||||
bool8 ExecuteTableBasedItemEffect(struct Pokemon *mon, u16 item, u8 partyIndex, u8 moveIndex);
|
||||
bool8 PokemonUseItemEffects(struct Pokemon *mon, u16 item, u8 partyIndex, u8 moveIndex, bool8 usedByAI);
|
||||
u8 GetItemEffectParamOffset(u32 battler, u16 itemId, u8 effectByte, u8 effectBit);
|
||||
// const u8 *Battle_PrintStatBoosterEffectMessage(u16 itemId);
|
||||
u8 CanLearnTeachableMove(u16 species, u16 move);
|
||||
u8 GetNature(struct Pokemon *mon);
|
||||
u8 GetNatureFromPersonality(u32 personality);
|
||||
u16 GetEvolutionTargetSpecies(struct Pokemon *mon, u8 type, u16 evolutionItem, struct Pokemon *tradePartner);
|
||||
u16 NationalPokedexNumToSpecies(u16 nationalNum);
|
||||
u16 SpeciesToNationalPokedexNum(u16 species);
|
||||
|
|
@ -777,7 +779,6 @@ u8 GetMoveRelearnerMoves(struct Pokemon *mon, u16 *moves);
|
|||
u8 GetLevelUpMovesBySpecies(u16 species, u16 *moves);
|
||||
u8 GetNumberOfRelearnableMoves(struct Pokemon *mon);
|
||||
u16 SpeciesToPokedexNum(u16 species);
|
||||
void ClearBattleMonForms(void);
|
||||
void PlayBattleBGM(void);
|
||||
void PlayMapChosenOrBattleBGM(u16 songId);
|
||||
const u32 *GetMonFrontSpritePal(struct Pokemon *mon);
|
||||
|
|
@ -819,5 +820,6 @@ bool8 HealStatusConditions(struct Pokemon *mon, u32 healMask, u8 battleId);
|
|||
u16 SanitizeSpeciesId(u16 species);
|
||||
bool32 IsSpeciesEnabled(u16 species);
|
||||
u32 GetUnownSpeciesId(u32 personality);
|
||||
u8 CalculatePartyCount(struct Pokemon *party);
|
||||
|
||||
#endif // GUARD_POKEMON_H
|
||||
|
|
|
|||
|
|
@ -178,7 +178,7 @@ void DrawDownArrow(u8 windowId, u16 x, u16 y, u8 bgColor, bool8 drawArrow, u8 *c
|
|||
u16 RenderText(struct TextPrinter *textPrinter);
|
||||
s32 (*GetFontWidthFunc(u8 glyphId))(u16, bool32);
|
||||
s32 GetStringWidth(u8 fontId, const u8 *str, s16 letterSpacing);
|
||||
u8 RenderTextHandleBold(u8 *pixels, u8 fontId, u8 *str, int a3, int a4, int a5, int a6, int a7);
|
||||
u8 RenderTextHandleBold(u8 *pixels, u8 fontId, u8 *str);
|
||||
u8 DrawKeypadIcon(u8 windowId, u8 keypadIconId, u16 x, u16 y);
|
||||
u8 GetKeypadIconTileOffset(u8 keypadIconId);
|
||||
u8 GetKeypadIconWidth(u8 keypadIconId);
|
||||
|
|
|
|||
|
|
@ -34,6 +34,8 @@ struct WildPokemonHeader
|
|||
};
|
||||
|
||||
extern const struct WildPokemonHeader gWildMonHeaders[];
|
||||
extern bool8 gIsFishingEncounter;
|
||||
extern bool8 gIsSurfingEncounter;
|
||||
|
||||
void DisableWildEncounters(bool8 disabled);
|
||||
bool8 StandardWildEncounter(u32 currMetatileAttrs, u16 previousMetaTileBehavior);
|
||||
|
|
@ -49,5 +51,6 @@ bool8 SweetScentWildEncounter(void);
|
|||
void SeedWildEncounterRng(u16 randVal);
|
||||
void ResetEncounterRateModifiers(void);
|
||||
bool8 TryStandardWildEncounter(u32 currMetatileAttrs);
|
||||
bool8 TryDoDoubleWildBattle(void);
|
||||
|
||||
#endif // GUARD_WILD_ENCOUNTER_H
|
||||
|
|
|
|||
|
|
@ -199,7 +199,6 @@ SECTIONS {
|
|||
src/heal_location.o(.text);
|
||||
src/region_map.o(.text);
|
||||
src/image_processing_effects.o(.text);
|
||||
src/battle_ai_script_commands.o(.text);
|
||||
src/wallclock.o(.text);
|
||||
src/fldeff_rocksmash.o(.text);
|
||||
src/fldeff_dig.o(.text);
|
||||
|
|
@ -288,6 +287,8 @@ SECTIONS {
|
|||
src/itemfinder.o(.text);
|
||||
src/buy_menu_helpers.o(.text);
|
||||
src/slot_machine.o(.text);
|
||||
src/battle_ai_main.o(.text);
|
||||
src/battle_ai_util.o(.text);
|
||||
src/roamer.o(.text);
|
||||
src/mystery_gift_menu.o(.text);
|
||||
src/ereader_screen.o(.text);
|
||||
|
|
@ -329,7 +330,6 @@ SECTIONS {
|
|||
data/battle_scripts_1.o(script_data);
|
||||
data/field_effect_scripts.o(script_data);
|
||||
data/battle_scripts_2.o(script_data);
|
||||
data/battle_ai_scripts.o(script_data);
|
||||
data/mystery_event_script_cmd_table.o(script_data);
|
||||
} > ROM =0
|
||||
|
||||
|
|
@ -429,6 +429,7 @@ SECTIONS {
|
|||
src/battle_controller_player.o(.rodata);
|
||||
src/battle_anim_smokescreen.o(.rodata);
|
||||
src/battle_controller_opponent.o(.rodata);
|
||||
src/battle_ai_switch_items.o(.rodata);
|
||||
src/battle_controller_link_opponent.o(.rodata);
|
||||
src/pokemon.o(.rodata);
|
||||
src/trig.o(.rodata);
|
||||
|
|
@ -514,7 +515,6 @@ SECTIONS {
|
|||
src/heal_location.o(.rodata);
|
||||
src/region_map.o(.rodata);
|
||||
src/image_processing_effects.o(.rodata);
|
||||
src/battle_ai_script_commands.o(.rodata);
|
||||
src/wallclock.o(.rodata);
|
||||
src/fldeff_flash.o(.rodata);
|
||||
src/time_events.o(.rodata);
|
||||
|
|
@ -588,6 +588,8 @@ SECTIONS {
|
|||
src/itemfinder.o(.rodata);
|
||||
src/buy_menu_helpers.o(.rodata);
|
||||
src/slot_machine.o(.rodata);
|
||||
src/battle_ai_main.o(.rodata);
|
||||
src/battle_ai_util.o(.rodata);
|
||||
src/roamer.o(.rodata);
|
||||
src/mystery_gift_menu.o(.rodata);
|
||||
src/ereader_screen.o(.rodata);
|
||||
|
|
|
|||
5189
src/battle_ai_main.c
Normal file
5189
src/battle_ai_main.c
Normal file
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
3724
src/battle_ai_util.c
Normal file
3724
src/battle_ai_util.c
Normal file
File diff suppressed because it is too large
Load Diff
|
|
@ -2300,7 +2300,7 @@ void AnimTask_TransformMon(u8 taskId)
|
|||
else
|
||||
position = GetBattlerPosition(gBattleAnimAttacker);
|
||||
|
||||
src = gMonSpritesGfxPtr->sprites[position] + (gBattleMonForms[gBattleAnimAttacker] << 11);
|
||||
src = gMonSpritesGfxPtr->sprites[position];
|
||||
dest = animBg.bgTiles;
|
||||
CpuCopy32(src, dest, MON_PIC_SIZE);
|
||||
LoadBgTiles(1, animBg.bgTiles, 0x800, animBg.tilesOffset);
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
#include "global.h"
|
||||
#include "gflib.h"
|
||||
#include "battle_anim.h"
|
||||
#include "battle_interface.h"
|
||||
#include "data.h"
|
||||
#include "decompress.h"
|
||||
#include "pokemon_icon.h"
|
||||
|
|
@ -86,10 +87,10 @@ u8 GetBattlerSpriteCoord(u8 battlerId, u8 coordType)
|
|||
{
|
||||
case BATTLER_COORD_X:
|
||||
case BATTLER_COORD_X_2:
|
||||
retVal = sBattlerCoords[IS_DOUBLE_BATTLE()][GetBattlerPosition(battlerId)].x;
|
||||
retVal = sBattlerCoords[WhichBattleCoords(battlerId)][GetBattlerPosition(battlerId)].x;
|
||||
break;
|
||||
case BATTLER_COORD_Y:
|
||||
retVal = sBattlerCoords[IS_DOUBLE_BATTLE()][GetBattlerPosition(battlerId)].y;
|
||||
retVal = sBattlerCoords[WhichBattleCoords(battlerId)][GetBattlerPosition(battlerId)].y;
|
||||
break;
|
||||
case BATTLER_COORD_Y_PIC_OFFSET:
|
||||
case BATTLER_COORD_Y_PIC_OFFSET_DEFAULT:
|
||||
|
|
@ -208,7 +209,7 @@ static u8 GetBattlerSpriteFinal_Y(u8 battlerId, u16 species, bool8 a3)
|
|||
offset = GetBattlerYDelta(battlerId, species);
|
||||
offset -= GetBattlerElevation(battlerId, species);
|
||||
}
|
||||
y = offset + sBattlerCoords[IS_DOUBLE_BATTLE()][GetBattlerPosition(battlerId)].y;
|
||||
y = offset + sBattlerCoords[WhichBattleCoords(battlerId)][GetBattlerPosition(battlerId)].y;
|
||||
if (a3)
|
||||
{
|
||||
if (GetBattlerSide(battlerId) == B_SIDE_PLAYER)
|
||||
|
|
@ -782,16 +783,6 @@ void InitSpritePosToAnimAttacker(struct Sprite *sprite, bool8 respectMonPicOffse
|
|||
sprite->y += gBattleAnimArgs[1];
|
||||
}
|
||||
|
||||
// u8 GetBattlerSide(u8 battlerId)
|
||||
// {
|
||||
// return GET_BATTLER_SIDE2(battlerId);
|
||||
// }
|
||||
|
||||
// u8 GetBattlerPosition(u8 battlerId)
|
||||
// {
|
||||
// return GET_BATTLER_POSITION(battlerId);
|
||||
// }
|
||||
|
||||
u8 GetBattlerAtPosition(u8 position)
|
||||
{
|
||||
u8 i;
|
||||
|
|
|
|||
|
|
@ -2040,21 +2040,17 @@ void AnimTask_SetTargetToEffectBattler(u8 taskId)
|
|||
void TryShinyAnimation(u8 battler, struct Pokemon *mon)
|
||||
{
|
||||
bool32 isShiny;
|
||||
u32 otId, personality;
|
||||
u32 shinyValue;
|
||||
u8 taskId1, taskId2;
|
||||
struct Pokemon* illusionMon;
|
||||
|
||||
isShiny = FALSE;
|
||||
isShiny = GetMonData(mon, MON_DATA_IS_SHINY);
|
||||
gBattleSpritesDataPtr->healthBoxesData[battler].triedShinyMonAnim = TRUE;
|
||||
otId = GetMonData(mon, MON_DATA_OT_ID);
|
||||
personality = GetMonData(mon, MON_DATA_PERSONALITY);
|
||||
illusionMon = GetIllusionMonPtr(battler);
|
||||
if (illusionMon != NULL)
|
||||
mon = illusionMon;
|
||||
|
||||
if (IsBattlerSpriteVisible(battler))
|
||||
if (IsBattlerSpriteVisible(battler) && IsValidForBattle(mon))
|
||||
{
|
||||
shinyValue = HIHALF(otId) ^ LOHALF(otId) ^ HIHALF(personality) ^ LOHALF(personality);
|
||||
if (shinyValue < SHINY_ODDS)
|
||||
isShiny = TRUE;
|
||||
|
||||
if (isShiny)
|
||||
{
|
||||
if (GetSpriteTileStartByTag(ANIM_TAG_GOLD_STARS) == 0xFFFF)
|
||||
|
|
|
|||
|
|
@ -777,7 +777,7 @@ static void DrawLinkBattleParticipantPokeballs(u8 taskId, u8 multiplayerId, u8 b
|
|||
}
|
||||
else
|
||||
{
|
||||
if (multiplayerId == gBattleStruct->multiplayerId)
|
||||
if (multiplayerId == gBattleScripting.multiplayerId)
|
||||
pokeballStatuses = gTasks[taskId].data[3];
|
||||
else
|
||||
pokeballStatuses = gTasks[taskId].data[4];
|
||||
|
|
@ -800,7 +800,7 @@ static void DrawLinkBattleVsScreenOutcomeText(void)
|
|||
{
|
||||
if (gBattleOutcome == B_OUTCOME_WON)
|
||||
{
|
||||
switch (gLinkPlayers[gBattleStruct->multiplayerId].id)
|
||||
switch (gLinkPlayers[gBattleScripting.multiplayerId].id)
|
||||
{
|
||||
case 0:
|
||||
BattlePutTextOnWindow(gText_Win, B_WIN_VS_OUTCOME_LEFT);
|
||||
|
|
@ -822,7 +822,7 @@ static void DrawLinkBattleVsScreenOutcomeText(void)
|
|||
}
|
||||
else
|
||||
{
|
||||
switch (gLinkPlayers[gBattleStruct->multiplayerId].id)
|
||||
switch (gLinkPlayers[gBattleScripting.multiplayerId].id)
|
||||
{
|
||||
case 0:
|
||||
BattlePutTextOnWindow(gText_Win, B_WIN_VS_OUTCOME_RIGHT);
|
||||
|
|
@ -845,7 +845,7 @@ static void DrawLinkBattleVsScreenOutcomeText(void)
|
|||
}
|
||||
else if (gBattleOutcome == B_OUTCOME_WON)
|
||||
{
|
||||
if (gLinkPlayers[gBattleStruct->multiplayerId].id != 0)
|
||||
if (gLinkPlayers[gBattleScripting.multiplayerId].id != 0)
|
||||
{
|
||||
BattlePutTextOnWindow(gText_Win, B_WIN_VS_OUTCOME_RIGHT);
|
||||
BattlePutTextOnWindow(gText_Loss, B_WIN_VS_OUTCOME_LEFT);
|
||||
|
|
@ -858,7 +858,7 @@ static void DrawLinkBattleVsScreenOutcomeText(void)
|
|||
}
|
||||
else
|
||||
{
|
||||
if (gLinkPlayers[gBattleStruct->multiplayerId].id != 0)
|
||||
if (gLinkPlayers[gBattleScripting.multiplayerId].id != 0)
|
||||
{
|
||||
BattlePutTextOnWindow(gText_Win, B_WIN_VS_OUTCOME_LEFT);
|
||||
BattlePutTextOnWindow(gText_Loss, B_WIN_VS_OUTCOME_RIGHT);
|
||||
|
|
@ -910,7 +910,7 @@ void InitLinkBattleVsScreen(u8 taskId)
|
|||
}
|
||||
else
|
||||
{
|
||||
u8 playerId = gBattleStruct->multiplayerId;
|
||||
u8 playerId = gBattleScripting.multiplayerId;
|
||||
u8 opponentId = playerId ^ BIT_SIDE;
|
||||
u8 opponentId_copy = opponentId;
|
||||
|
||||
|
|
|
|||
|
|
@ -838,7 +838,7 @@ static void OakOldManHandleChoosePokemon(u32 battler)
|
|||
gBattleControllerData[battler] = CreateTask(TaskDummy, 0xFF);
|
||||
gTasks[gBattleControllerData[battler]].data[0] = gBattleResources->bufferA[battler][1] & 0xF;
|
||||
*(&gBattleStruct->battlerPreventingSwitchout) = gBattleResources->bufferA[battler][1] >> 4;
|
||||
*(&gBattleStruct->playerPartyIdx) = gBattleResources->bufferA[battler][2];
|
||||
*(&gBattleStruct->prevSelectedPartySlot) = gBattleResources->bufferA[battler][2];
|
||||
*(&gBattleStruct->abilityPreventingSwitchout) = (gBattleResources->bufferA[battler][3] & 0xFF) | (gBattleResources->bufferA[battler][7] << 8);
|
||||
for (i = 0; i < 3; ++i)
|
||||
gBattlePartyCurrentOrder[i] = gBattleResources->bufferA[battler][4 + i];
|
||||
|
|
|
|||
|
|
@ -7,17 +7,21 @@
|
|||
#include "pokeball.h"
|
||||
#include "random.h"
|
||||
#include "battle.h"
|
||||
#include "battle_ai_main.h"
|
||||
#include "battle_ai_util.h"
|
||||
#include "battle_anim.h"
|
||||
#include "battle_controllers.h"
|
||||
#include "battle_message.h"
|
||||
#include "battle_interface.h"
|
||||
#include "battle_tower.h"
|
||||
#include "battle_gfx_sfx_util.h"
|
||||
#include "battle_ai_script_commands.h"
|
||||
#include "battle_ai_switch_items.h"
|
||||
#include "party_menu.h"
|
||||
#include "trainer_tower.h"
|
||||
#include "constants/battle_ai.h"
|
||||
#include "constants/battle_anim.h"
|
||||
#include "constants/moves.h"
|
||||
#include "constants/party_menu.h"
|
||||
#include "constants/songs.h"
|
||||
#include "constants/sound.h"
|
||||
|
||||
|
|
@ -35,6 +39,7 @@ static void OpponentHandleIntroTrainerBallThrow(u32 battler);
|
|||
static void OpponentHandleDrawPartyStatusSummary(u32 battler);
|
||||
static void OpponentHandleBattleAnimation(u32 battler);
|
||||
static void OpponentHandleEndLinkBattle(u32 battler);
|
||||
static u8 CountAIAliveNonEggMonsExcept(u8 slotToIgnore);
|
||||
|
||||
static void OpponentBufferRunCommand(u32 battler);
|
||||
static void SwitchIn_HandleSoundAndEnd(u32 battler);
|
||||
|
|
@ -61,9 +66,9 @@ static void (*const sOpponentBufferCommands[CONTROLLER_CMDS_COUNT])(u32 battler)
|
|||
[CONTROLLER_PRINTSTRINGPLAYERONLY] = BtlController_Empty, // done
|
||||
[CONTROLLER_CHOOSEACTION] = OpponentHandleChooseAction, // done
|
||||
[CONTROLLER_UNKNOWNYESNOBOX] = BtlController_Empty, // done
|
||||
[CONTROLLER_CHOOSEMOVE] = OpponentHandleChooseMove, // done TODO: AI refactoring
|
||||
[CONTROLLER_CHOOSEMOVE] = OpponentHandleChooseMove, // done
|
||||
[CONTROLLER_OPENBAG] = OpponentHandleChooseItem, // done
|
||||
[CONTROLLER_CHOOSEPOKEMON] = OpponentHandleChoosePokemon, // done TODO: AI refactoring
|
||||
[CONTROLLER_CHOOSEPOKEMON] = OpponentHandleChoosePokemon, // done
|
||||
[CONTROLLER_23] = BtlController_Empty, // done
|
||||
[CONTROLLER_HEALTHBARUPDATE] = OpponentHandleHealthBarUpdate, // done
|
||||
[CONTROLLER_EXPUPDATE] = BtlController_Empty, // done
|
||||
|
|
@ -356,50 +361,117 @@ static void OpponentHandleChooseMove(u32 battler)
|
|||
u8 chosenMoveId;
|
||||
struct ChooseMoveStruct *moveInfo = (struct ChooseMoveStruct *)(&gBattleResources->bufferA[battler][4]);
|
||||
|
||||
if (gBattleTypeFlags & (BATTLE_TYPE_TRAINER | BATTLE_TYPE_FIRST_BATTLE | BATTLE_TYPE_SAFARI | BATTLE_TYPE_ROAMER))
|
||||
if (gBattleTypeFlags & (BATTLE_TYPE_TRAINER | BATTLE_TYPE_FIRST_BATTLE | BATTLE_TYPE_SAFARI | BATTLE_TYPE_ROAMER)
|
||||
|| IsWildMonSmart())
|
||||
{
|
||||
// TODO: update with AI refactoring
|
||||
BattleAI_SetupAIData(battler);
|
||||
chosenMoveId = BattleAI_ChooseMoveOrAction();
|
||||
|
||||
chosenMoveId = gBattleStruct->aiMoveOrAction[battler];
|
||||
gBattlerTarget = gBattleStruct->aiChosenTarget[battler];
|
||||
switch (chosenMoveId)
|
||||
{
|
||||
case AI_CHOICE_WATCH:
|
||||
BtlController_EmitTwoReturnValues(battler, 1, B_ACTION_SAFARI_WATCH_CAREFULLY, 0);
|
||||
BtlController_EmitTwoReturnValues(battler, BUFFER_B, B_ACTION_SAFARI_WATCH_CAREFULLY, 0);
|
||||
break;
|
||||
case AI_CHOICE_FLEE:
|
||||
BtlController_EmitTwoReturnValues(battler, 1, B_ACTION_RUN, 0);
|
||||
BtlController_EmitTwoReturnValues(battler, BUFFER_B, B_ACTION_RUN, 0);
|
||||
break;
|
||||
case AI_CHOICE_SWITCH:
|
||||
BtlController_EmitTwoReturnValues(battler, BUFFER_B, 10, 0xFFFF);
|
||||
break;
|
||||
case 6:
|
||||
BtlController_EmitTwoReturnValues(battler, BUFFER_B, 15, gBattlerTarget);
|
||||
break;
|
||||
default:
|
||||
if (gMovesInfo[moveInfo->moves[chosenMoveId]].target & (MOVE_TARGET_USER_OR_SELECTED | MOVE_TARGET_USER))
|
||||
gBattlerTarget = battler;
|
||||
if (gMovesInfo[moveInfo->moves[chosenMoveId]].target & MOVE_TARGET_BOTH)
|
||||
{
|
||||
gBattlerTarget = GetBattlerAtPosition(B_POSITION_PLAYER_LEFT);
|
||||
if (gAbsentBattlerFlags & gBitTable[gBattlerTarget])
|
||||
gBattlerTarget = GetBattlerAtPosition(B_POSITION_PLAYER_RIGHT);
|
||||
u16 chosenMove = moveInfo->moves[chosenMoveId];
|
||||
bool32 isSecondTrainer = (GetBattlerPosition(battler) == B_POSITION_OPPONENT_RIGHT) && (gBattleTypeFlags & BATTLE_TYPE_TWO_OPPONENTS) && !BATTLE_TWO_VS_ONE_OPPONENT;
|
||||
u16 trainerId = isSecondTrainer ? gTrainerBattleOpponent_B : gTrainerBattleOpponent_A;
|
||||
const struct TrainerMon *party = GetTrainerPartyFromId(trainerId);
|
||||
bool32 shouldDynamax = FALSE;
|
||||
if (party != NULL)
|
||||
shouldDynamax = party[isSecondTrainer ? gBattlerPartyIndexes[battler] - MULTI_PARTY_SIZE : gBattlerPartyIndexes[battler]].shouldDynamax;
|
||||
|
||||
if (GetBattlerMoveTargetType(battler, chosenMove) & (MOVE_TARGET_USER_OR_SELECTED | MOVE_TARGET_USER))
|
||||
gBattlerTarget = battler;
|
||||
if (GetBattlerMoveTargetType(battler, chosenMove) & MOVE_TARGET_BOTH)
|
||||
{
|
||||
gBattlerTarget = GetBattlerAtPosition(B_POSITION_PLAYER_LEFT);
|
||||
if (gAbsentBattlerFlags & gBitTable[gBattlerTarget])
|
||||
gBattlerTarget = GetBattlerAtPosition(B_POSITION_PLAYER_RIGHT);
|
||||
}
|
||||
// TODO: Z-Moves
|
||||
// if (ShouldUseZMove(battler, gBattlerTarget, chosenMove))
|
||||
// QueueZMove(battler, chosenMove);
|
||||
// If opponent can Mega Evolve, do it.
|
||||
if (CanMegaEvolve(battler))
|
||||
BtlController_EmitTwoReturnValues(battler, BUFFER_B, 10, (chosenMoveId) | (RET_MEGA_EVOLUTION) | (gBattlerTarget << 8));
|
||||
// If opponent can Ultra Burst, do it.
|
||||
else if (CanUltraBurst(battler))
|
||||
BtlController_EmitTwoReturnValues(battler, BUFFER_B, 10, (chosenMoveId) | (RET_ULTRA_BURST) | (gBattlerTarget << 8));
|
||||
// If opponent can Dynamax and is allowed in the partydata, do it.
|
||||
else if (CanDynamax(battler) && shouldDynamax)
|
||||
BtlController_EmitTwoReturnValues(battler, BUFFER_B, 10, (chosenMoveId) | (RET_DYNAMAX) | (gBattlerTarget << 8));
|
||||
else
|
||||
BtlController_EmitTwoReturnValues(battler, BUFFER_B, 10, (chosenMoveId) | (gBattlerTarget << 8));
|
||||
}
|
||||
BtlController_EmitTwoReturnValues(battler, 1, 10, (chosenMoveId) | (gBattlerTarget << 8));
|
||||
break;
|
||||
}
|
||||
OpponentBufferExecCompleted(battler);
|
||||
}
|
||||
else
|
||||
else // Wild pokemon - use random move
|
||||
{
|
||||
u16 move;
|
||||
|
||||
u8 target;
|
||||
do
|
||||
{
|
||||
chosenMoveId = Random() & 3;
|
||||
move = moveInfo->moves[chosenMoveId];
|
||||
}
|
||||
while (move == MOVE_NONE);
|
||||
if (gMovesInfo[move].target & (MOVE_TARGET_USER_OR_SELECTED | MOVE_TARGET_USER))
|
||||
BtlController_EmitTwoReturnValues(battler, 1, 10, (chosenMoveId) | (battler << 8));
|
||||
} while (move == MOVE_NONE);
|
||||
|
||||
if (GetBattlerMoveTargetType(battler, move) & (MOVE_TARGET_USER_OR_SELECTED | MOVE_TARGET_USER))
|
||||
BtlController_EmitTwoReturnValues(battler, BUFFER_B, 10, (chosenMoveId) | (battler << 8));
|
||||
else if (gBattleTypeFlags & BATTLE_TYPE_DOUBLE)
|
||||
BtlController_EmitTwoReturnValues(battler, 1, 10, (chosenMoveId) | (GetBattlerAtPosition(Random() & 2) << 8));
|
||||
{
|
||||
do {
|
||||
target = GetBattlerAtPosition(Random() & 2);
|
||||
} while (!CanTargetBattler(battler, target, move));
|
||||
|
||||
// Don't bother to loop through table if the move can't attack ally
|
||||
if (B_WILD_NATURAL_ENEMIES == TRUE && !(gMovesInfo[move].target & MOVE_TARGET_BOTH))
|
||||
{
|
||||
u16 i, speciesAttacker, speciesTarget, isPartnerEnemy = FALSE;
|
||||
static const u16 naturalEnemies[][2] =
|
||||
{
|
||||
// Attacker Target
|
||||
{SPECIES_ZANGOOSE, SPECIES_SEVIPER},
|
||||
{SPECIES_SEVIPER, SPECIES_ZANGOOSE},
|
||||
{SPECIES_HEATMOR, SPECIES_DURANT},
|
||||
{SPECIES_DURANT, SPECIES_HEATMOR},
|
||||
{SPECIES_SABLEYE, SPECIES_CARBINK},
|
||||
{SPECIES_MAREANIE, SPECIES_CORSOLA},
|
||||
};
|
||||
speciesAttacker = gBattleMons[battler].species;
|
||||
speciesTarget = gBattleMons[GetBattlerAtPosition(BATTLE_PARTNER(battler))].species;
|
||||
|
||||
for (i = 0; i < ARRAY_COUNT(naturalEnemies); i++)
|
||||
{
|
||||
if (speciesAttacker == naturalEnemies[i][0] && speciesTarget == naturalEnemies[i][1])
|
||||
{
|
||||
isPartnerEnemy = TRUE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (isPartnerEnemy && CanTargetBattler(battler, target, move))
|
||||
BtlController_EmitTwoReturnValues(battler, BUFFER_B, 10, (chosenMoveId) | (GetBattlerAtPosition(BATTLE_PARTNER(battler)) << 8));
|
||||
else
|
||||
BtlController_EmitTwoReturnValues(battler, BUFFER_B, 10, (chosenMoveId) | (target << 8));
|
||||
}
|
||||
else
|
||||
{
|
||||
BtlController_EmitTwoReturnValues(battler, BUFFER_B, 10, (chosenMoveId) | (target << 8));
|
||||
}
|
||||
}
|
||||
else
|
||||
BtlController_EmitTwoReturnValues(battler, 1, 10, (chosenMoveId) | (GetBattlerAtPosition(B_POSITION_PLAYER_LEFT) << 8));
|
||||
BtlController_EmitTwoReturnValues(battler, BUFFER_B, 10, (chosenMoveId) | (GetBattlerAtPosition(B_POSITION_PLAYER_LEFT) << 8));
|
||||
|
||||
OpponentBufferExecCompleted(battler);
|
||||
}
|
||||
|
|
@ -414,14 +486,20 @@ static void OpponentHandleChooseItem(u32 battler)
|
|||
static void OpponentHandleChoosePokemon(u32 battler)
|
||||
{
|
||||
s32 chosenMonId;
|
||||
s32 pokemonInBattle = 1;
|
||||
|
||||
if (*(gBattleStruct->AI_monToSwitchIntoId + (GetBattlerPosition(battler) >> 1)) == PARTY_SIZE)
|
||||
// Choosing Revival Blessing target
|
||||
if ((gBattleResources->bufferA[battler][1] & 0xF) == PARTY_ACTION_CHOOSE_FAINTED_MON)
|
||||
{
|
||||
chosenMonId = GetMostSuitableMonToSwitchInto(battler);
|
||||
|
||||
chosenMonId = gSelectedMonPartyId = GetFirstFaintedPartyIndex(battler);
|
||||
}
|
||||
// Switching out
|
||||
else if (*(gBattleStruct->AI_monToSwitchIntoId + battler) == PARTY_SIZE)
|
||||
{
|
||||
chosenMonId = GetMostSuitableMonToSwitchInto(battler, TRUE);
|
||||
if (chosenMonId == PARTY_SIZE)
|
||||
{
|
||||
s32 battler1, battler2;
|
||||
s32 battler1, battler2, firstId, lastId;
|
||||
|
||||
if (!(gBattleTypeFlags & BATTLE_TYPE_DOUBLE))
|
||||
{
|
||||
|
|
@ -431,24 +509,52 @@ static void OpponentHandleChoosePokemon(u32 battler)
|
|||
{
|
||||
battler1 = GetBattlerAtPosition(B_POSITION_OPPONENT_LEFT);
|
||||
battler2 = GetBattlerAtPosition(B_POSITION_OPPONENT_RIGHT);
|
||||
pokemonInBattle = 2;
|
||||
}
|
||||
for (chosenMonId = 0; chosenMonId < PARTY_SIZE; ++chosenMonId)
|
||||
if (GetMonData(&gEnemyParty[chosenMonId], MON_DATA_HP) != 0
|
||||
&& chosenMonId != gBattlerPartyIndexes[battler1]
|
||||
&& chosenMonId != gBattlerPartyIndexes[battler2])
|
||||
|
||||
GetAIPartyIndexes(battler, &firstId, &lastId);
|
||||
|
||||
for (chosenMonId = (lastId-1); chosenMonId >= firstId; chosenMonId--)
|
||||
{
|
||||
if (IsValidForBattle(&gEnemyParty[chosenMonId])
|
||||
&& chosenMonId != gBattlerPartyIndexes[battler1]
|
||||
&& chosenMonId != gBattlerPartyIndexes[battler2]
|
||||
&& (!(AI_THINKING_STRUCT->aiFlags[battler] & AI_FLAG_ACE_POKEMON)
|
||||
|| chosenMonId != CalculateEnemyPartyCount() - 1
|
||||
|| CountAIAliveNonEggMonsExcept(PARTY_SIZE) == pokemonInBattle))
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
*(gBattleStruct->monToSwitchIntoId + battler) = chosenMonId;
|
||||
}
|
||||
else
|
||||
{
|
||||
chosenMonId = *(gBattleStruct->AI_monToSwitchIntoId + (GetBattlerPosition(battler) >> 1));
|
||||
*(gBattleStruct->AI_monToSwitchIntoId + (GetBattlerPosition(battler) >> 1)) = PARTY_SIZE;
|
||||
chosenMonId = *(gBattleStruct->AI_monToSwitchIntoId + battler);
|
||||
*(gBattleStruct->AI_monToSwitchIntoId + battler) = PARTY_SIZE;
|
||||
*(gBattleStruct->monToSwitchIntoId + battler) = chosenMonId;
|
||||
}
|
||||
*(gBattleStruct->monToSwitchIntoId + battler) = chosenMonId;
|
||||
BtlController_EmitChosenMonReturnValue(battler, 1, chosenMonId, NULL);
|
||||
BtlController_EmitChosenMonReturnValue(battler, BUFFER_B, chosenMonId, NULL);
|
||||
OpponentBufferExecCompleted(battler);
|
||||
}
|
||||
|
||||
static u8 CountAIAliveNonEggMonsExcept(u8 slotToIgnore)
|
||||
{
|
||||
u16 i, count;
|
||||
|
||||
for (i = 0, count = 0; i < PARTY_SIZE; i++)
|
||||
{
|
||||
if (i != slotToIgnore
|
||||
&& IsValidForBattle(&gEnemyParty[i]))
|
||||
{
|
||||
count++;
|
||||
}
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
static void OpponentHandleHealthBarUpdate(u32 battler)
|
||||
{
|
||||
BtlController_HandleHealthBarUpdate(battler, FALSE);
|
||||
|
|
|
|||
|
|
@ -1002,37 +1002,38 @@ static void Intro_DelayAndEnd(u32 battler)
|
|||
|
||||
static void Intro_WaitForShinyAnimAndHealthbox(u32 battler)
|
||||
{
|
||||
bool8 var = FALSE;
|
||||
bool8 healthboxAnimDone = FALSE;
|
||||
|
||||
if (!IsDoubleBattle() || (IsDoubleBattle() && (gBattleTypeFlags & BATTLE_TYPE_MULTI)))
|
||||
{
|
||||
if (gSprites[gHealthboxSpriteIds[battler]].callback == SpriteCallbackDummy)
|
||||
var = TRUE;
|
||||
}
|
||||
else
|
||||
// Check if healthbox has finished sliding in
|
||||
if (TwoPlayerIntroMons(battler) && !(gBattleTypeFlags & BATTLE_TYPE_MULTI))
|
||||
{
|
||||
if (gSprites[gHealthboxSpriteIds[battler]].callback == SpriteCallbackDummy
|
||||
&& gSprites[gHealthboxSpriteIds[BATTLE_PARTNER(battler)]].callback == SpriteCallbackDummy)
|
||||
var = TRUE;
|
||||
healthboxAnimDone = TRUE;
|
||||
}
|
||||
if (IsCryPlayingOrClearCrySongs())
|
||||
var = FALSE;
|
||||
if (var && gBattleSpritesDataPtr->healthBoxesData[battler].finishedShinyMonAnim
|
||||
else
|
||||
{
|
||||
if (gSprites[gHealthboxSpriteIds[battler]].callback == SpriteCallbackDummy)
|
||||
healthboxAnimDone = TRUE;
|
||||
}
|
||||
|
||||
// If healthbox and shiny anim are done
|
||||
if (healthboxAnimDone && gBattleSpritesDataPtr->healthBoxesData[battler].finishedShinyMonAnim
|
||||
&& gBattleSpritesDataPtr->healthBoxesData[BATTLE_PARTNER(battler)].finishedShinyMonAnim)
|
||||
{
|
||||
// Reset shiny anim (even if it didn't occur)
|
||||
gBattleSpritesDataPtr->healthBoxesData[battler].triedShinyMonAnim = FALSE;
|
||||
gBattleSpritesDataPtr->healthBoxesData[battler].finishedShinyMonAnim = FALSE;
|
||||
gBattleSpritesDataPtr->healthBoxesData[BATTLE_PARTNER(battler)].triedShinyMonAnim = FALSE;
|
||||
gBattleSpritesDataPtr->healthBoxesData[BATTLE_PARTNER(battler)].finishedShinyMonAnim = FALSE;
|
||||
FreeSpriteTilesByTag(ANIM_TAG_GOLD_STARS);
|
||||
FreeSpritePaletteByTag(ANIM_TAG_GOLD_STARS);
|
||||
if (gBattleTypeFlags & BATTLE_TYPE_MULTI)
|
||||
m4aMPlayContinue(&gMPlayInfo_BGM);
|
||||
else
|
||||
m4aMPlayVolumeControl(&gMPlayInfo_BGM, TRACKS_ALL, 256);
|
||||
|
||||
HandleLowHpMusicChange(&gPlayerParty[gBattlerPartyIndexes[battler]], battler);
|
||||
if (IsDoubleBattle())
|
||||
|
||||
if (TwoPlayerIntroMons(battler))
|
||||
HandleLowHpMusicChange(&gPlayerParty[gBattlerPartyIndexes[BATTLE_PARTNER(battler)]], BATTLE_PARTNER(battler));
|
||||
|
||||
gBattleSpritesDataPtr->healthBoxesData[battler].introEndDelay = 3;
|
||||
gBattlerControllerFuncs[battler] = Intro_DelayAndEnd;
|
||||
}
|
||||
|
|
@ -1040,28 +1041,86 @@ static void Intro_WaitForShinyAnimAndHealthbox(u32 battler)
|
|||
|
||||
static void Intro_TryShinyAnimShowHealthbox(u32 battler)
|
||||
{
|
||||
if (!gBattleSpritesDataPtr->healthBoxesData[battler].ballAnimActive && !gBattleSpritesDataPtr->healthBoxesData[BATTLE_PARTNER(battler)].ballAnimActive)
|
||||
bool32 bgmRestored = FALSE;
|
||||
bool32 battlerAnimsDone = FALSE;
|
||||
|
||||
// Start shiny animation if applicable for 1st Pokémon
|
||||
if (!gBattleSpritesDataPtr->healthBoxesData[battler].triedShinyMonAnim
|
||||
&& !gBattleSpritesDataPtr->healthBoxesData[battler].ballAnimActive)
|
||||
TryShinyAnimation(battler, &gPlayerParty[gBattlerPartyIndexes[battler]]);
|
||||
|
||||
// Start shiny animation if applicable for 2nd Pokémon
|
||||
if (!gBattleSpritesDataPtr->healthBoxesData[BATTLE_PARTNER(battler)].triedShinyMonAnim
|
||||
&& !gBattleSpritesDataPtr->healthBoxesData[BATTLE_PARTNER(battler)].ballAnimActive)
|
||||
TryShinyAnimation(BATTLE_PARTNER(battler), &gPlayerParty[gBattlerPartyIndexes[BATTLE_PARTNER(battler)]]);
|
||||
|
||||
// Show healthbox after ball anim
|
||||
if (!gBattleSpritesDataPtr->healthBoxesData[battler].ballAnimActive
|
||||
&& !gBattleSpritesDataPtr->healthBoxesData[BATTLE_PARTNER(battler)].ballAnimActive)
|
||||
{
|
||||
if (!gBattleSpritesDataPtr->healthBoxesData[battler].triedShinyMonAnim)
|
||||
TryShinyAnimation(battler, &gPlayerParty[gBattlerPartyIndexes[battler]]);
|
||||
if (!gBattleSpritesDataPtr->healthBoxesData[BATTLE_PARTNER(battler)].triedShinyMonAnim)
|
||||
TryShinyAnimation(BATTLE_PARTNER(battler), &gPlayerParty[gBattlerPartyIndexes[BATTLE_PARTNER(battler)]]);
|
||||
if (IsDoubleBattle() && !(gBattleTypeFlags & BATTLE_TYPE_MULTI))
|
||||
if (!gBattleSpritesDataPtr->healthBoxesData[battler].healthboxSlideInStarted)
|
||||
{
|
||||
DestroySprite(&gSprites[gBattleControllerData[BATTLE_PARTNER(battler)]]);
|
||||
UpdateHealthboxAttribute(gHealthboxSpriteIds[BATTLE_PARTNER(battler)],
|
||||
&gPlayerParty[gBattlerPartyIndexes[BATTLE_PARTNER(battler)]],
|
||||
HEALTHBOX_ALL);
|
||||
StartHealthboxSlideIn(BATTLE_PARTNER(battler));
|
||||
SetHealthboxSpriteVisible(gHealthboxSpriteIds[BATTLE_PARTNER(battler)]);
|
||||
if (TwoPlayerIntroMons(battler) && !(gBattleTypeFlags & BATTLE_TYPE_MULTI))
|
||||
{
|
||||
UpdateHealthboxAttribute(gHealthboxSpriteIds[BATTLE_PARTNER(battler)], &gPlayerParty[gBattlerPartyIndexes[BATTLE_PARTNER(battler)]], HEALTHBOX_ALL);
|
||||
StartHealthboxSlideIn(BATTLE_PARTNER(battler));
|
||||
SetHealthboxSpriteVisible(gHealthboxSpriteIds[BATTLE_PARTNER(battler)]);
|
||||
}
|
||||
UpdateHealthboxAttribute(gHealthboxSpriteIds[battler], &gPlayerParty[gBattlerPartyIndexes[battler]], HEALTHBOX_ALL);
|
||||
StartHealthboxSlideIn(battler);
|
||||
SetHealthboxSpriteVisible(gHealthboxSpriteIds[battler]);
|
||||
}
|
||||
gBattleSpritesDataPtr->healthBoxesData[battler].healthboxSlideInStarted = TRUE;
|
||||
}
|
||||
|
||||
// Restore bgm after cry has played and healthbox anim is started
|
||||
if (!gBattleSpritesDataPtr->healthBoxesData[battler].waitForCry
|
||||
&& gBattleSpritesDataPtr->healthBoxesData[battler].healthboxSlideInStarted
|
||||
&& !gBattleSpritesDataPtr->healthBoxesData[BATTLE_PARTNER(battler)].waitForCry
|
||||
&& !IsCryPlayingOrClearCrySongs())
|
||||
{
|
||||
if (!gBattleSpritesDataPtr->healthBoxesData[battler].bgmRestored)
|
||||
{
|
||||
if (gBattleTypeFlags & BATTLE_TYPE_MULTI && gBattleTypeFlags & BATTLE_TYPE_LINK)
|
||||
m4aMPlayContinue(&gMPlayInfo_BGM);
|
||||
else
|
||||
m4aMPlayVolumeControl(&gMPlayInfo_BGM, TRACKS_ALL, 0x100);
|
||||
}
|
||||
gBattleSpritesDataPtr->healthBoxesData[battler].bgmRestored = TRUE;
|
||||
bgmRestored = TRUE;
|
||||
}
|
||||
|
||||
// Wait for battler anims
|
||||
if (TwoPlayerIntroMons(battler) && !(gBattleTypeFlags & BATTLE_TYPE_MULTI))
|
||||
{
|
||||
if (gSprites[gBattleControllerData[battler]].callback == SpriteCallbackDummy
|
||||
&& gSprites[gBattlerSpriteIds[battler]].callback == SpriteCallbackDummy
|
||||
&& gSprites[gBattleControllerData[BATTLE_PARTNER(battler)]].callback == SpriteCallbackDummy
|
||||
&& gSprites[gBattlerSpriteIds[BATTLE_PARTNER(battler)]].callback == SpriteCallbackDummy)
|
||||
{
|
||||
battlerAnimsDone = TRUE;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (gSprites[gBattleControllerData[battler]].callback == SpriteCallbackDummy
|
||||
&& gSprites[gBattlerSpriteIds[battler]].callback == SpriteCallbackDummy)
|
||||
{
|
||||
battlerAnimsDone = TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
// Clean up
|
||||
if (bgmRestored && battlerAnimsDone)
|
||||
{
|
||||
if (TwoPlayerIntroMons(battler) && !(gBattleTypeFlags & BATTLE_TYPE_MULTI))
|
||||
DestroySprite(&gSprites[gBattleControllerData[BATTLE_PARTNER(battler)]]);
|
||||
DestroySprite(&gSprites[gBattleControllerData[battler]]);
|
||||
UpdateHealthboxAttribute(gHealthboxSpriteIds[battler],
|
||||
&gPlayerParty[gBattlerPartyIndexes[battler]],
|
||||
HEALTHBOX_ALL);
|
||||
StartHealthboxSlideIn(battler);
|
||||
SetHealthboxSpriteVisible(gHealthboxSpriteIds[battler]);
|
||||
|
||||
gBattleSpritesDataPtr->animationData->introAnimActive = FALSE;
|
||||
gBattleSpritesDataPtr->healthBoxesData[battler].bgmRestored = FALSE;
|
||||
gBattleSpritesDataPtr->healthBoxesData[battler].healthboxSlideInStarted = FALSE;
|
||||
|
||||
gBattlerControllerFuncs[battler] = Intro_WaitForShinyAnimAndHealthbox;
|
||||
}
|
||||
}
|
||||
|
|
@ -1783,7 +1842,7 @@ static void PlayerHandleChoosePokemon(u32 battler)
|
|||
gBattleControllerData[battler] = CreateTask(TaskDummy, 0xFF);
|
||||
gTasks[gBattleControllerData[battler]].data[0] = gBattleResources->bufferA[battler][1] & 0xF;
|
||||
*(&gBattleStruct->battlerPreventingSwitchout) = gBattleResources->bufferA[battler][1] >> 4;
|
||||
*(&gBattleStruct->playerPartyIdx) = gBattleResources->bufferA[battler][2];
|
||||
*(&gBattleStruct->prevSelectedPartySlot) = gBattleResources->bufferA[battler][2];
|
||||
*(&gBattleStruct->abilityPreventingSwitchout) = (gBattleResources->bufferA[battler][3] & 0xFF) | (gBattleResources->bufferA[battler][7] << 8);
|
||||
BeginNormalPaletteFade(PALETTES_ALL, 0, 0, 0x10, RGB_BLACK);
|
||||
gBattlerControllerFuncs[battler] = OpenPartyMenuToChooseMon;
|
||||
|
|
|
|||
|
|
@ -735,7 +735,7 @@ static void PokedudeHandleChoosePokemon(u32 battler)
|
|||
gBattleControllerData[battler] = CreateTask(TaskDummy, 0xFF);
|
||||
gTasks[gBattleControllerData[battler]].data[0] = gBattleResources->bufferA[battler][1] & 0xF;
|
||||
*(&gBattleStruct->battlerPreventingSwitchout) = gBattleResources->bufferA[battler][1] >> 4;
|
||||
*(&gBattleStruct->playerPartyIdx) = gBattleResources->bufferA[battler][2];
|
||||
*(&gBattleStruct->prevSelectedPartySlot) = gBattleResources->bufferA[battler][2];
|
||||
*(&gBattleStruct->abilityPreventingSwitchout) = (gBattleResources->bufferA[battler][3] & 0xFF) | (gBattleResources->bufferA[battler][7] << 8);
|
||||
for (i = 0; i < 3; ++i)
|
||||
gBattlePartyCurrentOrder[i] = gBattleResources->bufferA[battler][4 + i];
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
#include "global.h"
|
||||
#include "battle.h"
|
||||
#include "battle_ai_script_commands.h"
|
||||
#include "battle_ai_main.h"
|
||||
#include "battle_ai_util.h"
|
||||
#include "battle_anim.h"
|
||||
#include "battle_controllers.h"
|
||||
#include "battle_interface.h"
|
||||
|
|
@ -69,8 +70,8 @@ void SetUpBattleVars(void)
|
|||
HandleLinkBattleSetup();
|
||||
gBattleControllerExecFlags = 0;
|
||||
ClearBattleAnimationVars();
|
||||
ClearBattleMonForms();
|
||||
BattleAI_HandleItemUseBeforeAISetup();
|
||||
BattleAI_SetupItems();
|
||||
BattleAI_SetupFlags();
|
||||
}
|
||||
|
||||
void InitBattleControllers(void)
|
||||
|
|
@ -313,16 +314,13 @@ static void SetBattlePartyIds(void)
|
|||
{
|
||||
for (i = 0; i < gBattlersCount; i++)
|
||||
{
|
||||
for (j = 0; j < PARTY_SIZE; ++j)
|
||||
for (j = 0; j < PARTY_SIZE; j++)
|
||||
{
|
||||
if (i < 2)
|
||||
{
|
||||
if (GET_BATTLER_SIDE2(i) == B_SIDE_PLAYER)
|
||||
if (GetBattlerSide(i) == B_SIDE_PLAYER)
|
||||
{
|
||||
if (GetMonData(&gPlayerParty[j], MON_DATA_HP) != 0
|
||||
&& GetMonData(&gPlayerParty[j], MON_DATA_SPECIES_OR_EGG) != SPECIES_NONE
|
||||
&& GetMonData(&gPlayerParty[j], MON_DATA_SPECIES_OR_EGG) != SPECIES_EGG
|
||||
&& !GetMonData(&gPlayerParty[j], MON_DATA_IS_EGG))
|
||||
if (IsValidForBattle(&gPlayerParty[j]))
|
||||
{
|
||||
gBattlerPartyIndexes[i] = j;
|
||||
break;
|
||||
|
|
@ -330,10 +328,7 @@ static void SetBattlePartyIds(void)
|
|||
}
|
||||
else
|
||||
{
|
||||
if (GetMonData(&gEnemyParty[j], MON_DATA_HP) != 0
|
||||
&& GetMonData(&gEnemyParty[j], MON_DATA_SPECIES_OR_EGG) != SPECIES_NONE
|
||||
&& GetMonData(&gEnemyParty[j], MON_DATA_SPECIES_OR_EGG) != SPECIES_EGG
|
||||
&& !GetMonData(&gEnemyParty[j], MON_DATA_IS_EGG))
|
||||
if (IsValidForBattle(&gEnemyParty[j]))
|
||||
{
|
||||
gBattlerPartyIndexes[i] = j;
|
||||
break;
|
||||
|
|
@ -342,13 +337,9 @@ static void SetBattlePartyIds(void)
|
|||
}
|
||||
else
|
||||
{
|
||||
if (GET_BATTLER_SIDE2(i) == B_SIDE_PLAYER)
|
||||
if (GetBattlerSide(i) == B_SIDE_PLAYER)
|
||||
{
|
||||
if (GetMonData(&gPlayerParty[j], MON_DATA_HP) != 0
|
||||
&& GetMonData(&gPlayerParty[j], MON_DATA_SPECIES) != SPECIES_NONE // Probably a typo by Game Freak. The rest use SPECIES2.
|
||||
&& GetMonData(&gPlayerParty[j], MON_DATA_SPECIES_OR_EGG) != SPECIES_EGG
|
||||
&& !GetMonData(&gPlayerParty[j], MON_DATA_IS_EGG)
|
||||
&& gBattlerPartyIndexes[i - 2] != j)
|
||||
if (IsValidForBattle(&gPlayerParty[j]) && gBattlerPartyIndexes[i - 2] != j)
|
||||
{
|
||||
gBattlerPartyIndexes[i] = j;
|
||||
break;
|
||||
|
|
@ -356,19 +347,24 @@ static void SetBattlePartyIds(void)
|
|||
}
|
||||
else
|
||||
{
|
||||
if (GetMonData(&gEnemyParty[j], MON_DATA_HP) != 0
|
||||
&& GetMonData(&gEnemyParty[j], MON_DATA_SPECIES_OR_EGG) != SPECIES_NONE
|
||||
&& GetMonData(&gEnemyParty[j], MON_DATA_SPECIES_OR_EGG) != SPECIES_EGG
|
||||
&& !GetMonData(&gEnemyParty[j], MON_DATA_IS_EGG)
|
||||
&& gBattlerPartyIndexes[i - 2] != j)
|
||||
if (IsValidForBattle(&gEnemyParty[j]) && gBattlerPartyIndexes[i - 2] != j)
|
||||
{
|
||||
gBattlerPartyIndexes[i] = j;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// No valid mons were found. Add the empty slot.
|
||||
if (gBattlerPartyIndexes[i - 2] == 0)
|
||||
gBattlerPartyIndexes[i] = 1;
|
||||
else
|
||||
gBattlerPartyIndexes[i] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (gBattleTypeFlags & BATTLE_TYPE_TWO_OPPONENTS)
|
||||
gBattlerPartyIndexes[1] = 0, gBattlerPartyIndexes[3] = 3;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -837,7 +833,7 @@ void BtlController_EmitChooseAction(u32 battler, u32 bufferId, u8 action, u16 it
|
|||
}
|
||||
|
||||
// Unused
|
||||
static void BtlController_EmitUnknownYesNoBox(u32 battler, u32 bufferId, u32 arg1) // TODO: Does the function name make sense for pokefirered?
|
||||
static void BtlController_EmitUnknownYesNoBox(u32 battler, u32 bufferId, u32 arg1)
|
||||
{
|
||||
gBattleResources->transferBuffer[0] = CONTROLLER_UNKNOWNYESNOBOX;
|
||||
gBattleResources->transferBuffer[1] = arg1;
|
||||
|
|
|
|||
|
|
@ -139,11 +139,7 @@ void SpriteCB_WaitForBattlerBallReleaseAnim(struct Sprite *sprite)
|
|||
if (gSprites[spriteId].animPaused)
|
||||
gSprites[spriteId].animPaused = 0;
|
||||
else if (gSprites[spriteId].animEnded)
|
||||
{
|
||||
gSprites[spriteId].callback = SetIdleSpriteCallback;
|
||||
StartSpriteAffineAnim(&gSprites[spriteId], 0);
|
||||
sprite->callback = SpriteCallbackDummy;
|
||||
}
|
||||
}
|
||||
|
||||
// Unused
|
||||
|
|
@ -211,7 +207,6 @@ bool8 TryHandleLaunchBattleTableAnimation(u8 activeBattler, u8 atkBattler, u8 de
|
|||
|
||||
if (tableId == B_ANIM_FORM_CHANGE && (argument & 0x80))
|
||||
{
|
||||
gBattleMonForms[activeBattler] = (argument & ~(0x80));
|
||||
return TRUE;
|
||||
}
|
||||
else if (gBattleSpritesDataPtr->battlerData[activeBattler].behindSubstitute
|
||||
|
|
@ -313,6 +308,8 @@ void BattleLoadMonSpriteGfx(struct Pokemon *mon, u32 battler)
|
|||
u32 monsPersonality, currentPersonality, isShiny, species, paletteOffset, position;
|
||||
const void *lzPaletteData;
|
||||
struct Pokemon *illusionMon = GetIllusionMonPtr(battler);
|
||||
if (illusionMon != NULL)
|
||||
mon = illusionMon;
|
||||
|
||||
if (GetMonData(mon, MON_DATA_IS_EGG) || GetMonData(mon, MON_DATA_SPECIES) == SPECIES_NONE) // Don't load GFX of egg pokemon.
|
||||
return;
|
||||
|
|
@ -497,7 +494,12 @@ bool8 BattleLoadAllHealthBoxesGfx(u8 state)
|
|||
else
|
||||
{
|
||||
if (state == 2)
|
||||
LoadCompressedSpriteSheetUsingHeap(&sSpriteSheets_DoublesPlayerHealthbox[0]);
|
||||
{
|
||||
if (WhichBattleCoords(0))
|
||||
LoadCompressedSpriteSheetUsingHeap(&sSpriteSheets_DoublesPlayerHealthbox[0]);
|
||||
else
|
||||
LoadCompressedSpriteSheetUsingHeap(&sSpriteSheet_SinglesPlayerHealthbox);
|
||||
}
|
||||
else if (state == 3)
|
||||
LoadCompressedSpriteSheetUsingHeap(&sSpriteSheets_DoublesPlayerHealthbox[1]);
|
||||
else if (state == 4)
|
||||
|
|
@ -697,7 +699,7 @@ void HandleSpeciesGfxDataChange(u8 battlerAtk, u8 battlerDef, bool32 megaEvo, bo
|
|||
CpuCopy32(&gPlttBufferFaded[paletteOffset], &gPlttBufferUnfaded[paletteOffset], PLTT_SIZEOF(16));
|
||||
gBattleSpritesDataPtr->battlerData[battlerAtk].transformSpecies = targetSpecies;
|
||||
}
|
||||
gBattleMonForms[battlerAtk] = gBattleMonForms[battlerDef];
|
||||
|
||||
gSprites[gBattlerSpriteIds[battlerAtk]].y = GetBattlerSpriteDefault_Y(battlerAtk);
|
||||
StartSpriteAnim(&gSprites[gBattlerSpriteIds[battlerAtk]], 0);
|
||||
}
|
||||
|
|
@ -717,11 +719,7 @@ void BattleLoadSubstituteOrMonSpriteGfx(u8 battlerId, bool8 loadMonSprite)
|
|||
LZDecompressVram(gSubstituteDollTilemap, gMonSpritesGfxPtr->sprites[position]);
|
||||
for (i = 1; i < 4; ++i)
|
||||
{
|
||||
u8 (*ptr)[4][0x800] = gMonSpritesGfxPtr->sprites[position];
|
||||
|
||||
++ptr;
|
||||
--ptr;
|
||||
DmaCopy32Defvars(3, (*ptr)[0], (*ptr)[i], 0x800);
|
||||
Dma3CopyLarge32_(gMonSpritesGfxPtr->sprites[position], &gMonSpritesGfxPtr->sprites[position][MON_PIC_SIZE * i], MON_PIC_SIZE);
|
||||
}
|
||||
palOffset = OBJ_PLTT_ID(battlerId);
|
||||
LoadCompressedPalette(gSubstituteDollPal, palOffset, PLTT_SIZE_4BPP);
|
||||
|
|
@ -738,7 +736,7 @@ void BattleLoadSubstituteOrMonSpriteGfx(u8 battlerId, bool8 loadMonSprite)
|
|||
void LoadBattleMonGfxAndAnimate(u8 battlerId, bool8 loadMonSprite, u8 spriteId)
|
||||
{
|
||||
BattleLoadSubstituteOrMonSpriteGfx(battlerId, loadMonSprite);
|
||||
StartSpriteAnim(&gSprites[spriteId], gBattleMonForms[battlerId]);
|
||||
StartSpriteAnim(&gSprites[spriteId], 0);
|
||||
if (!loadMonSprite)
|
||||
gSprites[spriteId].y = GetSubstituteSpriteDefault_Y(battlerId);
|
||||
else
|
||||
|
|
@ -946,7 +944,6 @@ void BattleInterfaceSetWindowPals(void)
|
|||
void ClearTemporarySpeciesSpriteData(u8 battlerId, bool8 dontClearSubstitute)
|
||||
{
|
||||
gBattleSpritesDataPtr->battlerData[battlerId].transformSpecies = SPECIES_NONE;
|
||||
gBattleMonForms[battlerId] = 0;
|
||||
if (!dontClearSubstitute)
|
||||
ClearBehindSubstituteBit(battlerId);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -67,7 +67,7 @@ struct TestingBar
|
|||
static void SpriteCB_HealthBoxOther(struct Sprite *sprite);
|
||||
static void SpriteCB_HealthBar(struct Sprite *sprite);
|
||||
static const u8 *GetBattleInterfaceGfxPtr(u8 which);
|
||||
static void UpdateHpTextInHealthboxInDoubles(u8 healthboxSpriteId, s16 value, u8 maxOrCurrent);
|
||||
static void UpdateHpTextInHealthboxInDoubles(u8 healthboxSpriteId, u32 maxOrCurrent, s16 currHp, s16 maxHp);
|
||||
static void Task_HidePartyStatusSummary_BattleStart_1(u8 taskId);
|
||||
static void Task_HidePartyStatusSummary_BattleStart_2(u8 taskId);
|
||||
static void SpriteCB_PartySummaryBar_Exit(struct Sprite *sprite);
|
||||
|
|
@ -682,7 +682,7 @@ u8 CreateBattlerHealthboxSprites(u8 battlerId)
|
|||
u8 healthbarSpriteId;
|
||||
struct Sprite *healthbarSprite;
|
||||
|
||||
if (!IsDoubleBattle())
|
||||
if (WhichBattleCoords(battlerId) == 0)
|
||||
{
|
||||
if (GetBattlerSide(battlerId) == B_SIDE_PLAYER)
|
||||
{
|
||||
|
|
@ -864,7 +864,7 @@ void InitBattlerHealthboxCoords(u8 battler)
|
|||
{
|
||||
s16 x = 0, y = 0;
|
||||
|
||||
if (!IsDoubleBattle())
|
||||
if (!WhichBattleCoords(battler))
|
||||
{
|
||||
if (GetBattlerSide(battler) != B_SIDE_PLAYER)
|
||||
x = 44, y = 30;
|
||||
|
|
@ -910,7 +910,7 @@ static void UpdateLvlInHealthbox(u8 healthboxSpriteId, u8 lvl)
|
|||
if (GetBattlerSide(gSprites[healthboxSpriteId].sBattlerId) == B_SIDE_PLAYER)
|
||||
{
|
||||
objVram = (void *)(OBJ_VRAM0);
|
||||
if (!IsDoubleBattle())
|
||||
if (!WhichBattleCoords(gSprites[healthboxSpriteId].sBattlerId))
|
||||
objVram += spriteTileNum + 0x820;
|
||||
else
|
||||
objVram += spriteTileNum + 0x420;
|
||||
|
|
@ -929,7 +929,7 @@ void UpdateHpTextInHealthbox(u32 healthboxSpriteId, u32 maxOrCurrent, s16 currHp
|
|||
u32 windowId, spriteTileNum;
|
||||
u8 *windowTileData;
|
||||
|
||||
if (GetBattlerSide(gSprites[healthboxSpriteId].sBattlerId) == B_SIDE_PLAYER && !IsDoubleBattle())
|
||||
if (GetBattlerSide(gSprites[healthboxSpriteId].sBattlerId) == B_SIDE_PLAYER && !WhichBattleCoords(gSprites[healthboxSpriteId].sBattlerId))
|
||||
{
|
||||
// Only in the Japanese release can HP be displayed as text outside of double battles
|
||||
u8 text[8];
|
||||
|
|
@ -960,12 +960,12 @@ void UpdateHpTextInHealthbox(u32 healthboxSpriteId, u32 maxOrCurrent, s16 currHp
|
|||
|
||||
u8 text[20] = __("{COLOR 01}{HIGHLIGHT 02}");
|
||||
battler = gSprites[healthboxSpriteId].sBattlerId;
|
||||
if (IsDoubleBattle() == TRUE || GetBattlerSide(battler) == B_SIDE_OPPONENT)
|
||||
if (WhichBattleCoords(battler) == TRUE || GetBattlerSide(battler) == B_SIDE_OPPONENT)
|
||||
{
|
||||
if (maxOrCurrent != HP_CURRENT)
|
||||
UpdateHpTextInHealthboxInDoubles(healthboxSpriteId, maxHp, maxOrCurrent);
|
||||
UpdateHpTextInHealthboxInDoubles(healthboxSpriteId, maxOrCurrent, currHp, maxHp);
|
||||
else
|
||||
UpdateHpTextInHealthboxInDoubles(healthboxSpriteId, currHp, maxOrCurrent);
|
||||
UpdateHpTextInHealthboxInDoubles(healthboxSpriteId, maxOrCurrent, currHp, maxHp);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
@ -992,7 +992,7 @@ void UpdateHpTextInHealthbox(u32 healthboxSpriteId, u32 maxOrCurrent, s16 currHp
|
|||
ConvertIntToDecimalStringN(text + 6, maxHp, STR_CONV_MODE_RIGHT_ALIGN, 3);
|
||||
else
|
||||
ConvertIntToDecimalStringN(text + 6, currHp, STR_CONV_MODE_RIGHT_ALIGN, 3);
|
||||
RenderTextHandleBold(gMonSpritesGfxPtr->barFontGfx, 0, text, 0, 0, 0, 0, 0);
|
||||
RenderTextHandleBold(gMonSpritesGfxPtr->barFontGfx, 0, text);
|
||||
|
||||
for (i = 0; i < 3; i++)
|
||||
{
|
||||
|
|
@ -1006,7 +1006,7 @@ void UpdateHpTextInHealthbox(u32 healthboxSpriteId, u32 maxOrCurrent, s16 currHp
|
|||
|
||||
static const u8 sText_Slash[] = _("/");
|
||||
|
||||
static void UpdateHpTextInHealthboxInDoubles(u8 healthboxSpriteId, s16 value, u8 maxOrCurrent)
|
||||
static void UpdateHpTextInHealthboxInDoubles(u8 healthboxSpriteId, u32 maxOrCurrent, s16 currHp, s16 maxHp)
|
||||
{
|
||||
u32 windowId, spriteTileNum;
|
||||
u8 *windowTileData;
|
||||
|
|
@ -1027,11 +1027,15 @@ static void UpdateHpTextInHealthboxInDoubles(u8 healthboxSpriteId, s16 value, u8
|
|||
var = 0;
|
||||
|
||||
healthBarSpriteId = gSprites[healthboxSpriteId].sHealthBarSpriteId;
|
||||
txtPtr = ConvertIntToDecimalStringN(text + 6, value, STR_CONV_MODE_RIGHT_ALIGN, 3);
|
||||
if (maxOrCurrent == HP_CURRENT)
|
||||
txtPtr = ConvertIntToDecimalStringN(text + 6, currHp, STR_CONV_MODE_RIGHT_ALIGN, 3);
|
||||
else
|
||||
txtPtr = ConvertIntToDecimalStringN(text + 6, maxHp, STR_CONV_MODE_RIGHT_ALIGN, 3);
|
||||
|
||||
if (maxOrCurrent == HP_CURRENT)
|
||||
StringCopy(txtPtr, sText_Slash);
|
||||
|
||||
RenderTextHandleBold(gMonSpritesGfxPtr->barFontGfx, 0, text, 0, 0, 0, 0, 0);
|
||||
RenderTextHandleBold(gMonSpritesGfxPtr->barFontGfx, 0, text);
|
||||
|
||||
for (i = var; i < var + 3; i++)
|
||||
{
|
||||
|
|
@ -1082,7 +1086,7 @@ static void PrintSafariMonInfo(u8 healthboxSpriteId, struct Pokemon *mon)
|
|||
var = 5;
|
||||
nature = GetNature(mon);
|
||||
StringCopy(text + 6, gNatureNamePointers[nature]);
|
||||
RenderTextHandleBold(barFontGfx, 0, text, 0, 0, 0, 0, 0);
|
||||
RenderTextHandleBold(barFontGfx, 0, text);
|
||||
|
||||
for (j = 6, i = 0; i < var; i++, j++)
|
||||
{
|
||||
|
|
@ -1114,7 +1118,7 @@ static void PrintSafariMonInfo(u8 healthboxSpriteId, struct Pokemon *mon)
|
|||
ConvertIntToDecimalStringN(text + 9, gBattleStruct->safariEscapeFactor, STR_CONV_MODE_RIGHT_ALIGN, 2);
|
||||
text[5] = CHAR_SPACE;
|
||||
text[8] = CHAR_SLASH;
|
||||
RenderTextHandleBold(gMonSpritesGfxPtr->barFontGfx, 0, text, 0, 0, 0, 0, 0);
|
||||
RenderTextHandleBold(gMonSpritesGfxPtr->barFontGfx, 0, text);
|
||||
|
||||
j = healthBarSpriteId; // Needed to match for some reason.
|
||||
for (j = 0; j < 5; j++)
|
||||
|
|
@ -1143,7 +1147,7 @@ void SwapHpBarsWithHpText(void)
|
|||
{
|
||||
if (gSprites[gHealthboxSpriteIds[i]].callback == SpriteCallbackDummy
|
||||
&& GetBattlerSide(i) != B_SIDE_OPPONENT
|
||||
&& (IsDoubleBattle() || GetBattlerSide(i) != B_SIDE_PLAYER))
|
||||
&& (WhichBattleCoords(i) || GetBattlerSide(i) != B_SIDE_PLAYER))
|
||||
{
|
||||
bool8 noBars;
|
||||
|
||||
|
|
@ -1151,18 +1155,20 @@ void SwapHpBarsWithHpText(void)
|
|||
noBars = gBattleSpritesDataPtr->battlerData[i].hpNumbersNoBars;
|
||||
if (GetBattlerSide(i) == B_SIDE_PLAYER)
|
||||
{
|
||||
if (!IsDoubleBattle())
|
||||
if (!WhichBattleCoords(i))
|
||||
continue;
|
||||
if (gBattleTypeFlags & BATTLE_TYPE_SAFARI)
|
||||
continue;
|
||||
|
||||
if (noBars == TRUE) // bars to text
|
||||
{
|
||||
s16 currHp = GetMonData(&gPlayerParty[gBattlerPartyIndexes[i]], MON_DATA_HP);
|
||||
s16 maxHp = GetMonData(&gPlayerParty[gBattlerPartyIndexes[i]], MON_DATA_MAX_HP);
|
||||
healthBarSpriteId = gSprites[gHealthboxSpriteIds[i]].sHealthBarSpriteId;
|
||||
|
||||
CpuFill32(0, (void *)(OBJ_VRAM0 + gSprites[healthBarSpriteId].oam.tileNum * TILE_SIZE_4BPP), 8 * TILE_SIZE_4BPP);
|
||||
UpdateHpTextInHealthboxInDoubles(gHealthboxSpriteIds[i], GetMonData(&gPlayerParty[gBattlerPartyIndexes[i]], MON_DATA_HP), HP_CURRENT);
|
||||
UpdateHpTextInHealthboxInDoubles(gHealthboxSpriteIds[i], GetMonData(&gPlayerParty[gBattlerPartyIndexes[i]], MON_DATA_MAX_HP), HP_MAX);
|
||||
UpdateHpTextInHealthboxInDoubles(gHealthboxSpriteIds[i], HP_CURRENT, currHp, maxHp);
|
||||
UpdateHpTextInHealthboxInDoubles(gHealthboxSpriteIds[i], HP_MAX, currHp, maxHp);
|
||||
}
|
||||
else // text to bars
|
||||
{
|
||||
|
|
@ -1184,11 +1190,13 @@ void SwapHpBarsWithHpText(void)
|
|||
}
|
||||
else
|
||||
{
|
||||
s16 currHp = GetMonData(&gEnemyParty[gBattlerPartyIndexes[i]], MON_DATA_HP);
|
||||
s16 maxHp = GetMonData(&gEnemyParty[gBattlerPartyIndexes[i]], MON_DATA_MAX_HP);
|
||||
healthBarSpriteId = gSprites[gHealthboxSpriteIds[i]].sHealthBarSpriteId;
|
||||
|
||||
CpuFill32(0, (void *)(OBJ_VRAM0 + gSprites[healthBarSpriteId].oam.tileNum * 32), 8 * TILE_SIZE_4BPP);
|
||||
UpdateHpTextInHealthboxInDoubles(gHealthboxSpriteIds[i], GetMonData(&gEnemyParty[gBattlerPartyIndexes[i]], MON_DATA_HP), HP_CURRENT);
|
||||
UpdateHpTextInHealthboxInDoubles(gHealthboxSpriteIds[i], GetMonData(&gEnemyParty[gBattlerPartyIndexes[i]], MON_DATA_MAX_HP), HP_MAX);
|
||||
UpdateHpTextInHealthboxInDoubles(gHealthboxSpriteIds[i], HP_CURRENT, currHp, maxHp);
|
||||
UpdateHpTextInHealthboxInDoubles(gHealthboxSpriteIds[i], HP_MAX, currHp, maxHp);
|
||||
}
|
||||
}
|
||||
else // text to bars
|
||||
|
|
@ -1496,7 +1504,7 @@ u8 CreatePartyStatusSummarySprites(u8 battlerId, struct HpAndStatus *partyInfo,
|
|||
{
|
||||
isOpponent = TRUE;
|
||||
|
||||
if (!isSwitchingMons || !IsDoubleBattle())
|
||||
if (!isSwitchingMons || !WhichBattleCoords(battlerId))
|
||||
x = 104, y = 40;
|
||||
else
|
||||
x = 104, y = 16;
|
||||
|
|
@ -1935,7 +1943,7 @@ void UpdateNickInHealthbox(u8 healthboxSpriteId, struct Pokemon *mon)
|
|||
{
|
||||
TextIntoHealthboxObject((void *)(OBJ_VRAM0 + 0x40 + spriteTileNum), windowTileData, 6);
|
||||
ptr = (void *)(OBJ_VRAM0);
|
||||
if (!IsDoubleBattle())
|
||||
if (!WhichBattleCoords(gSprites[healthboxSpriteId].sBattlerId))
|
||||
ptr += spriteTileNum + 0x800;
|
||||
else
|
||||
ptr += spriteTileNum + 0x400;
|
||||
|
|
@ -2005,7 +2013,7 @@ static void UpdateStatusIconInHealthbox(u8 healthboxSpriteId)
|
|||
if (GetBattlerSide(battlerId) == B_SIDE_PLAYER)
|
||||
{
|
||||
status = GetMonData(&gPlayerParty[gBattlerPartyIndexes[battlerId]], MON_DATA_STATUS);
|
||||
if (!IsDoubleBattle())
|
||||
if (!WhichBattleCoords(battlerId))
|
||||
tileNumAdder = 0x1A;
|
||||
else
|
||||
tileNumAdder = 0x12;
|
||||
|
|
@ -2065,7 +2073,7 @@ static void UpdateStatusIconInHealthbox(u8 healthboxSpriteId)
|
|||
FillPalette(sStatusIconColors[statusPalId], pltAdder + OBJ_PLTT_OFFSET, PLTT_SIZEOF(1));
|
||||
CpuCopy16(&gPlttBufferUnfaded[OBJ_PLTT_OFFSET + pltAdder], (u16 *)OBJ_PLTT + pltAdder, PLTT_SIZEOF(1));
|
||||
CpuCopy32(statusGfxPtr, (void *)(OBJ_VRAM0 + (gSprites[healthboxSpriteId].oam.tileNum + tileNumAdder) * TILE_SIZE_4BPP), 3 * TILE_SIZE_4BPP);
|
||||
if (IsDoubleBattle() == TRUE || GetBattlerSide(battlerId) == B_SIDE_OPPONENT)
|
||||
if (WhichBattleCoords(battlerId) == TRUE || GetBattlerSide(battlerId) == B_SIDE_OPPONENT)
|
||||
{
|
||||
if (!gBattleSpritesDataPtr->battlerData[battlerId].hpNumbersNoBars)
|
||||
{
|
||||
|
|
@ -2171,31 +2179,30 @@ static void UpdateLeftNoOfBallsTextOnHealthbox(u8 healthboxSpriteId)
|
|||
|
||||
void UpdateHealthboxAttribute(u8 healthboxSpriteId, struct Pokemon *mon, u8 elementId)
|
||||
{
|
||||
s32 maxHp, currHp;
|
||||
u8 battlerId = gSprites[healthboxSpriteId].sBattlerId;
|
||||
s32 maxHp = GetMonData(mon, MON_DATA_MAX_HP);
|
||||
s32 currHp = GetMonData(mon, MON_DATA_HP);
|
||||
|
||||
if (elementId == HEALTHBOX_ALL && !IsDoubleBattle())
|
||||
GetBattlerSide(battlerId); // Pointless function call.
|
||||
|
||||
if (GetBattlerSide(gSprites[healthboxSpriteId].sBattlerId) == B_SIDE_PLAYER)
|
||||
if (GetBattlerSide(battlerId) == B_SIDE_PLAYER)
|
||||
{
|
||||
u8 isDoubles;
|
||||
u8 isDoubles = WhichBattleCoords(battlerId);
|
||||
|
||||
maxHp = GetMonData(mon, MON_DATA_MAX_HP);
|
||||
currHp = GetMonData(mon, MON_DATA_HP);
|
||||
if (elementId == HEALTHBOX_LEVEL || elementId == HEALTHBOX_ALL)
|
||||
UpdateLvlInHealthbox(healthboxSpriteId, GetMonData(mon, MON_DATA_LEVEL));
|
||||
|
||||
|
||||
if (elementId == HEALTHBOX_CURRENT_HP || elementId == HEALTHBOX_ALL)
|
||||
UpdateHpTextInHealthbox(healthboxSpriteId, HP_CURRENT, currHp, maxHp);
|
||||
if (elementId == HEALTHBOX_MAX_HP || elementId == HEALTHBOX_ALL)
|
||||
UpdateHpTextInHealthbox(healthboxSpriteId, HP_MAX, currHp, maxHp);
|
||||
|
||||
if (elementId == HEALTHBOX_HEALTH_BAR || elementId == HEALTHBOX_ALL)
|
||||
{
|
||||
LoadBattleBarGfx(0);
|
||||
SetBattleBarStruct(battlerId, healthboxSpriteId, maxHp, currHp, 0);
|
||||
MoveBattleBar(battlerId, healthboxSpriteId, HEALTH_BAR, 0);
|
||||
}
|
||||
isDoubles = IsDoubleBattle();
|
||||
|
||||
if (!isDoubles && (elementId == HEALTHBOX_EXP_BAR || elementId == HEALTHBOX_ALL))
|
||||
{
|
||||
u16 species;
|
||||
|
|
|
|||
|
|
@ -471,7 +471,7 @@ void CopyBattlerSpriteToBg(s32 bgId, u8 x, u8 y, u8 battlerPosition, u8 palno, u
|
|||
u8 battler = GetBattlerAtPosition(battlerPosition);
|
||||
s32 offset = tilesOffset;
|
||||
|
||||
CpuCopy16(gMonSpritesGfxPtr->sprites[battlerPosition] + BG_SCREEN_SIZE * gBattleMonForms[battler], tilesDest, BG_SCREEN_SIZE);
|
||||
CpuCopy16(gMonSpritesGfxPtr->sprites[battlerPosition], tilesDest, BG_SCREEN_SIZE);
|
||||
LoadBgTiles(bgId, tilesDest, 0x1000, tilesOffset);
|
||||
for (i = y; i < y + 8; ++i)
|
||||
for (j = x; j < x + 8; ++j)
|
||||
|
|
|
|||
2441
src/battle_main.c
2441
src/battle_main.c
File diff suppressed because it is too large
Load Diff
|
|
@ -2149,15 +2149,15 @@ const u16 gSafariReactionStringIds[NUM_SAFARI_REACTIONS] =
|
|||
[B_MSG_MON_EATING] = STRINGID_PKMNEATING
|
||||
};
|
||||
|
||||
const u16 gTrainerItemCuredStatusStringIds[] =
|
||||
{
|
||||
[AI_HEAL_CONFUSION] = STRINGID_PKMNSITEMSNAPPEDOUT,
|
||||
[AI_HEAL_PARALYSIS] = STRINGID_PKMNSITEMCUREDPARALYSIS,
|
||||
[AI_HEAL_FREEZE] = STRINGID_PKMNSITEMDEFROSTEDIT,
|
||||
[AI_HEAL_BURN] = STRINGID_PKMNSITEMHEALEDBURN,
|
||||
[AI_HEAL_POISON] = STRINGID_PKMNSITEMCUREDPOISON,
|
||||
[AI_HEAL_SLEEP] = STRINGID_PKMNSITEMWOKEIT
|
||||
};
|
||||
// const u16 gTrainerItemCuredStatusStringIds[] =
|
||||
// {
|
||||
// [AI_HEAL_CONFUSION] = STRINGID_PKMNSITEMSNAPPEDOUT,
|
||||
// [AI_HEAL_PARALYSIS] = STRINGID_PKMNSITEMCUREDPARALYSIS,
|
||||
// [AI_HEAL_FREEZE] = STRINGID_PKMNSITEMDEFROSTEDIT,
|
||||
// [AI_HEAL_BURN] = STRINGID_PKMNSITEMHEALEDBURN,
|
||||
// [AI_HEAL_POISON] = STRINGID_PKMNSITEMCUREDPOISON,
|
||||
// [AI_HEAL_SLEEP] = STRINGID_PKMNSITEMWOKEIT
|
||||
// };
|
||||
|
||||
const u16 gBerryEffectStringIds[] =
|
||||
{
|
||||
|
|
@ -2478,7 +2478,7 @@ void BufferStringBattle(u32 battler, u16 stringId)
|
|||
}
|
||||
else if (gBattleTypeFlags & BATTLE_TYPE_LEGENDARY)
|
||||
stringPtr = sText_WildPkmnAppeared2;
|
||||
else if (gBattleTypeFlags & BATTLE_TYPE_DOUBLE) // interesting, looks like they had something planned for wild double battles
|
||||
else if (gBattleTypeFlags & BATTLE_TYPE_DOUBLE && IsValidForBattle(&gEnemyParty[gBattlerPartyIndexes[GetBattlerAtPosition(B_POSITION_OPPONENT_RIGHT)]])) // interesting, looks like they had something planned for wild double battles
|
||||
stringPtr = sText_TwoWildPkmnAppeared;
|
||||
else if (gBattleTypeFlags & BATTLE_TYPE_OLD_MAN_TUTORIAL)
|
||||
stringPtr = sText_WildPkmnAppearedPause;
|
||||
|
|
@ -2489,9 +2489,13 @@ void BufferStringBattle(u32 battler, u16 stringId)
|
|||
case STRINGID_INTROSENDOUT: // poke first send-out
|
||||
if (GetBattlerSide(battler) == B_SIDE_PLAYER)
|
||||
{
|
||||
if (gBattleTypeFlags & BATTLE_TYPE_DOUBLE)
|
||||
if (gBattleTypeFlags & BATTLE_TYPE_DOUBLE && IsValidForBattle(&gPlayerParty[gBattlerPartyIndexes[BATTLE_PARTNER(battler)]]))
|
||||
{
|
||||
if (gBattleTypeFlags & BATTLE_TYPE_MULTI)
|
||||
if (gBattleTypeFlags & BATTLE_TYPE_INGAME_PARTNER)
|
||||
stringPtr = sText_InGamePartnerSentOutZGoN;
|
||||
else if (gBattleTypeFlags & BATTLE_TYPE_TWO_OPPONENTS)
|
||||
stringPtr = sText_GoTwoPkmn;
|
||||
else if (gBattleTypeFlags & BATTLE_TYPE_MULTI)
|
||||
stringPtr = sText_LinkPartnerSentOutPkmnGoPkmn;
|
||||
else
|
||||
stringPtr = sText_GoTwoPkmn;
|
||||
|
|
@ -2503,9 +2507,13 @@ void BufferStringBattle(u32 battler, u16 stringId)
|
|||
}
|
||||
else
|
||||
{
|
||||
if (gBattleTypeFlags & BATTLE_TYPE_DOUBLE)
|
||||
if (gBattleTypeFlags & BATTLE_TYPE_DOUBLE && IsValidForBattle(&gEnemyParty[gBattlerPartyIndexes[BATTLE_PARTNER(battler)]]))
|
||||
{
|
||||
if (gBattleTypeFlags & BATTLE_TYPE_MULTI)
|
||||
if (BATTLE_TWO_VS_ONE_OPPONENT)
|
||||
stringPtr = sText_Trainer1SentOutTwoPkmn;
|
||||
else if (gBattleTypeFlags & BATTLE_TYPE_TWO_OPPONENTS)
|
||||
stringPtr = sText_TwoTrainersSentPkmn;
|
||||
else if (gBattleTypeFlags & BATTLE_TYPE_MULTI)
|
||||
stringPtr = sText_TwoLinkTrainersSentOutPkmn;
|
||||
else if (gBattleTypeFlags & BATTLE_TYPE_LINK)
|
||||
stringPtr = sText_LinkTrainerSentOutTwoPkmn;
|
||||
|
|
@ -2827,6 +2835,24 @@ static const u8 *BattleStringGetTrainerName(u8 *text, u8 multiplayerId, u8 battl
|
|||
return BattleStringGetOpponentName(text, multiplayerId, battler);
|
||||
}
|
||||
|
||||
static const u8 *BattleStringGetOpponentClassByTrainerId(u16 trainerId)
|
||||
{
|
||||
const u8 *toCpy;
|
||||
|
||||
if (trainerId == TRAINER_UNION_ROOM)
|
||||
toCpy = gTrainerClasses[GetUnionRoomTrainerClass()].name;
|
||||
else if (gBattleTypeFlags & BATTLE_TYPE_BATTLE_TOWER)
|
||||
toCpy = gTrainerClasses[GetBattleTowerTrainerClassNameId()].name;
|
||||
else if (gBattleTypeFlags & BATTLE_TYPE_TRAINER_TOWER)
|
||||
toCpy = gTrainerClasses[GetTrainerTowerOpponentClass()].name;
|
||||
else if (gBattleTypeFlags & BATTLE_TYPE_EREADER_TRAINER)
|
||||
toCpy = gTrainerClasses[GetEreaderTrainerClassId()].name;
|
||||
else
|
||||
toCpy = gTrainerClasses[GetTrainerClassFromId(trainerId)].name;
|
||||
|
||||
return toCpy;
|
||||
}
|
||||
|
||||
u32 BattleStringExpandPlaceholders(const u8 *src, u8 *dst)
|
||||
{
|
||||
u32 dstId = 0; // if they used dstId, why not use srcId as well?
|
||||
|
|
@ -2876,18 +2902,14 @@ u32 BattleStringExpandPlaceholders(const u8 *src, u8 *dst)
|
|||
toCpy = gBattleTextBuff3;
|
||||
break;
|
||||
case B_TXT_TRAINER2_CLASS:
|
||||
// TODO: trainer name
|
||||
// toCpy = BattleStringGetOpponentClassByTrainerId(gTrainerBattleOpponent_B);
|
||||
toCpy = "TODO";
|
||||
toCpy = BattleStringGetOpponentClassByTrainerId(gTrainerBattleOpponent_B);
|
||||
break;
|
||||
case B_TXT_TRAINER2_NAME:
|
||||
// TODO: trainer name
|
||||
// toCpy = BattleStringGetOpponentNameByTrainerId(gTrainerBattleOpponent_B, text, multiplayerId, GetBattlerAtPosition(B_POSITION_OPPONENT_RIGHT));
|
||||
toCpy = "TODO";
|
||||
toCpy = BattleStringGetOpponentNameByTrainerId(gTrainerBattleOpponent_B, text, multiplayerId, GetBattlerAtPosition(B_POSITION_OPPONENT_RIGHT));
|
||||
break;
|
||||
case B_TXT_PARTNER_CLASS:
|
||||
// TODO: trainer name
|
||||
// toCpy = gTrainerClassNames[GetFrontierOpponentClass(gPartnerTrainerId)].name;
|
||||
// toCpy = gTrainerClasses[GetFrontierOpponentClass(gPartnerTrainerId)].name;
|
||||
toCpy = "TODO";
|
||||
break;
|
||||
case B_TXT_PARTNER_NAME:
|
||||
|
|
@ -3000,8 +3022,8 @@ u32 BattleStringExpandPlaceholders(const u8 *src, u8 *dst)
|
|||
{
|
||||
if (!(gBattleTypeFlags & BATTLE_TYPE_MULTI))
|
||||
{
|
||||
if ((gBattleStruct->multiplayerId != 0 && (gPotentialItemEffectBattler & BIT_SIDE))
|
||||
|| (gBattleStruct->multiplayerId == 0 && !(gPotentialItemEffectBattler & BIT_SIDE)))
|
||||
if ((gBattleScripting.multiplayerId != 0 && (gPotentialItemEffectBattler & BIT_SIDE))
|
||||
|| (gBattleScripting.multiplayerId == 0 && !(gPotentialItemEffectBattler & BIT_SIDE)))
|
||||
{
|
||||
StringCopy(text, gEnigmaBerries[gPotentialItemEffectBattler].name);
|
||||
StringAppend(text, sText_BerrySuffix);
|
||||
|
|
@ -3014,7 +3036,7 @@ u32 BattleStringExpandPlaceholders(const u8 *src, u8 *dst)
|
|||
}
|
||||
else
|
||||
{
|
||||
if (gLinkPlayers[gBattleStruct->multiplayerId].id == gPotentialItemEffectBattler)
|
||||
if (gLinkPlayers[gBattleScripting.multiplayerId].id == gPotentialItemEffectBattler)
|
||||
{
|
||||
StringCopy(text, gEnigmaBerries[gPotentialItemEffectBattler].name);
|
||||
StringAppend(text, sText_BerrySuffix);
|
||||
|
|
@ -3053,17 +3075,17 @@ u32 BattleStringExpandPlaceholders(const u8 *src, u8 *dst)
|
|||
break;
|
||||
case B_TXT_TRAINER1_CLASS: // trainer class name
|
||||
if (gTrainerBattleOpponent_A == TRAINER_SECRET_BASE)
|
||||
toCpy = gTrainerClassNames[GetSecretBaseTrainerNameIndex()];
|
||||
toCpy = gTrainerClasses[GetSecretBaseTrainerNameIndex()].name;
|
||||
else if (gTrainerBattleOpponent_A == TRAINER_UNION_ROOM)
|
||||
toCpy = gTrainerClassNames[GetUnionRoomTrainerClass()];
|
||||
toCpy = gTrainerClasses[GetUnionRoomTrainerClass()].name;
|
||||
else if (gBattleTypeFlags & BATTLE_TYPE_BATTLE_TOWER)
|
||||
toCpy = gTrainerClassNames[GetBattleTowerTrainerClassNameId()];
|
||||
toCpy = gTrainerClasses[GetBattleTowerTrainerClassNameId()].name;
|
||||
else if (gBattleTypeFlags & BATTLE_TYPE_TRAINER_TOWER)
|
||||
toCpy = gTrainerClassNames[GetTrainerTowerOpponentClass()];
|
||||
toCpy = gTrainerClasses[GetTrainerTowerOpponentClass()].name;
|
||||
else if (gBattleTypeFlags & BATTLE_TYPE_EREADER_TRAINER)
|
||||
toCpy = gTrainerClassNames[GetEreaderTrainerClassId()];
|
||||
toCpy = gTrainerClasses[GetEreaderTrainerClassId()].name;
|
||||
else
|
||||
toCpy = gTrainerClassNames[gTrainers[gTrainerBattleOpponent_A].trainerClass];
|
||||
toCpy = gTrainerClasses[gTrainers[gTrainerBattleOpponent_A].trainerClass].name;
|
||||
break;
|
||||
case B_TXT_TRAINER1_NAME: // trainer1 name
|
||||
if (gTrainerBattleOpponent_A == TRAINER_SECRET_BASE)
|
||||
|
|
@ -3199,24 +3221,24 @@ u32 BattleStringExpandPlaceholders(const u8 *src, u8 *dst)
|
|||
toCpy = BattleStringGetTrainerName(text, multiplayerId, gBattlerAttacker);
|
||||
break;
|
||||
case B_TXT_ATK_TRAINER_CLASS:
|
||||
// TODO: get trainer name
|
||||
toCpy = "TODO";
|
||||
// switch (GetBattlerPosition(gBattlerAttacker))
|
||||
// {
|
||||
// case B_POSITION_PLAYER_RIGHT:
|
||||
// if (gBattleTypeFlags & BATTLE_TYPE_INGAME_PARTNER)
|
||||
// toCpy = gTrainerClasses[GetFrontierOpponentClass(gPartnerTrainerId)].name;
|
||||
// break;
|
||||
// case B_POSITION_OPPONENT_LEFT:
|
||||
// toCpy = BattleStringGetOpponentClassByTrainerId(gTrainerBattleOpponent_A);
|
||||
// break;
|
||||
// case B_POSITION_OPPONENT_RIGHT:
|
||||
// if (gBattleTypeFlags & BATTLE_TYPE_TWO_OPPONENTS && !BATTLE_TWO_VS_ONE_OPPONENT)
|
||||
// toCpy = BattleStringGetOpponentClassByTrainerId(gTrainerBattleOpponent_B);
|
||||
// else
|
||||
// toCpy = BattleStringGetOpponentClassByTrainerId(gTrainerBattleOpponent_A);
|
||||
// break;
|
||||
// }
|
||||
switch (GetBattlerPosition(gBattlerAttacker))
|
||||
{
|
||||
case B_POSITION_PLAYER_RIGHT:
|
||||
// TODO: implement partner trainers?
|
||||
// if (gBattleTypeFlags & BATTLE_TYPE_INGAME_PARTNER)
|
||||
// toCpy = gTrainerClasses[GetFrontierOpponentClass(gPartnerTrainerId)].name;
|
||||
toCpy = gTrainerClasses[TRAINER_CLASS_NONE].name;
|
||||
break;
|
||||
case B_POSITION_OPPONENT_LEFT:
|
||||
toCpy = BattleStringGetOpponentClassByTrainerId(gTrainerBattleOpponent_A);
|
||||
break;
|
||||
case B_POSITION_OPPONENT_RIGHT:
|
||||
if (gBattleTypeFlags & BATTLE_TYPE_TWO_OPPONENTS && !BATTLE_TWO_VS_ONE_OPPONENT)
|
||||
toCpy = BattleStringGetOpponentClassByTrainerId(gTrainerBattleOpponent_B);
|
||||
else
|
||||
toCpy = BattleStringGetOpponentClassByTrainerId(gTrainerBattleOpponent_A);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case B_TXT_ATK_TEAM1:
|
||||
if (GetBattlerSide(gBattlerAttacker) == B_SIDE_PLAYER)
|
||||
|
|
@ -3364,7 +3386,7 @@ static void ExpandBattleTextBuffPlaceholders(const u8 *src, u8 *dst)
|
|||
{
|
||||
if (hword == ITEM_ENIGMA_BERRY)
|
||||
{
|
||||
if (gLinkPlayers[gBattleStruct->multiplayerId].id == gPotentialItemEffectBattler)
|
||||
if (gLinkPlayers[gBattleScripting.multiplayerId].id == gPotentialItemEffectBattler)
|
||||
{
|
||||
StringCopy(dst, gEnigmaBerries[gPotentialItemEffectBattler].name);
|
||||
StringAppend(dst, sText_BerrySuffix);
|
||||
|
|
|
|||
|
|
@ -20,14 +20,16 @@
|
|||
#include "trainer_pokemon_sprites.h"
|
||||
#include "field_specials.h"
|
||||
#include "battle.h"
|
||||
#include "battle_ai_main.h"
|
||||
#include "battle_ai_util.h"
|
||||
#include "battle_message.h"
|
||||
#include "battle_anim.h"
|
||||
#include "battle_ai_script_commands.h"
|
||||
#include "battle_scripts.h"
|
||||
#include "reshow_battle_screen.h"
|
||||
#include "battle_controllers.h"
|
||||
#include "battle_interface.h"
|
||||
#include "rtc.h"
|
||||
#include "wild_encounter.h"
|
||||
#include "constants/battle_anim.h"
|
||||
#include "constants/battle_move_effects.h"
|
||||
#include "constants/battle_script_commands.h"
|
||||
|
|
@ -321,7 +323,6 @@ static const u16 sWhiteOutBadgeMoney[9] = { 8, 16, 24, 36, 48, 64, 80, 100, 120
|
|||
#define TAG_LVLUP_BANNER_MON_ICON 55130
|
||||
|
||||
static void TrySetDestinyBondToHappen(void);
|
||||
static u8 AttacksThisTurn(u8 battlerId, u16 move); // Note: returns 1 if it's a charging turn, otherwise 2.
|
||||
static u32 ChangeStatBuffs(s8 statValue, u32 statId, u32 flags, const u8 *BS_ptr);
|
||||
static void InitLevelUpBanner(void);
|
||||
static bool8 SlideInLevelUpBanner(void);
|
||||
|
|
@ -1400,14 +1401,13 @@ static void Cmd_attackcanceler(void)
|
|||
}
|
||||
|
||||
// Z-moves and Max Moves bypass protection, but deal reduced damage (factored in AccumulateOtherModifiers)
|
||||
// TODO: Z-Moves and Dynamax
|
||||
// if ((gBattleStruct->zmove.active || IsMaxMove(gCurrentMove))
|
||||
// && IS_BATTLER_PROTECTED(gBattlerTarget))
|
||||
// {
|
||||
// BattleScriptPush(cmd->nextInstr);
|
||||
// gBattlescriptCurrInstr = BattleScript_CouldntFullyProtect;
|
||||
// return;
|
||||
// }
|
||||
if ((gBattleStruct->zmove.active || IsMaxMove(gCurrentMove))
|
||||
&& IS_BATTLER_PROTECTED(gBattlerTarget))
|
||||
{
|
||||
BattleScriptPush(cmd->nextInstr);
|
||||
gBattlescriptCurrInstr = BattleScript_CouldntFullyProtect;
|
||||
return;
|
||||
}
|
||||
|
||||
for (i = 0; i < gBattlersCount; i++)
|
||||
{
|
||||
|
|
@ -1935,6 +1935,14 @@ s32 CalcCritChanceStage(u32 battlerAtk, u32 battlerDef, u32 move, bool32 recordA
|
|||
}
|
||||
#undef BENEFITS_FROM_LEEK
|
||||
|
||||
s32 GetCritHitChance(s32 critChanceIndex)
|
||||
{
|
||||
if (critChanceIndex < 0)
|
||||
return -1;
|
||||
else
|
||||
return sCriticalHitChance[critChanceIndex];
|
||||
}
|
||||
|
||||
static void Cmd_critcalc(void)
|
||||
{
|
||||
CMD_ARGS();
|
||||
|
|
@ -1973,19 +1981,6 @@ static void Cmd_damagecalc(void)
|
|||
gBattlescriptCurrInstr = cmd->nextInstr;
|
||||
}
|
||||
|
||||
void AI_CalcDmg(u8 attacker, u8 defender)
|
||||
{
|
||||
u32 sideStatus = gSideStatuses[GET_BATTLER_SIDE(defender)];
|
||||
u8 moveType;
|
||||
s32 critChance;
|
||||
|
||||
GET_MOVE_TYPE(gCurrentMove, moveType);
|
||||
critChance = CalcCritChanceStage(attacker, defender, gCurrentMove, TRUE);
|
||||
gIsCriticalHit = RandomWeighted(RNG_CRITICAL_HIT, sCriticalHitChance[critChance] - 1, 1);
|
||||
gBattleMoveDamage = CalculateMoveDamage(gCurrentMove, attacker, defender, moveType, 0, gIsCriticalHit, TRUE, TRUE);
|
||||
CalcTypeEffectivenessMultiplier(gCurrentMove, moveType, gBattlerAttacker, gBattlerTarget, GetBattlerAbility(gBattlerTarget), TRUE);
|
||||
}
|
||||
|
||||
static void Cmd_typecalc(void)
|
||||
{
|
||||
CMD_ARGS();
|
||||
|
|
@ -1998,127 +1993,6 @@ static void Cmd_typecalc(void)
|
|||
gBattlescriptCurrInstr = cmd->nextInstr;
|
||||
}
|
||||
|
||||
// Same as ModulateDmgByType except different arguments
|
||||
static void ModulateDmgByType2(uq4_12_t multiplier, u16 move, u8 *flags)
|
||||
{
|
||||
gBattleMoveDamage = uq4_12_multiply(gBattleMoveDamage, multiplier);
|
||||
if (gBattleMoveDamage == 0 && multiplier != 0)
|
||||
gBattleMoveDamage = 1;
|
||||
|
||||
switch (multiplier)
|
||||
{
|
||||
case UQ_4_12(0.0):
|
||||
*flags |= MOVE_RESULT_DOESNT_AFFECT_FOE;
|
||||
*flags &= ~MOVE_RESULT_NOT_VERY_EFFECTIVE;
|
||||
*flags &= ~MOVE_RESULT_SUPER_EFFECTIVE;
|
||||
break;
|
||||
case UQ_4_12(0.5):
|
||||
if (gMovesInfo[move].power && !(*flags & MOVE_RESULT_NO_EFFECT))
|
||||
{
|
||||
if (*flags & MOVE_RESULT_SUPER_EFFECTIVE)
|
||||
*flags &= ~MOVE_RESULT_SUPER_EFFECTIVE;
|
||||
else
|
||||
*flags |= MOVE_RESULT_NOT_VERY_EFFECTIVE;
|
||||
}
|
||||
break;
|
||||
case UQ_4_12(2.0):
|
||||
if (gMovesInfo[move].power && !(*flags & MOVE_RESULT_NO_EFFECT))
|
||||
{
|
||||
if (*flags & MOVE_RESULT_NOT_VERY_EFFECTIVE)
|
||||
*flags &= ~MOVE_RESULT_NOT_VERY_EFFECTIVE;
|
||||
else
|
||||
*flags |= MOVE_RESULT_SUPER_EFFECTIVE;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
u8 TypeCalc(u16 move, u8 attacker, u8 defender)
|
||||
{
|
||||
s32 i = 0;
|
||||
u8 flags = 0;
|
||||
u8 moveType;
|
||||
|
||||
if (move == MOVE_STRUGGLE)
|
||||
return 0;
|
||||
|
||||
moveType = gMovesInfo[move].type;
|
||||
|
||||
// check stab
|
||||
if (IS_BATTLER_OF_TYPE(attacker, moveType))
|
||||
{
|
||||
gBattleMoveDamage = gBattleMoveDamage * 15;
|
||||
gBattleMoveDamage = gBattleMoveDamage / 10;
|
||||
}
|
||||
|
||||
if (gBattleMons[defender].ability == ABILITY_LEVITATE && moveType == TYPE_GROUND)
|
||||
{
|
||||
flags |= (MOVE_RESULT_MISSED | MOVE_RESULT_DOESNT_AFFECT_FOE);
|
||||
}
|
||||
else
|
||||
{
|
||||
ModulateDmgByType2(gTypeEffectivenessTable[moveType][gBattleMons[defender].type1], move, &flags);
|
||||
ModulateDmgByType2(gTypeEffectivenessTable[moveType][gBattleMons[defender].type2], move, &flags);
|
||||
}
|
||||
|
||||
if (gBattleMons[defender].ability == ABILITY_WONDER_GUARD && !(flags & MOVE_RESULT_MISSED)
|
||||
&& AttacksThisTurn(attacker, move) == 2
|
||||
&& (!(flags & MOVE_RESULT_SUPER_EFFECTIVE) || ((flags & (MOVE_RESULT_SUPER_EFFECTIVE | MOVE_RESULT_NOT_VERY_EFFECTIVE)) == (MOVE_RESULT_SUPER_EFFECTIVE | MOVE_RESULT_NOT_VERY_EFFECTIVE)))
|
||||
&& gMovesInfo[move].power)
|
||||
{
|
||||
flags |= MOVE_RESULT_MISSED;
|
||||
}
|
||||
return flags;
|
||||
}
|
||||
|
||||
u8 AI_TypeCalc(u16 move, u16 targetSpecies, u16 targetAbility)
|
||||
{
|
||||
s32 i = 0;
|
||||
u8 flags = 0;
|
||||
u8 type1 = gSpeciesInfo[targetSpecies].types[0], type2 = gSpeciesInfo[targetSpecies].types[1];
|
||||
u8 moveType;
|
||||
|
||||
if (move == MOVE_STRUGGLE)
|
||||
return 0;
|
||||
|
||||
moveType = gMovesInfo[move].type;
|
||||
|
||||
if (targetAbility == ABILITY_LEVITATE && moveType == TYPE_GROUND)
|
||||
{
|
||||
flags = MOVE_RESULT_MISSED | MOVE_RESULT_DOESNT_AFFECT_FOE;
|
||||
}
|
||||
else
|
||||
{
|
||||
ModulateDmgByType2(gTypeEffectivenessTable[moveType][type1], move, &flags);
|
||||
ModulateDmgByType2(gTypeEffectivenessTable[moveType][type2], move, &flags);
|
||||
}
|
||||
if (targetAbility == ABILITY_WONDER_GUARD
|
||||
&& (!(flags & MOVE_RESULT_SUPER_EFFECTIVE) || ((flags & (MOVE_RESULT_SUPER_EFFECTIVE | MOVE_RESULT_NOT_VERY_EFFECTIVE)) == (MOVE_RESULT_SUPER_EFFECTIVE | MOVE_RESULT_NOT_VERY_EFFECTIVE)))
|
||||
&& gMovesInfo[move].power)
|
||||
flags |= MOVE_RESULT_DOESNT_AFFECT_FOE;
|
||||
return flags;
|
||||
}
|
||||
|
||||
// Multiplies the damage by a random factor between 85% to 100% inclusive
|
||||
static inline void ApplyRandomDmgMultiplier(void)
|
||||
{
|
||||
u16 rand = Random();
|
||||
u16 randPercent = 100 - (rand % 16);
|
||||
|
||||
if (gBattleMoveDamage != 0)
|
||||
{
|
||||
gBattleMoveDamage *= randPercent;
|
||||
gBattleMoveDamage /= 100;
|
||||
if (gBattleMoveDamage == 0)
|
||||
gBattleMoveDamage = 1;
|
||||
}
|
||||
}
|
||||
|
||||
static void Unused_ApplyRandomDmgMultiplier(void)
|
||||
{
|
||||
ApplyRandomDmgMultiplier();
|
||||
}
|
||||
|
||||
static void Cmd_adjustdamage(void)
|
||||
{
|
||||
CMD_ARGS();
|
||||
|
|
@ -6499,7 +6373,7 @@ static void Cmd_getswitchedmondata(void)
|
|||
u32 battler = GetBattlerForBattleScript(cmd->battler);
|
||||
if (gBattleControllerExecFlags)
|
||||
return;
|
||||
|
||||
|
||||
gBattlerPartyIndexes[battler] = gBattleStruct->monToSwitchIntoId[battler];
|
||||
BtlController_EmitGetMonData(battler, BUFFER_A, REQUEST_ALL_BATTLE, gBitTable[gBattlerPartyIndexes[battler]]);
|
||||
MarkBattlerForControllerExec(battler);
|
||||
|
|
@ -7654,14 +7528,11 @@ static u32 GetTrainerMoneyToGive(u16 trainerId)
|
|||
}
|
||||
else
|
||||
{
|
||||
// TODO: Update Trainer struct
|
||||
// const struct TrainerMon *party = GetTrainerPartyFromId(trainerId);
|
||||
// if (party == NULL)
|
||||
// return 20;
|
||||
// lastMonLevel = party[GetTrainerPartySizeFromId(trainerId) - 1].lvl;
|
||||
// trainerMoney = gTrainerClasses[GetTrainerClassFromId(trainerId)].money;
|
||||
lastMonLevel = 10;
|
||||
trainerMoney = 100;
|
||||
const struct TrainerMon *party = GetTrainerPartyFromId(trainerId);
|
||||
if (party == NULL)
|
||||
return 20;
|
||||
lastMonLevel = party[GetTrainerPartySizeFromId(trainerId) - 1].lvl;
|
||||
trainerMoney = gTrainerClasses[GetTrainerClassFromId(trainerId)].money;
|
||||
|
||||
if (gBattleTypeFlags & BATTLE_TYPE_TWO_OPPONENTS)
|
||||
moneyReward = 4 * lastMonLevel * gBattleStruct->moneyMultiplier * trainerMoney;
|
||||
|
|
@ -13072,24 +12943,6 @@ static void Cmd_copymovepermanently(void)
|
|||
}
|
||||
}
|
||||
|
||||
static u8 AttacksThisTurn(u8 battlerId, u16 move) // Note: returns 1 if it's a charging turn, otherwise 2
|
||||
{
|
||||
// first argument is unused
|
||||
if (gMovesInfo[move].effect == EFFECT_SOLAR_BEAM
|
||||
&& (gBattleWeather & B_WEATHER_SUN))
|
||||
return 2;
|
||||
|
||||
if (gMovesInfo[move].effect == EFFECT_TWO_TURNS_ATTACK
|
||||
|| gMovesInfo[move].effect == EFFECT_SOLAR_BEAM
|
||||
|| gMovesInfo[move].effect == EFFECT_SEMI_INVULNERABLE
|
||||
|| gMovesInfo[move].effect == EFFECT_BIDE)
|
||||
{
|
||||
if ((gHitMarker & HITMARKER_CHARGING))
|
||||
return 1;
|
||||
}
|
||||
return 2;
|
||||
}
|
||||
|
||||
static void Cmd_trychoosesleeptalkmove(void)
|
||||
{
|
||||
CMD_ARGS(const u8 *failInstr);
|
||||
|
|
@ -15171,10 +15024,9 @@ static void Cmd_handleballthrow(void)
|
|||
ballMultiplier = B_NET_BALL_MODIFIER >= GEN_7 ? 350 : 300;
|
||||
break;
|
||||
case ITEM_DIVE_BALL:
|
||||
// TODO: gIsFishingEncounter and gIsSurfingEncounter
|
||||
// if (GetCurrentMapType() == MAP_TYPE_UNDERWATER
|
||||
// || (B_DIVE_BALL_MODIFIER >= GEN_4 && (gIsFishingEncounter || gIsSurfingEncounter)))
|
||||
// ballMultiplier = 350;
|
||||
if (GetCurrentMapType() == MAP_TYPE_UNDERWATER
|
||||
|| (B_DIVE_BALL_MODIFIER >= GEN_4 && (gIsFishingEncounter || gIsSurfingEncounter)))
|
||||
ballMultiplier = 350;
|
||||
break;
|
||||
case ITEM_NEST_BALL:
|
||||
if (B_NEST_BALL_MODIFIER >= GEN_6)
|
||||
|
|
@ -15224,16 +15076,15 @@ static void Cmd_handleballthrow(void)
|
|||
ballMultiplier = 200;
|
||||
break;
|
||||
case ITEM_LURE_BALL:
|
||||
// TODO: gIsFishingEncounter
|
||||
// if (gIsFishingEncounter)
|
||||
// {
|
||||
// if (B_LURE_BALL_MODIFIER >= GEN_8)
|
||||
// ballMultiplier = 400;
|
||||
// else if (B_LURE_BALL_MODIFIER >= GEN_7)
|
||||
// ballMultiplier = 500;
|
||||
// else
|
||||
// ballMultiplier = 300;
|
||||
// }
|
||||
if (gIsFishingEncounter)
|
||||
{
|
||||
if (B_LURE_BALL_MODIFIER >= GEN_8)
|
||||
ballMultiplier = 400;
|
||||
else if (B_LURE_BALL_MODIFIER >= GEN_7)
|
||||
ballMultiplier = 500;
|
||||
else
|
||||
ballMultiplier = 300;
|
||||
}
|
||||
break;
|
||||
case ITEM_MOON_BALL:
|
||||
{
|
||||
|
|
|
|||
|
|
@ -59,7 +59,7 @@ struct TrainerBattleParameter
|
|||
|
||||
static void DoSafariBattle(void);
|
||||
static void DoGhostBattle(void);
|
||||
static void DoStandardWildBattle(void);
|
||||
static void DoStandardWildBattle(bool32 isDouble);
|
||||
static void CB2_EndWildBattle(void);
|
||||
static u8 GetWildBattleTransition(void);
|
||||
static u8 GetTrainerBattleTransition(void);
|
||||
|
|
@ -242,16 +242,23 @@ void StartWildBattle(void)
|
|||
else if (CheckSilphScopeInPokemonTower(gSaveBlock1Ptr->location.mapGroup, gSaveBlock1Ptr->location.mapNum))
|
||||
DoGhostBattle();
|
||||
else
|
||||
DoStandardWildBattle();
|
||||
DoStandardWildBattle(FALSE);
|
||||
}
|
||||
|
||||
static void DoStandardWildBattle(void)
|
||||
void StartDoubleWildBattle(void)
|
||||
{
|
||||
DoStandardWildBattle(TRUE);
|
||||
}
|
||||
|
||||
static void DoStandardWildBattle(bool32 isDouble)
|
||||
{
|
||||
LockPlayerFieldControls();
|
||||
FreezeObjectEvents();
|
||||
StopPlayerAvatar();
|
||||
gMain.savedCallback = CB2_EndWildBattle;
|
||||
gBattleTypeFlags = 0;
|
||||
if (isDouble)
|
||||
gBattleTypeFlags |= BATTLE_TYPE_DOUBLE;
|
||||
CreateBattleStartTask(GetWildBattleTransition(), 0);
|
||||
IncrementGameStat(GAME_STAT_TOTAL_BATTLES);
|
||||
IncrementGameStat(GAME_STAT_WILD_BATTLES);
|
||||
|
|
@ -564,49 +571,17 @@ static u8 GetSumOfEnemyPartyLevel(u16 opponentId, u8 numMons)
|
|||
u8 i;
|
||||
u8 sum;
|
||||
u32 count = numMons;
|
||||
const struct TrainerMon *party;
|
||||
|
||||
if (GetTrainerPartySizeFromId(opponentId) < count)
|
||||
count = GetTrainerPartySizeFromId(opponentId);
|
||||
|
||||
if (gTrainers[opponentId].partySize < count)
|
||||
count = gTrainers[opponentId].partySize;
|
||||
sum = 0;
|
||||
switch (gTrainers[opponentId].partyFlags)
|
||||
{
|
||||
case 0:
|
||||
{
|
||||
const struct TrainerMonNoItemDefaultMoves *party;
|
||||
|
||||
party = gTrainers[opponentId].party.NoItemDefaultMoves;
|
||||
for (i = 0; i < count; ++i)
|
||||
sum += party[i].lvl;
|
||||
}
|
||||
break;
|
||||
case F_TRAINER_PARTY_CUSTOM_MOVESET:
|
||||
{
|
||||
const struct TrainerMonNoItemCustomMoves *party;
|
||||
party = GetTrainerPartyFromId(opponentId);
|
||||
for (i = 0; i < count && party != NULL; i++)
|
||||
sum += party[i].lvl;
|
||||
|
||||
party = gTrainers[opponentId].party.NoItemCustomMoves;
|
||||
for (i = 0; i < count; ++i)
|
||||
sum += party[i].lvl;
|
||||
}
|
||||
break;
|
||||
case F_TRAINER_PARTY_HELD_ITEM:
|
||||
{
|
||||
const struct TrainerMonItemDefaultMoves *party;
|
||||
|
||||
party = gTrainers[opponentId].party.ItemDefaultMoves;
|
||||
for (i = 0; i < count; ++i)
|
||||
sum += party[i].lvl;
|
||||
}
|
||||
break;
|
||||
case F_TRAINER_PARTY_CUSTOM_MOVESET | F_TRAINER_PARTY_HELD_ITEM:
|
||||
{
|
||||
const struct TrainerMonItemCustomMoves *party;
|
||||
|
||||
party = gTrainers[opponentId].party.ItemCustomMoves;
|
||||
for (i = 0; i < count; ++i)
|
||||
sum += party[i].lvl;
|
||||
}
|
||||
break;
|
||||
}
|
||||
return sum;
|
||||
}
|
||||
|
||||
|
|
@ -628,29 +603,30 @@ static u8 GetTrainerBattleTransition(void)
|
|||
u8 transitionType;
|
||||
u8 enemyLevel;
|
||||
u8 playerLevel;
|
||||
u32 trainerId = SanitizeTrainerId(gTrainerBattleOpponent_A);
|
||||
|
||||
if (gTrainerBattleOpponent_A == TRAINER_SECRET_BASE)
|
||||
if (trainerId == TRAINER_SECRET_BASE)
|
||||
return B_TRANSITION_BLUE;
|
||||
if (gTrainers[gTrainerBattleOpponent_A].trainerClass == TRAINER_CLASS_ELITE_FOUR)
|
||||
if (gTrainers[trainerId].trainerClass == TRAINER_CLASS_ELITE_FOUR)
|
||||
{
|
||||
if (gTrainerBattleOpponent_A == TRAINER_ELITE_FOUR_LORELEI || gTrainerBattleOpponent_A == TRAINER_ELITE_FOUR_LORELEI_2)
|
||||
if (trainerId == TRAINER_ELITE_FOUR_LORELEI || trainerId == TRAINER_ELITE_FOUR_LORELEI_2)
|
||||
return B_TRANSITION_LORELEI;
|
||||
if (gTrainerBattleOpponent_A == TRAINER_ELITE_FOUR_BRUNO || gTrainerBattleOpponent_A == TRAINER_ELITE_FOUR_BRUNO_2)
|
||||
if (trainerId == TRAINER_ELITE_FOUR_BRUNO || trainerId == TRAINER_ELITE_FOUR_BRUNO_2)
|
||||
return B_TRANSITION_BRUNO;
|
||||
if (gTrainerBattleOpponent_A == TRAINER_ELITE_FOUR_AGATHA || gTrainerBattleOpponent_A == TRAINER_ELITE_FOUR_AGATHA_2)
|
||||
if (trainerId == TRAINER_ELITE_FOUR_AGATHA || trainerId == TRAINER_ELITE_FOUR_AGATHA_2)
|
||||
return B_TRANSITION_AGATHA;
|
||||
if (gTrainerBattleOpponent_A == TRAINER_ELITE_FOUR_LANCE || gTrainerBattleOpponent_A == TRAINER_ELITE_FOUR_LANCE_2)
|
||||
if (trainerId == TRAINER_ELITE_FOUR_LANCE || trainerId == TRAINER_ELITE_FOUR_LANCE_2)
|
||||
return B_TRANSITION_LANCE;
|
||||
return B_TRANSITION_BLUE;
|
||||
}
|
||||
if (gTrainers[gTrainerBattleOpponent_A].trainerClass == TRAINER_CLASS_CHAMPION)
|
||||
if (gTrainers[trainerId].trainerClass == TRAINER_CLASS_CHAMPION)
|
||||
return B_TRANSITION_BLUE;
|
||||
if (gTrainers[gTrainerBattleOpponent_A].doubleBattle == TRUE)
|
||||
if (gTrainers[trainerId].doubleBattle == TRUE)
|
||||
minPartyCount = 2; // double battles always at least have 2 pokemon.
|
||||
else
|
||||
minPartyCount = 1;
|
||||
transitionType = GetBattleTransitionTypeByMap();
|
||||
enemyLevel = GetSumOfEnemyPartyLevel(gTrainerBattleOpponent_A, minPartyCount);
|
||||
enemyLevel = GetSumOfEnemyPartyLevel(trainerId, minPartyCount);
|
||||
playerLevel = GetSumOfPlayerPartyLevel(minPartyCount);
|
||||
if (enemyLevel < playerLevel)
|
||||
return sBattleTransitionTable_Trainer[transitionType][0];
|
||||
|
|
|
|||
1046
src/battle_util.c
1046
src/battle_util.c
File diff suppressed because it is too large
Load Diff
|
|
@ -3,6 +3,7 @@
|
|||
#include "battle.h"
|
||||
#include "battle_anim.h"
|
||||
#include "malloc.h"
|
||||
#include "party_menu.h"
|
||||
#include "pokemon.h"
|
||||
#include "trainer_tower.h"
|
||||
|
||||
|
|
@ -20,6 +21,10 @@ void AllocateBattleResources(void)
|
|||
|
||||
gBattleStruct = AllocZeroed(sizeof(*gBattleStruct));
|
||||
|
||||
#if B_FLAG_SKY_BATTLE
|
||||
gBattleStruct->isSkyBattle = FlagGet(B_FLAG_SKY_BATTLE);
|
||||
#endif
|
||||
|
||||
gBattleResources = AllocZeroed(sizeof(*gBattleResources));
|
||||
gBattleResources->secretBase = AllocZeroed(sizeof(*gBattleResources->secretBase));
|
||||
gBattleResources->flags = AllocZeroed(sizeof(*gBattleResources->flags));
|
||||
|
|
@ -27,8 +32,9 @@ void AllocateBattleResources(void)
|
|||
gBattleResources->battleCallbackStack = AllocZeroed(sizeof(*gBattleResources->battleCallbackStack));
|
||||
gBattleResources->beforeLvlUp = AllocZeroed(sizeof(*gBattleResources->beforeLvlUp));
|
||||
gBattleResources->ai = AllocZeroed(sizeof(*gBattleResources->ai));
|
||||
gBattleResources->aiData = AllocZeroed(sizeof(*gBattleResources->aiData));
|
||||
gBattleResources->aiParty = AllocZeroed(sizeof(*gBattleResources->aiParty));
|
||||
gBattleResources->battleHistory = AllocZeroed(sizeof(*gBattleResources->battleHistory));
|
||||
gBattleResources->AI_ScriptsStack = AllocZeroed(sizeof(*gBattleResources->AI_ScriptsStack));
|
||||
|
||||
gLinkBattleSendBuffer = AllocZeroed(BATTLE_BUFFER_LINK_SIZE);
|
||||
gLinkBattleRecvBuffer = AllocZeroed(BATTLE_BUFFER_LINK_SIZE);
|
||||
|
|
@ -53,6 +59,7 @@ void FreeBattleResources(void)
|
|||
FREE_AND_SET_NULL(gPokedudeBattlerStates[i]);
|
||||
}
|
||||
}
|
||||
gFieldStatuses = 0;
|
||||
if (gBattleResources != NULL)
|
||||
{
|
||||
FREE_AND_SET_NULL(gBattleStruct);
|
||||
|
|
@ -63,8 +70,9 @@ void FreeBattleResources(void)
|
|||
FREE_AND_SET_NULL(gBattleResources->battleCallbackStack);
|
||||
FREE_AND_SET_NULL(gBattleResources->beforeLvlUp);
|
||||
FREE_AND_SET_NULL(gBattleResources->ai);
|
||||
FREE_AND_SET_NULL(gBattleResources->aiData);
|
||||
FREE_AND_SET_NULL(gBattleResources->aiParty);
|
||||
FREE_AND_SET_NULL(gBattleResources->battleHistory);
|
||||
FREE_AND_SET_NULL(gBattleResources->AI_ScriptsStack);
|
||||
FREE_AND_SET_NULL(gBattleResources);
|
||||
|
||||
FREE_AND_SET_NULL(gLinkBattleSendBuffer);
|
||||
|
|
@ -106,3 +114,18 @@ void AdjustFriendshipOnBattleFaint(u8 battler)
|
|||
AdjustFriendship(&gPlayerParty[gBattlerPartyIndexes[battler]], FRIENDSHIP_EVENT_FAINT_SMALL);
|
||||
}
|
||||
}
|
||||
|
||||
void SwitchPartyOrderInGameMulti(u8 battler, u8 arg1)
|
||||
{
|
||||
if (GetBattlerSide(battler) != B_SIDE_OPPONENT)
|
||||
{
|
||||
s32 i;
|
||||
for (i = 0; i < (int)ARRAY_COUNT(gBattlePartyCurrentOrder); i++)
|
||||
gBattlePartyCurrentOrder[i] = *(0 * 3 + i + (u8 *)(gBattleStruct->battlerPartyOrders));
|
||||
|
||||
SwitchPartyMonSlots(GetPartyIdFromBattlePartyId(gBattlerPartyIndexes[battler]), GetPartyIdFromBattlePartyId(arg1));
|
||||
|
||||
for (i = 0; i < (int)ARRAY_COUNT(gBattlePartyCurrentOrder); i++)
|
||||
*(0 * 3 + i + (u8 *)(gBattleStruct->battlerPartyOrders)) = gBattlePartyCurrentOrder[i];
|
||||
}
|
||||
}
|
||||
|
|
|
|||
10
src/berry.c
10
src/berry.c
|
|
@ -1004,12 +1004,14 @@ const struct Berry * GetBerryInfo(u8 berryIdx)
|
|||
return &gBerries[berryIdx - 1];
|
||||
}
|
||||
|
||||
u8 ItemIdToBerryType(u16 itemId)
|
||||
u8 ItemIdToBerryType(u16 item)
|
||||
{
|
||||
if (itemId - FIRST_BERRY_INDEX < 0 || itemId - FIRST_BERRY_INDEX > ITEM_ENIGMA_BERRY - FIRST_BERRY_INDEX)
|
||||
return 1;
|
||||
u16 berry = item - FIRST_BERRY_INDEX;
|
||||
|
||||
return ITEM_TO_BERRY(itemId);
|
||||
if (berry > LAST_BERRY_INDEX - FIRST_BERRY_INDEX)
|
||||
return ITEM_TO_BERRY(FIRST_BERRY_INDEX);
|
||||
else
|
||||
return ITEM_TO_BERRY(item);
|
||||
}
|
||||
|
||||
u16 BerryTypeToItemId(u16 berryType)
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@
|
|||
#include "battle.h"
|
||||
#include "data.h"
|
||||
#include "graphics.h"
|
||||
#include "constants/abilities.h"
|
||||
#include "constants/items.h"
|
||||
#include "constants/moves.h"
|
||||
#include "constants/battle_ai.h"
|
||||
|
|
@ -290,5 +291,5 @@ const union AnimCmd *const gAnims_MonPic[] =
|
|||
#include "data/trainer_graphics/back_pic_tables.h"
|
||||
|
||||
#include "data/trainer_parties.h"
|
||||
#include "data/text/trainer_class_names.h"
|
||||
#include "data/trainers.h"
|
||||
#include "data/battle_partners.h"
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ const struct Trainer gBattlePartners[] = {
|
|||
[PARTNER_NONE] =
|
||||
{
|
||||
.party = NULL,
|
||||
.trainerClass = TRAINER_CLASS_PKMN_TRAINER_1,
|
||||
.trainerClass = TRAINER_CLASS_NONE,
|
||||
.encounterMusic_gender = TRAINER_ENCOUNTER_MUSIC_MALE,
|
||||
.trainerPic = TRAINER_PIC_HIKER,
|
||||
.trainerName = _(""),
|
||||
|
|
|
|||
|
|
@ -1,109 +0,0 @@
|
|||
const u8 gTrainerClassNames[][13] = {
|
||||
[TRAINER_CLASS_NONE] = _("{PKMN} TRAINER"),
|
||||
[TRAINER_CLASS_PKMN_TRAINER_UNUSED] = _("{PKMN} TRAINER"),
|
||||
[TRAINER_CLASS_AQUA_LEADER] = _("AQUA LEADER"),
|
||||
[TRAINER_CLASS_TEAM_AQUA] = _("TEAM AQUA"),
|
||||
[TRAINER_CLASS_RS_AROMA_LADY] = _("AROMA LADY"),
|
||||
[TRAINER_CLASS_RS_RUIN_MANIAC] = _("RUIN MANIAC"),
|
||||
[TRAINER_CLASS_INTERVIEWER] = _("INTERVIEWER"),
|
||||
[TRAINER_CLASS_RS_TUBER_F] = _("TUBER"),
|
||||
[TRAINER_CLASS_RS_TUBER_M] = _("TUBER"),
|
||||
[TRAINER_CLASS_RS_COOLTRAINER] = _("COOLTRAINER"),
|
||||
[TRAINER_CLASS_HEX_MANIAC] = _("HEX MANIAC"),
|
||||
[TRAINER_CLASS_RS_LADY] = _("LADY"),
|
||||
[TRAINER_CLASS_RS_BEAUTY] = _("BEAUTY"),
|
||||
[TRAINER_CLASS_RICH_BOY] = _("RICH BOY"),
|
||||
[TRAINER_CLASS_RS_POKEMANIAC] = _("POKéMANIAC"),
|
||||
[TRAINER_CLASS_RS_SWIMMER_M] = _("SWIMMER♂"),
|
||||
[TRAINER_CLASS_RS_BLACK_BELT] = _("BLACK BELT"),
|
||||
[TRAINER_CLASS_GUITARIST] = _("GUITARIST"),
|
||||
[TRAINER_CLASS_KINDLER] = _("KINDLER"),
|
||||
[TRAINER_CLASS_RS_CAMPER] = _("CAMPER"),
|
||||
[TRAINER_CLASS_BUG_MANIAC] = _("BUG MANIAC"),
|
||||
[TRAINER_CLASS_RS_PSYCHIC] = _("PSYCHIC"),
|
||||
[TRAINER_CLASS_RS_GENTLEMAN] = _("GENTLEMAN"),
|
||||
[TRAINER_CLASS_RS_ELITE_FOUR] = _("ELITE FOUR"),
|
||||
[TRAINER_CLASS_RS_LEADER] = _("LEADER"),
|
||||
[TRAINER_CLASS_SCHOOL_KID] = _("SCHOOL KID"),
|
||||
[TRAINER_CLASS_SR_AND_JR] = _("SR. AND JR."),
|
||||
[TRAINER_CLASS_POKEFAN] = _("POKéFAN"),
|
||||
[TRAINER_CLASS_EXPERT] = _("EXPERT"),
|
||||
[TRAINER_CLASS_RS_YOUNGSTER] = _("YOUNGSTER"),
|
||||
[TRAINER_CLASS_RS_CHAMPION] = _("CHAMPION"),
|
||||
[TRAINER_CLASS_RS_FISHERMAN] = _("FISHERMAN"),
|
||||
[TRAINER_CLASS_TRIATHLETE] = _("TRIATHLETE"),
|
||||
[TRAINER_CLASS_DRAGON_TAMER] = _("DRAGON TAMER"),
|
||||
[TRAINER_CLASS_RS_BIRD_KEEPER] = _("BIRD KEEPER"),
|
||||
[TRAINER_CLASS_NINJA_BOY] = _("NINJA BOY"),
|
||||
[TRAINER_CLASS_BATTLE_GIRL] = _("BATTLE GIRL"),
|
||||
[TRAINER_CLASS_PARASOL_LADY] = _("PARASOL LADY"),
|
||||
[TRAINER_CLASS_RS_SWIMMER_F] = _("SWIMMER♀"),
|
||||
[TRAINER_CLASS_RS_PICNICKER] = _("PICNICKER"),
|
||||
[TRAINER_CLASS_RS_TWINS] = _("TWINS"),
|
||||
[TRAINER_CLASS_RS_SAILOR] = _("SAILOR"),
|
||||
[TRAINER_CLASS_BOARDER] = _("BOARDER"),
|
||||
[TRAINER_CLASS_COLLECTOR] = _("COLLECTOR"),
|
||||
[TRAINER_CLASS_PKMN_TRAINER] = _("{PKMN} TRAINER"),
|
||||
[TRAINER_CLASS_RS_PKMN_BREEDER] = _("{PKMN} BREEDER"),
|
||||
[TRAINER_CLASS_RS_PKMN_RANGER] = _("{PKMN} RANGER"),
|
||||
[TRAINER_CLASS_MAGMA_LEADER] = _("MAGMA LEADER"),
|
||||
[TRAINER_CLASS_TEAM_MAGMA] = _("TEAM MAGMA"),
|
||||
[TRAINER_CLASS_RS_LASS] = _("LASS"),
|
||||
[TRAINER_CLASS_RS_BUG_CATCHER] = _("BUG CATCHER"),
|
||||
[TRAINER_CLASS_RS_HIKER] = _("HIKER"),
|
||||
[TRAINER_CLASS_RS_YOUNG_COUPLE] = _("YOUNG COUPLE"),
|
||||
[TRAINER_CLASS_OLD_COUPLE] = _("OLD COUPLE"),
|
||||
[TRAINER_CLASS_RS_SIS_AND_BRO] = _("SIS AND BRO"),
|
||||
[TRAINER_CLASS_AQUA_ADMIN] = _("AQUA ADMIN"),
|
||||
[TRAINER_CLASS_MAGMA_ADMIN] = _("MAGMA ADMIN"),
|
||||
[TRAINER_CLASS_YOUNGSTER] = _("YOUNGSTER"),
|
||||
[TRAINER_CLASS_BUG_CATCHER] = _("BUG CATCHER"),
|
||||
[TRAINER_CLASS_LASS] = _("LASS"),
|
||||
[TRAINER_CLASS_SAILOR] = _("SAILOR"),
|
||||
[TRAINER_CLASS_CAMPER] = _("CAMPER"),
|
||||
[TRAINER_CLASS_PICNICKER] = _("PICNICKER"),
|
||||
[TRAINER_CLASS_POKEMANIAC] = _("POKéMANIAC"),
|
||||
[TRAINER_CLASS_SUPER_NERD] = _("SUPER NERD"),
|
||||
[TRAINER_CLASS_HIKER] = _("HIKER"),
|
||||
[TRAINER_CLASS_BIKER] = _("BIKER"),
|
||||
[TRAINER_CLASS_BURGLAR] = _("BURGLAR"),
|
||||
[TRAINER_CLASS_ENGINEER] = _("ENGINEER"),
|
||||
[TRAINER_CLASS_FISHERMAN] = _("FISHERMAN"),
|
||||
[TRAINER_CLASS_SWIMMER_M] = _("SWIMMER♂"),
|
||||
[TRAINER_CLASS_CUE_BALL] = _("CUE BALL"),
|
||||
[TRAINER_CLASS_GAMER] = _("GAMER"),
|
||||
[TRAINER_CLASS_BEAUTY] = _("BEAUTY"),
|
||||
[TRAINER_CLASS_SWIMMER_F] = _("SWIMMER♀"),
|
||||
[TRAINER_CLASS_PSYCHIC] = _("PSYCHIC"),
|
||||
[TRAINER_CLASS_ROCKER] = _("ROCKER"),
|
||||
[TRAINER_CLASS_JUGGLER] = _("JUGGLER"),
|
||||
[TRAINER_CLASS_TAMER] = _("TAMER"),
|
||||
[TRAINER_CLASS_BIRD_KEEPER] = _("BIRD KEEPER"),
|
||||
[TRAINER_CLASS_BLACK_BELT] = _("BLACK BELT"),
|
||||
[TRAINER_CLASS_RIVAL_EARLY] = _("RIVAL"),
|
||||
[TRAINER_CLASS_SCIENTIST] = _("SCIENTIST"),
|
||||
[TRAINER_CLASS_BOSS] = _("BOSS"),
|
||||
[TRAINER_CLASS_LEADER] = _("LEADER"),
|
||||
[TRAINER_CLASS_TEAM_ROCKET] = _("TEAM ROCKET"),
|
||||
[TRAINER_CLASS_COOLTRAINER] = _("COOLTRAINER"),
|
||||
[TRAINER_CLASS_ELITE_FOUR] = _("ELITE FOUR"),
|
||||
[TRAINER_CLASS_GENTLEMAN] = _("GENTLEMAN"),
|
||||
[TRAINER_CLASS_RIVAL_LATE] = _("RIVAL"),
|
||||
[TRAINER_CLASS_CHAMPION] = _("CHAMPION"),
|
||||
[TRAINER_CLASS_CHANNELER] = _("CHANNELER"),
|
||||
[TRAINER_CLASS_TWINS] = _("TWINS"),
|
||||
[TRAINER_CLASS_COOL_COUPLE] = _("COOL COUPLE"),
|
||||
[TRAINER_CLASS_YOUNG_COUPLE] = _("YOUNG COUPLE"),
|
||||
[TRAINER_CLASS_CRUSH_KIN] = _("CRUSH KIN"),
|
||||
[TRAINER_CLASS_SIS_AND_BRO] = _("SIS AND BRO"),
|
||||
[TRAINER_CLASS_PKMN_PROF] = _("{PKMN} PROF."),
|
||||
[TRAINER_CLASS_PLAYER] = _("PLAYER"),
|
||||
[TRAINER_CLASS_CRUSH_GIRL] = _("CRUSH GIRL"),
|
||||
[TRAINER_CLASS_TUBER] = _("TUBER"),
|
||||
[TRAINER_CLASS_PKMN_BREEDER] = _("{PKMN} BREEDER"),
|
||||
[TRAINER_CLASS_PKMN_RANGER] = _("{PKMN} RANGER"),
|
||||
[TRAINER_CLASS_AROMA_LADY] = _("AROMA LADY"),
|
||||
[TRAINER_CLASS_RUIN_MANIAC] = _("RUIN MANIAC"),
|
||||
[TRAINER_CLASS_LADY] = _("LADY"),
|
||||
[TRAINER_CLASS_PAINTER] = _("PAINTER"),
|
||||
};
|
||||
File diff suppressed because it is too large
Load Diff
2978
src/data/trainers.h
2978
src/data/trainers.h
File diff suppressed because it is too large
Load Diff
|
|
@ -8263,27 +8263,27 @@
|
|||
{
|
||||
"min_level": 3,
|
||||
"max_level": 3,
|
||||
"species": "SPECIES_CHARIZARD"
|
||||
"species": "SPECIES_FARFETCHD_GALARIAN"
|
||||
},
|
||||
{
|
||||
"min_level": 3,
|
||||
"max_level": 3,
|
||||
"species": "SPECIES_CHARIZARD"
|
||||
"species": "SPECIES_FARFETCHD_GALARIAN"
|
||||
},
|
||||
{
|
||||
"min_level": 3,
|
||||
"max_level": 3,
|
||||
"species": "SPECIES_CHARIZARD"
|
||||
"species": "SPECIES_FARFETCHD_GALARIAN"
|
||||
},
|
||||
{
|
||||
"min_level": 3,
|
||||
"max_level": 3,
|
||||
"species": "SPECIES_CHARIZARD"
|
||||
"species": "SPECIES_FARFETCHD_GALARIAN"
|
||||
},
|
||||
{
|
||||
"min_level": 2,
|
||||
"max_level": 2,
|
||||
"species": "SPECIES_CHARIZARD"
|
||||
"species": "SPECIES_FARFETCHD_GALARIAN"
|
||||
},
|
||||
{
|
||||
"min_level": 2,
|
||||
|
|
@ -10499,29 +10499,29 @@
|
|||
"encounter_rate": 21,
|
||||
"mons": [
|
||||
{
|
||||
"min_level": 6,
|
||||
"max_level": 6,
|
||||
"species": "SPECIES_PARAS"
|
||||
"min_level": 14,
|
||||
"max_level": 14,
|
||||
"species": "SPECIES_MAGIKARP"
|
||||
},
|
||||
{
|
||||
"min_level": 6,
|
||||
"max_level": 6,
|
||||
"species": "SPECIES_PARAS"
|
||||
"min_level": 14,
|
||||
"max_level": 14,
|
||||
"species": "SPECIES_MAGIKARP"
|
||||
},
|
||||
{
|
||||
"min_level": 6,
|
||||
"max_level": 6,
|
||||
"species": "SPECIES_PARAS"
|
||||
"min_level": 14,
|
||||
"max_level": 14,
|
||||
"species": "SPECIES_MAGIKARP"
|
||||
},
|
||||
{
|
||||
"min_level": 6,
|
||||
"max_level": 6,
|
||||
"species": "SPECIES_PARAS"
|
||||
"min_level": 14,
|
||||
"max_level": 14,
|
||||
"species": "SPECIES_MAGIKARP"
|
||||
},
|
||||
{
|
||||
"min_level": 2,
|
||||
"max_level": 2,
|
||||
"species": "SPECIES_RATTATA"
|
||||
"min_level": 14,
|
||||
"max_level": 14,
|
||||
"species": "SPECIES_MAGIKARP"
|
||||
},
|
||||
{
|
||||
"min_level": 2,
|
||||
|
|
|
|||
|
|
@ -1219,6 +1219,24 @@ static void HandleChooseMonSelection(u8 taskId, s8 *slotPtr)
|
|||
if (IsSelectedMonNotEgg((u8 *)slotPtr))
|
||||
TryEnterMonForMinigame(taskId, (u8)*slotPtr);
|
||||
break;
|
||||
case PARTY_ACTION_CHOOSE_FAINTED_MON:
|
||||
{
|
||||
u8 partyId = GetPartyIdFromBattleSlot((u8)*slotPtr);
|
||||
if (GetMonData(&gPlayerParty[*slotPtr], MON_DATA_HP) > 0
|
||||
|| GetMonData(&gPlayerParty[*slotPtr], MON_DATA_SPECIES_OR_EGG) == SPECIES_EGG
|
||||
|| ((gBattleTypeFlags & BATTLE_TYPE_MULTI) && partyId >= (PARTY_SIZE / 2)))
|
||||
{
|
||||
// Can't select if egg, alive, or doesn't belong to you
|
||||
PlaySE(SE_FAILURE);
|
||||
}
|
||||
else
|
||||
{
|
||||
PlaySE(SE_SELECT);
|
||||
gSelectedMonPartyId = partyId;
|
||||
Task_ClosePartyMenu(taskId);
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
case PARTY_ACTION_ABILITY_PREVENTS:
|
||||
case PARTY_ACTION_SWITCHING:
|
||||
|
|
@ -6307,10 +6325,10 @@ void ChooseMonForWirelessMinigame(void)
|
|||
|
||||
static u8 GetPartyLayoutFromBattleType(void)
|
||||
{
|
||||
if (IsDoubleBattle() == FALSE)
|
||||
return PARTY_LAYOUT_SINGLE;
|
||||
if (IsMultiBattle() == TRUE)
|
||||
return PARTY_LAYOUT_MULTI;
|
||||
if (!IsDoubleBattle() || gPlayerPartyCount == 1)
|
||||
return PARTY_LAYOUT_SINGLE;
|
||||
return PARTY_LAYOUT_DOUBLE;
|
||||
}
|
||||
|
||||
|
|
@ -6431,7 +6449,7 @@ static bool8 TrySwitchInPokemon(void)
|
|||
StringExpandPlaceholders(gStringVar4, gText_EggCantBattle);
|
||||
return FALSE;
|
||||
}
|
||||
if (GetPartyIdFromBattleSlot(slot) == gBattleStruct->playerPartyIdx)
|
||||
if (GetPartyIdFromBattleSlot(slot) == gBattleStruct->prevSelectedPartySlot)
|
||||
{
|
||||
GetMonNickname(&gPlayerParty[slot], gStringVar1);
|
||||
StringExpandPlaceholders(gStringVar4, gText_PkmnAlreadySelected);
|
||||
|
|
@ -6560,12 +6578,12 @@ static void BufferBattlePartyOrderBySide(u8 *partyBattleOrder, u8 flankId, u8 ba
|
|||
{
|
||||
j = 1;
|
||||
partyIndexes[0] = gBattlerPartyIndexes[leftBattler];
|
||||
for (i = 0; i < PARTY_SIZE; ++i)
|
||||
for (i = 0; i < PARTY_SIZE; i++)
|
||||
{
|
||||
if (i != partyIndexes[0])
|
||||
{
|
||||
partyIndexes[j] = i;
|
||||
++j;
|
||||
j++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -6574,16 +6592,16 @@ static void BufferBattlePartyOrderBySide(u8 *partyBattleOrder, u8 flankId, u8 ba
|
|||
j = 2;
|
||||
partyIndexes[0] = gBattlerPartyIndexes[leftBattler];
|
||||
partyIndexes[1] = gBattlerPartyIndexes[rightBattler];
|
||||
for (i = 0; i < PARTY_SIZE; ++i)
|
||||
for (i = 0; i < PARTY_SIZE; i++)
|
||||
{
|
||||
if (i != partyIndexes[0] && i != partyIndexes[1])
|
||||
{
|
||||
partyIndexes[j] = i;
|
||||
++j;
|
||||
j++;
|
||||
}
|
||||
}
|
||||
}
|
||||
for (i = 0; i < 3; ++i)
|
||||
for (i = 0; i < 3; i++)
|
||||
partyBattleOrder[i] = (partyIndexes[0 + (i * 2)] << 4) | partyIndexes[1 + (i * 2)];
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -672,8 +672,10 @@ static void SpriteCB_BallThrow_Shake(struct Sprite *sprite)
|
|||
#define tCryTaskSpecies data[0]
|
||||
#define tCryTaskPan data[1]
|
||||
#define tCryTaskWantedCry data[2]
|
||||
#define tCryTaskMonPtr1 data[3]
|
||||
#define tCryTaskMonPtr2 data[4]
|
||||
#define tCryTaskBattler data[3]
|
||||
#define tCryTaskMonSpriteId data[4]
|
||||
#define tCryTaskMonPtr1 data[5]
|
||||
#define tCryTaskMonPtr2 data[6]
|
||||
#define tCryTaskFrames data[10]
|
||||
#define tCryTaskState data[15]
|
||||
|
||||
|
|
@ -682,15 +684,15 @@ static void Task_PlayCryWhenReleasedFromBall(u8 taskId)
|
|||
u8 wantedCry = gTasks[taskId].tCryTaskWantedCry;
|
||||
s8 pan = gTasks[taskId].tCryTaskPan;
|
||||
u16 species = gTasks[taskId].tCryTaskSpecies;
|
||||
u8 battlerId = gTasks[taskId].tCryTaskBattler;
|
||||
u8 monSpriteId = gTasks[taskId].tCryTaskMonSpriteId;
|
||||
struct Pokemon *mon = (void *)(u32)((gTasks[taskId].tCryTaskMonPtr1 << 16) | (u16)(gTasks[taskId].tCryTaskMonPtr2));
|
||||
|
||||
switch (gTasks[taskId].tCryTaskState)
|
||||
{
|
||||
case 0:
|
||||
default:
|
||||
if (gTasks[taskId].data[8] < 3)
|
||||
gTasks[taskId].data[8]++;
|
||||
else
|
||||
if (gSprites[monSpriteId].affineAnimEnded)
|
||||
gTasks[taskId].tCryTaskState = wantedCry + 1;
|
||||
break;
|
||||
case 1:
|
||||
|
|
@ -699,7 +701,7 @@ static void Task_PlayCryWhenReleasedFromBall(u8 taskId)
|
|||
PlayCry_ByMode(species, pan, CRY_MODE_NORMAL);
|
||||
else
|
||||
PlayCry_ByMode(species, pan, CRY_MODE_WEAK);
|
||||
|
||||
gBattleSpritesDataPtr->healthBoxesData[battlerId].waitForCry = FALSE;
|
||||
DestroyTask(taskId);
|
||||
break;
|
||||
case 2:
|
||||
|
|
@ -716,6 +718,7 @@ static void Task_PlayCryWhenReleasedFromBall(u8 taskId)
|
|||
else
|
||||
PlayCry_ReleaseDouble(species, pan, CRY_MODE_WEAK_DOUBLES);
|
||||
|
||||
gBattleSpritesDataPtr->healthBoxesData[battlerId].waitForCry = FALSE;
|
||||
DestroyTask(taskId);
|
||||
}
|
||||
else
|
||||
|
|
@ -755,6 +758,7 @@ static void Task_PlayCryWhenReleasedFromBall(u8 taskId)
|
|||
else
|
||||
PlayCry_ReleaseDouble(species, pan, CRY_MODE_WEAK);
|
||||
|
||||
gBattleSpritesDataPtr->healthBoxesData[battlerId].waitForCry = FALSE;
|
||||
DestroyTask(taskId);
|
||||
break;
|
||||
}
|
||||
|
|
@ -773,7 +777,7 @@ static void SpriteCB_ReleaseMonFromBall(struct Sprite *sprite)
|
|||
|
||||
if (gMain.inBattle)
|
||||
{
|
||||
struct Pokemon *mon;
|
||||
struct Pokemon *mon, *illusionMon;
|
||||
u16 species;
|
||||
s8 pan;
|
||||
u16 wantedCryCase;
|
||||
|
|
@ -812,10 +816,20 @@ static void SpriteCB_ReleaseMonFromBall(struct Sprite *sprite)
|
|||
else
|
||||
wantedCryCase = 2;
|
||||
|
||||
gBattleSpritesDataPtr->healthBoxesData[battlerId].waitForCry = TRUE;
|
||||
|
||||
taskId = CreateTask(Task_PlayCryWhenReleasedFromBall, 3);
|
||||
gTasks[taskId].tCryTaskSpecies = species;
|
||||
|
||||
illusionMon = GetIllusionMonPtr(battlerId);
|
||||
if (illusionMon != NULL)
|
||||
gTasks[taskId].tCryTaskSpecies = GetMonData(illusionMon, MON_DATA_SPECIES);
|
||||
else
|
||||
gTasks[taskId].tCryTaskSpecies = GetMonData(mon, MON_DATA_SPECIES);
|
||||
|
||||
gTasks[taskId].tCryTaskPan = pan;
|
||||
gTasks[taskId].tCryTaskWantedCry = wantedCryCase;
|
||||
gTasks[taskId].tCryTaskBattler = battlerId;
|
||||
gTasks[taskId].tCryTaskMonSpriteId = gBattlerSpriteIds[sprite->sBattler];
|
||||
gTasks[taskId].tCryTaskMonPtr1 = (u32)(mon) >> 16;
|
||||
gTasks[taskId].tCryTaskMonPtr2 = (u32)(mon);
|
||||
gTasks[taskId].tCryTaskState = 0;
|
||||
|
|
@ -829,6 +843,8 @@ static void SpriteCB_ReleaseMonFromBall(struct Sprite *sprite)
|
|||
#undef tCryTaskSpecies
|
||||
#undef tCryTaskPan
|
||||
#undef tCryTaskWantedCry
|
||||
#undef tCryTaskBattler
|
||||
#undef tCryTaskMonSpriteId
|
||||
#undef tCryTaskMonPtr1
|
||||
#undef tCryTaskMonPtr2
|
||||
#undef tCryTaskFrames
|
||||
|
|
|
|||
174
src/pokemon.c
174
src/pokemon.c
|
|
@ -62,7 +62,6 @@ static EWRAM_DATA struct MonSpritesGfxManager *sMonSpritesGfxManager = NULL;
|
|||
|
||||
static union PokemonSubstruct *GetSubstruct(struct BoxPokemon *boxMon, u32 personality, u8 substructType);
|
||||
static bool8 IsShinyOtIdPersonality(u32 otId, u32 personality);
|
||||
static u8 GetNatureFromPersonality(u32 personality);
|
||||
static bool8 PartyMonHasStatus(struct Pokemon *mon, u32 unused, u32 healMask, u8 battleId);
|
||||
static bool8 IsPokemonStorageFull(void);
|
||||
static u8 CopyMonToPC(struct Pokemon *mon);
|
||||
|
|
@ -3126,30 +3125,28 @@ static u8 CopyMonToPC(struct Pokemon *mon)
|
|||
return MON_CANT_GIVE;
|
||||
}
|
||||
|
||||
u8 CalculatePlayerPartyCount(void)
|
||||
u8 CalculatePartyCount(struct Pokemon *party)
|
||||
{
|
||||
gPlayerPartyCount = 0;
|
||||
u32 partyCount = 0;
|
||||
|
||||
while (gPlayerPartyCount < PARTY_SIZE
|
||||
&& GetMonData(&gPlayerParty[gPlayerPartyCount], MON_DATA_SPECIES, NULL) != SPECIES_NONE)
|
||||
while (partyCount < PARTY_SIZE
|
||||
&& GetMonData(&party[partyCount], MON_DATA_SPECIES, NULL) != SPECIES_NONE)
|
||||
{
|
||||
gPlayerPartyCount++;
|
||||
partyCount++;
|
||||
}
|
||||
|
||||
return partyCount;
|
||||
}
|
||||
|
||||
u8 CalculatePlayerPartyCount(void)
|
||||
{
|
||||
gPlayerPartyCount = CalculatePartyCount(gPlayerParty);
|
||||
return gPlayerPartyCount;
|
||||
}
|
||||
|
||||
|
||||
u8 CalculateEnemyPartyCount(void)
|
||||
{
|
||||
gEnemyPartyCount = 0;
|
||||
|
||||
while (gEnemyPartyCount < PARTY_SIZE
|
||||
&& GetMonData(&gEnemyParty[gEnemyPartyCount], MON_DATA_SPECIES, NULL) != SPECIES_NONE)
|
||||
{
|
||||
gEnemyPartyCount++;
|
||||
}
|
||||
|
||||
gEnemyPartyCount = CalculatePartyCount(gEnemyParty);
|
||||
return gEnemyPartyCount;
|
||||
}
|
||||
|
||||
|
|
@ -3370,6 +3367,55 @@ void RemoveBattleMonPPBonus(struct BattlePokemon *mon, u8 moveIndex)
|
|||
mon->ppBonuses &= gPPUpClearMask[moveIndex];
|
||||
}
|
||||
|
||||
void PokemonToBattleMon(struct Pokemon *src, struct BattlePokemon *dst)
|
||||
{
|
||||
s32 i;
|
||||
u8 nickname[POKEMON_NAME_BUFFER_SIZE];
|
||||
|
||||
for (i = 0; i < MAX_MON_MOVES; i++)
|
||||
{
|
||||
dst->moves[i] = GetMonData(src, MON_DATA_MOVE1 + i, NULL);
|
||||
dst->pp[i] = GetMonData(src, MON_DATA_PP1 + i, NULL);
|
||||
}
|
||||
|
||||
dst->species = GetMonData(src, MON_DATA_SPECIES, NULL);
|
||||
dst->item = GetMonData(src, MON_DATA_HELD_ITEM, NULL);
|
||||
dst->ppBonuses = GetMonData(src, MON_DATA_PP_BONUSES, NULL);
|
||||
dst->friendship = GetMonData(src, MON_DATA_FRIENDSHIP, NULL);
|
||||
dst->experience = GetMonData(src, MON_DATA_EXP, NULL);
|
||||
dst->hpIV = GetMonData(src, MON_DATA_HP_IV, NULL);
|
||||
dst->attackIV = GetMonData(src, MON_DATA_ATK_IV, NULL);
|
||||
dst->defenseIV = GetMonData(src, MON_DATA_DEF_IV, NULL);
|
||||
dst->speedIV = GetMonData(src, MON_DATA_SPEED_IV, NULL);
|
||||
dst->spAttackIV = GetMonData(src, MON_DATA_SPATK_IV, NULL);
|
||||
dst->spDefenseIV = GetMonData(src, MON_DATA_SPDEF_IV, NULL);
|
||||
dst->personality = GetMonData(src, MON_DATA_PERSONALITY, NULL);
|
||||
dst->status1 = GetMonData(src, MON_DATA_STATUS, NULL);
|
||||
dst->level = GetMonData(src, MON_DATA_LEVEL, NULL);
|
||||
dst->hp = GetMonData(src, MON_DATA_HP, NULL);
|
||||
dst->maxHP = GetMonData(src, MON_DATA_MAX_HP, NULL);
|
||||
dst->attack = GetMonData(src, MON_DATA_ATK, NULL);
|
||||
dst->defense = GetMonData(src, MON_DATA_DEF, NULL);
|
||||
dst->speed = GetMonData(src, MON_DATA_SPEED, NULL);
|
||||
dst->spAttack = GetMonData(src, MON_DATA_SPATK, NULL);
|
||||
dst->spDefense = GetMonData(src, MON_DATA_SPDEF, NULL);
|
||||
dst->abilityNum = GetMonData(src, MON_DATA_ABILITY_NUM, NULL);
|
||||
dst->otId = GetMonData(src, MON_DATA_OT_ID, NULL);
|
||||
dst->type1 = gSpeciesInfo[dst->species].types[0];
|
||||
dst->type2 = gSpeciesInfo[dst->species].types[1];
|
||||
dst->type3 = TYPE_MYSTERY;
|
||||
dst->ability = GetAbilityBySpecies(dst->species, dst->abilityNum);
|
||||
GetMonData(src, MON_DATA_NICKNAME, nickname);
|
||||
StringCopy_Nickname(dst->nickname, nickname);
|
||||
GetMonData(src, MON_DATA_OT_NAME, dst->otName);
|
||||
|
||||
for (i = 0; i < NUM_BATTLE_STATS; i++)
|
||||
dst->statStages[i] = DEFAULT_STAT_STAGE;
|
||||
|
||||
dst->status2 = 0;
|
||||
}
|
||||
|
||||
|
||||
bool8 ExecuteTableBasedItemEffect(struct Pokemon *mon, u16 item, u8 partyIndex, u8 moveIndex)
|
||||
{
|
||||
return PokemonUseItemEffects(mon, item, partyIndex, moveIndex, FALSE);
|
||||
|
|
@ -3982,7 +4028,7 @@ u8 GetNature(struct Pokemon *mon)
|
|||
return GetMonData(mon, MON_DATA_PERSONALITY, NULL) % NUM_NATURES;
|
||||
}
|
||||
|
||||
static u8 GetNatureFromPersonality(u32 personality)
|
||||
u8 GetNatureFromPersonality(u32 personality)
|
||||
{
|
||||
return personality % NUM_NATURES;
|
||||
}
|
||||
|
|
@ -5053,6 +5099,91 @@ bool8 TryIncrementMonLevel(struct Pokemon *mon)
|
|||
}
|
||||
}
|
||||
|
||||
static const u16 sUniversalMoves[] =
|
||||
{
|
||||
MOVE_BIDE,
|
||||
MOVE_FRUSTRATION,
|
||||
MOVE_HIDDEN_POWER,
|
||||
MOVE_MIMIC,
|
||||
MOVE_NATURAL_GIFT,
|
||||
MOVE_RAGE,
|
||||
MOVE_RETURN,
|
||||
MOVE_SECRET_POWER,
|
||||
MOVE_SUBSTITUTE,
|
||||
MOVE_TERA_BLAST,
|
||||
};
|
||||
|
||||
u8 CanLearnTeachableMove(u16 species, u16 move)
|
||||
{
|
||||
if (species == SPECIES_EGG)
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
else if (species == SPECIES_MEW)
|
||||
{
|
||||
switch (move)
|
||||
{
|
||||
case MOVE_BADDY_BAD:
|
||||
case MOVE_BOUNCY_BUBBLE:
|
||||
case MOVE_BUZZY_BUZZ:
|
||||
case MOVE_DRAGON_ASCENT:
|
||||
case MOVE_FLOATY_FALL:
|
||||
case MOVE_FREEZY_FROST:
|
||||
case MOVE_GLITZY_GLOW:
|
||||
case MOVE_RELIC_SONG:
|
||||
case MOVE_SAPPY_SEED:
|
||||
case MOVE_SECRET_SWORD:
|
||||
case MOVE_SIZZLY_SLIDE:
|
||||
case MOVE_SPARKLY_SWIRL:
|
||||
case MOVE_SPLISHY_SPLASH:
|
||||
case MOVE_VOLT_TACKLE:
|
||||
case MOVE_ZIPPY_ZAP:
|
||||
return FALSE;
|
||||
default:
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
u32 i, j;
|
||||
const u16 *teachableLearnset = GetSpeciesTeachableLearnset(species);
|
||||
for (i = 0; i < ARRAY_COUNT(sUniversalMoves); i++)
|
||||
{
|
||||
if (sUniversalMoves[i] == move)
|
||||
{
|
||||
if (!gSpeciesInfo[species].tmIlliterate)
|
||||
{
|
||||
if (move == MOVE_TERA_BLAST && GET_BASE_SPECIES_ID(species) == SPECIES_TERAPAGOS)
|
||||
return FALSE;
|
||||
if (GET_BASE_SPECIES_ID(species) == SPECIES_PYUKUMUKU && (move == MOVE_HIDDEN_POWER || move == MOVE_RETURN || move == MOVE_FRUSTRATION))
|
||||
return FALSE;
|
||||
return TRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
const struct LevelUpMove *learnset = GetSpeciesLevelUpLearnset(species);
|
||||
|
||||
if (P_TM_LITERACY < GEN_6)
|
||||
return FALSE;
|
||||
|
||||
for (j = 0; j < MAX_LEVEL_UP_MOVES && learnset[j].move != LEVEL_UP_MOVE_END; j++)
|
||||
{
|
||||
if (learnset[j].move == move)
|
||||
return TRUE;
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
}
|
||||
for (i = 0; teachableLearnset[i] != MOVE_UNAVAILABLE; i++)
|
||||
{
|
||||
if (teachableLearnset[i] == move)
|
||||
return TRUE;
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
u32 CanMonLearnTMHM(struct Pokemon *mon, u8 tm)
|
||||
{
|
||||
u16 i;
|
||||
|
|
@ -5186,13 +5317,6 @@ u16 SpeciesToPokedexNum(u16 species)
|
|||
return species > 0 ? species : 0xFFFF;
|
||||
}
|
||||
|
||||
void ClearBattleMonForms(void)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < MAX_BATTLERS_COUNT; i++)
|
||||
gBattleMonForms[i] = 0;
|
||||
}
|
||||
|
||||
static u16 GetBattleBGM(void)
|
||||
{
|
||||
if (gBattleTypeFlags & BATTLE_TYPE_KYOGRE_GROUDON)
|
||||
|
|
@ -5590,9 +5714,9 @@ u16 FacilityClassToPicIndex(u16 facilityClass)
|
|||
u16 PlayerGenderToFrontTrainerPicId(u8 playerGender)
|
||||
{
|
||||
if (playerGender != MALE)
|
||||
return FacilityClassToPicIndex(FACILITY_CLASS_MAY);
|
||||
return FacilityClassToPicIndex(FACILITY_CLASS_LEAF);
|
||||
else
|
||||
return FacilityClassToPicIndex(FACILITY_CLASS_BRENDAN);
|
||||
return FacilityClassToPicIndex(FACILITY_CLASS_RED);
|
||||
}
|
||||
|
||||
void HandleSetPokedexFlag(u16 nationalNum, u8 caseId, u32 personality)
|
||||
|
|
|
|||
|
|
@ -128,7 +128,7 @@ void TrySetQuestLogLinkBattleEvent(void)
|
|||
}
|
||||
|
||||
for (i = 0; i < PLAYER_NAME_LENGTH; i++)
|
||||
data->playerNames[0][i] = gLinkPlayers[gBattleStruct->multiplayerId ^ 1].name[i];
|
||||
data->playerNames[0][i] = gLinkPlayers[gBattleScripting.multiplayerId ^ 1].name[i];
|
||||
}
|
||||
SetQuestLogEvent(eventId, (const u16 *)data);
|
||||
Free(data);
|
||||
|
|
@ -139,12 +139,12 @@ static void GetLinkMultiBattlePlayerIndexes(s32 * partnerIdx, s32 * opponentIdxs
|
|||
{
|
||||
s32 i;
|
||||
s32 numOpponentsFound = 0;
|
||||
u8 partnerId = gLinkPlayers[gBattleStruct->multiplayerId].id ^ 2;
|
||||
u8 partnerId = gLinkPlayers[gBattleScripting.multiplayerId].id ^ 2;
|
||||
for (i = 0; i < MAX_BATTLERS_COUNT; i++)
|
||||
{
|
||||
if (partnerId == gLinkPlayers[i].id)
|
||||
*partnerIdx = i;
|
||||
else if (i != gBattleStruct->multiplayerId)
|
||||
else if (i != gBattleScripting.multiplayerId)
|
||||
opponentIdxs[numOpponentsFound++] = i;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -236,7 +236,7 @@ static void CreateBattlerSprite(u8 battler)
|
|||
gSprites[gBattlerSpriteIds[battler]].callback = SpriteCallbackDummy;
|
||||
gSprites[gBattlerSpriteIds[battler]].data[0] = battler;
|
||||
gSprites[gBattlerSpriteIds[battler]].data[2] = GetMonData(&gEnemyParty[gBattlerPartyIndexes[battler]], MON_DATA_SPECIES);
|
||||
StartSpriteAnim(&gSprites[gBattlerSpriteIds[battler]], gBattleMonForms[battler]);
|
||||
StartSpriteAnim(&gSprites[gBattlerSpriteIds[battler]], 0);
|
||||
}
|
||||
else if (gBattleTypeFlags & BATTLE_TYPE_SAFARI && battler == B_POSITION_PLAYER_LEFT)
|
||||
{
|
||||
|
|
@ -270,7 +270,7 @@ static void CreateBattlerSprite(u8 battler)
|
|||
gSprites[gBattlerSpriteIds[battler]].callback = SpriteCallbackDummy;
|
||||
gSprites[gBattlerSpriteIds[battler]].data[0] = battler;
|
||||
gSprites[gBattlerSpriteIds[battler]].data[2] = GetMonData(&gPlayerParty[gBattlerPartyIndexes[battler]], MON_DATA_SPECIES);
|
||||
StartSpriteAnim(&gSprites[gBattlerSpriteIds[battler]], gBattleMonForms[battler]);
|
||||
StartSpriteAnim(&gSprites[gBattlerSpriteIds[battler]], 0);
|
||||
}
|
||||
gSprites[gBattlerSpriteIds[battler]].invisible = gBattleSpritesDataPtr->battlerData[battler].invisible;
|
||||
}
|
||||
|
|
@ -306,9 +306,10 @@ static void CreateHealthboxSprite(u8 battler)
|
|||
if (GetMonData(&gEnemyParty[gBattlerPartyIndexes[battler]], MON_DATA_HP) == 0)
|
||||
SetHealthboxSpriteInvisible(healthboxSpriteId);
|
||||
}
|
||||
else if (!(gBattleTypeFlags & BATTLE_TYPE_SAFARI) && GetMonData(&gPlayerParty[gBattlerPartyIndexes[battler]], MON_DATA_HP) == 0)
|
||||
{
|
||||
SetHealthboxSpriteInvisible(healthboxSpriteId);
|
||||
else if (!(gBattleTypeFlags & BATTLE_TYPE_SAFARI))
|
||||
{
|
||||
if (!IsValidForBattle(&gPlayerParty[gBattlerPartyIndexes[battler]]))
|
||||
SetHealthboxSpriteInvisible(healthboxSpriteId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1179,7 +1179,7 @@ s32 GetStringWidth(u8 fontId, const u8 *str, s16 letterSpacing)
|
|||
return width;
|
||||
}
|
||||
|
||||
u8 RenderTextHandleBold(u8 *pixels, u8 fontId, u8 *str, int a3, int a4, int a5, int a6, int a7)
|
||||
u8 RenderTextHandleBold(u8 *pixels, u8 fontId, u8 *str)
|
||||
{
|
||||
u8 shadowColor;
|
||||
u8 *strLocal;
|
||||
|
|
|
|||
|
|
@ -4280,7 +4280,7 @@ static void ViewURoomPartnerTrainerCard(u8 *unused, struct WirelessLink_URoom *
|
|||
|
||||
DynamicPlaceholderTextUtil_Reset();
|
||||
|
||||
StringCopy(uroom->trainerCardStrBuffer[0], gTrainerClassNames[GetUnionRoomTrainerClass()]);
|
||||
StringCopy(uroom->trainerCardStrBuffer[0], gTrainerClasses[GetUnionRoomTrainerClass()].name);
|
||||
DynamicPlaceholderTextUtil_SetPlaceholderPtr(0, uroom->trainerCardStrBuffer[0]);
|
||||
|
||||
DynamicPlaceholderTextUtil_SetPlaceholderPtr(1, trainerCard->rse.playerName);
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@
|
|||
#include "script.h"
|
||||
#include "link.h"
|
||||
#include "quest_log.h"
|
||||
#include "safari_zone.h"
|
||||
#include "constants/maps.h"
|
||||
#include "constants/abilities.h"
|
||||
#include "constants/items.h"
|
||||
|
|
@ -33,6 +34,8 @@ struct WildEncounterData
|
|||
|
||||
static EWRAM_DATA struct WildEncounterData sWildEncounterData = {};
|
||||
static EWRAM_DATA bool8 sWildEncountersDisabled = FALSE;
|
||||
EWRAM_DATA bool8 gIsFishingEncounter = 0;
|
||||
EWRAM_DATA bool8 gIsSurfingEncounter = 0;
|
||||
|
||||
static bool8 UnlockedTanobyOrAreNotInTanoby(void);
|
||||
static u32 GenerateUnownPersonalityByLetter(u8 letter);
|
||||
|
|
@ -392,7 +395,17 @@ bool8 StandardWildEncounter(u32 currMetatileAttrs, u16 previousMetatileBehavior)
|
|||
// try a regular wild land encounter
|
||||
if (TryGenerateWildMon(gWildMonHeaders[headerId].landMonsInfo, WILD_AREA_LAND, WILD_CHECK_REPEL) == TRUE)
|
||||
{
|
||||
StartWildBattle();
|
||||
if (TryDoDoubleWildBattle())
|
||||
{
|
||||
struct Pokemon mon1 = gEnemyParty[0];
|
||||
TryGenerateWildMon(gWildMonHeaders[headerId].landMonsInfo, WILD_AREA_LAND, WILD_CHECK_KEEN_EYE);
|
||||
gEnemyParty[1] = mon1;
|
||||
StartDoubleWildBattle();
|
||||
}
|
||||
else
|
||||
{
|
||||
StartWildBattle();
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
else
|
||||
|
|
@ -428,8 +441,19 @@ bool8 StandardWildEncounter(u32 currMetatileAttrs, u16 previousMetatileBehavior)
|
|||
else // try a regular surfing encounter
|
||||
{
|
||||
if (TryGenerateWildMon(gWildMonHeaders[headerId].waterMonsInfo, WILD_AREA_WATER, WILD_CHECK_REPEL) == TRUE)
|
||||
{
|
||||
StartWildBattle();
|
||||
{
|
||||
gIsSurfingEncounter = TRUE;
|
||||
if (TryDoDoubleWildBattle())
|
||||
{
|
||||
struct Pokemon mon1 = gEnemyParty[0];
|
||||
TryGenerateWildMon(gWildMonHeaders[headerId].waterMonsInfo, WILD_AREA_WATER, WILD_CHECK_KEEN_EYE);
|
||||
gEnemyParty[1] = mon1;
|
||||
StartDoubleWildBattle();
|
||||
}
|
||||
else
|
||||
{
|
||||
StartWildBattle();
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
else
|
||||
|
|
@ -520,6 +544,7 @@ void FishingWildEncounter(u8 rod)
|
|||
{
|
||||
GenerateFishingEncounter(gWildMonHeaders[GetCurrentMapWildMonHeaderId()].fishingMonsInfo, rod);
|
||||
IncrementGameStat(GAME_STAT_FISHING_CAPTURES);
|
||||
gIsFishingEncounter = TRUE;
|
||||
StartWildBattle();
|
||||
}
|
||||
|
||||
|
|
@ -782,3 +807,15 @@ static void AddToWildEncounterRateBuff(u8 encounterRate)
|
|||
else
|
||||
sWildEncounterData.encounterRateBuff = 0;
|
||||
}
|
||||
|
||||
bool8 TryDoDoubleWildBattle(void)
|
||||
{
|
||||
if (GetSafariZoneFlag()
|
||||
|| (B_DOUBLE_WILD_REQUIRE_2_MONS == TRUE && GetMonsStateToDoubles() != PLAYER_HAS_TWO_USABLE_MONS))
|
||||
return FALSE;
|
||||
else if (B_FLAG_FORCE_DOUBLE_WILD != 0 && FlagGet(B_FLAG_FORCE_DOUBLE_WILD))
|
||||
return TRUE;
|
||||
else if (B_DOUBLE_WILD_CHANCE != 0 && ((Random() % 100) + 1 <= B_DOUBLE_WILD_CHANCE))
|
||||
return TRUE;
|
||||
return FALSE;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -62,7 +62,7 @@
|
|||
.include "src/mail.o"
|
||||
.include "src/menu_helpers.o"
|
||||
.include "src/region_map.o"
|
||||
.include "src/battle_ai_script_commands.o"
|
||||
.include "src/battle_ai_main.o"
|
||||
.include "src/fldeff_rocksmash.o"
|
||||
.include "src/field_specials.o"
|
||||
.include "src/battle_records.o"
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user